From b64dcf720205f1fe30cc630ec0e61baca7450bb4 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 7 Jun 2012 22:37:38 -0500 Subject: Change self.prefix_dir -> self.options.prefix_dir --- acprep | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/acprep b/acprep index 1118babe..a9189e32 100755 --- a/acprep +++ b/acprep @@ -390,8 +390,8 @@ class PrepareBuild(CommandLineApp): ######################################################################### def prefix_directory(self): - if self.prefix_dir: - return self.prefix_dir + if self.options.prefix_dir: + return self.options.prefix_dir else: return None @@ -399,7 +399,7 @@ class PrepareBuild(CommandLineApp): return join(os.environ['HOME'], "Products") def products_directory(self): - if not self.products_dir: + if not self.options.products_dir: products = self.default_products_directory() if not exists(products) or not isdir(products): @@ -407,15 +407,15 @@ class PrepareBuild(CommandLineApp): products = join(products, basename(self.source_dir)) - self.products_dir = products + self.options.products_dir = products - return self.products_dir + return self.options.products_dir def build_directory(self): - if not self.build_dir: - self.build_dir = join(self.products_directory(), - self.current_flavor) - return self.build_dir + if not self.options.build_dir: + self.options.build_dir = join(self.products_directory(), + self.current_flavor) + return self.optionsbuild_dir def ensure(self, dirname): if not exists(dirname): -- cgit v1.2.3 From 571d711523508168406d8e3b83dcfefd2d82dfde Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 8 Jun 2012 15:06:11 -0500 Subject: Was missing a period --- acprep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acprep b/acprep index a9189e32..4e715ee7 100755 --- a/acprep +++ b/acprep @@ -415,7 +415,7 @@ class PrepareBuild(CommandLineApp): if not self.options.build_dir: self.options.build_dir = join(self.products_directory(), self.current_flavor) - return self.optionsbuild_dir + return self.options.build_dir def ensure(self, dirname): if not exists(dirname): -- cgit v1.2.3 From 2720f7952242e3e4b27092bc53e22c4c9d0ec9c2 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 11 Jun 2012 18:57:17 -0500 Subject: Fix reference to self.options.products_dir --- acprep | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acprep b/acprep index 4e715ee7..d5cbcddc 100755 --- a/acprep +++ b/acprep @@ -399,7 +399,7 @@ class PrepareBuild(CommandLineApp): return join(os.environ['HOME'], "Products") def products_directory(self): - if not self.options.products_dir: + if not self.products_dir: products = self.default_products_directory() if not exists(products) or not isdir(products): @@ -407,9 +407,9 @@ class PrepareBuild(CommandLineApp): products = join(products, basename(self.source_dir)) - self.options.products_dir = products + self.products_dir = products - return self.options.products_dir + return self.products_dir def build_directory(self): if not self.options.build_dir: -- cgit v1.2.3 From cbf4cba18bd207917a24a8beb797ea773b3ad1ce Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 25 Jun 2012 19:10:45 -0500 Subject: Fixed a minor documentation bug --- doc/ledger3.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 30d7d5a4..bfe12a75 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -1335,7 +1335,7 @@ Or to see a particular funds expenses, the @samp{School} fund in this case: @smallexample -ledger --code-as-payee -P reg ^Expenses -- School +ledger --code-as-payee -P reg ^Expenses @School @end smallexample Both approaches yield different kinds of flexibility, depending on how -- cgit v1.2.3 From 8869566331b5b95a43214157b3dd36ce076deee3 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 27 Jun 2012 16:55:46 -0500 Subject: Fixed a subtle memory overwrite Fixes #608 --- src/xact.cc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/xact.cc b/src/xact.cc index b5cb2a38..a54da81a 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -355,14 +355,16 @@ bool xact_base_t::finalize() } } } else { - if (post->amount.has_annotation()) { - if (breakdown.amount.has_annotation()) - breakdown.amount.annotation().tag = post->amount.annotation().tag; - else - breakdown.amount.annotate - (annotation_t(none, none, post->amount.annotation().tag)); - } - post->amount = breakdown.amount; + post->amount = + breakdown.amount.has_annotation() ? + amount_t(breakdown.amount, + annotation_t(breakdown.amount.annotation().price, + breakdown.amount.annotation().date, + post->amount.has_annotation() ? + post->amount.annotation().tag : + breakdown.amount.annotation().tag, + breakdown.amount.annotation().value_expr)) : + breakdown.amount; DEBUG("xact.finalize", "added breakdown, balance = " << balance); } -- cgit v1.2.3 From 1751a8ee27107bdd1ad11417223bdd003c24363a Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 2 Jul 2012 16:45:01 -0500 Subject: Change git:// submodule URL to http:// --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 18e192aa..26e5425c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "lib/utfcpp"] path = lib/utfcpp - url = git://github.com/jwiegley/utfcpp.git + url = http://github.com/jwiegley/utfcpp.git -- cgit v1.2.3 From 628fc01962131d6429918216a6780499e6dff9dd Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 30 Jul 2012 22:32:10 -0500 Subject: Add ability to visit source line from ldg-report --- lisp/ldg-report.el | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 5a668847..29c5ce4c 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -1,3 +1,6 @@ +(eval-when-compile + (require 'cl)) + (defcustom ledger-reports '(("bal" "ledger -f %(ledger-file) bal") ("reg" "ledger -f %(ledger-file) reg") @@ -66,6 +69,7 @@ text that should replace the format specifier." 'ledger-report-kill) (define-key map [(control ?c) (control ?l) (control ?e)] 'ledger-report-edit) + (define-key map [(control ?c) (control ?c)] 'ledger-report-visit-source) (use-local-map map))) (defun ledger-report-read-name () @@ -234,7 +238,23 @@ the default." (format "Command: %s\n" cmd) (make-string (- (window-width) 1) ?=) "\n") - (shell-command cmd t nil)) + (shell-command + (concat cmd " --prepend-format='%(filename):%(beg_line):'") t nil) + (goto-char (point-min)) + (while (re-search-forward "^\\([^:]+\\)?:\\([0-9]+\\)?:" nil t) + (let ((file (match-string 1)) + (line (string-to-number (match-string 2)))) + (delete-region (match-beginning 0) (match-end 0)) + (set-text-properties (line-beginning-position) (line-end-position) + (list 'ledger-source (cons file line)))))) + +(defun ledger-report-visit-source () + (interactive) + (destructuring-bind (file . line) + (get-text-property (point) 'ledger-source) + (find-file-other-window file) + (goto-char (point-min)) + (forward-line (1- line)))) (defun ledger-report-goto () "Goto the ledger report buffer." @@ -446,3 +466,5 @@ specified line, returns nil." (if (eq (ledger-context-line-type context-info) 'entry) (ledger-context-field-value context-info 'payee) nil)))) + +(provide 'ldg-report) -- cgit v1.2.3 From e6acb5a9ccd65bd1f50f52ddc8e6d349e7dabd3a Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 30 Jul 2012 22:32:29 -0500 Subject: Require ldg-report from ldg-new (for now) --- lisp/ldg-new.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index 64377bb9..8505fe4a 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -36,6 +36,7 @@ (require 'ldg-mode) (require 'ldg-complete) (require 'ldg-state) +(require 'ldg-report) ;(autoload #'ledger-mode "ldg-mode" nil t) ;(autoload #'ledger-fully-complete-entry "ldg-complete" nil t) -- cgit v1.2.3 From d203393cab1963cbb6718aa9b3ec9880b49b139f Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 30 Jul 2012 22:35:21 -0500 Subject: Allow non-register reports to work again --- lisp/ldg-report.el | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 29c5ce4c..9a51c32c 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -238,23 +238,27 @@ the default." (format "Command: %s\n" cmd) (make-string (- (window-width) 1) ?=) "\n") - (shell-command - (concat cmd " --prepend-format='%(filename):%(beg_line):'") t nil) - (goto-char (point-min)) - (while (re-search-forward "^\\([^:]+\\)?:\\([0-9]+\\)?:" nil t) - (let ((file (match-string 1)) - (line (string-to-number (match-string 2)))) - (delete-region (match-beginning 0) (match-end 0)) - (set-text-properties (line-beginning-position) (line-end-position) - (list 'ledger-source (cons file line)))))) + (let ((register-report (string-match " reg\\(ister\\)? " cmd))) + (shell-command + (if register-report + (concat cmd " --prepend-format='%(filename):%(beg_line):'") + cmd) t nil) + (when register-report + (goto-char (point-min)) + (while (re-search-forward "^\\([^:]+\\)?:\\([0-9]+\\)?:" nil t) + (let ((file (match-string 1)) + (line (string-to-number (match-string 2)))) + (delete-region (match-beginning 0) (match-end 0)) + (set-text-properties (line-beginning-position) (line-end-position) + (list 'ledger-source (cons file line)))))))) (defun ledger-report-visit-source () (interactive) - (destructuring-bind (file . line) - (get-text-property (point) 'ledger-source) - (find-file-other-window file) - (goto-char (point-min)) - (forward-line (1- line)))) + (let ((prop (get-text-property (point) 'ledger-source))) + (destructuring-bind (file . line) prop + (find-file-other-window file) + (goto-char (point-min)) + (forward-line (1- line))))) (defun ledger-report-goto () "Goto the ledger report buffer." -- cgit v1.2.3 From 39ce225004e88d397ca3fd3ce2051d54eedaecc0 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 30 Jul 2012 23:20:55 -0500 Subject: Added a link_directories statement --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 13962647..0b6f2498 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,7 @@ find_package(Boost 1.46.0 ${BOOST_PYTHON}) include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) +link_directories(${Boost_LIBRARY_DIRS}) ######################################################################## -- cgit v1.2.3 From 14ab4f7775fe203e6e5cd2b9cb4d364c465c4e4e Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 30 Jul 2012 23:22:42 -0500 Subject: Updated to Boost 1.50 --- CMakeLists.txt | 1 + acprep | 11 +++++++---- lib/Makefile | 4 ++-- lib/build.sh | 6 +++--- tools/build.sh | 17 ++++++++++------- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b6f2498..487fe429 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,7 @@ else() set(HAVE_BOOST_PYTHON 0) endif() +# Set BOOST_ROOT to help CMake to find the right Boost version find_package(Boost 1.46.0 REQUIRED date_time filesystem system iostreams regex unit_test_framework ${BOOST_PYTHON}) diff --git a/acprep b/acprep index d5cbcddc..1c05596f 100755 --- a/acprep +++ b/acprep @@ -99,7 +99,7 @@ class CommandLineApp(object): force_exit = True # If true, always ends run() with sys.exit() log_handler = None - boost_major = "1_49" + boost_major = "1_50" options = { 'debug': False, @@ -674,14 +674,17 @@ class PrepareBuild(CommandLineApp): self.CXXFLAGS.append('-Wno-disabled-macro-expansion') if self.current_flavor == 'opt': - self.configure_args.append('-DCMAKE_CXX_FLAGS:STRING=-O4') - self.configure_args.append('-DCMAKE_CXX_LINK_FLAGS:STRING=-O4') + self.configure_args.append('-DCMAKE_CXX_FLAGS_RELEASE:STRING=-O4') + self.configure_args.append('-DCMAKE_CXX_LINK_FLAGS_RELEASE:STRING=-O4') + #else: + # self.CXXFLAGS.append('-g -O1 -faddress-sanitizer') + # self.LDFLAGS.append('-g -O1 -faddress-sanitizer') self.configure_args.append('-DCMAKE_INCLUDE_PATH:STRING=/usr/local/include;/opt/local/include') self.configure_args.append('-DCMAKE_LIBRARY_PATH:STRING=/usr/local/lib;/opt/local/lib') self.configure_args.append('-DBOOST_ROOT=/usr/local') - self.configure_args.append('-DBOOST_INCLUDEDIR=/usr/local/include/boost-1_49') + self.configure_args.append('-DBOOST_INCLUDEDIR=/usr/local/include/boost-1_50') self.configure_args.append('-DBoost_COMPILER=-clang-darwin') self.configure_args.append(self.source_dir) diff --git a/lib/Makefile b/lib/Makefile index cb05e44d..92ec38ce 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -6,7 +6,7 @@ STOW_ROOT = /usr/local/stow PRODUCTS = $(HOME)/Products GCC_VERSION = 4.7 -BOOST_VERSION = 1_49_0 +BOOST_VERSION = 1_50_0 CC = gcc-mp-$(GCC_VERSION) ifeq ($(CC),clang) @@ -27,7 +27,7 @@ BOOST_SOURCE = boost-release ifeq ($(GCC_VERSION),4.7) BOOST_DEFINES = define=_GLIBCXX__PTHREADS=1 else -BOOST_DEFINES = +BOOST_DEFINES = endif ifeq ($(CC),clang) BOOST_TOOLSET = clang diff --git a/lib/build.sh b/lib/build.sh index 28408d73..4fadccfa 100755 --- a/lib/build.sh +++ b/lib/build.sh @@ -7,11 +7,11 @@ export PATH=$PATH:/opt/local/lib/openmpi/bin cat > ~/user-config.jam <-std=c++11 /usr/local/include ; +using clang-darwin : : "/usr/local/bin/clang++" : -std=c++11 ; EOF # jww (2012-04-24): This is still linking against /usr/lib/libc++.1.dylib # instead of /usr/local/lib/libc++.1.dylib -make CXX=clang++ LD=clang++ CC=clang OPTJ=-j20 \ +make CXX=clang++ LD=clang++ CC=clang OPTJ=-j20 \ BOOST_TOOLSET=clang-darwin DIR_SUFFIX=clang31 \ - BOOST_DEFINES="-sICU_PATH=/usr/local cxxflags=\"-g -std=c++11 -nostdlibinc -I/usr/local/include -I/usr/local/include/c++/v1 -I/opt/local/include -I/usr/include -stdlib=libc++\" linkflags=\"-g -Z -L/usr/local/lib -L/opt/local/lib -L/usr/lib /usr/local/lib/libc++.dylib -stdlib=libc++\"" + BOOST_DEFINES="-sHAVE_ICONV=1 -sICONV_PATH=/usr/local -sHAVE_ICU=1 -sICU_PATH=/usr/local cxxflags=\"-g -std=c++11 $* -nostdlibinc -isystem /usr/local/include -isystem /opt/local/include -isystem /usr/local/include/c++/v1 -isystem /usr/include -stdlib=libc++\" linkflags=\"-g $* -L/usr/local/lib -L/opt/local/lib -L/usr/lib /usr/local/lib/libc++.dylib -stdlib=libc++\"" diff --git a/tools/build.sh b/tools/build.sh index 185fe791..a37b06f4 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -3,10 +3,13 @@ flavor=$1 shift 1 -time ( \ - cd ~/src/ledger ; \ - PATH=/usr/local/bin:/opt/local/bin:$PATH \ - nice -n 20 ./acprep $flavor --debug --python --doxygen make "$@" && \ - PATH=/usr/local/bin:/opt/local/bin:$PATH \ - nice -n 20 ./acprep $flavor --debug --python --doxygen check "$@" \ -) \ No newline at end of file +JOBS=-j$(sysctl -n hw.activecpu) +OPTIONS="$flavor --debug --python --doxygen $JOBS" + +time ( \ + cd ~/src/ledger ; \ + PATH=/usr/local/bin:/opt/local/bin:$PATH \ + nice -n 20 ./acprep $OPTIONS make "$@" && \ + PATH=/usr/local/bin:/opt/local/bin:$PATH \ + nice -n 20 ./acprep $OPTIONS check "$@" \ +) -- cgit v1.2.3 From 8538878d8dc685b9dd6abae91312e52b9c35bfbd Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 30 Jul 2012 23:24:15 -0500 Subject: Guard some function definitions for ASan --- src/utils.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/utils.cc b/src/utils.cc index 1a82787d..bdce009f 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -153,6 +153,8 @@ std::size_t current_memory_size() return memory_size; } +#if !defined(__has_feature) || !__has_feature(address_sanitizer) + static void trace_new_func(void * ptr, const char * which, std::size_t size) { if (! live_memory || ! memory_tracing_active) return; @@ -221,8 +223,12 @@ static void trace_delete_func(void * ptr, const char * which) memory_tracing_active = true; } +#endif // !defined(__has_feature) || !__has_feature(address_sanitizer) + } // namespace ledger +#if !defined(__has_feature) || !__has_feature(address_sanitizer) + void * operator new(std::size_t size) throw (std::bad_alloc) { void * ptr = std::malloc(size); if (DO_VERIFY() && ledger::memory_tracing_active) @@ -268,6 +274,8 @@ void operator delete[](void * ptr, const std::nothrow_t&) throw() { std::free(ptr); } +#endif // !defined(__has_feature) || !__has_feature(address_sanitizer) + namespace ledger { namespace { -- cgit v1.2.3 From f34a4e315eee54f31993432a349804ed51ea9138 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 1 Aug 2012 16:08:43 -0500 Subject: Change occurences of #+srcname to #+name --- doc/ledger3.texi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index bfe12a75..cdae6bcc 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -4183,7 +4183,7 @@ The easiest, albeit possibly less useful, way in which to use Ledger within an org file is to use a single source block to record all Ledger entries. The following is an example source block: @smallexample -#+srcname: allinone +#+name: allinone #+begin_src ledger 2010/01/01 * Starting balance assets:bank:savings £1300.00 @@ -4254,7 +4254,7 @@ placed several entries, but we could have had each entry in a separate src block. Note that all code blocks you wish to refer to later must have the :noweb yes babel header argument specified. @smallexample -#+srcname: income +#+name: income #+begin_src ledger :noweb yes 2010/01/01 * Starting balance assets:bank:savings £1300.00 @@ -4279,7 +4279,7 @@ The following entries relate to personal expenses, such as rent and food. Again, these have all been placed in a single src block but could have been done individually. @smallexample -#+srcname: expenses +#+name: expenses #+begin_src ledger :noweb yes 2010/07/23 Rent expenses:rent £500.00 @@ -4306,7 +4306,7 @@ to Ledger. This code block can now be evaluated (C-c C-c) and the results generated by incorporating the transactions referred to by the <> and <>= lines. @smallexample -#+srcname: balance +#+name: balance #+begin_src ledger :cmdline bal :noweb yes <> <> @@ -4348,7 +4348,7 @@ each monthly period (the -M argument) with a running total in the final column (which should be 0 at the end if all the entries are correct). @smallexample -#+srcname: monthlyregister +#+name: monthlyregister #+begin_src ledger :cmdline -M reg :noweb yes <> <> @@ -4372,7 +4372,7 @@ are increasing (or decreasing!). In this case, the final column will be the running total of the assets in our ledger. @smallexample -#+srcname: monthlyassetsregister +#+name: monthlyassetsregister #+begin_src ledger :cmdline -M reg assets :noweb yes <> <> -- cgit v1.2.3 From 2de6af2761672c1b0697e285de20b291a3fc3a55 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 2 Aug 2012 13:11:19 -0500 Subject: Don't use __has_feature in utils.cc --- src/utils.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils.cc b/src/utils.cc index bdce009f..e5faf184 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -153,7 +153,7 @@ std::size_t current_memory_size() return memory_size; } -#if !defined(__has_feature) || !__has_feature(address_sanitizer) +//#if !defined(__has_feature) || !__has_feature(address_sanitizer) static void trace_new_func(void * ptr, const char * which, std::size_t size) { @@ -223,11 +223,11 @@ static void trace_delete_func(void * ptr, const char * which) memory_tracing_active = true; } -#endif // !defined(__has_feature) || !__has_feature(address_sanitizer) +//#endif // !defined(__has_feature) || !__has_feature(address_sanitizer) } // namespace ledger -#if !defined(__has_feature) || !__has_feature(address_sanitizer) +//#if !defined(__has_feature) || !__has_feature(address_sanitizer) void * operator new(std::size_t size) throw (std::bad_alloc) { void * ptr = std::malloc(size); @@ -274,7 +274,7 @@ void operator delete[](void * ptr, const std::nothrow_t&) throw() { std::free(ptr); } -#endif // !defined(__has_feature) || !__has_feature(address_sanitizer) +//#endif // !defined(__has_feature) || !__has_feature(address_sanitizer) namespace ledger { -- cgit v1.2.3 From afc023406ad658f6f9a2cda69d7d6ce9492bc3af Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 2 Aug 2012 16:13:58 -0500 Subject: Always store absolute paths internally --- src/context.h | 12 ++++++------ src/textual.cc | 5 ++--- test/baseline/cmd-convert.test | 4 ++-- test/baseline/opt-file.test | 2 +- test/regress/25A099C9.test | 40 ++++++++++++++++++++-------------------- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/context.h b/src/context.h index 09734b3e..7373be39 100644 --- a/src/context.h +++ b/src/context.h @@ -112,16 +112,16 @@ inline parse_context_t open_for_reading(const path& pathname, const path& cwd) { path filename = resolve_path(pathname); - +#if BOOST_VERSION >= 104600 && BOOST_FILESYSTEM_VERSION >= 3 + filename = filesystem::absolute(filename, cwd); +#else + filename = filesystem::complete(filename, cwd); +#endif if (! exists(filename)) throw_(std::runtime_error, _f("Cannot read journal file %1%") % filename); -#if BOOST_VERSION >= 104600 && BOOST_FILESYSTEM_VERSION >= 3 - path parent(filesystem::absolute(pathname, cwd).parent_path()); -#else - path parent(filesystem::complete(pathname, cwd).parent_path()); -#endif + path parent(pathname.parent_path()); shared_ptr stream(new ifstream(filename)); parse_context_t context(stream, parent); context.pathname = filename; diff --git a/src/textual.cc b/src/textual.cc index a5ae2f68..0ead9232 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -532,9 +532,8 @@ void instance_t::option_directive(char * line) *p++ = '\0'; } - path abs_path(filesystem::absolute(context.pathname, - context.current_directory)); - if (! process_option(abs_path.string(), line + 2, *context.scope, p, line)) + if (! process_option(context.pathname.string(), line + 2, *context.scope, + p, line)) throw_(option_error, _f("Illegal option --%1%") % (line + 2)); } diff --git a/test/baseline/cmd-convert.test b/test/baseline/cmd-convert.test index 181165df..1c36d4bb 100644 --- a/test/baseline/cmd-convert.test +++ b/test/baseline/cmd-convert.test @@ -17,7 +17,7 @@ end test test -f /dev/null --input-date-format "%m/%d/%Y" convert test/baseline/cmd-convert3.dat -> 1 __ERROR__ -While parsing file "test/baseline/cmd-convert3.dat", line 1: +While parsing file "$sourcepath/test/baseline/cmd-convert3.dat", line 1: While parsing CSV line: 01/01/2011,, @@ -26,7 +26,7 @@ end test test -f /dev/null convert test/baseline/cmd-convert4.dat -> 1 __ERROR__ -While parsing file "test/baseline/cmd-convert4.dat", line 1: +While parsing file "$sourcepath/test/baseline/cmd-convert4.dat", line 1: While parsing CSV line: bogus,$10, diff --git a/test/baseline/opt-file.test b/test/baseline/opt-file.test index e01d929d..66d0ab1b 100644 --- a/test/baseline/opt-file.test +++ b/test/baseline/opt-file.test @@ -1,6 +1,6 @@ test -f opt-file-does-not-exist.dat bal -> 1 __ERROR__ -Error: Cannot read journal file "opt-file-does-not-exist.dat" +Error: Cannot read journal file "$sourcepath/opt-file-does-not-exist.dat" end test test -f test/baseline/opt-file1.dat -f test/baseline/opt-file2.dat bal diff --git a/test/regress/25A099C9.test b/test/regress/25A099C9.test index 1ef5ebef..d4eab662 100644 --- a/test/regress/25A099C9.test +++ b/test/regress/25A099C9.test @@ -1,43 +1,43 @@ test -f src/amount.h reg -> 20 __ERROR__ -While parsing file "src/amount.h", line 2: +While parsing file "$sourcepath/src/amount.h", line 2: Error: Unexpected whitespace at beginning of line -While parsing file "src/amount.h", line 33: +While parsing file "$sourcepath/src/amount.h", line 33: Error: Unexpected whitespace at beginning of line -While parsing file "src/amount.h", line 37: +While parsing file "$sourcepath/src/amount.h", line 37: Error: Unexpected whitespace at beginning of line -While parsing file "src/amount.h", line 66: +While parsing file "$sourcepath/src/amount.h", line 66: Error: No quantity specified for amount -While parsing file "src/amount.h", line 69: +While parsing file "$sourcepath/src/amount.h", line 69: Error: Unexpected whitespace at beginning of line -While parsing file "src/amount.h", line 83: +While parsing file "$sourcepath/src/amount.h", line 83: Error: Unexpected whitespace at beginning of line -While parsing file "src/amount.h", line 93: +While parsing file "$sourcepath/src/amount.h", line 93: Error: Unexpected whitespace at beginning of line -While parsing file "src/amount.h", line 99: +While parsing file "$sourcepath/src/amount.h", line 99: Error: Unexpected whitespace at beginning of line -While parsing file "src/amount.h", line 121: +While parsing file "$sourcepath/src/amount.h", line 121: Error: Unexpected whitespace at beginning of line -While parsing file "src/amount.h", line 132: +While parsing file "$sourcepath/src/amount.h", line 132: Error: Unexpected whitespace at beginning of line -While parsing file "src/amount.h", line 702: +While parsing file "$sourcepath/src/amount.h", line 702: Error: Unexpected whitespace at beginning of line -While parsing file "src/amount.h", line 732: +While parsing file "$sourcepath/src/amount.h", line 732: Error: Unexpected whitespace at beginning of line -While parsing file "src/amount.h", line 740: +While parsing file "$sourcepath/src/amount.h", line 740: Error: Unexpected whitespace at beginning of line -While parsing file "src/amount.h", line 743: +While parsing file "$sourcepath/src/amount.h", line 743: Error: Invalid date/time: line amount_t amoun -While parsing file "src/amount.h", line 749: +While parsing file "$sourcepath/src/amount.h", line 749: Error: Invalid date/time: line string amount_ -While parsing file "src/amount.h", line 755: +While parsing file "$sourcepath/src/amount.h", line 755: Error: Invalid date/time: line string amount_ -While parsing file "src/amount.h", line 761: +While parsing file "$sourcepath/src/amount.h", line 761: Error: Invalid date/time: line string amount_ -While parsing file "src/amount.h", line 767: +While parsing file "$sourcepath/src/amount.h", line 767: Error: Invalid date/time: line std::ostream& -While parsing file "src/amount.h", line 774: +While parsing file "$sourcepath/src/amount.h", line 774: Error: Invalid date/time: line std::istream& -While parsing file "src/amount.h", line 780: +While parsing file "$sourcepath/src/amount.h", line 780: Error: Unexpected whitespace at beginning of line end test -- cgit v1.2.3 From a54ee9047b11b52e6bc1edf1431d65977ea9f714 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Tue, 7 Aug 2012 15:19:59 -0500 Subject: Doc fix --- doc/ledger3.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index cdae6bcc..1ea4fd02 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -1335,7 +1335,7 @@ Or to see a particular funds expenses, the @samp{School} fund in this case: @smallexample -ledger --code-as-payee -P reg ^Expenses @School +ledger --code-as-payee -P reg ^Expenses @@School @end smallexample Both approaches yield different kinds of flexibility, depending on how -- cgit v1.2.3 From e716995311076464e65ed402a9000892e8012d2e Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 8 Aug 2012 00:34:07 -0500 Subject: Patch reports with markers to allow xact shifting --- lisp/ldg-mode.el | 4 +++- lisp/ldg-report.el | 48 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 4d13d7d2..6090a312 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -51,7 +51,9 @@ (define-key map [tab] 'pcomplete) (define-key map [(control ?i)] 'pcomplete) (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) - (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry))) + (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry)) + + (ledger-report-patch-reports (current-buffer))) (defun ledger-time-less-p (t1 t2) "Say whether time value T1 is less than time value T2." diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 9a51c32c..f9c6afca 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -231,6 +231,28 @@ the default." (ledger-reports-custom-save)) report-cmd)) +(defvar ledger-report-patch-alist nil) + +(defun ledger-report-patch-reports (buf) + (when ledger-report-patch-alist + (let ((entry (assoc (expand-file-name (buffer-file-name buf)) + ledger-report-patch-alist))) + (when entry + (dolist (b (cdr entry)) + (if (buffer-live-p b) + (with-current-buffer b + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (let ((record (get-text-property (point) 'ledger-source))) + (if (and record (not (markerp (cdr record)))) + (setcdr record (with-current-buffer buf + (save-excursion + (goto-char (point-min)) + (forward-line (cdr record)) + (point-marker)))))) + (forward-line 1)))))))))) + (defun ledger-do-report (cmd) "Run a report command line." (goto-char (point-min)) @@ -238,7 +260,8 @@ the default." (format "Command: %s\n" cmd) (make-string (- (window-width) 1) ?=) "\n") - (let ((register-report (string-match " reg\\(ister\\)? " cmd))) + (let ((register-report (string-match " reg\\(ister\\)? " cmd)) + files-in-report) (shell-command (if register-report (concat cmd " --prepend-format='%(filename):%(beg_line):'") @@ -250,15 +273,30 @@ the default." (line (string-to-number (match-string 2)))) (delete-region (match-beginning 0) (match-end 0)) (set-text-properties (line-beginning-position) (line-end-position) - (list 'ledger-source (cons file line)))))))) + (list 'ledger-source (cons file line))) + (let* ((fullpath (expand-file-name file)) + (entry (assoc fullpath ledger-report-patch-alist))) + (if entry + (nconc (cdr entry) (list (current-buffer))) + (push (cons (expand-file-name file) + (list (current-buffer))) + ledger-report-patch-alist)) + (add-to-list 'files-in-report fullpath))) + + (dolist (path files-in-report) + (let ((buf (get-file-buffer path))) + (if (and buf (buffer-live-p buf)) + (ledger-report-patch-reports buf)))))))) (defun ledger-report-visit-source () (interactive) (let ((prop (get-text-property (point) 'ledger-source))) - (destructuring-bind (file . line) prop + (destructuring-bind (file . line-or-marker) prop (find-file-other-window file) - (goto-char (point-min)) - (forward-line (1- line))))) + (if (markerp line-or-marker) + (goto-char line-or-marker) + (goto-char (point-min)) + (forward-line (1- line-or-marker)))))) (defun ledger-report-goto () "Goto the ledger report buffer." -- cgit v1.2.3 From 97693b43b54423e023091c7b866a1061b644eebc Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 9 Aug 2012 16:56:53 -0500 Subject: Resolve account.date to latest post in the account --- src/account.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/account.cc b/src/account.cc index 72709f95..8a5cdffa 100644 --- a/src/account.cc +++ b/src/account.cc @@ -380,7 +380,9 @@ expr_t::ptr_op_t account_t::lookup(const symbol_t::kind_t kind, break; case 'd': - if (fn_name == "depth") + if (fn_name == "date") + return WRAP_FUNCTOR(get_wrapper<&get_latest>); + else if (fn_name == "depth") return WRAP_FUNCTOR(get_wrapper<&get_depth>); else if (fn_name == "depth_spacer") return WRAP_FUNCTOR(get_wrapper<&get_depth_spacer>); -- cgit v1.2.3 From 6ccb5e96873716086e6d86a491df862627de5451 Mon Sep 17 00:00:00 2001 From: Hyrum Wright Date: Tue, 14 Aug 2012 01:23:04 -0400 Subject: Fix compilation warning: be sure we call the base class copy constructor. --- src/report.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/report.h b/src/report.h index 0f4fc103..4a02843e 100644 --- a/src/report.h +++ b/src/report.h @@ -123,7 +123,7 @@ public: TRACE_CTOR(report_t, "session_t&"); } report_t(const report_t& report) - : session(report.session), + : scope_t(report), session(report.session), output_stream(report.output_stream), terminus(report.terminus), budget_flags(report.budget_flags) { -- cgit v1.2.3 From 73aa585efae21cf596996f76330834a83da299ac Mon Sep 17 00:00:00 2001 From: Hyrum Wright Date: Tue, 14 Aug 2012 01:23:32 -0400 Subject: Fix compilation warning: ensure a destructor is properly defined to avoid compiler confusion. --- src/history.cc | 4 ++++ src/history.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/history.cc b/src/history.cc index 25335680..414fc15d 100644 --- a/src/history.cc +++ b/src/history.cc @@ -129,6 +129,10 @@ commodity_history_t::commodity_history_t() p_impl.reset(new commodity_history_impl_t); } +commodity_history_t::~commodity_history_t() +{ +} + void commodity_history_t::add_commodity(commodity_t& comm) { p_impl->add_commodity(comm); diff --git a/src/history.h b/src/history.h index 4362c9f9..b763cb0b 100644 --- a/src/history.h +++ b/src/history.h @@ -88,6 +88,7 @@ public: const datetime_t& oldest = datetime_t()); void print_map(std::ostream& out, const datetime_t& moment = datetime_t()); + ~commodity_history_t(); }; } // namespace ledger -- cgit v1.2.3 From bb9ba01cd2b566024055da1e352923c0f5d9037b Mon Sep 17 00:00:00 2001 From: Martin Michlmayr Date: Wed, 15 Aug 2012 12:24:32 +0100 Subject: Typo fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c914e55..e44fd7b2 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ command: sudo apt-get install build-essential cmake autopoint texinfo python-dev zlib1g-dev libbz2-dev libgmp3-dev gettext libmpfr-dev libboost-date-time1.49-dev libboost-filesystem1.49-dev - libboost-graph49-dev libboost-iostreams1.49-dev + libboost-graph1.49-dev libboost-iostreams1.49-dev libboost-python1.49-dev libboost-regex1.49-dev libboost-test1.49-dev ## Building -- cgit v1.2.3 From f01e09e5196127fa12e7291f3fc029ffa99eaef8 Mon Sep 17 00:00:00 2001 From: adamsrl Date: Wed, 22 Aug 2012 18:00:42 -0500 Subject: Created contrib/raw for examples to be shared among advanced Ledger users and made generic to enable code reuse. --- contrib/raw/README | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 contrib/raw/README diff --git a/contrib/raw/README b/contrib/raw/README new file mode 100644 index 00000000..82ae74e1 --- /dev/null +++ b/contrib/raw/README @@ -0,0 +1,5 @@ +These scripts are from my (rladams) local ledger customizations. + +They are intended as examples for features that can be made generic to benefit other Ledger users. + +As they become refined, the raw files will be removed and replaced by suitable sources in contrib. -- cgit v1.2.3 From 6de14e08677f6cb0c10c9d34c3024918bf979d68 Mon Sep 17 00:00:00 2001 From: adamsrl Date: Wed, 22 Aug 2012 18:27:23 -0500 Subject: Added raw copies of my custom ledger scripts and elisp additions. Next need to isolate features and make them more generic for reuse by other Ledger users. --- contrib/raw/GenerateLatexExpeneseReport.pl | 429 +++++++++++++++++++++++++ contrib/raw/MetadataExample.dat | 111 +++++++ contrib/raw/VerifyImages.sh | 14 + contrib/raw/dotemacs.el | 201 ++++++++++++ contrib/raw/ledger-matching.el | 212 ++++++++++++ contrib/raw/ledger-shell-environment-functions | 90 ++++++ 6 files changed, 1057 insertions(+) create mode 100755 contrib/raw/GenerateLatexExpeneseReport.pl create mode 100644 contrib/raw/MetadataExample.dat create mode 100755 contrib/raw/VerifyImages.sh create mode 100644 contrib/raw/dotemacs.el create mode 100644 contrib/raw/ledger-matching.el create mode 100644 contrib/raw/ledger-shell-environment-functions diff --git a/contrib/raw/GenerateLatexExpeneseReport.pl b/contrib/raw/GenerateLatexExpeneseReport.pl new file mode 100755 index 00000000..670d9f21 --- /dev/null +++ b/contrib/raw/GenerateLatexExpeneseReport.pl @@ -0,0 +1,429 @@ +#!/usr/bin/perl + +use warnings; +use strict; +use Getopt::Long; # Options processing +use Smart::Comments -ENV, "###"; # Ignore my dividers, and use + # Smart_Comments=1 to activate +use Cwd; +use File::Basename; +use 5.10.0; +use POSIX qw(strftime); +use Date::Calc qw(Add_Delta_Days); + +use Template; +my $TT = Template->new( { POST_CHOMP => 1 } ); + +###################################################################### +# TODO +# +# DONE Meal summaries are broken for multi-week reports + +###################################################################### +# Options + +# Is this an internal report? +my $ExpenseReportCode = undef; +my $Internal = undef; +my $SuppressMeals = 0; +my $ViewAfter = 0; +my $ImageDir = "."; +my $Anonymize = 0; +my $Help = undef; + +GetOptions( 'c' => \$Internal, + 'm' => \$SuppressMeals, + 'v' => \$ViewAfter, + 'a' => \$Anonymize, + 'I' => \$ImageDir, + 'e:s' => \$ExpenseReportCode, + 'h|help' => \$Help + ); + +# Help + +defined $Help && do { + print <" unless defined $ExpenseReportCode; + +###################################################################### +# Report items + +my @ItemizedExpenses; +my $ItemizedTotal = 0.00; + +my @ItemizedReceipts; + +my @MealsReport; + +###################################################################### +# Gather required data about this expense report from the directory name +# ie: ./AISER0015 20090419-20090425 AGIL2078 Shands HACMP/ +# +# ExpenseReportCode = AISER0015 +# DateRange = 20090419-20090425 +# ProjectCode = AGIL2078 +# Description = Shands HACMP + + +###################################################################### +# Remaining options + +# Where is the ledger binary? +my $LedgerBin = "./ledger -f ./.ledger -V"; + +# -E Show empty accounts +# -S d Sort by date +# -V Convert mileage to $ +my $LedgerOpts = "--no-color -S d"; + +my $LedgerAcct = "^Dest:Projects"; + +my $LedgerCriteria = "%" . "ER=$ExpenseReportCode"; + +# Internal report? + +if ( $Internal ) { + + # No mileage on an internal report + # $LedgerCriteria .= "&!/Mileage/"; # This shouldn't matter, just don't put metadata for ER on mileage + $LedgerAcct = "^Dest:Internal"; + +} + +my $CmdLine = "$LedgerBin reg $LedgerOpts -E \"$LedgerCriteria\" and ^Stub " + . "--format \"%(tag('ER'))~%(tag('PROJECT'))~%(tag('NOTE'))\n\""; +### $CmdLine + +my @TempLine = `$CmdLine`; + +# Match all remaining items +$TempLine[0] =~ m,^(?.*?)~ + (?.*?)~ + (?.*?)\s*$,x; + +my $ProjectCode= $+{'Project'}; +my $Description= $+{'Note'}; + +### $ExpenseReportCode +### $ProjectCode +### $Description +### $LedgerAcct +### $Internal +### $Anonymize +### $LedgerAcct +### $LedgerOpts +### $LedgerCriteria + + +###################################################################### +# Pull main ledger report of line items for the expense report +# Using ~ as a delimiter +# +# Example: +# '2009/04/25~AR:Projects:AGIL2078:PersMealsLunch~:AISER0015: PILOT 00004259 MIDWAY, FL~ 8.68~Receipts/AGIL2078/20090425_Pilot_8_68_21204.jpg\n' +# +#./ledger --no-color reg %ER=AISER0040 and ^Projects -y "%Y/%m/%d" -V --format "%(date)~%(account)~%(payee)~%(amount)~%(tag('NOTE'))\n" + +$CmdLine = "$LedgerBin reg $LedgerOpts \"$LedgerCriteria\" and \"$LedgerAcct\" " + . "-y \"%Y/%m/%d\" " + . "--format \"%(date)~%(tag('CATEGORY'))~%(payee)~%(display_amount)~%(tag('NOTE'))~%(tag('RECEIPT'))\\n\""; +### $CmdLine +my @MainReport = `$CmdLine`; + + +### MainReport: @MainReport + +# Remove any project codes and linefeeds +#map { chomp(); s/(:AISER[0-9][0-9][0-9][0-9])+://g; } @MainReport; # No need, thats now metadata + +foreach my $line (@MainReport) { ### Processing Main Report... done + + # Remove bad chars (#&) + $line =~ tr/#&//d; + + # Match all remaining items + $line =~ m,^(?[0-9]{4}/[0-9]{2}/[0-9]{2})~ + (?.*?)~ + (?.*?)~ + (?.*?)~ + (?.*?)~ + (?.*?)\s*$,x; + my %Record = %+; + + $Record{'Amount'}=~tr/$,//d; + + foreach (keys %Record) { + $Record{$_} =~ s/^\s+//g; + } + + + # Grab images from <> + my $ImageList = $Record{'Receipts'}; + $ImageList //= ''; + my @Images = split( /,/, $ImageList ); + + # Cleanup + # Take last word of account name as category + $Record{'Category'} = ( split( /:/, $Record{'Category'} ) )[-1]; + + # If no images, italicise the line item. + $Record{'Italics'} = 1; + + # Test images + foreach my $Image (@Images) { + + # Turn off italics because there is an image + $Record{'Italics'} = 0; + + if (! -r $ImageDir . "/" . $Image) { + print STDERR "Missing $ImageDir/$Image\n"; + } + } + + # Add to itemized expenses to be printed + push( @ItemizedExpenses, \%Record ); + $ItemizedTotal += $Record{'Amount'}; + + # Add to itemized reciepts for printing + push( @ItemizedReceipts, { 'Vendor' => $Record{'Vendor'}, + 'Amount' => $Record{'Amount'}, + 'Date' => $Record{'Date'}, + 'Images' => \@Images } ) + if $ImageList; + +} + +### @ItemizedExpenses + +###################################################################### +# Meals report + +# Summarize total spent on meals by day +$CmdLine = "$LedgerBin reg $LedgerOpts " + . "\"$LedgerCriteria\" and \"$LedgerAcct\" and \%CATEGORY=Meals " + . "-D -n " + . "--format \"%(account)~%(payee)~%(display_amount)~%(total)\n\" " + . "| grep -v ''"; + +### $CmdLine +my @MealsOutput = `$CmdLine`; + +### @MealsOutput + +foreach my $line (@MealsOutput) { + + # Match all remaining items + $line =~ m,^(?.*?)~ + (?.*?)~\$ + (?\s*[0-9]+\.[0-9]+)~\$ + (?.*?)\s*$,x; + my %TRecord=%+; + $TRecord{'Account'}=~s/^Projects://g; + $TRecord{'DOW'}=~s/^- //g; + + # Add to itemized expenses to be printed + push( @MealsReport, \%TRecord ); + +} + +###################################################################### +# Total by category + +$CmdLine = "$LedgerBin bal $LedgerOpts " + . "\"$LedgerCriteria\" and \"$LedgerAcct\" '--account=tag(\"CATEGORY\")' " + . "--format \"%(account)~%(display_total)\\n\""; + +### $CmdLine +my @CategoryOutput = `$CmdLine`; + +### @CategoryOutput + +my @CategoryReport; + +foreach my $line (@CategoryOutput) { + + chomp $line; + $line =~ tr/\$,//d; + + # Match all remaining items + my @Temp = split(/~/,$line); + + my %TRecord= ( 'Category' => $Temp[0], + 'Amount' => $Temp[1]); + + if ($TRecord{'Category'} eq '') { + $TRecord{'Category'} = '\\hline \\bf Total'; + } + + # Cleanup + # Take last word of account name as category + $TRecord{'Category'} = ( split( /:/, $TRecord{'Category'} ) )[0]; + + # Add to itemized expenses to be printed + push( @CategoryReport, \%TRecord ); + +} + +### @CategoryReport + + +###################################################################### +# Output +###################################################################### + +my $TTVars = { + 'Internal' => $Internal, + 'SuppressMeals' => $SuppressMeals, + 'ExpenseReportCode' => $ExpenseReportCode, + 'ProjectCode' => $ProjectCode, + 'Description' => $Description, + 'ItemizedExpenses' => \@ItemizedExpenses, + 'ItemizedTotal' => $ItemizedTotal, + 'MealsReport' => \@MealsReport, + 'CategoryReport' => \@CategoryReport, + 'ItemizedReceipts' => \@ItemizedReceipts, + 'ImageDir' => $ImageDir, + 'Anonymize' => $Anonymize +}; + +#### $TTVars + +my $LatexTemplate = <process( \$LatexTemplate, $TTVars, "./tmp/" . $LatexFN ) || do { + my $error = $TT->error(); + print "error type: ", $error->type(), "\n"; + print "error info: ", $error->info(), "\n"; + die $error; +}; + + +my $LatexOutput = `pdflatex -interaction batchmode -output-directory ./tmp "$LatexFN"`; +### $LatexOutput + + $LatexOutput = `pdflatex -interaction batchmode -output-directory ./tmp "$LatexFN"`; +### $LatexOutput + +if ($ViewAfter) { + my $ViewFN = $LatexFN; + $ViewFN =~ s/\.tex$/.pdf/; + `acroread "./tmp/$ViewFN"`; +} + diff --git a/contrib/raw/MetadataExample.dat b/contrib/raw/MetadataExample.dat new file mode 100644 index 00000000..791eaf77 --- /dev/null +++ b/contrib/raw/MetadataExample.dat @@ -0,0 +1,111 @@ +; TAG key: value + +2009/09/27 * (09/28/2009) HUDSON NEWS HOUSTN HBB HOUSTON, TX + Source:Visa -$6.55 + Projects:Meals + ; ER: AISER0033 + ; PROJECT: PROJXXXX + +2009/09/27 * (09/28/2009) PEET'S COFFEE & TEA KINGWOOD, TX + Source:Visa -$2.44 + Projects:Meals + ; ER: AISER0033 + ; PROJECT: PROJXXXX + +2009/09/28 * (09/29/2009) FUSIA NEW YORK, NY + Source:Visa -$15.25 + Projects:Meals + ; ER: AISER0033 + ; PROJECT: PROJXXXX + + +2009/09/29 * (09/30/2009) BALUCHI'S NEW YORK, NY + Source:Visa + Projects:Meals $20.00 + ; ER: AISER0033 + ; PROJECT: PROJXXXX + Internal:Travel $10.44 + ; ER: AISER0036 + ; PROJECT: Internal + + +2009/10/01 * Reimbursing AISER0036 + Bank:AISChecking + ; ER: AISER0036 + ; PROJECT: Internal + Source:Visa $10.44 + + +---------- + +$ ./ledger -Ef AISER0033.dat bal '--account=tag("ER")' + $-44.24 + $44.24 AISER0033 + 0 AISER0036 +-------------------- + 0 + +$ ./ledger -Ef AISER0033.dat bal + $-10.44 Bank:AISChecking + $10.44 Internal:Travel + $44.24 Projects:Meals + $-44.24 Source:Visa +-------------------- + 0 + +$ ./ledger -Ef AISER0033.dat bal '--account=tag("PROJECT")' + $-44.24 + 0 Internal + $44.24 PROJXXXX +-------------------- + 0 + +$ ./ledger -f AISER0033.dat reg '--account=tag("PROJECT")' +09-Sep-27 HUDSON NEWS HOUSTN .. $-6.55 $-6.55 +09-Sep-27 HUDSON NEWS HOUSTN .. PROJXXXX $6.55 0 +09-Sep-27 PEET'S COFFEE & TEA.. $-2.44 $-2.44 +09-Sep-27 PEET'S COFFEE & TEA.. PROJXXXX $2.44 0 +09-Sep-28 FUSIA NEW YORK, NY $-15.25 $-15.25 +09-Sep-28 FUSIA NEW YORK, NY PROJXXXX $15.25 0 +09-Sep-29 BALUCHI'S NEW YORK,.. $-30.44 $-30.44 +09-Sep-29 BALUCHI'S NEW YORK,.. PROJXXXX $20.00 $-10.44 +09-Sep-29 BALUCHI'S NEW YORK,.. Internal $10.44 0 +09-Oct-01 Reimbursing AISER0036 Internal $-10.44 $-10.44 +09-Oct-01 Reimbursing AISER0036 $10.44 0 + +$ ./ledger -f AISER0033.dat reg '--account=tag("ER")' +09-Sep-27 HUDSON NEWS HOUSTN .. $-6.55 $-6.55 +09-Sep-27 HUDSON NEWS HOUSTN .. AISER0033 $6.55 0 +09-Sep-27 PEET'S COFFEE & TEA.. $-2.44 $-2.44 +09-Sep-27 PEET'S COFFEE & TEA.. AISER0033 $2.44 0 +09-Sep-28 FUSIA NEW YORK, NY $-15.25 $-15.25 +09-Sep-28 FUSIA NEW YORK, NY AISER0033 $15.25 0 +09-Sep-29 BALUCHI'S NEW YORK,.. $-30.44 $-30.44 +09-Sep-29 BALUCHI'S NEW YORK,.. AISER0033 $20.00 $-10.44 +09-Sep-29 BALUCHI'S NEW YORK,.. AISER0036 $10.44 0 +09-Oct-01 Reimbursing AISER0036 AISER0036 $-10.44 $-10.44 +09-Oct-01 Reimbursing AISER0036 $10.44 0 + + +$ ./ledger -f AISER0033.dat reg %ER=AISER0033 +09-Sep-27 HUDSON NEWS HOUSTN .. Projects:Meals $6.55 $6.55 +09-Sep-27 PEET'S COFFEE & TEA.. Projects:Meals $2.44 $8.99 +09-Sep-28 FUSIA NEW YORK, NY Projects:Meals $15.25 $24.24 +09-Sep-29 BALUCHI'S NEW YORK,.. Projects:Meals $20.00 $44.24 + + +$ ./ledger -f AISER0033.dat reg %ER=AISER0036 +09-Sep-29 BALUCHI'S NEW YORK,.. Internal:Travel $10.44 $10.44 +09-Oct-01 Reimbursing AISER0036 Bank:AISChecking $-10.44 0 + +$ ./ledger -f AISER0033.dat reg %PROJECT=PROJXXXX +09-Sep-27 HUDSON NEWS HOUSTN .. Projects:Meals $6.55 $6.55 +09-Sep-27 PEET'S COFFEE & TEA.. Projects:Meals $2.44 $8.99 +09-Sep-28 FUSIA NEW YORK, NY Projects:Meals $15.25 $24.24 +09-Sep-29 BALUCHI'S NEW YORK,.. Projects:Meals $20.00 $44.24 + +$ ./ledger -f AISER0033.dat --prepend-format='%(tag("IMG")) ' reg %ER=0033 +image1.jpg 09-Sep-27 HUDSON NEWS HOUSTN .. Projects:Meals $6.55 $6.55 +image2.jpg 09-Sep-27 PEET'S COFFEE & TEA.. Projects:Meals $2.44 $8.99 +image3.jpg 09-Sep-28 FUSIA NEW YORK, NY Projects:Meals $15.25 $24.24 +image4.jpg 09-Sep-29 BALUCHI'S NEW YORK,.. Projects:Meals $20.00 $44.24 diff --git a/contrib/raw/VerifyImages.sh b/contrib/raw/VerifyImages.sh new file mode 100755 index 00000000..5975f7cf --- /dev/null +++ b/contrib/raw/VerifyImages.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +grep -h '; RECEIPT: ' \ + *.dat \ + */*.dat \ + | sed 's,\W*; RECEIPT: ,,g' \ + | tr , '\n' \ + | sort -u \ + | while read X +do + [ -f "$X" ] \ + && echo OK $X \ + || echo XX $X +done diff --git a/contrib/raw/dotemacs.el b/contrib/raw/dotemacs.el new file mode 100644 index 00000000..b270042e --- /dev/null +++ b/contrib/raw/dotemacs.el @@ -0,0 +1,201 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Ledger + +;; Maybe later add this to the expense repo once it settles +(add-to-list 'load-path "/home/adamsrl/.emacs.d/addons/ledger") + +(add-to-list 'load-path "/home/adamsrl/AdamsInfoServ/BusinessDocuments/Ledger/AdamsRussell/bin") +(autoload 'ledger-mode "ldg-new" nil t) +(add-to-list 'auto-mode-alist '("\\.dat$" . ledger-mode)) + +(add-hook 'ledger-mode-hook + (lambda () + (setq truncate-lines 1) + (url-handler-mode 1) ; Enable hyperlinks + (require 'ledger-matching) ; Requires ldg-report anyway + (load-file "/home/adamsrl/.emacs.d/addons/ledger/ldg-xact.el") + (let ((map (current-local-map))) + (define-key map (kbd "\C-c o") 'find-file-at-point) ; Open images + (define-key map (kbd "") 'ledger-expense-shortcut) + (define-key map (kbd "M-i") 'ledger-expense-internal) + (define-key map (kbd "M-o") 'ledger-expense-personal) + (define-key map (kbd "M-'") 'ledger-expense-split) + (define-key map (kbd "M-n") '(lambda () + (interactive) + (ledger-post-next-xact) + (recenter) + (when (get-buffer "*Receipt*") + (ledger-expense-show-receipt)))) + (define-key map (kbd "M-p") '(lambda () (interactive) + (ledger-post-prev-xact) + (recenter) + (when (get-buffer "*Receipt*") + (ledger-expense-show-receipt)))) + (local-unset-key [tab]) ; Ideally this turns off pcomplete + (local-unset-key [(control ?i)]) ; Ideally this turns off pcomplete + ) + + ;(defface ledger-report-face-account-ok '((t (:foreground "Cyan"))) "Derp") + ;(defface ledger-report-face-account-bad '((t (:foreground "Red"))) "Derp") + + (font-lock-add-keywords + 'ledger-mode + '(("Unassigned\\|Unknown\\|; RECEIPT:$" 0 'highlight prepend))) )) + +;; My customizations to make receipt image matching work with ledger-report mode +(add-hook 'ledger-report-mode-hook + (lambda () + (hl-line-mode 1) + (local-set-key (kbd "") 'ledger-report-visit-source) ; Make return jump to the right txn + (local-set-key (kbd "") 'ledger-report-visit-source) ; Make tab jump to the right txn + (local-set-key (kbd "n") '(lambda () + (interactive) + (save-selected-window + (next-line) + (ledger-report-visit-source)))) ; Update a txn window but keep focus + (local-set-key (kbd "p") '(lambda () + (interactive) + (save-selected-window + (previous-line) + (ledger-report-visit-source)))) ; Update a txn window but keep focus + + + (local-set-key (kbd "M-r") 'ledger-receipt-matching) ; Link receipt to current item + (local-set-key (kbd "M-l") 'ledger-matching-tie-receipt-to-txn) ; Link receipt to current item + (local-set-key (kbd "M-n") '(lambda () + (interactive) + (ledger-matching-image-offset-adjust 1))) ; Next receipt image + (local-set-key (kbd "M-p") '(lambda () + (interactive) + (ledger-matching-image-offset-adjust -1))) ; prev receipt image + (local-set-key (kbd "M-s") '(lambda () + (interactive) + (ledger-receipt-skip))) ; Skip receipt image + (local-set-key (kbd "C-c C-e") '(lambda () (interactive) + (save-selected-window + (ledger-report-visit-source) + (ledger-toggle-current-entry) ))) ; Toggle entry + )) + +(defvar *ledger-expense-shortcut-ER* + "Current expense report number, just last four digits (ie: 1234 results in AISER1234).") + +(defvar *ledger-expense-shortcut-split-ER* + "Split (ie: internal) expense report number, just last four digits (ie: 1234 results in AISER1234).") + +(defvar *ledger-expense-shortcut-Proj* "" + "Current export report project code (ie: AGIL1292)") + +(defun ledger-expense-shortcut-ER-format-specifier () *ledger-expense-shortcut-ER*) + +(defun ledger-expense-shortcut-setup (ER Split Proj) + "Sets the variables expanded into the transaction." + (interactive "MER Number (4 digit number only): \nMSplit ER Number (4 digit number only): \nMProject: ") + (setq *ledger-expense-shortcut-ER* + (concatenate 'string "AISER" ER)) + (setq *ledger-expense-shortcut-split-ER* + (concatenate 'string "AISER" Split)) + (setq *ledger-expense-shortcut-Proj* Proj) + (setq ledger-matching-project Proj) + (message "Set Proj to %s and ER to %s, split to %s" + *ledger-expense-shortcut-Proj* + *ledger-expense-shortcut-ER* + *ledger-expense-shortcut-split-ER*)) + +(defun ledger-expense-shortcut () + "Updates the ER and Project metadata with the current values of the shortcut variables." + (interactive) + (when (eq major-mode 'ledger-mode) + (if (or (eql *ledger-expense-shortcut-ER* "") + (eql *ledger-expense-shortcut-Proj* "")) + (message "Run ledger-expense-shortcut-setup first.") + (save-excursion + (search-forward "; ER:") + (kill-line nil) + (insert " " *ledger-expense-shortcut-ER*)) + (save-excursion + (search-forward "; PROJECT:") + (kill-line nil) + (insert " " *ledger-expense-shortcut-Proj*))))) + +(defun ledger-expense-split () + "Splits the current transaction between internal and projects." + (interactive) + (when (eq major-mode 'ledger-mode) ; I made this local now, should only trigger in ldg-mode + (save-excursion + (end-of-line) + (re-search-backward "^[0-9]\\{4\\}/") + (re-search-forward "^ +Dest:Projects") + (move-beginning-of-line nil) + (let ((begin (point)) + (end (re-search-forward "^$"))) + (goto-char end) + (insert (buffer-substring begin end)) + (goto-char end) + (re-search-forward "^ Dest:Projects") + (replace-match " Dest:Internal") + (re-search-forward "; ER: +[A-Za-z0-9]+") + (replace-match (concat "; ER: " *ledger-expense-shortcut-split-ER*) t) + (when (re-search-forward "; CATEGORY: Meals" (save-excursion (re-search-forward "^$")) t) + (replace-match "; CATEGORY: Travel" t)))) + (re-search-backward "^[0-9]\\{4\\}/") + (re-search-forward "^ +Dest:Projects") + (insert-string " $") )) + +(defun ledger-expense-internal () + "Makes the expense an internal one." + (interactive) + (when (eq major-mode 'ledger-mode) ; I made this local now, should only trigger in ldg-mode + (save-excursion + (end-of-line) + (re-search-backward "^[0-9]\\{4\\}/") + (let ((begin (point)) + (end (save-excursion (re-search-forward "^$")))) + (when (re-search-forward "^ Dest:Projects" end t) + (replace-match " Dest:Internal") ) + (when (re-search-forward "; CATEGORY: Meals" (save-excursion (re-search-forward "^$")) t) + (replace-match "; CATEGORY: Travel" t)))))) + +(defun ledger-expense-personal () + "Makes the expense an personal one, eliminating metadata and receipts." + (interactive) + (when (eq major-mode 'ledger-mode) ; I made this local now, should only trigger in ldg-mode + (save-excursion + (end-of-line) + (re-search-backward "^[0-9]\\{4\\}/") + (let ((begin (point)) + (end (save-excursion (re-search-forward "^$")))) + (when (re-search-forward "^ Dest:Projects" end t) + (replace-match " Other:Personal")) + (goto-char begin) + (save-excursion + (when (re-search-forward "^ +; ER:" end t) + (beginning-of-line) + (kill-line 1))) + (save-excursion + (when (re-search-forward "^ +; PROJECT:" end t) + (beginning-of-line) + (kill-line 1))) + (save-excursion + (when (re-search-forward "^ +; CATEGORY:" end t) + (beginning-of-line) + (kill-line 1))) + (save-excursion + (when (re-search-forward "^ +; RECEIPT:" end t) + (beginning-of-line) + (kill-line 1))) + (ledger-toggle-current-entry))))) + +(defun ledger-expense-show-receipt () + "Uses the Receipt buffer to show the receipt of the txn we're on." + (when (eq major-mode 'ledger-mode) ; I made this local now, should only trigger in ldg-mode + (save-excursion + (end-of-line) + (re-search-backward "^[0-9]\\{4\\}/") + (let ((begin (point)) + (end (save-excursion (re-search-forward "^$")))) + (save-excursion + (when (re-search-forward "^\\( +; RECEIPT: +\\)\\([^,]+?.jpg\\).*$" end t) + (ledger-matching-display-image + (concat "/home/adamsrl/AdamsInfoServ/BusinessDocuments/Ledger/AdamsRussell/" + (match-string 2))) )))))) diff --git a/contrib/raw/ledger-matching.el b/contrib/raw/ledger-matching.el new file mode 100644 index 00000000..d12c3937 --- /dev/null +++ b/contrib/raw/ledger-matching.el @@ -0,0 +1,212 @@ +;; This library is intended to allow me to view a receipt on one panel, and tie it to ledger transactions in another + +(require 'ldg-report) + +(defgroup ledger-matching nil + "Ledger image matching") + +(defcustom ledger-matching-sourcedir "~/AdamsInfoServ/BusinessDocuments/Ledger/Incoming" + "Source directory for images to process, ie: the incoming queue of images." + :group 'ledger-matching) + +(defcustom ledger-matching-destdir "~/AdamsInfoServ/BusinessDocuments/Ledger/AdamsRussell/Receipts" + "Destination directory for images when matched, will still have a project directory appended to it." + :group 'ledger-matching) + +(defcustom ledger-matching-relative-receipt-dir "Receipts" + "Relative directory root for destination images used in Ledger entries, will have the project directory appended and receipt filename." + :group 'ledger-matching) + +(defcustom ledger-matching-convert-binary "/usr/bin/convert" + "Path to the Imagemagick convert command." + :group 'ledger-matching) + +(defcustom ledger-matching-scale 50 + "Scaling parameter to Imagemagick's convert to resize an image for viewing." + :group 'ledger-matching) + +(defcustom ledger-matching-rotation 0 + "Rotation parameter to Imagemagick's convert to rotate an image for viewing. Images on disk should always be upright for reading." + :group 'ledger-matching) + + +(defconst ledger-matching-image-buffer "*Receipt*" + "Buffer name we load images into. Created if it doesn't exist, and persists across image loads.") + + +(defvar ledger-matching-project "Internal" + "The directory appended to the destination for the project code where receipts will be stored.") + +(defvar ledger-matching-image-offset 0 + "The index of the current file from the SORTED source directory contents.") + +(defvar ledger-matching-image-name nil + "The filename only of the current image.") + + +(defun ledger-matching-display-image (image-filename) + "Resize the image and load it into our viewing buffer." + + ;; Create our viewing buffer if needed, and set it. Do NOT switch, + ;; this buffer isn't the primary. Let the user leave it where they + ;; place it. + (unless (get-buffer ledger-matching-image-buffer) + (get-buffer-create ledger-matching-image-buffer)) + (set-buffer ledger-matching-image-buffer) + (erase-buffer) + (goto-char (point-min)) + (insert-string image-filename "\n") + + ;; Convert the source to the temporary dest applying resizing and rotation + (let* ((source (expand-file-name image-filename ledger-matching-sourcedir)) + (dest (make-temp-file "ledger-matching-" nil ".jpg")) + (result (call-process ledger-matching-convert-binary nil (get-buffer "*Messages*") nil + source + "-scale" (concat (number-to-string ledger-matching-scale) "%") + "-rotate" (number-to-string ledger-matching-rotation) + dest))) + + (if (/= 0 result) + + ;; Bomb out if the convert fails + (message "Error running convert, see *Messages* buffer for details.") + + ;; Insert scaled image into the viewing buffer, replacing + ;; current contents Temp buffer is to force sync reading into + ;; memory of the jpeg due to async race condition with display + ;; and file deletion + (let ((image (create-image (with-temp-buffer + (insert-file-contents-literally dest) + (string-as-unibyte (buffer-string))) + 'jpeg t))) + (insert-image image) + (goto-char (point-min)) + + ;; Redisplay is required to prevent a race condition between displaying the image and the deletion. Apparently its async. + ;; Either redisplay or the above string method work, both together can't hurt. + (redisplay) + )) + + ;; Delete our temporary file + (delete-file dest))) + + + +(defun ledger-matching-update-current-image () + "Grab the image from the source directory by offset and display" + + (let* ((file-listing (directory-files ledger-matching-sourcedir nil "\.jpg$" nil)) + (len (safe-length file-listing))) + + ;; Ensure our offset doesn't exceed the file list + (cond ((= len 0) + (message "No files found in source directory.")) + + ((< len 0) + (message "Error, list of files should never be negative. Epic fail.")) + + ((>= ledger-matching-image-offset len) + (message "Hit end of list. Last image.") + (setq ledger-matching-image-offset (1- len))) + + ((< ledger-matching-image-offset 0) + (message "Beginning of list. First image.") + (setq ledger-matching-image-offset 0))) + + ;; Get the name for the offset + (setq ledger-matching-image-name (nth ledger-matching-image-offset file-listing)) + + (ledger-matching-display-image ledger-matching-image-name))) + + + +(defun ledger-matching-image-offset-adjust (amount) + "Incr/decr the offset and update the receipt buffer." + + (setq ledger-matching-image-offset (+ ledger-matching-image-offset amount)) + (ledger-matching-update-current-image)) + + + +(defun ledger-receipt-matching () + "Open the receipt buffer and start with the first image." + (interactive) + (setq ledger-matching-image-offset 0) + (ledger-matching-update-current-image)) + + + +(defun ledger-matching-tie-receipt-to-txn () + (interactive) + (save-selected-window + (ledger-report-visit-source) + + ;; Assumes we're in a narrowed buffer with ONLY this txn + (backward-paragraph) + (beginning-of-line) + + ;; Update the ER and Project while I'm there + (save-excursion + (search-forward "; ER:") + (kill-line nil) + (insert " " *ledger-expense-shortcut-ER*)) + (save-excursion + (search-forward "; PROJECT:") + (kill-line nil) + (insert " " *ledger-expense-shortcut-Proj*)) + + ;; Goto the receipt line, unless their isn't one then add one + (unless (search-forward "RECEIPT:" nil t) + + ;; Still at date line if that failed + (next-line) + (newline) + (insert-string " ; RECEIPT:")) + + ;; Point immediately after : on tag + + ;; Check for existing jpg file + (if (search-forward ".jpg" (line-end-position) t) + + ;; if present make it a comma delimited list + (insert-string ",") + + ;; otherwise just add a space to pad + (insert-string " ")) + + ;; Add our relative filename as the value of the RECEIPT tag + (insert-string (concat ledger-matching-relative-receipt-dir "/" + ledger-matching-project "/" + ledger-matching-image-name)) + + ;; Create the destination project dir if it doesn't exist. + (let ((full-destination (concat ledger-matching-destdir "/" ledger-matching-project ))) + (unless (file-accessible-directory-p full-destination) + (make-directory full-destination t))) + + ;; Rename the file from the source directory to its permanent home + (rename-file (concat ledger-matching-sourcedir "/" + ledger-matching-image-name) + (concat ledger-matching-destdir "/" + ledger-matching-project "/" + ledger-matching-image-name)) + + ;; Update the receipt screen + (ledger-matching-update-current-image) )) + + + +(defun ledger-receipt-skip () + "Move the current image to the Skip directory because its not relevant." + + (rename-file (concat ledger-matching-sourcedir "/" + ledger-matching-image-name) + (concat ledger-matching-sourcedir "/Skip/" + ledger-matching-image-name)) + + ;; Update the receipt screen at the same offset + (ledger-matching-update-current-image)) + + + +(provide 'ledger-matching) diff --git a/contrib/raw/ledger-shell-environment-functions b/contrib/raw/ledger-shell-environment-functions new file mode 100644 index 00000000..7746dc41 --- /dev/null +++ b/contrib/raw/ledger-shell-environment-functions @@ -0,0 +1,90 @@ +# Environment for ledger expenses + +[ $(whoami) == "adamsrl" ] \ + && export LEDGER_HOME="/home/adamsrl/AdamsInfoServ/BusinessDocuments/Ledger/AdamsRussell" \ + || export LEDGER_HOME="/home/Heather/AdamsRussell" + +[ $(hostname) == "cardamom" ] \ + && export LEDGER_BIN="${LEDGER_HOME}/ledger" \ + || export LEDGER_BIN="${LEDGER_HOME}/ledger.exe" + +[ $(whoami) == "andersonll" ] \ + && export LEDGER_HOME="/home/andersonll/AdamsInfoServ/Expenses" \ + && export LEDGER_BIN="${LEDGER_HOME}/ledger" + +# Common reports + +alias ledger='${LEDGER_BIN} -f "${LEDGER_HOME}/.ledger" -VE ' +alias ERSummary='ledger --pivot ER bal | egrep "AIS(ER|IN)[0-9]+|Unassigned"' + +function ERTxns() { + [ -z "$1" ] && echo "Please specify an ER number (ie: AISER0042)." && return + + ledger reg "%ER=${1}" +} + +function ERCategorySummary() { + [ -z "$1" ] && echo "Please specify an ER number (ie: AISER0042)." && return + + ledger bal --pivot CATEGORY "%ER=${1}" +} + +function ERMealSummary() { + [ -z "$1" ] && echo "Please specify an ER number (ie: AISER0042)." && return + + ledger reg "%ER=${1}" and %CATEGORY=Meals -D +} + +function ERMeals() { + [ -z "$1" ] && echo "Please specify an ER number (ie: AISER0042)." && return + + ledger reg "%ER=${1}" and %CATEGORY=Meals +} + +function ERUncleared() { + [ -z "$1" ] && echo "Please specify an ER number (ie: AISER0042)." && return + + ledger reg "%ER=${1}" -U +} + +function ERMissingReceipts() { + [ -z "$1" ] && echo "Please specify an ER number (ie: AISER0042)." && return + + ledger reg "%ER=${1}" and not %RECEIPT +} + +function ERVerify() { + [ -z "$1" ] && echo "Please specify an ER number (ie: AISER0042)." && return + + echo "========== Uncleared txns below ==========" + ERUncleared "$1" + echo "========== Missing receipts below (miles and stubs ok) ==========" + ERMissingReceipts "$1" + echo "========== Category Summary (airline? mileage? car? hotel? ==========" + ERCategorySummary "$1" + echo "========== Meal summary (<\$50 / day unless otherwise specified) ==========" + ERMealSummary "$1" + echo "========== Account Verification (Internal vs Project ER should be ONE type) ==========" + echo $1 | grep AISIN >/dev/null 2>&1 \ + || { ledger reg "%ER=${1}" | grep Dest:Internal ; } \ + && { ledger reg "%ER=${1}" | grep Dest:Projects ; } + echo "========== Project Verification (only one project code should be listed) ==========" + ledger print "%ER=${1}" | grep PROJECT | sort -u + echo "========== Receipts missing ==========" + ledger print "%ER=${1}" | grep -h '; RECEIPT: ' \ + | sed 's,\W*; RECEIPT: ,,g' \ + | tr , '\n' \ + | sort -u \ + | while read X ; do + [ -f "${LEDGER_HOME}/${X}" ] \ + || echo XX $X + done +} + +function ERListing() { + ledger reg Stub --register-format="%(tag('ER')) %(tag('NOTE'))\n" | sort -u +} + +function ERQueue() { + ledger reg %ER=Unassigned --prepend-format="%(filename) " +} -- cgit v1.2.3 From 72fa58b7fb3c70444481519b53267d8ef1e01cca Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 6 Sep 2012 16:12:31 -0400 Subject: Ledger's Python API is known to work best against Python 2.7, then Python 2.6 Indeed, at the moment, it doesn't work against Python 3.x at all, so ideally, we'd like to tell CMake that no Python versions except 2.7 and 2.6 are acceptable. However, at least as of CMake 2.8.8, there appears to be no way to instruct CMake to never consider other versions of Python. In other words, Python_ADDITIONAL_VERSIONS is prepended to the list of possible Python versions considered, rather than replacing it wholly. Theoretically, we could try to diddle withe the internal CMake variables _PYTHON_FIND_OTHER_VERSIONS or _Python_VERSIONS somehow, but that seems kludgey and dangerous. This patch is probably "enough for now" to at least make sure that if the user has both Python 2.x and Python 3.x installed, some version of 2.x that is known to work will be preferred. --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 487fe429..a4109a17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ endif() find_package(PythonInterp) # Used for running tests if(USE_PYTHON) + set(Python_ADDITIONAL_VERSIONS 2.7 2.6) find_package(PythonLibs) if(PYTHONLIBS_FOUND) set(BOOST_PYTHON python) -- cgit v1.2.3 From 5b916dae6c7cac78bb4a2100d814470fb7cd5649 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 6 Sep 2012 19:25:09 -0400 Subject: Correct cmake variable for install prefix is "CMAKE_INSTALL_PREFIX", not "CMAKE_PREFIX_PATH". CMAKE_PREFIX_PATH is for searching for other programs, not for the place to install this one. Based on acprep's --help, I think the intention was to use CMAKE_INSTALL_PREFIX here. --- acprep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acprep b/acprep index 1c05596f..83ff4ab2 100755 --- a/acprep +++ b/acprep @@ -847,7 +847,7 @@ class PrepareBuild(CommandLineApp): self.options.boost_include) if self.prefix_directory(): - conf_args.append('-DCMAKE_PREFIX_PATH=%s' % self.prefix_directory()) + conf_args.append('-DCMAKE_INSTALL_PREFIX=%s' % self.prefix_directory()) return (environ, conf_args + self.configure_args) -- cgit v1.2.3 From 6fff6e993aea3b6315b0ce9e09d4d607ece99b5a Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 6 Sep 2012 19:35:21 -0400 Subject: FAQ entry on how build your own Boost and/or CMake for use with Ledger. Debian squeeze, which is currently the stable distribution at the time of this commit, has both a Boost and a CMake that is too old for Ledger. This FAQ entry explains how to build your own Boost and CMake for use with Ledger, and the exact commands to type to build and install each, and then configure, build and install Ledger against those new versions. --- README-1ST | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/README-1ST b/README-1ST index 4643d655..45e9800a 100644 --- a/README-1ST +++ b/README-1ST @@ -114,3 +114,43 @@ it's usually fairly obvious where things have gone astray. A: This can happen for the same reason as above. It can also happen if you have ICU support enabled. This is a bug I'm still trying to track down. + + ---------------------------------------------------------------------- + + - Q: My distribution has a versions of Boost and/or CMake that are too + old for Ledger. How do I build my own Boost and/or CMake binaries + that will work properly with Ledger? Thereafter, how do I configure + Ledger properly to use those newly built verisons of Boost and/or + CMake? + + A: Here's commands that one user used to make this work, for Boost + 1.51.0 on Debian GNU/Linux 6.0.x (aka Debian squeeze). It's likely + to work ok for other versions of Boost as well. YMMV on other + distributions and/or other Debian distribution versions, though. + + # Preparing and building Boost 1.51.0 + + $ cd /somewhere/you/want/to/build/boost + $ wget -N http://iweb.dl.sourceforge.net/project/boost/boost/1.51.0/boost_1_51_0.tar.bz2 + $ tar xvf boost_1_51_0.tar.bz2 + $ cd boost_1_51_0 + $ ./bootstrap.sh + $ ./b2 --build-type=complete --layout=tagged --prefix=/where/you/want/boost/installed + $ ./b2 --build-type=complete --layout=tagged --prefix=/where/you/want/boost/installed install + + # Preparing and building CMake 2.8.8 + + $ cd /somewhere/you/want/to/build/cmake + $ wget -N http://www.cmake.org/files/v2.8/cmake-2.8.8.tar.gz + $ tar xvf cmake-2.8.8.tar.gz + $ cd cmake-2.8.8 + $ ./configure --prefix=/where/you/want/cmake/installed/ + $ make + $ make install + + # Building Ledger using the CMake and/or Boost as installed above + + $ cd /path/to/ledger/sources + $ env PATH=/where/you/want/cmake/installed/bin:$PATH BOOST_ROOT=/where/you/want/boost/installed ./acprep --prefix=/where/you/want/ledger/installed --debug --python config + $ env PATH=/where/you/want/cmake/installed/bin:$PATH BOOST_ROOT=/where/you/want/boost/installed ./acprep --prefix=/where/you/want/ledger/installed --debug --python make + $ env PATH=/where/you/want/cmake/installed/bin:$PATH BOOST_ROOT=/where/you/want/boost/installed ./acprep --prefix=/where/you/want/ledger/installed --debug --python install -- cgit v1.2.3 From cd2fef1c0fbf15eb31e54d8c7d0de85a31352805 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 6 Sep 2012 19:25:09 -0400 Subject: Correct cmake variable for install prefix is "CMAKE_INSTALL_PREFIX", not "CMAKE_PREFIX_PATH". CMAKE_PREFIX_PATH is for searching for other programs, not for the place to install this one. Based on acprep's --help, I think the intention was to use CMAKE_INSTALL_PREFIX here. --- acprep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acprep b/acprep index 1c05596f..83ff4ab2 100755 --- a/acprep +++ b/acprep @@ -847,7 +847,7 @@ class PrepareBuild(CommandLineApp): self.options.boost_include) if self.prefix_directory(): - conf_args.append('-DCMAKE_PREFIX_PATH=%s' % self.prefix_directory()) + conf_args.append('-DCMAKE_INSTALL_PREFIX=%s' % self.prefix_directory()) return (environ, conf_args + self.configure_args) -- cgit v1.2.3 From 41a7184be34ea2d705f65ef41a6cb9223da9493f Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 6 Sep 2012 19:35:21 -0400 Subject: FAQ entry on how build your own Boost and/or CMake for use with Ledger. Debian squeeze, which is currently the stable distribution at the time of this commit, has both a Boost and a CMake that is too old for Ledger. This FAQ entry explains how to build your own Boost and CMake for use with Ledger, and the exact commands to type to build and install each, and then configure, build and install Ledger against those new versions. --- README-1ST | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/README-1ST b/README-1ST index 4643d655..45e9800a 100644 --- a/README-1ST +++ b/README-1ST @@ -114,3 +114,43 @@ it's usually fairly obvious where things have gone astray. A: This can happen for the same reason as above. It can also happen if you have ICU support enabled. This is a bug I'm still trying to track down. + + ---------------------------------------------------------------------- + + - Q: My distribution has a versions of Boost and/or CMake that are too + old for Ledger. How do I build my own Boost and/or CMake binaries + that will work properly with Ledger? Thereafter, how do I configure + Ledger properly to use those newly built verisons of Boost and/or + CMake? + + A: Here's commands that one user used to make this work, for Boost + 1.51.0 on Debian GNU/Linux 6.0.x (aka Debian squeeze). It's likely + to work ok for other versions of Boost as well. YMMV on other + distributions and/or other Debian distribution versions, though. + + # Preparing and building Boost 1.51.0 + + $ cd /somewhere/you/want/to/build/boost + $ wget -N http://iweb.dl.sourceforge.net/project/boost/boost/1.51.0/boost_1_51_0.tar.bz2 + $ tar xvf boost_1_51_0.tar.bz2 + $ cd boost_1_51_0 + $ ./bootstrap.sh + $ ./b2 --build-type=complete --layout=tagged --prefix=/where/you/want/boost/installed + $ ./b2 --build-type=complete --layout=tagged --prefix=/where/you/want/boost/installed install + + # Preparing and building CMake 2.8.8 + + $ cd /somewhere/you/want/to/build/cmake + $ wget -N http://www.cmake.org/files/v2.8/cmake-2.8.8.tar.gz + $ tar xvf cmake-2.8.8.tar.gz + $ cd cmake-2.8.8 + $ ./configure --prefix=/where/you/want/cmake/installed/ + $ make + $ make install + + # Building Ledger using the CMake and/or Boost as installed above + + $ cd /path/to/ledger/sources + $ env PATH=/where/you/want/cmake/installed/bin:$PATH BOOST_ROOT=/where/you/want/boost/installed ./acprep --prefix=/where/you/want/ledger/installed --debug --python config + $ env PATH=/where/you/want/cmake/installed/bin:$PATH BOOST_ROOT=/where/you/want/boost/installed ./acprep --prefix=/where/you/want/ledger/installed --debug --python make + $ env PATH=/where/you/want/cmake/installed/bin:$PATH BOOST_ROOT=/where/you/want/boost/installed ./acprep --prefix=/where/you/want/ledger/installed --debug --python install -- cgit v1.2.3 From e98fcf3cb91b60a83d7881c6310887809d2cd9ca Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 6 Sep 2012 19:48:56 -0400 Subject: contrib/non-profit-audit-reports/ directory will be a small GPLv3'd application. Upon discussion with John Wiegley on #ledger on irc.freenode.net, the following was indicated: bkuhn: as long as the GPL infection stays in contrib, I see no problem with it ... ... I got the ... answer, which is "johnw will accept GPL'd stuff in contrib/..., as long as it's careful to not cause GPL to cover the main Ledger codebase that's not in contrib/..." Therefore, the non-profit-audit-reports/ application will be licensed GPLv3-or-later. --- contrib/non-profit-audit-reports/GPLv3 | 674 +++++++++++++++++++++++++++++++ contrib/non-profit-audit-reports/LICENSE | 14 + 2 files changed, 688 insertions(+) create mode 100644 contrib/non-profit-audit-reports/GPLv3 create mode 100644 contrib/non-profit-audit-reports/LICENSE diff --git a/contrib/non-profit-audit-reports/GPLv3 b/contrib/non-profit-audit-reports/GPLv3 new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/contrib/non-profit-audit-reports/GPLv3 @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/contrib/non-profit-audit-reports/LICENSE b/contrib/non-profit-audit-reports/LICENSE new file mode 100644 index 00000000..c8c63924 --- /dev/null +++ b/contrib/non-profit-audit-reports/LICENSE @@ -0,0 +1,14 @@ +Contents under contrib/non-profit-audit-reports/ are licensed GPLv3-or-later. + +The GPLv3-or-later licensing of the contents of this directory does not, +to our knowledge and belief, impact the licensing of any other part of +Ledger. Parts of the files herein are likely derivative works of the rest +of Ledger, but these works are under this subdirectory are not, to our +knowledge, used, imported, included, copied, etc. into other parts of the +codebase. + +In short, this is a small application written to use Ledger like a +library, particularly via its Python API interface. It derives from +Ledger, but Ledger does not, to our knowledge, derive from it. + +We are not lawyers and this is not legal advice. -- cgit v1.2.3 From 7c57cf4e5409a8addc4256293b34defffd762adc Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 6 Sep 2012 19:57:22 -0400 Subject: Initial test data for the non-profit-audit-reports contrib application. The basic idea here is that given non-profit-test-data.ledger herein, there should be a script that I could run, in this fashion: $ general-ledger-report -b 2011/03/01 -e 2012/03/01 -f tests/non-profit-test-data.ledger that would generate: non-profit-test-data_chart-of-accounts.txt non-profit-test-data_general-ledger.ods Note that the ODS file currently has placeholders, as I haven't fully figured out how to use the =hyperlink() function to make relative hyperlinks. --- .../tests/non-profit-test-data.ledger | 22 +++++++++++++++++++++ .../non-profit-test-data_chart-of-accounts.txt | 4 ++++ .../tests/non-profit-test-data_general-ledger.ods | Bin 0 -> 11412 bytes 3 files changed, 26 insertions(+) create mode 100644 contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger create mode 100644 contrib/non-profit-audit-reports/tests/non-profit-test-data_chart-of-accounts.txt create mode 100644 contrib/non-profit-audit-reports/tests/non-profit-test-data_general-ledger.ods diff --git a/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger b/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger new file mode 100644 index 00000000..4eeabcf5 --- /dev/null +++ b/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger @@ -0,0 +1,22 @@ + +2010/01/01 A Donation to Project Foo + Income:Foo:Donation $-100.00 + ;INVOICE: Projects/Foo/Invoices/Invoice20110315.pdf + Assets:Checking $100.00 + + +2011/03/15 A Later Donation to Project Foo + Income:Foo:Donation $-400.00 + Assets:Checking $400.00 + +2011/04/20 (1) A Later Donation to Project Foo + Expenses:Foo:Hosting $250.00 + ;RECEIPT: Projects/Foo/Expenses/hosting/AprilHostingReceipt.pdf + Assets:Checking $-250.00 + +2011/05/10 Donation to General Fund + Income:Donation $-50.00 + ;INVOICE: Financial/Invoices/Invoice20110510.pdf + Assets:Checking $50.00 + + diff --git a/contrib/non-profit-audit-reports/tests/non-profit-test-data_chart-of-accounts.txt b/contrib/non-profit-audit-reports/tests/non-profit-test-data_chart-of-accounts.txt new file mode 100644 index 00000000..57e636b9 --- /dev/null +++ b/contrib/non-profit-audit-reports/tests/non-profit-test-data_chart-of-accounts.txt @@ -0,0 +1,4 @@ +Assets:Checking +Expenses:Foo:Hosting +Income:Donation +Income:Foo:Donation diff --git a/contrib/non-profit-audit-reports/tests/non-profit-test-data_general-ledger.ods b/contrib/non-profit-audit-reports/tests/non-profit-test-data_general-ledger.ods new file mode 100644 index 00000000..80771a6d Binary files /dev/null and b/contrib/non-profit-audit-reports/tests/non-profit-test-data_general-ledger.ods differ -- cgit v1.2.3 From 8c8973e6cbb072b64e77d3a3276177b3dff24d63 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 7 Sep 2012 12:45:07 -0400 Subject: General ledger reporting script, used for preparing a report for non-profit auditors. I developed this, and therefore have the full git commit history, in my personal "Small-Hacks" repository, which can be cloned from: git://gitorious.org/bkuhn/small-hacks.git More details on that are available by visiting: https://gitorious.org/bkuhn/small-hacks --- .../general-ledger-report.plx | 128 +++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100755 contrib/non-profit-audit-reports/general-ledger-report.plx diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx new file mode 100755 index 00000000..87706a31 --- /dev/null +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -0,0 +1,128 @@ +#!/usr/bin/perl +# general-ledger-report.plx -*- Perl -*- +# +# Script to generate a General Ledger report that accountants like +# using Ledger. +# +# Copyright (C) 2011, Bradley M. Kuhn +# +# This program gives you software freedom; you can copy, modify, convey, +# and/or redistribute it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program in a file called 'GPLv3'. If not, write to the: +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor +# Boston, MA 02110-1301, USA. + +use strict; +use warnings; + +use Math::BigFloat; +use Date::Manip; + +my $LEDGER_CMD = "/usr/bin/ledger"; + +my $ACCT_WIDTH = 75; + +sub ParseNumber($) { + $_[0] =~ s/,//g; + return Math::BigFloat->new($_[0]); +} + +Math::BigFloat->precision(-2); +my $ZERO = Math::BigFloat->new("0.00"); + +if (@ARGV < 2) { + print STDERR "usage: $0 \n"; + exit 1; +} + +my($beginDate, $endDate, @otherLedgerOpts) = @ARGV; + +my(@chartOfAccountsOpts) = ('--wide-register-format', "%150A\n", '-w', '-s', + '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg'); + +open(CHART_DATA, "-|", $LEDGER_CMD, @chartOfAccountsOpts) + or die "Unable to run $LEDGER_CMD @chartOfAccountsOpts: $!"; + +open(CHART_OUTPUT, ">", "chart-of-accounts.txt") or die "unable to write chart-of-accounts.txt: $!"; + +my @accounts; +while (my $line = ) { + chomp $line; + $line =~ s/^\s*//; $line =~ s/\s*$//; + push(@accounts, $line); + +} +close(CHART_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; + +open(CHART_OUTPUT, ">", "chart-of-accounts.txt") or die "unable to write chart-of-accounts.txt: $!"; + +my @sortedAccounts; +foreach my $acct ( + # Proper sorting for a chart of accounts + sort { + if ($a =~ /^Assets/ and $b !~ /^Assets/) { + return -1; + } elsif ($a =~ /^Liabilities/ and $b !~ /^Liabilitie/) { + return -1; + } else { + return $a cmp $b; + } + } @accounts) { + print CHART_OUTPUT "$acct\n"; + push(@sortedAccounts, $acct); +} +close(CHART_OUTPUT); die "error writing to chart-of-accounts.txt: $!" unless $? == 0; + +my $formattedEndDate = new Date::Manip::Date; +die "badly formatted end date, $endDate" if $formattedEndDate->parse($endDate); +my $oneDayLess = new Date::Manip::Delta; +die "bad one day less" if $oneDayLess->parse("- 1 day"); +$formattedEndDate = $formattedEndDate->calc($oneDayLess); +$formattedEndDate = $formattedEndDate->printf("%Y/%m/%d"); + +open(GL_TEXT_OUT, ">", "general-ledger.txt") or die "unable to write general-ledger.txt: $!"; +open(GL_CSV_OUT, ">", "general-ledger.csv") or die "unable to write general-ledger.csv: $!"; + +foreach my $acct (@sortedAccounts) { + print GL_TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; + my @acctLedgerOpts = ('--wide-register-format', + "%D %-.10C %-.80P %-.80N %18t %18T\n", '-w', '--sort', 'd', + '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); + open(GL_TEXT_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) + or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!"; + + foreach my $line () { + print GL_TEXT_OUT $line; + } + close(GL_TEXT_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; + + print GL_CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; + print GL_CSV_OUT '"DATE","CHECK NUM","NAME","MEMO","TRANSACTION AMT","RUNNING TOTAL"', "\n"; + @acctLedgerOpts = ('--wide-register-format', + '"%D","%C","%P","%N","%t","%T"\n', '-w', '--sort', 'd', + '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); + open(GL_CSV_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) + or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!"; + + foreach my $line () { + print GL_CSV_OUT $line; + } + close(GL_CSV_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; +} +close(GL_TEXT_OUT); die "error writing to general-ledger.txt: $!" unless $? == 0; +close(GL_CSV_OUT); die "error writing to general-ledger.csv: $!" unless $? == 0; +############################################################################### +# +# Local variables: +# compile-command: "perl -c general-ledger-report.plx" +# End: + -- cgit v1.2.3 From 6a104ecc3e7816bf081ccdf569c1af535c770e68 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 7 Sep 2012 12:45:29 -0400 Subject: Switch ledger binary to /usr/local/bin/ledger. --- contrib/non-profit-audit-reports/general-ledger-report.plx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 87706a31..97cf0174 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -27,7 +27,7 @@ use warnings; use Math::BigFloat; use Date::Manip; -my $LEDGER_CMD = "/usr/bin/ledger"; +my $LEDGER_CMD = "/usr/local/bin/ledger"; my $ACCT_WIDTH = 75; -- cgit v1.2.3 From 0e8a0e8fb261660154183d4b551aaeab0298a89e Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 7 Sep 2012 12:48:30 -0400 Subject: A few fixes to make this work with Ledger 3.x instead of 2.6.2 * --wide-register-format is no long an option, use -F * %D now must be %(date) --- contrib/non-profit-audit-reports/general-ledger-report.plx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 97cf0174..739f5657 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -46,7 +46,7 @@ if (@ARGV < 2) { my($beginDate, $endDate, @otherLedgerOpts) = @ARGV; -my(@chartOfAccountsOpts) = ('--wide-register-format', "%150A\n", '-w', '-s', +my(@chartOfAccountsOpts) = ('-F', "%150A\n", '-w', '-s', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg'); open(CHART_DATA, "-|", $LEDGER_CMD, @chartOfAccountsOpts) @@ -94,8 +94,8 @@ open(GL_CSV_OUT, ">", "general-ledger.csv") or die "unable to write general-ledg foreach my $acct (@sortedAccounts) { print GL_TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; - my @acctLedgerOpts = ('--wide-register-format', - "%D %-.10C %-.80P %-.80N %18t %18T\n", '-w', '--sort', 'd', + my @acctLedgerOpts = ('-F', + "%(date) %-.10C %-.80P %-.80N %18t %18T\n", '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); open(GL_TEXT_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!"; @@ -107,8 +107,8 @@ foreach my $acct (@sortedAccounts) { print GL_CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; print GL_CSV_OUT '"DATE","CHECK NUM","NAME","MEMO","TRANSACTION AMT","RUNNING TOTAL"', "\n"; - @acctLedgerOpts = ('--wide-register-format', - '"%D","%C","%P","%N","%t","%T"\n', '-w', '--sort', 'd', + @acctLedgerOpts = ('-F', + '"%(date)","%C","%P","%N","%t","%T"\n', '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); open(GL_CSV_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!"; -- cgit v1.2.3 From fb6f60477f35e883ce111ee296709493d832a2d1 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 7 Sep 2012 12:48:51 -0400 Subject: There needs to be at least 3 args here, clearly. --- contrib/non-profit-audit-reports/general-ledger-report.plx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 739f5657..d5bc1888 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -39,7 +39,7 @@ sub ParseNumber($) { Math::BigFloat->precision(-2); my $ZERO = Math::BigFloat->new("0.00"); -if (@ARGV < 2) { +if (@ARGV < 3) { print STDERR "usage: $0 \n"; exit 1; } -- cgit v1.2.3 From ca77b08fccd82f16096f6b8e1faa9ff0f4263748 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 7 Sep 2012 12:49:31 -0400 Subject: Make test data slightly more realistic. --- contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger b/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger index 4eeabcf5..6b911061 100644 --- a/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger +++ b/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger @@ -9,7 +9,7 @@ Income:Foo:Donation $-400.00 Assets:Checking $400.00 -2011/04/20 (1) A Later Donation to Project Foo +2011/04/20 (1) Baz Hosting Services, LLC Expenses:Foo:Hosting $250.00 ;RECEIPT: Projects/Foo/Expenses/hosting/AprilHostingReceipt.pdf Assets:Checking $-250.00 -- cgit v1.2.3 From 5aea0446e104b35441a270cd024b179a6fa1e231 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 7 Sep 2012 13:17:15 -0400 Subject: Don't use all caps for tags in test data. --- contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger b/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger index 6b911061..df760ac5 100644 --- a/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger +++ b/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger @@ -1,7 +1,7 @@ 2010/01/01 A Donation to Project Foo Income:Foo:Donation $-100.00 - ;INVOICE: Projects/Foo/Invoices/Invoice20110315.pdf + ;Invoice: Projects/Foo/Invoices/Invoice20110315.pdf Assets:Checking $100.00 @@ -11,12 +11,12 @@ 2011/04/20 (1) Baz Hosting Services, LLC Expenses:Foo:Hosting $250.00 - ;RECEIPT: Projects/Foo/Expenses/hosting/AprilHostingReceipt.pdf + ;Receipt: Projects/Foo/Expenses/hosting/AprilHostingReceipt.pdf Assets:Checking $-250.00 2011/05/10 Donation to General Fund Income:Donation $-50.00 - ;INVOICE: Financial/Invoices/Invoice20110510.pdf + ;Invoice: Financial/Invoices/Invoice20110510.pdf Assets:Checking $50.00 -- cgit v1.2.3 From 65e0c266bed3dd49be687471bb63b3072ad54bb7 Mon Sep 17 00:00:00 2001 From: Tom Marble Date: Fri, 7 Sep 2012 13:24:26 -0500 Subject: Changed general-ledger-report.plx to use tags for Receipt and Invoice (was %N) Added sample PDF artifacts for the example (see README) --- contrib/non-profit-audit-reports/README | 13 +++++++++++++ .../non-profit-audit-reports/general-ledger-report.plx | 3 +-- .../tests/Financial/Invoices/Invoice20110510.pdf | Bin 0 -> 13890 bytes .../tests/Financial/Invoices/Invoice20110510.txt | 5 +++++ .../Foo/Expenses/hosting/AprilHostingReceipt.pdf | Bin 0 -> 14813 bytes .../Foo/Expenses/hosting/AprilHostingReceipt.txt | 6 ++++++ 6 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 contrib/non-profit-audit-reports/README create mode 100644 contrib/non-profit-audit-reports/tests/Financial/Invoices/Invoice20110510.pdf create mode 100644 contrib/non-profit-audit-reports/tests/Financial/Invoices/Invoice20110510.txt create mode 100644 contrib/non-profit-audit-reports/tests/Projects/Foo/Expenses/hosting/AprilHostingReceipt.pdf create mode 100644 contrib/non-profit-audit-reports/tests/Projects/Foo/Expenses/hosting/AprilHostingReceipt.txt diff --git a/contrib/non-profit-audit-reports/README b/contrib/non-profit-audit-reports/README new file mode 100644 index 00000000..e2bbfc62 --- /dev/null +++ b/contrib/non-profit-audit-reports/README @@ -0,0 +1,13 @@ +README + +This document provides backround on the enclosed example + +Sample PDF files +---------------- +The sample PDF files were created as follows: + +paps --font="Courier 12" --paper letter --top-margin=18 tests/Projects/Foo/Expenses/hosting/AprilHostingReceipt.txt | ps2pdf - tests/Projects/Foo/Expenses/hosting/AprilHostingReceipt.pdf + +paps --font="Courier 12" --paper letter --top-margin=18 tests/Financial/Invoices/Invoice20110510.txt | ps2pdf - tests/Financial/Invoices/Invoice20110510.pdf + + diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index d5bc1888..aead7c3d 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -108,8 +108,7 @@ foreach my $acct (@sortedAccounts) { print GL_CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; print GL_CSV_OUT '"DATE","CHECK NUM","NAME","MEMO","TRANSACTION AMT","RUNNING TOTAL"', "\n"; @acctLedgerOpts = ('-F', - '"%(date)","%C","%P","%N","%t","%T"\n', '-w', '--sort', 'd', - '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); + '"%(date)","%C","%P","%(tag(\'Receipt\'))","%(tag(\'Invoice\'))","%t","%T"\n', '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); open(GL_CSV_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!"; diff --git a/contrib/non-profit-audit-reports/tests/Financial/Invoices/Invoice20110510.pdf b/contrib/non-profit-audit-reports/tests/Financial/Invoices/Invoice20110510.pdf new file mode 100644 index 00000000..e2e06c98 Binary files /dev/null and b/contrib/non-profit-audit-reports/tests/Financial/Invoices/Invoice20110510.pdf differ diff --git a/contrib/non-profit-audit-reports/tests/Financial/Invoices/Invoice20110510.txt b/contrib/non-profit-audit-reports/tests/Financial/Invoices/Invoice20110510.txt new file mode 100644 index 00000000..4d5fc907 --- /dev/null +++ b/contrib/non-profit-audit-reports/tests/Financial/Invoices/Invoice20110510.txt @@ -0,0 +1,5 @@ +Invoice + +Date: May 10, 2011 + +Donation to the General Fund: $50.00 diff --git a/contrib/non-profit-audit-reports/tests/Projects/Foo/Expenses/hosting/AprilHostingReceipt.pdf b/contrib/non-profit-audit-reports/tests/Projects/Foo/Expenses/hosting/AprilHostingReceipt.pdf new file mode 100644 index 00000000..8441f3e6 Binary files /dev/null and b/contrib/non-profit-audit-reports/tests/Projects/Foo/Expenses/hosting/AprilHostingReceipt.pdf differ diff --git a/contrib/non-profit-audit-reports/tests/Projects/Foo/Expenses/hosting/AprilHostingReceipt.txt b/contrib/non-profit-audit-reports/tests/Projects/Foo/Expenses/hosting/AprilHostingReceipt.txt new file mode 100644 index 00000000..e2722c45 --- /dev/null +++ b/contrib/non-profit-audit-reports/tests/Projects/Foo/Expenses/hosting/AprilHostingReceipt.txt @@ -0,0 +1,6 @@ +Baz Hosting Services, LLC + +Date: April 20, 2011 + +Charge: $250.00 + -- cgit v1.2.3 From b9e534d37200af16c473683df01cea4e823f5079 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 7 Sep 2012 14:58:36 -0400 Subject: Fixed 2010/01/01 test data and added an invoice for it. --- .../tests/Projects/Foo/Invoices/Invoice20100101.pdf | Bin 0 -> 14926 bytes .../tests/non-profit-test-data.ledger | 5 ++--- 2 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 contrib/non-profit-audit-reports/tests/Projects/Foo/Invoices/Invoice20100101.pdf diff --git a/contrib/non-profit-audit-reports/tests/Projects/Foo/Invoices/Invoice20100101.pdf b/contrib/non-profit-audit-reports/tests/Projects/Foo/Invoices/Invoice20100101.pdf new file mode 100644 index 00000000..11f6286c Binary files /dev/null and b/contrib/non-profit-audit-reports/tests/Projects/Foo/Invoices/Invoice20100101.pdf differ diff --git a/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger b/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger index df760ac5..a796258c 100644 --- a/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger +++ b/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger @@ -1,7 +1,7 @@ -2010/01/01 A Donation to Project Foo +2010/01/01 Kindly T. Donor Income:Foo:Donation $-100.00 - ;Invoice: Projects/Foo/Invoices/Invoice20110315.pdf + ;Invoice: Projects/Foo/Invoices/Invoice20100101.pdf Assets:Checking $100.00 @@ -19,4 +19,3 @@ ;Invoice: Financial/Invoices/Invoice20110510.pdf Assets:Checking $50.00 - -- cgit v1.2.3 From 7f565df353e91784cb40f0dae1f278f60b31d6e0 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 7 Sep 2012 15:04:44 -0400 Subject: Added additional transaction to test data, this one has both Receipt and Invoice. --- .../Blah/Expenses/hosting/AprilHostingReceipt.pdf | 106 +++++++++++++++++++++ .../Blah/Expenses/hosting/april-invoice.pdf | Bin 0 -> 3153 bytes .../tests/non-profit-test-data.ledger | 5 + 3 files changed, 111 insertions(+) create mode 100644 contrib/non-profit-audit-reports/tests/Projects/Blah/Expenses/hosting/AprilHostingReceipt.pdf create mode 100644 contrib/non-profit-audit-reports/tests/Projects/Blah/Expenses/hosting/april-invoice.pdf diff --git a/contrib/non-profit-audit-reports/tests/Projects/Blah/Expenses/hosting/AprilHostingReceipt.pdf b/contrib/non-profit-audit-reports/tests/Projects/Blah/Expenses/hosting/AprilHostingReceipt.pdf new file mode 100644 index 00000000..b6937670 --- /dev/null +++ b/contrib/non-profit-audit-reports/tests/Projects/Blah/Expenses/hosting/AprilHostingReceipt.pdf @@ -0,0 +1,106 @@ +%PDF-1.4 +%쏢 +5 0 obj +<> +stream +xn0E~1q#]4 @;0x؆*tQ!d_Bp:;=F&='(X}]D\+cQٲ K^jyYHTTMq> +/Contents 5 0 R +>> +endobj +3 0 obj +<< /Type /Pages /Kids [ +4 0 R +] /Count 1 +>> +endobj +1 0 obj +<> +endobj +7 0 obj +<>endobj +11 0 obj +<> +endobj +12 0 obj +<> +endobj +9 0 obj +<> +endobj +8 0 obj +<> +endobj +10 0 obj +<> +endobj +13 0 obj +<>stream + + + + + +2012-09-07T15:02:10-04:00 +2012-09-07T15:02:10-04:00 +a2ps version 4.14 + +receiptBradley M. Kuhn + + + + + +endstream +endobj +2 0 obj +<>endobj +xref +0 14 +0000000000 65535 f +0000000692 00000 n +0000002544 00000 n +0000000633 00000 n +0000000473 00000 n +0000000015 00000 n +0000000454 00000 n +0000000757 00000 n +0000000942 00000 n +0000000878 00000 n +0000001004 00000 n +0000000798 00000 n +0000000828 00000 n +0000001074 00000 n +trailer +<< /Size 14 /Root 1 0 R /Info 2 0 R +/ID [<346C5213A8B2262C0696706A70350365><346C5213A8B2262C0696706A70350365>] +>> +startxref +2736 +%%EOF diff --git a/contrib/non-profit-audit-reports/tests/Projects/Blah/Expenses/hosting/april-invoice.pdf b/contrib/non-profit-audit-reports/tests/Projects/Blah/Expenses/hosting/april-invoice.pdf new file mode 100644 index 00000000..7241909a Binary files /dev/null and b/contrib/non-profit-audit-reports/tests/Projects/Blah/Expenses/hosting/april-invoice.pdf differ diff --git a/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger b/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger index a796258c..69aeb571 100644 --- a/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger +++ b/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger @@ -19,3 +19,8 @@ ;Invoice: Financial/Invoices/Invoice20110510.pdf Assets:Checking $50.00 +2011/04/20 (2) Baz Hosting Services, LLC + Expenses:Blah:Hosting $250.00 + ;Receipt: Projects/Blah/Expenses/hosting/AprilHostingReceipt.pdf + ;Invoice: Projects/Blah/Expenses/hosting/april-invoice.pdf + Assets:Checking $-250.00 -- cgit v1.2.3 From fb601e2a656945cdd32a714b5efc9c483935c338 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 7 Sep 2012 15:06:18 -0400 Subject: Updated copyright notice to reflect reality. Both Tom and I have made copyrightable changes to this file this year. --- contrib/non-profit-audit-reports/general-ledger-report.plx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index aead7c3d..41cf0cc9 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -4,7 +4,8 @@ # Script to generate a General Ledger report that accountants like # using Ledger. # -# Copyright (C) 2011, Bradley M. Kuhn +# Copyright (C) 2011, 2012 Bradley M. Kuhn +# Copyright (C) 2012 Tom Marble # # This program gives you software freedom; you can copy, modify, convey, # and/or redistribute it under the terms of the GNU General Public License -- cgit v1.2.3 From 47130b2dfb2d2489b0dc825d43fe31c2644ac0b6 Mon Sep 17 00:00:00 2001 From: Tom Marble Date: Sat, 8 Sep 2012 00:30:37 -0500 Subject: First pass technical study of creating ODS from ledger --- contrib/non-profit-audit-reports/README | 87 + contrib/non-profit-audit-reports/csv2ods.py | 106 ++ contrib/non-profit-audit-reports/demo.sh | 43 + .../general-ledger-report.plx | 5 +- .../non-profit-audit-reports/ooolib2/__init__.py | 1987 ++++++++++++++++++++ contrib/non-profit-audit-reports/readcsv.py | 31 + 6 files changed, 2256 insertions(+), 3 deletions(-) create mode 100755 contrib/non-profit-audit-reports/csv2ods.py create mode 100755 contrib/non-profit-audit-reports/demo.sh create mode 100644 contrib/non-profit-audit-reports/ooolib2/__init__.py create mode 100755 contrib/non-profit-audit-reports/readcsv.py diff --git a/contrib/non-profit-audit-reports/README b/contrib/non-profit-audit-reports/README index e2bbfc62..b4897f21 100644 --- a/contrib/non-profit-audit-reports/README +++ b/contrib/non-profit-audit-reports/README @@ -2,6 +2,54 @@ README This document provides backround on the enclosed example +Demo +---- +To run the demo do +./demo.sh + +Which should generate the following files in tests/ + chart-of-accounts.txt + general-ledger.txt + general-ledger.csv + general-ledger.ods + +And a final, "portable" zip file with the spreadsheet in + general-ledger.zip + +It *should* be possible to copy general-ledger.zip to another system, +unzip it, open general-ledger.ods in Libre Office and have the relative +links resolve correctly. + +NOTE: Export to PDF should also work. + + +Known Dependencies +------------------ +ledger (3.0) +python (2.x) +zip +libdate-manip-perl +libmath-gmp-perl + + +Temporary Hacks +--------------- +Due to an urgent project deadline the ooolib2 directory +represents some fixes to: + http://ooolib.sourceforge.net/ + +The proper version of this library can be installed on Debian systems with +# apt-get install python-ooolib + +Compare the deltas to the current version with +# diff -u /usr/share/pyshared/ooolib/__init__.py ooolib2/__init__.py + +Note also that the csv2ods.py treats columns 4 and 5 (numbering from 1) of the csv +magically. If column 4 contains a non-empty string which is not 'Receipt' +then it is interpreted as a relative path of an artifact to link to. +Similary for column 5 and 'Invoice'. + + Sample PDF files ---------------- The sample PDF files were created as follows: @@ -11,3 +59,42 @@ paps --font="Courier 12" --paper letter --top-margin=18 tests/Projects/Foo/Expen paps --font="Courier 12" --paper letter --top-margin=18 tests/Financial/Invoices/Invoice20110510.txt | ps2pdf - tests/Financial/Invoices/Invoice20110510.pdf +Resources +--------- +ooolib + http://ooolib.sourceforge.net/ + +LIBPF + probably does not replace ooolib + http://wp.libpf.com/?p=82 + +Libre Office Calc Guide (contains function reference) + https://www.libreoffice.org/get-help/documentation/ + +Libre Office API + http://api.libreoffice.org/examples/examples.html + http://api.libreoffice.org/examples/DevelopersGuide/examples.html + +OpenOffice Developers Guide + http://wiki.openoffice.org/wiki/Documentation/DevGuide/OpenOffice.org_Developers_Guide + +Spreadsheet Documents + http://wiki.openoffice.org/wiki/Documentation/DevGuide/Spreadsheets/Spreadsheet_Documents + +How to correctly create ODF documents using zip +(Do NOT do this, use ooolib instead) + http://www.jejik.com/articles/2010/03/how_to_correctly_create_odf_documents_using_zip/ + +Line Breaks + fo:break-before="page" + http://books.evc-cit.info/oobook/ch03.html#page-content-section + +ODF Validator + http://opendocumentfellowship.com/validator + +Editing Hyperlinks + http://help.libreoffice.org/Common/Editing_Hyperlinks + +Perl OODoc +NOTE: a replacement for POD, not ooolib + http://search.cpan.org/dist/OpenOffice-OODoc/ diff --git a/contrib/non-profit-audit-reports/csv2ods.py b/contrib/non-profit-audit-reports/csv2ods.py new file mode 100755 index 00000000..c0c5c6d3 --- /dev/null +++ b/contrib/non-profit-audit-reports/csv2ods.py @@ -0,0 +1,106 @@ +#!/usr/bin/python +# csv2ods.py +# Convert example csv file to ods +# +# Copyright (c) 2012 Tom Marble +# +# This program gives you software freedom; you can copy, modify, convey, +# and/or redistribute it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program in a file called 'GPLv3'. If not, write to the: +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor +# Boston, MA 02110-1301, USA. + +import sys, os, os.path, optparse +import csv +import ooolib2 + +def err(msg): + print 'error: %s' % msg + sys.exit(1) + +def csv2ods(csvname, odsname, verbose = False): + if verbose: + print 'converting from %s to %s' % (csvname, odsname) + doc = ooolib2.Calc() + # add a pagebreak style + style = 'pagebreak' + style_pagebreak = doc.styles.get_next_style('row') + style_data = tuple([style, ('style:row-height', doc.styles.property_row_height)]) + doc.styles.style_config[style_data] = style_pagebreak + # add a currency style + style = 'currency' + style_currency = doc.styles.get_next_style('cell') + style_data = tuple([style]) + doc.styles.style_config[style_data] = style_currency + + row = 1 + csvdir = os.path.dirname(csvname) + if len(csvdir) == 0: + csvdir = '.' + csvfile = open(csvname, 'rb') + reader = csv.reader(csvfile, delimiter=',', quotechar='"') + for fields in reader: + if len(fields) > 0: + for col in range(len(fields)): + val = fields[col] + if len(val) > 0 and val[0] == '$': + doc.set_cell_value(col + 1, row, 'currency', val[1:]) + else: + if ( (col == 3) and (val != 'Receipt') and len(val) > 0) or ( (col == 4) and (val != 'Invoice') and len(val) > 0): + linkrel = '../' + val # ../ means remove the name of the *.ods + linkname = os.path.basename(val) # name is just the last component + doc.set_cell_value(col + 1, row, 'link', (linkrel, linkname)) + linkpath = csvdir + '/' + val + if verbose: + if os.path.exists(linkpath): + print 'relative link %s EXISTS at %s' % (val, linkpath) + else: + print 'relative link %s DOES NOT EXIST at %s' % (val, linkpath) + else: + doc.set_cell_value(col + 1, row, 'string', val) + else: + # enter an empty string for blank lines + doc.set_cell_value(1, row, 'string', '') + # put a pagebreak here + doc.sheets[doc.sheet_index].set_sheet_config(('row', row), style_pagebreak) + row += 1 + # save the file + doc.save(odsname) + +def main(): + program = os.path.basename(sys.argv[0]) + version = '0.1' + parser = optparse.OptionParser(usage='%prog [--help] [--verbose]', + version='%prog ' + version) + parser.add_option('-v', '--verbose', action='store_true', + dest='verbose', + help='provide extra information while processing') + parser.add_option('-c', '--csv', action='store', + help='csv file to process') + parser.add_option('-o', '--ods', action='store', + help='ods output filename') + (options, args) = parser.parse_args() + if len(args) != 0: + parser.error("not expecting extra args") + if not os.path.exists(options.csv): + err('csv does not exist: %s' % options.csv) + if not options.ods: + (root, ext) = os.path.splitext(options.csv) + options.ods = root + '.ods' + if options.verbose: + print '%s: verbose mode on' % program + print 'csv:', options.csv + print 'ods:', options.ods + csv2ods(options.csv, options.ods, options.verbose) + +if __name__ == '__main__': + main() diff --git a/contrib/non-profit-audit-reports/demo.sh b/contrib/non-profit-audit-reports/demo.sh new file mode 100755 index 00000000..6a9dcadf --- /dev/null +++ b/contrib/non-profit-audit-reports/demo.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# demo.sh +# Demonstrate a non-profit GL export and conversion to ODS + +program=$(basename $0) +dir=$(dirname $0) +cd $dir +dir=$(pwd -P) +export PYTHONPATH=$dir/ooolib2 + +getcsv=$dir/general-ledger-report.plx +csv2ods=$dir/csv2ods.py + +echo "Demonstrating ledger to ODS export in $dir/tests" +cd $dir/tests +sampledata=non-profit-test-data.ledger +echo " based on the sample data in $sampledata" + +$getcsv 2011/03/01 2012/03/01 -f $sampledata +if [ -e general-ledger.csv ]; then + echo "data was exported to: general-ledger.csv" +else + echo "error creating csv file" + exit 1 +fi + +$csv2ods --verbose --csv general-ledger.csv +if [ -e general-ledger.ods ]; then + echo "csv was converted to: general-ledger.ods" +else + echo "error creating ods file" + exit 1 +fi + +# create a portable zip file with the spreadsheet +# and the linked artifacts + +echo creating portable zipfile... +zip -r ../general-ledger.zip general-ledger.ods Financial Projects -x '*.txt' + +echo " " +echo "created general-ledger.zip" + diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 41cf0cc9..cc3dc087 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -107,9 +107,8 @@ foreach my $acct (@sortedAccounts) { close(GL_TEXT_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; print GL_CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; - print GL_CSV_OUT '"DATE","CHECK NUM","NAME","MEMO","TRANSACTION AMT","RUNNING TOTAL"', "\n"; - @acctLedgerOpts = ('-F', - '"%(date)","%C","%P","%(tag(\'Receipt\'))","%(tag(\'Invoice\'))","%t","%T"\n', '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); + print GL_CSV_OUT '"DATE","CHECK NUM","NAME","Receipt","Invoice","TRANSACTION AMT","RUNNING TOTAL"', "\n"; + @acctLedgerOpts = ('-F', '"%(date)","%C","%P","%(tag(\'Receipt\'))","%(tag(\'Invoice\'))","%t","%T"\n', '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); open(GL_CSV_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!"; diff --git a/contrib/non-profit-audit-reports/ooolib2/__init__.py b/contrib/non-profit-audit-reports/ooolib2/__init__.py new file mode 100644 index 00000000..6106fc5c --- /dev/null +++ b/contrib/non-profit-audit-reports/ooolib2/__init__.py @@ -0,0 +1,1987 @@ +"ooolib-python - Copyright (C) 2006-2009 Joseph Colton" + +# ooolib-python - Python module for creating Open Document Format documents. +# Copyright (C) 2006-2009 Joseph Colton + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +# You can contact me by email at josephcolton@gmail.com + +# Import Standard Modules +import zipfile # Needed for reading/writing documents +import time +import sys +import glob +import os +import re +import xml.parsers.expat # Needed for parsing documents + +def version_number(): + "Get the ooolib-python version number" + return "0.0.17" + +def version(): + "Get the ooolib-python version" + return "ooolib-python-%s" % version_number() + +def clean_string(data): + "Returns an XML friendly copy of the data string" + + data = unicode(data) # This line thanks to Chris Ender + + data = data.replace('&', '&') + data = data.replace("'", ''') + data = data.replace('"', '"') + data = data.replace('<', '<') + data = data.replace('>', '>') + data = data.replace('\t', '') + data = data.replace('\n', '') + return data + +class XML: + "XML Class - Used to convert nested lists into XML" + def __init__(self): + "Initialize ooolib XML instance" + pass + + def _xmldata(self, data): + datatype = data.pop(0) + datavalue = data.pop(0) + outstring = '%s' % datavalue + return outstring + + def _xmltag(self, data): + outstring = '' + # First two + datatype = data.pop(0) + dataname = data.pop(0) + outstring = '<%s' % dataname + # Element Section + element = 1 + while(data): + # elements + newdata = data.pop(0) + if (newdata[0] == 'element' and element): + newstring = self._xmlelement(newdata) + outstring = '%s %s' % (outstring, newstring) + continue + if (newdata[0] != 'element' and element): + element = 0 + outstring = '%s>' % outstring + if (newdata[0] == 'tag' or newdata[0] == 'tagline'): + outstring = '%s\n' % outstring + if (newdata[0] == 'tag'): + newstring = self._xmltag(newdata) + outstring = '%s%s' % (outstring, newstring) + continue + if (newdata[0] == 'tagline'): + newstring = self._xmltagline(newdata) + outstring = '%s%s' % (outstring, newstring) + continue + if (newdata[0] == 'data'): + newstring = self._xmldata(newdata) + outstring = '%s%s' % (outstring, newstring) + continue + if (element): + element = 0 + outstring = '%s>\n' % outstring + outstring = '%s\n' % (outstring, dataname) + return outstring + + def _xmltagline(self, data): + outstring = '' + # First two + datatype = data.pop(0) + dataname = data.pop(0) + outstring = '<%s' % dataname + # Element Section + while(data): + # elements + newdata = data.pop(0) + if (newdata[0] != 'element'): break + newstring = self._xmlelement(newdata) + outstring = '%s %s' % (outstring, newstring) + outstring = '%s/>\n' % outstring + # Non-Element Section should not exist + return outstring + + def _xmlelement(self, data): + datatype = data.pop(0) + dataname = data.pop(0) + datavalue = data.pop(0) + outstring = '%s="%s"' % (dataname, datavalue) + return outstring + + def convert(self, data): + """Convert nested lists into XML + + The convert method takes a nested lists and converts them + into XML to be used in Open Document Format documents. + There are three types of lists that are recognized at this + time. They are as follows: + + 'tag' - Tag opens a set of data that is eventually closed + with a similar tag. + List: ['tag', 'xml'] + XML: + + 'tagline' - Taglines are similar to tags, except they open + and close themselves. + List: ['tagline', 'xml'] + XML: + + 'element' - Elements are pieces of information stored in an + opening tag or tagline. + List: ['element', 'color', 'blue'] + XML: color="blue" + + 'data' - Data is plain text directly inserted into the XML + document. + List: ['data', 'hello'] + XML: hello + + Bring them all together for something like this. + + Lists: + ['tag', 'xml', ['element', 'a', 'b'], ['tagline', 'xml2'], + ['data', 'asdf']] + + XML: + asdf + """ + outlines = [] + outlines.append('') + if (type(data) == type([]) and len(data) > 0): + if data[0] == 'tag': outlines.append(self._xmltag(data)) + return outlines + +class Meta: + "Meta Data Class" + + def __init__(self, doctype, debug=False): + self.doctype = doctype + + # Set the debug mode + self.debug = debug + + # The generator should always default to the version number + self.meta_generator = version() + self.meta_title = '' + self.meta_subject = '' + self.meta_description = '' + self.meta_keywords = [] + self.meta_creator = 'ooolib-python' + self.meta_editor = '' + self.meta_user1_name = 'Info 1' + self.meta_user2_name = 'Info 2' + self.meta_user3_name = 'Info 3' + self.meta_user4_name = 'Info 4' + self.meta_user1_value = '' + self.meta_user2_value = '' + self.meta_user3_value = '' + self.meta_user4_value = '' + self.meta_creation_date = self.meta_time() + + # Parser data + self.parser_element_list = [] + self.parser_element = "" + self.parser_count = 0 + + def set_meta(self, metaname, value): + """Set meta data in your document. + + Currently implemented metaname options are as follows: + 'creator' - The document author + """ + if metaname == 'creator': self.meta_creator = value + if metaname == 'editor': self.meta_editor = value + if metaname == 'title': self.meta_title = value + if metaname == 'subject': self.meta_subject = value + if metaname == 'description': self.meta_description = value + if metaname == 'user1name': self.meta_user1_name = value + if metaname == 'user2name': self.meta_user2_name = value + if metaname == 'user3name': self.meta_user3_name = value + if metaname == 'user4name': self.meta_user4_name = value + if metaname == 'user1value': self.meta_user1_value = value + if metaname == 'user2value': self.meta_user2_value = value + if metaname == 'user3value': self.meta_user3_value = value + if metaname == 'user4value': self.meta_user4_value = value + if metaname == 'keyword': + if value not in self.meta_keywords: + self.meta_keywords.append(value) + + def get_meta_value(self, metaname): + "Get meta data value for a given metaname." + + if metaname == 'creator': return self.meta_creator + if metaname == 'editor': return self.meta_editor + if metaname == 'title': return self.meta_title + if metaname == 'subject': return self.meta_subject + if metaname == 'description': return self.meta_description + if metaname == 'user1name': return self.meta_user1_name + if metaname == 'user2name': return self.meta_user2_name + if metaname == 'user3name': return self.meta_user3_name + if metaname == 'user4name': return self.meta_user4_name + if metaname == 'user1value': return self.meta_user1_value + if metaname == 'user2value': return self.meta_user2_value + if metaname == 'user3value': return self.meta_user3_value + if metaname == 'user4value': return self.meta_user4_value + if metaname == 'keyword': return self.meta_keywords + + def meta_time(self): + "Return time string in meta data format" + t = time.localtime() + stamp = "%04d-%02d-%02dT%02d:%02d:%02d" % (t[0], t[1], t[2], t[3], t[4], t[5]) + return stamp + + def parse_start_element(self, name, attrs): + if self.debug: print '* Start element:', name + self.parser_element_list.append(name) + self.parser_element = self.parser_element_list[-1] + + # Need the meta name from the user-defined tags + if (self.parser_element == "meta:user-defined"): + self.parser_count += 1 + # Set user-defined name + self.set_meta("user%dname" % self.parser_count, attrs['meta:name']) + + # Debugging statements + if self.debug: print " List: ", self.parser_element_list + if self.debug: print " Attributes: ", attrs + + + def parse_end_element(self, name): + if self.debug: print '* End element:', name + if name != self.parser_element: + print "Tag Mismatch: '%s' != '%s'" % (name, self.parser_element) + self.parser_element_list.pop() + + # Readjust parser_element_list and parser_element + if (self.parser_element_list): + self.parser_element = self.parser_element_list[-1] + else: + self.parser_element = "" + + def parse_char_data(self, data): + if self.debug: print " Character data: ", repr(data) + + # Collect Meta data fields + if (self.parser_element == "dc:title"): + self.set_meta("title", data) + if (self.parser_element == "dc:description"): + self.set_meta("description", data) + if (self.parser_element == "dc:subject"): + self.set_meta("subject", data) + if (self.parser_element == "meta:initial-creator"): + self.set_meta("creator", data) + + # Try to maintain the same creation date + if (self.parser_element == "meta:creation-date"): + self.meta_creation_date = data + + # The user defined fields need to be kept track of, parser_count does that + if (self.parser_element == "meta:user-defined"): + self.set_meta("user%dvalue" % self.parser_count, data) + + def meta_parse(self, data): + "Parse Meta Data from a meta.xml file" + + # Debugging statements + if self.debug: + # Sometimes it helps to see the document that was read from + print data + print "\n\n\n" + + # Create parser + parser = xml.parsers.expat.ParserCreate() + # Set up parser callback functions + parser.StartElementHandler = self.parse_start_element + parser.EndElementHandler = self.parse_end_element + parser.CharacterDataHandler = self.parse_char_data + + # Actually parse the data + parser.Parse(data, 1) + + def get_meta(self): + "Generate meta.xml file data" + self.meta_date = self.meta_time() + self.data = ['tag', 'office:document-meta', + ['element', 'xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'], + ['element', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'], + ['element', 'xmlns:dc', 'http://purl.org/dc/elements/1.1/'], + ['element', 'xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'], + ['element', 'xmlns:ooo', 'http://openoffice.org/2004/office'], + ['element', 'office:version', '1.0'], + ['tag', 'office:meta', + ['tag', 'meta:generator', # Was: 'OpenOffice.org/2.0$Linux OpenOffice.org_project/680m5$Build-9011' + ['data', self.meta_generator]], # Generator is set the the ooolib-python version. + ['tag', 'dc:title', + ['data', self.meta_title]], # This data is the document title + ['tag', 'dc:description', + ['data', self.meta_description]], # This data is the document description + ['tag', 'dc:subject', + ['data', self.meta_subject]], # This data is the document subject + ['tag', 'meta:initial-creator', + ['data', self.meta_creator]], # This data is the document creator + ['tag', 'meta:creation-date', + ['data', self.meta_creation_date]], # This is the original creation date of the document + ['tag', 'dc:creator', + ['data', self.meta_editor]], # This data is the document editor + ['tag', 'dc:date', + ['data', self.meta_date]], # This is the last modified date of the document + ['tag', 'dc:language', + ['data', 'en-US']], # We will probably always use en-US for language + ['tag', 'meta:editing-cycles', + ['data', '1']], # Edit cycles will probably always be 1 for generated documents + ['tag', 'meta:editing-duration', + ['data', 'PT0S']], # Editing duration is modified - creation date + ['tag', 'meta:user-defined', + ['element', 'meta:name', self.meta_user1_name], + ['data', self.meta_user1_value]], + ['tag', 'meta:user-defined', + ['element', 'meta:name', self.meta_user2_name], + ['data', self.meta_user2_value]], + ['tag', 'meta:user-defined', + ['element', 'meta:name', self.meta_user3_name], + ['data', self.meta_user3_value]], + ['tag', 'meta:user-defined', + ['element', 'meta:name', self.meta_user4_name], + ['data', self.meta_user4_value]]]] +# ['tagline', 'meta:document-statistic', +# ['element', 'meta:table-count', len(self.sheets)], # len(self.sheets) ? +# ['element', 'meta:cell-count', '15']]]] # Not sure how to keep track + + # Generate content.xml XML data + xml = XML() + self.lines = xml.convert(self.data) + self.filedata = '\n'.join(self.lines) + # Return generated data + return self.filedata + + + +class CalcStyles: + "Calc Style Management - Used to keep track of created styles." + + def __init__(self): + self.style_config = {} + # Style Counters + self.style_table = 1 + self.style_column = 1 + self.style_row = 1 + self.style_cell = 1 + # Style Properties (Defaults) - To be used later + self.property_column_width_default = '0.8925in' # Default Column Width + self.property_row_height_default = '0.189in' # Default Row Height + # Set Defaults + self.property_column_width = '0.8925in' # Default Column Width + self.property_row_height = '0.189in' # Default Row Height + self.property_cell_bold = False # Bold off be default + self.property_cell_italic = False # Italic off be default + self.property_cell_underline = False # Underline off be default + self.property_cell_fg_color = 'default' # Text Color Default + self.property_cell_bg_color = 'default' # Cell Background Default + self.property_cell_bg_image = 'none' # Cell Background Default + self.property_cell_fontsize = '10' # Cell Font Size Default + self.property_cell_valign = 'default' # Vertial Alignment Default + self.property_cell_halign = 'default' # Horizantal Alignment Default + + def get_next_style(self, style): + "Returns the next style code for the given style" + style_code = "" + if style == 'table': + style_code = 'ta%d' % self.style_table + self.style_table+=1 + if style == 'column': + style_code = 'co%d' % self.style_column + self.style_column+=1 + if style == 'row': + style_code = 'ro%d' % self.style_row + self.style_row+=1 + if style == 'cell': + style_code = 'ce%d' % self.style_cell + self.style_cell+=1 + return style_code + + def set_property(self, style, name, value): + "Sets a property which will later be turned into a code" + if style == 'table': + pass + if style == 'column': + if name == 'style:column-width': self.property_column_width = value + if style == 'row': + if name == 'style:row-height': self.property_row_height = value + if style == 'cell': + if name == 'bold' and type(value) == type(True): self.property_cell_bold = value + if name == 'italic' and type(value) == type(True): self.property_cell_italic = value + if name == 'underline' and type(value) == type(True): self.property_cell_underline = value + if name == 'fontsize': self.property_cell_fontsize = value + if name == 'color': + self.property_cell_fg_color = 'default' + redata = re.search("^(#[\da-fA-F]{6})$", value) + if redata: self.property_cell_fg_color = value.lower() + if name == 'background': + self.property_cell_bg_color = 'default' + redata = re.search("^(#[\da-fA-F]{6})$", value) + if redata: self.property_cell_bg_color = value.lower() + if name == 'backgroundimage': + self.property_cell_bg_image = value + if name == 'valign': + self.property_cell_valign = value + if name == 'halign': + self.property_cell_halign = value + + def get_style_code(self, style): + style_code = "" + if style == 'table': + style_code = "ta1" + if style == 'column': + style_data = tuple([style, + ('style:column-width', self.property_column_width)]) + if style_data in self.style_config: + # Style Exists, return code + style_code = self.style_config[style_data] + else: + # Style does not exist, create code and return it + style_code = self.get_next_style(style) + self.style_config[style_data] = style_code + if style == 'row': + style_data = tuple([style, + ('style:row-height', self.property_row_height)]) + if style_data in self.style_config: + # Style Exists, return code + style_code = self.style_config[style_data] + else: + # Style does not exist, create code and return it + style_code = self.get_next_style(style) + self.style_config[style_data] = style_code + if style == 'cell': + style_data = [style] + # Add additional styles + if self.property_cell_bold: style_data.append(('bold', True)) + if self.property_cell_italic: style_data.append(('italic', True)) + if self.property_cell_underline: style_data.append(('underline', True)) + if self.property_cell_fontsize != '10': + style_data.append(('fontsize', self.property_cell_fontsize)) + if self.property_cell_fg_color != 'default': + style_data.append(('color', self.property_cell_fg_color)) + if self.property_cell_bg_color != 'default': + style_data.append(('background', self.property_cell_bg_color)) + if self.property_cell_bg_image != 'none': + style_data.append(('backgroundimage', self.property_cell_bg_image)) + if self.property_cell_valign != 'default': + style_data.append(('valign', self.property_cell_valign)) + if self.property_cell_halign != 'default': + style_data.append(('halign', self.property_cell_halign)) + + style_data = tuple(style_data) + if style_data in self.style_config: + # Style Exists, return code + style_code = self.style_config[style_data] + else: + # Style does not exist, create code and return it + style_code = self.get_next_style(style) + self.style_config[style_data] = style_code + return style_code + + def get_automatic_styles(self): + "Return 'office:automatic-styles' lists" + automatic_styles = ['tag', 'office:automatic-styles'] + + for style_data in self.style_config: + style_code = self.style_config[style_data] + style_data = list(style_data) + style = style_data.pop(0) + + if style == 'column': + style_list = ['tag', 'style:style', + ['element', 'style:name', style_code], # Column 'co1' properties + ['element', 'style:family', 'table-column']] + tagline = ['tagline', 'style:table-column-properties', + ['element', 'fo:break-before', 'auto']] # unsure what break before means + + for set in style_data: + name, value = set + if name == 'style:column-width': + tagline.append(['element', 'style:column-width', value]) + style_list.append(tagline) + automatic_styles.append(style_list) + + if style == 'row': + style_list = ['tag', 'style:style', + ['element', 'style:name', style_code], # Column 'ro1' properties + ['element', 'style:family', 'table-row']] + tagline = ['tagline', 'style:table-row-properties'] + + for set in style_data: + name, value = set + if name == 'style:row-height': + tagline.append(['element', 'style:row-height', value]) + tagline.append(['element', 'fo:break-before', 'auto']) +# tagline.append(['element', 'style:use-optimal-row-height', 'true']) # Overrides settings + style_list.append(tagline) + automatic_styles.append(style_list) + + if style == 'pagebreak': + style_list = ['tag', 'style:style', + ['element', 'style:name', style_code], # Column 'ro1' properties + ['element', 'style:family', 'table-row']] + tagline = ['tagline', 'style:table-row-properties'] + + for set in style_data: + name, value = set + if name == 'style:row-height': + tagline.append(['element', 'style:row-height', value]) + tagline.append(['element', 'fo:break-before', 'page']) +# tagline.append(['element', 'style:use-optimal-row-height', 'true']) # Overrides settings + style_list.append(tagline) + automatic_styles.append(style_list) + + if style == 'cell': + style_list = ['tag', 'style:style', + ['element', 'style:name', style_code], # ce1 style + ['element', 'style:family', 'table-cell'], # cell + ['element', 'style:parent-style-name', 'Default']] # parent is Default + # hack for currency + if style_code == 'ce1': + style_list.append(['element', + 'style:data-style-name', + 'N104']) + + # Cell Properties + tagline = ['tag', 'style:table-cell-properties'] + tagline_additional = [] + for set in style_data: + name, value = set + if name == 'background': + tagline.append(['element', 'fo:background-color', value]) + if name == 'backgroundimage': + tagline.append(['element', 'fo:background-color', 'transparent']) + # Additional tags added later + bgimagetag = ['tagline', 'style:background-image'] + bgimagetag.append(['element', 'xlink:href', value]) + bgimagetag.append(['element', 'xlink:type', 'simple']) + bgimagetag.append(['element', 'xlink:actuate', 'onLoad']) + tagline_additional.append(bgimagetag) + if name == 'valign': + if value in ['top', 'bottom', 'middle']: + tagline.append(['element', 'style:vertical-align', value]) + if name == 'halign': + tagline.append(['element', 'style:text-align-source', 'fix']) + if value in ['filled']: + tagline.append(['element', 'style:repeat-content', 'true']) + else: + tagline.append(['element', 'style:repeat-content', 'false']) + + # Add any additional internal tags + while tagline_additional: + tagadd = tagline_additional.pop(0) + tagline.append(tagadd) + + style_list.append(tagline) + + # Paragraph Properties + tagline = ['tagline', 'style:paragraph-properties'] + tagline_valid = False + for set in style_data: + name, value = set + if name == 'halign': + tagline_valid = True + if value in ['center']: + tagline.append(['element', 'fo:text-align', 'center']) + if value in ['end', 'right']: + tagline.append(['element', 'fo:text-align', 'end']) + if value in ['start', 'filled', 'left']: + tagline.append(['element', 'fo:text-align', 'start']) + if value in ['justify']: + tagline.append(['element', 'fo:text-align', 'justify']) + # Conditionally add the tagline + if tagline_valid: style_list.append(tagline) + + + # Text Properties + tagline = ['tagline', 'style:text-properties'] + for set in style_data: + name, value = set + if name == 'bold': + tagline.append(['element', 'fo:font-weight', 'bold']) + if name == 'italic': + tagline.append(['element', 'fo:font-style', 'italic']) + if name == 'underline': + tagline.append(['element', 'style:text-underline-style', 'solid']) + tagline.append(['element', 'style:text-underline-width', 'auto']) + tagline.append(['element', 'style:text-underline-color', 'font-color']) + if name == 'color': + tagline.append(['element', 'fo:color', value]) + if name == 'fontsize': + tagline.append(['element', 'fo:font-size', '%spt' % value]) + style_list.append(tagline) + + automatic_styles.append(style_list) + + + # Attach ta1 style + automatic_styles.append(['tag', 'style:style', + ['element', 'style:name', 'ta1'], + ['element', 'style:family', 'table'], + ['element', 'style:master-page-name', 'Default'], + ['tagline', 'style:table-properties', + ['element', 'table:display', 'true'], + ['element', 'style:writing-mode', 'lr-tb']]]) + + + return automatic_styles + + + +class CalcSheet: + "Calc Sheet Class - Used to keep track of the data for an individual sheet." + + def __init__(self, sheetname): + "Initialize a sheet" + self.sheet_name = sheetname + self.sheet_values = {} + self.sheet_config = {} + self.max_col = 0 + self.max_row = 0 + + def get_sheet_dimensions(self): + "Returns the max column and row" + return (self.max_col, self.max_row) + + def clean_formula(self, data): + "Returns a formula for use in ODF" + # Example Translations + # '=SUM(A1:A2)' + # datavalue = 'oooc:=SUM([.A1:.A2])' + # '=IF((A5>A4);A4;"")' + # datavalue = 'oooc:=IF(([.A5]>[.A4]);[.A4];"")' + data = str(data) + data = clean_string(data) + redata = re.search('^=([A-Z]+)(\(.*)$', data) + if redata: + # funct is the function name. The rest if the string will be the functArgs + funct = redata.group(1) + functArgs = redata.group(2) + # Search for cell lebels and replace them + reList = re.findall('([A-Z]+\d+)', functArgs) + # sort and keep track so we do not do a cell more than once + reList.sort() + lastVar = '' + while reList: + # Replace each cell label + curVar = reList.pop() + if curVar == lastVar: continue + lastVar = curVar + functArgs = functArgs.replace(curVar, '[.%s]' % curVar) + data = 'oooc:=%s%s' % (funct, functArgs) + return data + + def get_name(self): + "Returns the sheet name" + return self.sheet_name + + def set_name(self, sheetname): + "Resets the sheet name" + self.sheet_name = sheetname + + def get_sheet_values(self): + "Returns the sheet cell values" + return self.sheet_values + + def get_sheet_value(self, col, row): + "Get the value contents of a cell" + cell = (col, row) + if cell in self.sheet_values: + return self.sheet_values[cell] + else: + return None + + def get_sheet_config(self): + "Returns the sheet cell properties" + return self.sheet_config + + def set_sheet_config(self, location, style_code): + "Sets Style Code for a given location" + self.sheet_config[location] = style_code + + def set_sheet_value(self, cell, datatype, datavalue): + """Sets the value for a specific cell + + cell must be in the format (col, row) where row and col are int. + Example: B5 would be written as (2, 5) + datatype must be one of 'string', 'float', 'formula', 'currency' + datavalue should be a string + """ + # Catch invalid data + if type(cell) != type(()) or len(cell) != 2: + print "Invalid Cell" + return + (col, row) = cell + if type(col) != type(1): + print "Invalid Cell" + return + if type(row) != type(1): + print "Invalid Cell" + return + # Fix String Data + if datatype in ['string', 'annotation']: + datavalue = clean_string(datavalue) + # Fix Link Data. Link's value is a tuple containing (url, description) + if (datatype == 'link'): + url = clean_string(datavalue[0]) + desc = clean_string(datavalue[1]) + datavalue = (url, desc) + # Fix Formula Data + if datatype == 'formula': + datavalue = self.clean_formula(datavalue) + # Adjust maximum sizes + if col > self.max_col: self.max_col = col + if row > self.max_row: self.max_row = row + datatype = str(datatype) + if (datatype not in ['string', 'float', 'currency', 'formula', 'annotation', 'link']): + # Set all unknown cell types to string + datatype = 'string' + datavalue = str(datavalue) + + # The following lines are taken directly from HPS + # self.sheet_values[cell] = (datatype, datavalue) + # HPS: Cell content is now a list of tuples instead of a tuple + # While storing here, store the cell contents first and the annotation next. While generating the XML reverse this + contents = self.sheet_values.get(cell, {'annotation':None,'link':None, 'value':None}) + if datatype == 'annotation': + contents['annotation'] = (datatype, datavalue) + elif datatype == 'link': + contents['link'] = (datatype, datavalue) + else: + contents['value'] = (datatype, datavalue) + + self.sheet_values[cell] = contents + + + def get_lists(self): + "Returns nested lists for XML processing" + if (self.max_col == 0 and self.max_row == 0): + sheet_lists = ['tag', 'table:table', + ['element', 'table:name', self.sheet_name], # Set the Sheet Name + ['element', 'table:style-name', 'ta1'], + ['element', 'table:print', 'false'], + ['tagline', 'table:table-column', + ['element', 'table:style-name', 'co1'], + ['element', 'table:default-cell-style-name', 'Default']], + ['tag', 'table:table-row', + ['element', 'table:style-name', 'ro1'], + ['tagline', 'table:table-cell']]] + else: + # Base Information + sheet_lists = ['tag', 'table:table', + ['element', 'table:name', self.sheet_name], # Set the sheet name + ['element', 'table:style-name', 'ta1'], + ['element', 'table:print', 'false']] + +# ['tagline', 'table:table-column', +# ['element', 'table:style-name', 'co1'], +# ['element', 'table:number-columns-repeated', self.max_col], # max_col? '2' +# ['element', 'table:default-cell-style-name', 'Default']], + + # Need to add column information + for col in range(1, self.max_col+1): + location = ('col', col) + style_code = 'co1' + if location in self.sheet_config: + style_code = self.sheet_config[location] + sheet_lists.append(['tagline', 'table:table-column', + ['element', 'table:style-name', style_code], + ['element', 'table:default-cell-style-name', 'Default']]) + + + # Need to create each row + for row in range(1, self.max_row + 1): + location = ('row', row) + style_code = 'ro1' + if location in self.sheet_config: + style_code = self.sheet_config[location] + rowlist = ['tag', 'table:table-row', + ['element', 'table:style-name', style_code]] + for col in range(1, self.max_col + 1): + cell = (col, row) + style_code = 'ce1' # Default all cells to ce1 + if cell in self.sheet_config: + style_code = self.sheet_config[cell] # Lookup cell if available + if cell in self.sheet_values: + # (datatype, datavalue) = self.sheet_values[cell] # Marked for removal + collist = ['tag', 'table:table-cell'] + if style_code != 'ce1': + collist.append(['element', 'table:style-name', style_code]) + + # Contents, annotations, and links added by HPS + contents = self.sheet_values[cell] # cell contents is a dictionary + if contents['value']: + (datatype, datavalue) = contents['value'] + if datatype == 'float': + collist.append(['element', 'office:value-type', datatype]) + collist.append(['element', 'office:value', datavalue]) + if datatype == 'currency': + collist.append(['element', 'table:style-name', "ce1"]) + collist.append(['element', 'office:value-type', datatype]) + collist.append(['element', 'office:currency', 'USD']) + collist.append(['element', 'office:value', datavalue]) + + if datatype == 'string': + collist.append(['element', 'office:value-type', datatype]) + if datatype == 'formula': + collist.append(['element', 'table:formula', datavalue]) + collist.append(['element', 'office:value-type', 'float']) + collist.append(['element', 'office:value', '0']) + datavalue = '0' + else: + datavalue = None + + if contents['annotation']: + (annotype, annoval) = contents['annotation'] + collist.append(['tag', 'office:annotation', + ['tag', 'text:p', ['data', annoval]]]) + + if contents['link']: + (linktype, linkval) = contents['link'] + if datavalue: + collist.append(['tag', 'text:p', ['data', datavalue], + ['tag', 'text:a', ['element', 'xlink:href', linkval[0]], + ['data', linkval[1]]]]) + else: # no value; just fill the link + collist.append(['tag', 'text:p', + ['tag', 'text:a', ['element', 'xlink:href', linkval[0]], + ['data', linkval[1]]]]) + else: + if datavalue: + collist.append(['tag', 'text:p', ['data', datavalue]]) + + + + else: + collist = ['tagline', 'table:table-cell'] + rowlist.append(collist) + sheet_lists.append(rowlist) + return sheet_lists + +class Calc: + "Calc Class - Used to create OpenDocument Format Calc Spreadsheets." + def __init__(self, sheetname=None, opendoc=None, debug=False): + "Initialize ooolib Calc instance" + # Default to no debugging + self.debug = debug + if not sheetname: sheetname = "Sheet1" + self.sheets = [CalcSheet(sheetname)] # The main sheet will be initially called 'Sheet1' + self.sheet_index = 0 # We initially start on the first sheet + self.styles = CalcStyles() + self.meta = Meta('ods') + self.styles.get_style_code('column') # Force generation of default column + self.styles.get_style_code('row') # Force generation of default row + self.styles.get_style_code('table') # Force generation of default table + self.styles.get_style_code('cell') # Force generation of default cell + self.manifest_files = [] # List of extra files included + self.manifest_index = 1 # Index of added manifest files + + # Data Parsing + self.parser_element_list = [] + self.parser_element = "" + self.parser_sheet_num = 0 + self.parser_sheet_row = 0 + self.parser_sheet_column = 0 + self.parser_cell_repeats = 0 + self.parser_cell_string_pending = False + self.parser_cell_string_line = "" + + # See if we need to read a document + if opendoc: + # Verify that the document exists + if self.debug: print "Opening Document: %s" % opendoc + + # Okay, now we load the file + self.load(opendoc) + + def debug_level(self, level): + """Set debug level: + True if you want debugging messages + False if you do not. + """ + self.debug = level + + def file_mimetype(self, filename): + "Determine the filetype from the filename" + parts = filename.lower().split('.') + ext = parts[-1] + if (ext == 'png'): return (ext, "image/png") + if (ext == 'gif'): return (ext, "image/gif") + return (ext, "image/unknown") + + def add_file(self, filename): + """Prepare a file for loading into ooolib + + The filename should be the local filesystem name for + the file. The file is then prepared to be included in + the creation of the final document. The file needs to + remain in place so that it is available when the actual + document creation happens. + """ + # mimetype set to (ext, filetype) + mimetype = self.file_mimetype(filename) + newname = "Pictures/%08d.%s" % (self.manifest_index, mimetype[0]) + self.manifest_index += 1 + filetype = mimetype[1] + self.manifest_files.append((filename, filetype, newname)) + return newname + + def set_meta(self, metaname, value): + "Set meta data in your document." + self.meta.set_meta(metaname, value) + + def get_meta_value(self, metaname): + "Get meta data value for a given metaname" + return self.meta.get_meta_value(metaname) + + def get_sheet_name(self): + "Returns the sheet name" + return self.sheets[self.sheet_index].get_name() + + def get_sheet_dimensions(self): + "Returns the sheet dimensions in (cols, rows)" + return self.sheets[self.sheet_index].get_sheet_dimensions() + + def set_column_property(self, column, name, value): + "Set Column Properties" + if name == 'width': + # column number column needs column-width set to value + self.styles.set_property('column', 'style:column-width', value) + style_code = self.styles.get_style_code('column') + self.sheets[self.sheet_index].set_sheet_config(('col', column), style_code) + + def set_row_property(self, row, name, value): + "Set row Properties" + if name == 'height': + # row number row needs row-height set to value + self.styles.set_property('row', 'style:row-height', value) + style_code = self.styles.get_style_code('row') + self.sheets[self.sheet_index].set_sheet_config(('row', row), style_code) + + def set_cell_property(self, name, value): + """Turn and off cell properties + + Actual application of properties is handled by setting a value.""" + # background images need to be handled a little differently + # because they need to also be inserted into the final document + if (name == 'backgroundimage'): + # Add file and modify value + value = self.add_file(value) + self.styles.set_property('cell', name, value) + + def get_sheet_index(self): + "Return the current sheet index number" + return self.sheet_index + + def set_sheet_index(self, index): + "Set the sheet index" + if type(index) == type(1): + if index >= 0 and index < len(self.sheets): + self.sheet_index = index + return self.sheet_index + + def get_sheet_count(self): + "Returns the number of existing sheets" + return len(self.sheets) + + def new_sheet(self, sheetname): + "Create a new sheet" + self.sheet_index = len(self.sheets) + self.sheets.append(CalcSheet(sheetname)) + return self.sheet_index + + def set_cell_value(self, col, row, datatype, value): + "Set the value for a given cell" + self.sheets[self.sheet_index].set_sheet_value((col, row), datatype, value) + style_code = self.styles.get_style_code('cell') + self.sheets[self.sheet_index].set_sheet_config((col, row), style_code) + + def get_cell_value(self, col, row): + "Get a cell value tuple (type, value) for a given cell" + sheetvalue = self.sheets[self.sheet_index].get_sheet_value(col, row) + # We stop here if there is no value for sheetvalue + if sheetvalue == None: return sheetvalue + # Now check to see if we have a value tuple + if 'value' in sheetvalue: + return sheetvalue['value'] + else: + return None + + def load(self, filename): + """Load .ods spreadsheet. + + The load function loads data from a document into the current cells. + """ + # Read in the important files + + # meta.xml + data = self._zip_read(filename, "meta.xml") + self.meta.meta_parse(data) + + # content.xml + data = self._zip_read(filename, "content.xml") + self.content_parse(data) + + # settings.xml - I do not remember putting anything here + # styles.xml - I do not remember putting anything here + + def parse_content_start_element(self, name, attrs): + if self.debug: print '* Start element:', name + self.parser_element_list.append(name) + self.parser_element = self.parser_element_list[-1] + + # Keep track of the current sheet number + if (self.parser_element == 'table:table'): + # Move to starting cell + self.parser_sheet_row = 0 + self.parser_sheet_column = 0 + # Increment the sheet number count + self.parser_sheet_num += 1 + if (self.parser_sheet_num - 1 != self.sheet_index): + # We are not on the first sheet and need to create a new sheet. + # We will automatically move to the new sheet + sheetname = "Sheet%d" % self.parser_sheet_num + if 'table:name' in attrs: sheetname = attrs['table:name'] + self.new_sheet(sheetname) + else: + # We are on the first sheet and will need to overwrite the default name + sheetname = "Sheet%d" % self.parser_sheet_num + if 'table:name' in attrs: sheetname = attrs['table:name'] + self.sheets[self.sheet_index].set_name(sheetname) + + # Update the row numbers + if (self.parser_element == 'table:table-row'): + self.parser_sheet_row += 1 + self.parser_sheet_column = 0 + + # Okay, now keep track of the sheet cell data + if (self.parser_element == 'table:table-cell'): + # By default it will repeat zero times + self.parser_cell_repeats = 0 + # We must be in a new column + self.parser_sheet_column += 1 + # Set some default values + datatype = "" + value = "" + # Get values from attrs hash + if 'office:value-type' in attrs: datatype = attrs['office:value-type'] + if 'office:value' in attrs: value = attrs['office:value'] + if 'table:formula' in attrs: + datatype = 'formula' + value = attrs['table:formula'] + if datatype == 'string': + datatype = "" + self.parser_cell_string_pending = True + self.parser_cell_string_line = "" + if 'table:number-columns-repeated' in attrs: + self.parser_cell_repeats = int(attrs['table:number-columns-repeated']) - 1 + # Set the cell value + if datatype: + # I should do this once per cell repeat above 0 + for i in range(0, self.parser_cell_repeats+1): + self.set_cell_value(self.parser_sheet_column+i, self.parser_sheet_row, datatype, value) + + # There are lots of interesting cases with table:table-cell data. One problem is + # reading the number of embedded spaces correctly. This code should help us get + # the number of spaces out. + + if (self.parser_element == 'text:s'): + # This means we have a number of spaces + count_num = 0 + if 'text:c' in attrs: + count_alpha = attrs['text:c'] + if (count_alpha.isdigit()): + count_num = int(count_alpha) + # I am not sure what to do if we do not have a string pending + if (self.parser_cell_string_pending == True): + # Append the currect number of spaces to the end + self.parser_cell_string_line = "%s%s" % (self.parser_cell_string_line, ' '*count_num) + + if (self.parser_element == 'text:tab-stop'): + if (self.parser_cell_string_pending == True): + self.parser_cell_string_line = "%s\t" % (self.parser_cell_string_line) + + if (self.parser_element == 'text:line-break'): + if (self.parser_cell_string_pending == True): + self.parser_cell_string_line = "%s\n" % (self.parser_cell_string_line) + + # Debugging statements + if self.debug: print " List: ", self.parser_element_list + if self.debug: print " Attributes: ", attrs + + + def parse_content_end_element(self, name): + if self.debug: print '* End element:', name + if name != self.parser_element: + print "Tag Mismatch: '%s' != '%s'" % (name, self.parser_element) + self.parser_element_list.pop() + + # If the element was text:p and we are in string mode + if (self.parser_element == 'text:p'): + if (self.parser_cell_string_pending): + self.parser_cell_string_pending = False + + # Take care of repeated cells + if (self.parser_element == 'table:table-cell'): + self.parser_sheet_column += self.parser_cell_repeats + + # Readjust parser_element_list and parser_element + if (self.parser_element_list): + self.parser_element = self.parser_element_list[-1] + else: + self.parser_element = "" + + def parse_content_char_data(self, data): + if self.debug: print " Character data: ", repr(data) + + if (self.parser_element == 'text:p' or self.parser_element == 'text:span'): + if (self.parser_cell_string_pending): + # Set the string and leave string pending mode + # This does feel a little kludgy, but it does the job + self.parser_cell_string_line = "%s%s" % (self.parser_cell_string_line, data) + + # I should do this once per cell repeat above 0 + for i in range(0, self.parser_cell_repeats+1): + self.set_cell_value(self.parser_sheet_column+i, self.parser_sheet_row, + 'string', self.parser_cell_string_line) + + + def content_parse(self, data): + "Parse Content Data from a content.xml file" + + # Debugging statements + if self.debug: + # Sometimes it helps to see the document that was read from + print data + print "\n\n\n" + + # Create parser + parser = xml.parsers.expat.ParserCreate() + # Set up parser callback functions + parser.StartElementHandler = self.parse_content_start_element + parser.EndElementHandler = self.parse_content_end_element + parser.CharacterDataHandler = self.parse_content_char_data + + # Actually parse the data + parser.Parse(data, 1) + + def save(self, filename): + """Save .ods spreadsheet. + + The save function saves the current cells and settings into a document. + """ + if self.debug: print "Writing %s" % filename + self.savefile = zipfile.ZipFile(filename, "w") + if self.debug: print " meta.xml" + self._zip_insert(self.savefile, "meta.xml", self.meta.get_meta()) + if self.debug: print " mimetype" + self._zip_insert(self.savefile, "mimetype", "application/vnd.oasis.opendocument.spreadsheet") + if self.debug: print " Configurations2/accelerator/current.xml" + self._zip_insert(self.savefile, "Configurations2/accelerator/current.xml", "") + if self.debug: print " META-INF/manifest.xml" + self._zip_insert(self.savefile, "META-INF/manifest.xml", self._ods_manifest()) + if self.debug: print " content.xml" + self._zip_insert(self.savefile, "content.xml", self._ods_content()) + if self.debug: print " settings.xml" + self._zip_insert(self.savefile, "settings.xml", self._ods_settings()) + if self.debug: print " styles.xml" + self._zip_insert(self.savefile, "styles.xml", self._ods_styles()) + + # Add additional files if needed + for fileset in self.manifest_files: + (filename, filetype, newname) = fileset + # Read in the file + data = self._file_load(filename) + if self.debug: print " Inserting '%s' as '%s'" % (filename, newname) + self._zip_insert_binary(self.savefile, newname, data) + + def _file_load(self, filename): + "Load a file" + file = open(filename, "rb") + data = file.read() + file.close() + return data + + def _zip_insert_binary(self, file, filename, data): + "Insert a binary file into the zip archive" + now = time.localtime(time.time())[:6] + info = zipfile.ZipInfo(filename) + info.date_time = now + info.compress_type = zipfile.ZIP_DEFLATED + file.writestr(info, data) + + + def _zip_insert(self, file, filename, data): + "Insert a file into the zip archive" + + # zip seems to struggle with non-ascii characters + data = data.encode('utf-8') + + now = time.localtime(time.time())[:6] + info = zipfile.ZipInfo(filename) + info.date_time = now + info.compress_type = zipfile.ZIP_DEFLATED + file.writestr(info, data) + + def _zip_read(self, file, filename): + "Get the data from a file in the zip archive by filename" + file = zipfile.ZipFile(file, "r") + data = file.read(filename) + # Need to close the file + file.close() + return data + + def _ods_content(self): + "Generate ods content.xml data" + + # This will list all of the sheets in the document + self.sheetdata = ['tag', 'office:spreadsheet'] + for sheet in self.sheets: + if self.debug: + sheet_name = sheet.get_name() + print " Creating Sheet '%s'" % sheet_name + sheet_list = sheet.get_lists() + self.sheetdata.append(sheet_list) + # Automatic Styles + self.automatic_styles = self.styles.get_automatic_styles() + + self.data = ['tag', 'office:document-content', + ['element', 'xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'], + ['element', 'xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'], + ['element', 'xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'], + ['element', 'xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'], + ['element', 'xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'], + ['element', 'xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'], + ['element', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'], + ['element', 'xmlns:dc', 'http://purl.org/dc/elements/1.1/'], + ['element', 'xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'], + ['element', 'xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'], + ['element', 'xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'], + ['element', 'xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'], + ['element', 'xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'], + ['element', 'xmlns:math', 'http://www.w3.org/1998/Math/MathML'], + ['element', 'xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'], + ['element', 'xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'], + ['element', 'xmlns:ooo', 'http://openoffice.org/2004/office'], + ['element', 'xmlns:ooow', 'http://openoffice.org/2004/writer'], + ['element', 'xmlns:oooc', 'http://openoffice.org/2004/calc'], + ['element', 'xmlns:dom', 'http://www.w3.org/2001/xml-events'], + ['element', 'xmlns:xforms', 'http://www.w3.org/2002/xforms'], + ['element', 'xmlns:xsd', 'http://www.w3.org/2001/XMLSchema'], + ['element', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'], + ['element', 'office:version', '1.0'], + ['tagline', 'office:scripts'], + ['tag', 'office:font-face-decls', + ['tagline', 'style:font-face', + ['element', 'style:name', 'DejaVu Sans'], + ['element', 'svg:font-family', ''DejaVu Sans''], + ['element', 'style:font-pitch', 'variable']], + ['tagline', 'style:font-face', + ['element', 'style:name', 'Nimbus Sans L'], + ['element', 'svg:font-family', ''Nimbus Sans L''], + ['element', 'style:font-family-generic', 'swiss'], + ['element', 'style:font-pitch', 'variable']]], + + # Automatic Styles + self.automatic_styles, + + ['tag', 'office:body', + self.sheetdata]] # Sheets are generated from the CalcSheet class + + # Generate content.xml XML data + xml = XML() + self.lines = xml.convert(self.data) + self.filedata = '\n'.join(self.lines) + # Return generated data + return self.filedata + + def _ods_manifest(self): + "Generate ods manifest.xml data" + self.data = ['tag', 'manifest:manifest', + ['element', 'xmlns:manifest', 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0'], + ['tagline', 'manifest:file-entry', + ['element', 'manifest:media-type', 'application/vnd.oasis.opendocument.spreadsheet'], + ['element', 'manifest:full-path', '/']], + ['tagline', 'manifest:file-entry', + ['element', 'manifest:media-type', 'application/vnd.sun.xml.ui.configuration'], + ['element', 'manifest:full-path', 'Configurations2/']], + ['tagline', 'manifest:file-entry', + ['element', 'manifest:media-type', ''], + ['element', 'manifest:full-path', 'Configurations2/accelerator/']], + ['tagline', 'manifest:file-entry', + ['element', 'manifest:media-type', ''], + ['element', 'manifest:full-path', 'Configurations2/accelerator/current.xml']], + ['tagline', 'manifest:file-entry', + ['element', 'manifest:media-type', 'text/xml'], + ['element', 'manifest:full-path', 'content.xml']], + ['tagline', 'manifest:file-entry', + ['element', 'manifest:media-type', 'text/xml'], + ['element', 'manifest:full-path', 'styles.xml']], + ['tagline', 'manifest:file-entry', + ['element', 'manifest:media-type', 'text/xml'], + ['element', 'manifest:full-path', 'meta.xml']], + ['tagline', 'manifest:file-entry', + ['element', 'manifest:media-type', 'text/xml'], + ['element', 'manifest:full-path', 'settings.xml']]] + + # Add additional files to manifest list + for fileset in self.manifest_files: + (filename, filetype, newname) = fileset + addfile = ['tagline', 'manifest:file-entry', + ['element', 'manifest:media-type', filetype], + ['element', 'manifest:full-path', newname]] + self.data.append(addfile) + + # Generate content.xml XML data + xml = XML() + self.lines = xml.convert(self.data) + self.filedata = '\n'.join(self.lines) + # Return generated data + return self.filedata + + + def _ods_settings(self): + "Generate ods settings.xml data" + self.data = ['tag', 'office:document-settings', + ['element', 'xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'], + ['element', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'], + ['element', 'xmlns:config', 'urn:oasis:names:tc:opendocument:xmlns:config:1.0'], + ['element', 'xmlns:ooo', 'http://openoffice.org/2004/office'], + ['element', 'office:version', '1.0'], + ['tag', 'office:settings', + ['tag', 'config:config-item-set', + ['element', 'config:name', 'ooo:view-settings'], + ['tag', 'config:config-item', + ['element', 'config:name', 'VisibleAreaTop'], + ['element', 'config:type', 'int'], + ['data', '0']], + ['tag', 'config:config-item', + ['element', 'config:name', 'VisibleAreaLeft'], + ['element', 'config:type', 'int'], + ['data', '0']], + ['tag', 'config:config-item', + ['element', 'config:name', 'VisibleAreaWidth'], + ['element', 'config:type', 'int'], + ['data', '6774']], + ['tag', 'config:config-item', + ['element', 'config:name', 'VisibleAreaHeight'], + ['element', 'config:type', 'int'], + ['data', '2389']], + ['tag', 'config:config-item-map-indexed', + ['element', 'config:name', 'Views'], + ['tag', 'config:config-item-map-entry', + ['tag', 'config:config-item', + ['element', 'config:name', 'ViewId'], + ['element', 'config:type', 'string'], + ['data', 'View1']], + ['tag', 'config:config-item-map-named', + ['element', 'config:name', 'Tables'], + ['tag', 'config:config-item-map-entry', + ['element', 'config:name', 'Sheet1'], + ['tag', 'config:config-item', + ['element', 'config:name', 'CursorPositionX'], # Cursor Position A + ['element', 'config:type', 'int'], + ['data', '0']], + ['tag', 'config:config-item', + ['element', 'config:name', 'CursorPositionY'], # Cursor Position 1 + ['element', 'config:type', 'int'], + ['data', '0']], + ['tag', 'config:config-item', + ['element', 'config:name', 'HorizontalSplitMode'], + ['element', 'config:type', 'short'], + ['data', '0']], + ['tag', 'config:config-item', + ['element', 'config:name', 'VerticalSplitMode'], + ['element', 'config:type', 'short'], + ['data', '0']], + ['tag', 'config:config-item', + ['element', 'config:name', 'HorizontalSplitPosition'], + ['element', 'config:type', 'int'], + ['data', '0']], + ['tag', 'config:config-item', + ['element', 'config:name', 'VerticalSplitPosition'], + ['element', 'config:type', 'int'], + ['data', '0']], + ['tag', 'config:config-item', + ['element', 'config:name', 'ActiveSplitRange'], + ['element', 'config:type', 'short'], + ['data', '2']], + ['tag', 'config:config-item', + ['element', 'config:name', 'PositionLeft'], + ['element', 'config:type', 'int'], + ['data', '0']], + ['tag', 'config:config-item', + ['element', 'config:name', 'PositionRight'], + ['element', 'config:type', 'int'], + ['data', '0']], + ['tag', 'config:config-item', + ['element', 'config:name', 'PositionTop'], + ['element', 'config:type', 'int'], + ['data', '0']], + ['tag', 'config:config-item', + ['element', 'config:name', 'PositionBottom'], + ['element', 'config:type', 'int'], + ['data', '0']]]], + ['tag', 'config:config-item', + ['element', 'config:name', 'ActiveTable'], + ['element', 'config:type', 'string'], + ['data', 'Sheet1']], + ['tag', 'config:config-item', + ['element', 'config:name', 'HorizontalScrollbarWidth'], + ['element', 'config:type', 'int'], + ['data', '270']], + ['tag', 'config:config-item', + ['element', 'config:name', 'ZoomType'], + ['element', 'config:type', 'short'], + ['data', '0']], + ['tag', 'config:config-item', + ['element', 'config:name', 'ZoomValue'], + ['element', 'config:type', 'int'], + ['data', '100']], + ['tag', 'config:config-item', + ['element', 'config:name', 'PageViewZoomValue'], + ['element', 'config:type', 'int'], + ['data', '60']], + ['tag', 'config:config-item', + ['element', 'config:name', 'ShowPageBreakPreview'], + ['element', 'config:type', 'boolean'], + ['data', 'false']], + ['tag', 'config:config-item', + ['element', 'config:name', 'ShowZeroValues'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'ShowNotes'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'ShowGrid'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'GridColor'], + ['element', 'config:type', 'long'], + ['data', '12632256']], + ['tag', 'config:config-item', + ['element', 'config:name', 'ShowPageBreaks'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'HasColumnRowHeaders'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'HasSheetTabs'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'IsOutlineSymbolsSet'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'IsSnapToRaster'], + ['element', 'config:type', 'boolean'], + ['data', 'false']], + ['tag', 'config:config-item', + ['element', 'config:name', 'RasterIsVisible'], + ['element', 'config:type', 'boolean'], + ['data', 'false']], + ['tag', 'config:config-item', + ['element', 'config:name', 'RasterResolutionX'], + ['element', 'config:type', 'int'], + ['data', '1270']], + ['tag', 'config:config-item', + ['element', 'config:name', 'RasterResolutionY'], + ['element', 'config:type', 'int'], + ['data', '1270']], + ['tag', 'config:config-item', + ['element', 'config:name', 'RasterSubdivisionX'], + ['element', 'config:type', 'int'], + ['data', '1']], + ['tag', 'config:config-item', + ['element', 'config:name', 'RasterSubdivisionY'], + ['element', 'config:type', 'int'], + ['data', '1']], + ['tag', 'config:config-item', + ['element', 'config:name', 'IsRasterAxisSynchronized'], + ['element', 'config:type', 'boolean'], + ['data', 'true']]]]], + ['tag', 'config:config-item-set', + ['element', 'config:name', 'ooo:configuration-settings'], + ['tag', 'config:config-item', + ['element', 'config:name', 'ShowZeroValues'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'ShowNotes'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'ShowGrid'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'GridColor'], + ['element', 'config:type', 'long'], + ['data', '12632256']], + ['tag', 'config:config-item', + ['element', 'config:name', 'ShowPageBreaks'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'LinkUpdateMode'], + ['element', 'config:type', 'short'], + ['data', '3']], + ['tag', 'config:config-item', + ['element', 'config:name', 'HasColumnRowHeaders'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'HasSheetTabs'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'IsOutlineSymbolsSet'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'IsSnapToRaster'], + ['element', 'config:type', 'boolean'], + ['data', 'false']], + ['tag', 'config:config-item', + ['element', 'config:name', 'RasterIsVisible'], + ['element', 'config:type', 'boolean'], + ['data', 'false']], + ['tag', 'config:config-item', + ['element', 'config:name', 'RasterResolutionX'], + ['element', 'config:type', 'int'], + ['data', '1270']], + ['tag', 'config:config-item', + ['element', 'config:name', 'RasterResolutionY'], + ['element', 'config:type', 'int'], + ['data', '1270']], + ['tag', 'config:config-item', + ['element', 'config:name', 'RasterSubdivisionX'], + ['element', 'config:type', 'int'], + ['data', '1']], + ['tag', 'config:config-item', + ['element', 'config:name', 'RasterSubdivisionY'], + ['element', 'config:type', 'int'], + ['data', '1']], + ['tag', 'config:config-item', + ['element', 'config:name', 'IsRasterAxisSynchronized'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'AutoCalculate'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'PrinterName'], + ['element', 'config:type', 'string'], + ['data', 'Generic Printer']], + ['tag', 'config:config-item', + ['element', 'config:name', 'PrinterSetup'], + ['element', 'config:type', 'base64Binary'], + ['data', 'YgH+/0dlbmVyaWMgUHJpbnRlcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU0dFTlBSVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWAAMAqAAAAAAA//8FAFZUAAAkbQAASm9iRGF0YSAxCnByaW50ZXI9R2VuZXJpYyBQcmludGVyCm9yaWVudGF0aW9uPVBvcnRyYWl0CmNvcGllcz0xCnNjYWxlPTEwMAptYXJnaW5kYWp1c3RtZW50PTAsMCwwLDAKY29sb3JkZXB0aD0yNApwc2xldmVsPTAKY29sb3JkZXZpY2U9MApQUERDb250ZXhEYXRhClBhZ2VTaXplOkxldHRlcgAA']], + ['tag', 'config:config-item', + ['element', 'config:name', 'ApplyUserData'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'CharacterCompressionType'], + ['element', 'config:type', 'short'], + ['data', '0']], + ['tag', 'config:config-item', + ['element', 'config:name', 'IsKernAsianPunctuation'], + ['element', 'config:type', 'boolean'], + ['data', 'false']], + ['tag', 'config:config-item', + ['element', 'config:name', 'SaveVersionOnClose'], + ['element', 'config:type', 'boolean'], + ['data', 'false']], + ['tag', 'config:config-item', + ['element', 'config:name', 'UpdateFromTemplate'], + ['element', 'config:type', 'boolean'], + ['data', 'false']], + ['tag', 'config:config-item', + ['element', 'config:name', 'AllowPrintJobCancel'], + ['element', 'config:type', 'boolean'], + ['data', 'true']], + ['tag', 'config:config-item', + ['element', 'config:name', 'LoadReadonly'], + ['element', 'config:type', 'boolean'], + ['data', 'false']]]]] + + # Generate content.xml XML data + xml = XML() + self.lines = xml.convert(self.data) + self.filedata = '\n'.join(self.lines) + # Return generated data + return self.filedata + + + def _ods_styles(self): + "Generate ods styles.xml data" + self.data = ['tag', 'office:document-styles', + ['element', 'xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'], + ['element', 'xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'], + ['element', 'xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'], + ['element', 'xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'], + ['element', 'xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'], + ['element', 'xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'], + ['element', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'], + ['element', 'xmlns:dc', 'http://purl.org/dc/elements/1.1/'], + ['element', 'xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'], + ['element', 'xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'], + ['element', 'xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'], + ['element', 'xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'], + ['element', 'xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'], + ['element', 'xmlns:math', 'http://www.w3.org/1998/Math/MathML'], + ['element', 'xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'], + ['element', 'xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'], + ['element', 'xmlns:ooo', 'http://openoffice.org/2004/office'], + ['element', 'xmlns:ooow', 'http://openoffice.org/2004/writer'], + ['element', 'xmlns:oooc', 'http://openoffice.org/2004/calc'], + ['element', 'xmlns:dom', 'http://www.w3.org/2001/xml-events'], + ['element', 'office:version', '1.0'], + ['tag', 'office:font-face-decls', + ['tagline', 'style:font-face', + ['element', 'style:name', 'DejaVu Sans'], + ['element', 'svg:font-family', ''DejaVu Sans''], + ['element', 'style:font-pitch', 'variable']], + ['tagline', 'style:font-face', + ['element', 'style:name', 'Nimbus Sans L'], + ['element', 'svg:font-family', ''Nimbus Sans L''], + ['element', 'style:font-family-generic', 'swiss'], + ['element', 'style:font-pitch', 'variable']]], + ['tag', 'office:styles', + ['tag', 'style:default-style', + ['element', 'style:family', 'table-cell'], + ['tagline', 'style:table-cell-properties', + ['element', 'style:decimal-places', '2']], + ['tagline', 'style:paragraph-properties', + ['element', 'style:tab-stop-distance', '0.5in']], + ['tagline', 'style:text-properties', + ['element', 'style:font-name', 'Nimbus Sans L'], + ['element', 'fo:language', 'en'], + ['element', 'fo:country', 'US'], + ['element', 'style:font-name-asian', 'DejaVu Sans'], + ['element', 'style:language-asian', 'none'], + ['element', 'style:country-asian', 'none'], + ['element', 'style:font-name-complex', 'DejaVu Sans'], + ['element', 'style:language-complex', 'none'], + ['element', 'style:country-complex', 'none']]], + ['tag', 'number:number-style', + ['element', 'style:name', 'N0'], + ['tagline', 'number:number', + ['element', 'number:min-integer-digits', '1']]], + ['tag', 'number:currency-style', + ['element', 'style:name', 'N104P0'], + ['element', 'style:volatile', 'true'], + ['tag', 'number:currency-symbol', + ['element', 'number:language', 'en'], + ['element', 'number:country', 'US'], + ['data', '$']], + ['tagline', 'number:number', + ['element', 'number:decimal-places', '2'], + ['element', 'number:min-integer-digits', '1'], + ['element', 'number:grouping', 'true']]], + ['tag', 'number:currency-style', + ['element', 'style:name', 'N104'], + ['tagline', 'style:text-properties', + ['element', 'fo:color', '#ff0000']], + ['tag', 'number:text', + ['data', '-']], + ['tag', 'number:currency-symbol', + ['element', 'number:language', 'en'], + ['element', 'number:country', 'US'], + ['data', '$']], + ['tagline', 'number:number', + ['element', 'number:decimal-places', '2'], + ['element', 'number:min-integer-digits', '1'], + ['element', 'number:grouping', 'true']], + ['tagline', 'style:map', + ['element', 'style:condition', 'value()>=0'], + ['element', 'style:apply-style-name', 'N104P0']]], + ['tagline', 'style:style', + ['element', 'style:name', 'Default'], + ['element', 'style:family', 'table-cell']], + ['tag', 'style:style', + ['element', 'style:name', 'Result'], + ['element', 'style:family', 'table-cell'], + ['element', 'style:parent-style-name', 'Default'], + ['tagline', 'style:text-properties', + ['element', 'fo:font-style', 'italic'], + ['element', 'style:text-underline-style', 'solid'], + ['element', 'style:text-underline-width', 'auto'], + ['element', 'style:text-underline-color', 'font-color'], + ['element', 'fo:font-weight', 'bold']]], + ['tagline', 'style:style', + ['element', 'style:name', 'Result2'], + ['element', 'style:family', 'table-cell'], + ['element', 'style:parent-style-name', 'Result'], + ['element', 'style:data-style-name', 'N104']], + ['tag', 'style:style', + ['element', 'style:name', 'Heading'], + ['element', 'style:family', 'table-cell'], + ['element', 'style:parent-style-name', 'Default'], + ['tagline', 'style:table-cell-properties', + ['element', 'style:text-align-source', 'fix'], + ['element', 'style:repeat-content', 'false']], + ['tagline', 'style:paragraph-properties', + ['element', 'fo:text-align', 'center']], + ['tagline', 'style:text-properties', + ['element', 'fo:font-size', '16pt'], + ['element', 'fo:font-style', 'italic'], + ['element', 'fo:font-weight', 'bold']]], + ['tag', 'style:style', + ['element', 'style:name', 'Heading1'], + ['element', 'style:family', 'table-cell'], + ['element', 'style:parent-style-name', 'Heading'], + ['tagline', 'style:table-cell-properties', + ['element', 'style:rotation-angle', '90']]]], + ['tag', 'office:automatic-styles', + ['tag', 'style:page-layout', + ['element', 'style:name', 'pm1'], + ['tagline', 'style:page-layout-properties', + ['element', 'style:writing-mode', 'lr-tb']], + ['tag', 'style:header-style', + ['tagline', 'style:header-footer-properties', + ['element', 'fo:min-height', '0.2957in'], + ['element', 'fo:margin-left', '0in'], + ['element', 'fo:margin-right', '0in'], + ['element', 'fo:margin-bottom', '0.0984in']]], + ['tag', 'style:footer-style', + ['tagline', 'style:header-footer-properties', + ['element', 'fo:min-height', '0.2957in'], + ['element', 'fo:margin-left', '0in'], + ['element', 'fo:margin-right', '0in'], + ['element', 'fo:margin-top', '0.0984in']]]], + ['tag', 'style:page-layout', + ['element', 'style:name', 'pm2'], + ['tagline', 'style:page-layout-properties', + ['element', 'style:writing-mode', 'lr-tb']], + ['tag', 'style:header-style', + ['tag', 'style:header-footer-properties', + ['element', 'fo:min-height', '0.2957in'], + ['element', 'fo:margin-left', '0in'], + ['element', 'fo:margin-right', '0in'], + ['element', 'fo:margin-bottom', '0.0984in'], + ['element', 'fo:border', '0.0346in solid #000000'], + ['element', 'fo:padding', '0.0071in'], + ['element', 'fo:background-color', '#c0c0c0'], + ['tagline', 'style:background-image']]], + ['tag', 'style:footer-style', + ['tag', 'style:header-footer-properties', + ['element', 'fo:min-height', '0.2957in'], + ['element', 'fo:margin-left', '0in'], + ['element', 'fo:margin-right', '0in'], + ['element', 'fo:margin-top', '0.0984in'], + ['element', 'fo:border', '0.0346in solid #000000'], + ['element', 'fo:padding', '0.0071in'], + ['element', 'fo:background-color', '#c0c0c0'], + ['tagline', 'style:background-image']]]]], + ['tag', 'office:master-styles', + ['tag', 'style:master-page', + ['element', 'style:name', 'Default'], + ['element', 'style:page-layout-name', 'pm1'], + ['tag', 'style:header', + ['tag', 'text:p', + ['data', '???']]], + ['tagline', 'style:header-left', + ['element', 'style:display', 'false']], + ['tag', 'style:footer', + ['tag', 'text:p', + ['data', 'Page 1']]], + ['tagline', 'style:footer-left', + ['element', 'style:display', 'false']]], + ['tag', 'style:master-page', + ['element', 'style:name', 'Report'], + ['element', 'style:page-layout-name', 'pm2'], + ['tag', 'style:header', + ['tag', 'style:region-left', + ['tag', 'text:p', + ['data', '??? (???)']]], + ['tag', 'style:region-right', + ['tag', 'text:p', + ['data', '09/29/2006, 13:02:56']]]], + ['tagline', 'style:header-left', + ['element', 'style:display', 'false']], + ['tag', 'style:footer', + ['tag', 'text:p', + ['data', 'Page 1 / 99']]], + ['tagline', 'style:footer-left', + ['element', 'style:display', 'false']]]]] + + + # Generate content.xml XML data + xml = XML() + self.lines = xml.convert(self.data) + self.filedata = '\n'.join(self.lines) + # Return generated data + return self.filedata + +class Writer: + "Writer Class - Used to create OpenDocument Format Writer Documents." + def __init__(self): + "Initialize ooolib Writer instance" + # Default to no debugging + self.debug = False + self.meta = Meta('odt') + + def set_meta(self, metaname, value): + "Set meta data in your document." + self.meta.set_meta(metaname, value) + + def save(self, filename): + """Save .odt document + + The save function saves the current .odt document. + """ + if self.debug: print "Writing %s" % filename + self.savefile = zipfile.ZipFile(filename, "w") + if self.debug: print " meta.xml" + self._zip_insert(self.savefile, "meta.xml", self.meta.get_meta()) + if self.debug: print " mimetype" + self._zip_insert(self.savefile, "mimetype", "application/vnd.oasis.opendocument.text") + if self.debug: print " META-INF/manifest.xml" + self._zip_insert(self.savefile, "META-INF/manifest.xml", self._odt_manifest()) + if self.debug: print " content.xml" + self._zip_insert(self.savefile, "content.xml", self._odt_content()) + if self.debug: print " settings.xml" + # self._zip_insert(self.savefile, "settings.xml", self._odt_settings()) + if self.debug: print " styles.xml" + # self._zip_insert(self.savefile, "styles.xml", self._odt_styles()) + + # We need to close the file now that we are done creating it. + self.savefile.close() + + def _zip_insert(self, file, filename, data): + now = time.localtime(time.time())[:6] + info = zipfile.ZipInfo(filename) + info.date_time = now + info.compress_type = zipfile.ZIP_DEFLATED + file.writestr(info, data) + + def _odt_manifest(self): + "Generate odt manifest.xml data" + + self.data = ['tag', 'manifest:manifest', + ['element', 'xmlns:manifest', 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0'], + ['tagline', 'manifest:file-entry', + ['element', 'manifest:media-type', 'application/vnd.oasis.opendocument.text'], + ['element', 'manifest:full-path', '/']], + ['tagline', 'manifest:file-entry', + ['element', 'manifest:media-type', 'text/xml'], + ['element', 'manifest:full-path', 'content.xml']], + ['tagline', 'manifest:file-entry', + ['element', 'manifest:media-type', 'text/xml'], + ['element', 'manifest:full-path', 'styles.xml']], + ['tagline', 'manifest:file-entry', + ['element', 'manifest:media-type', 'text/xml'], + ['element', 'manifest:full-path', 'meta.xml']], + ['tagline', 'manifest:file-entry', + ['element', 'manifest:media-type', 'text/xml'], + ['element', 'manifest:full-path', 'settings.xml']]] + + # Generate content.xml XML data + xml = XML() + self.lines = xml.convert(self.data) + self.lines.insert(1, '') + self.filedata = '\n'.join(self.lines) + # Return generated data + return self.filedata + + def _odt_content(self): + "Generate odt content.xml data" + + self.data = ['tag', 'office:document-content', + ['element', 'xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'], + ['element', 'xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'], + ['element', 'xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'], + ['element', 'xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'], + ['element', 'xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'], + ['element', 'xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'], + ['element', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'], + ['element', 'xmlns:dc', 'http://purl.org/dc/elements/1.1/'], + ['element', 'xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'], + ['element', 'xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'], + ['element', 'xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'], + ['element', 'xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'], + ['element', 'xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'], + ['element', 'xmlns:math', 'http://www.w3.org/1998/Math/MathML'], + ['element', 'xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'], + ['element', 'xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'], + ['element', 'xmlns:ooo', 'http://openoffice.org/2004/office'], + ['element', 'xmlns:ooow', 'http://openoffice.org/2004/writer'], + ['element', 'xmlns:oooc', 'http://openoffice.org/2004/calc'], + ['element', 'xmlns:dom', 'http://www.w3.org/2001/xml-events'], + ['element', 'xmlns:xforms', 'http://www.w3.org/2002/xforms'], + ['element', 'xmlns:xsd', 'http://www.w3.org/2001/XMLSchema'], + ['element', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'], + ['element', 'office:version', '1.0'], + ['tagline', 'office:scripts'], + ['tag', 'office:font-face-decls', + ['tagline', 'style:font-face', + ['element', 'style:name', 'DejaVu Sans'], + ['element', 'svg:font-family', ''DejaVu Sans''], + ['element', 'style:font-pitch', 'variable']], + ['tagline', 'style:font-face', + ['element', 'style:name', 'Nimbus Roman No9 L'], + ['element', 'svg:font-family', ''Nimbus Roman No9 L''], + ['element', 'style:font-family-generic', 'roman'], + ['element', 'style:font-pitch', 'variable']], + ['tagline', 'style:font-face', + ['element', 'style:name', 'Nimbus Sans L'], + ['element', 'svg:font-family', ''Nimbus Sans L''], + ['element', 'style:font-family-generic', 'swiss'], + ['element', 'style:font-pitch', 'variable']]], + ['tagline', 'office:automatic-styles'], + ['tag', 'office:body', + ['tag', 'office:text', + ['tagline', 'office:forms', + ['element', 'form:automatic-focus', 'false'], + ['element', 'form:apply-design-mode', 'false']], + ['tag', 'text:sequence-decls', + ['tagline', 'text:sequence-decl', + ['element', 'text:display-outline-level', '0'], + ['element', 'text:name', 'Illustration']], + ['tagline', 'text:sequence-decl', + ['element', 'text:display-outline-level', '0'], + ['element', 'text:name', 'Table']], + ['tagline', 'text:sequence-decl', + ['element', 'text:display-outline-level', '0'], + ['element', 'text:name', 'Text']], + ['tagline', 'text:sequence-decl', + ['element', 'text:display-outline-level', '0'], + ['element', 'text:name', 'Drawing']]], + ['tagline', 'text:p', + ['element', 'text:style-name', 'Standard']]]]] + + # Generate content.xml XML data + xml = XML() + self.lines = xml.convert(self.data) + self.filedata = '\n'.join(self.lines) + # Return generated data + return self.filedata + + diff --git a/contrib/non-profit-audit-reports/readcsv.py b/contrib/non-profit-audit-reports/readcsv.py new file mode 100755 index 00000000..67fc5663 --- /dev/null +++ b/contrib/non-profit-audit-reports/readcsv.py @@ -0,0 +1,31 @@ +#!/usr/bin/python +# readcsv.py +# CSV reading technical study +# +# Copyright (c) 2012 Tom Marble +# +# This program gives you software freedom; you can copy, modify, convey, +# and/or redistribute it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program in a file called 'GPLv3'. If not, write to the: +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor +# Boston, MA 02110-1301, USA. + +import csv + +dialects = csv.list_dialects() +for dialect in dialects: + print 'dialect %s' % str(dialect) + +csvfile = open('tests/general-ledger.csv', 'rb') +reader = csv.reader(csvfile, delimiter=',', quotechar='"') +for row in reader: + print row -- cgit v1.2.3 From 8dd41dc9e7b7e01fda1ba09b8dc8adf2b19d2572 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sat, 8 Sep 2012 14:31:36 -0400 Subject: Add to .gitignore items generated by contrib/non-profit-audit-reports/demo.sh --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 37921df5..0c12801a 100644 --- a/.gitignore +++ b/.gitignore @@ -97,3 +97,9 @@ system.hh system.hh.[gp]ch* Ledger*.dmg Ledger*.sh +# Files that generated by running ./demo.sh in contrib/non-profit-audit-reports +contrib/non-profit-audit-reports/tests/chart-of-accounts.txt +contrib/non-profit-audit-reports/tests/general-ledger.csv +contrib/non-profit-audit-reports/tests/general-ledger.ods +contrib/non-profit-audit-reports/tests/general-ledger.txt +contrib/non-profit-audit-reports/general-ledger.zip -- cgit v1.2.3 From 613eb6ba71f2c1198b7a679bde804226e27861fb Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sat, 8 Sep 2012 14:34:15 -0400 Subject: Receipt/Invoice are additional information thus better if they're final columns. Change the column of Receipt and Invoice in the CSV file first, then the generated ODS file must have the same change propagated, which requires changes to the column numbers hard-coding in csv2ods.py. Perhaps if/when this application is refactored these things shouldn't be hard-coded in this way in the first place. --- contrib/non-profit-audit-reports/csv2ods.py | 3 ++- contrib/non-profit-audit-reports/general-ledger-report.plx | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/contrib/non-profit-audit-reports/csv2ods.py b/contrib/non-profit-audit-reports/csv2ods.py index c0c5c6d3..f6150158 100755 --- a/contrib/non-profit-audit-reports/csv2ods.py +++ b/contrib/non-profit-audit-reports/csv2ods.py @@ -3,6 +3,7 @@ # Convert example csv file to ods # # Copyright (c) 2012 Tom Marble +# Copyright (c) 2012 Bradley M. Kuhn # # This program gives you software freedom; you can copy, modify, convey, # and/or redistribute it under the terms of the GNU General Public License @@ -55,7 +56,7 @@ def csv2ods(csvname, odsname, verbose = False): if len(val) > 0 and val[0] == '$': doc.set_cell_value(col + 1, row, 'currency', val[1:]) else: - if ( (col == 3) and (val != 'Receipt') and len(val) > 0) or ( (col == 4) and (val != 'Invoice') and len(val) > 0): + if ( (col == 5) and (val != 'Receipt') and len(val) > 0) or ( (col == 6) and (val != 'Invoice') and len(val) > 0): linkrel = '../' + val # ../ means remove the name of the *.ods linkname = os.path.basename(val) # name is just the last component doc.set_cell_value(col + 1, row, 'link', (linkrel, linkname)) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index cc3dc087..5286d625 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -107,8 +107,8 @@ foreach my $acct (@sortedAccounts) { close(GL_TEXT_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; print GL_CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; - print GL_CSV_OUT '"DATE","CHECK NUM","NAME","Receipt","Invoice","TRANSACTION AMT","RUNNING TOTAL"', "\n"; - @acctLedgerOpts = ('-F', '"%(date)","%C","%P","%(tag(\'Receipt\'))","%(tag(\'Invoice\'))","%t","%T"\n', '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); + print GL_CSV_OUT '"DATE","CHECK NUM","NAME","TRANSACTION AMT","RUNNING TOTAL","Receipt","Invoice"', "\n"; + @acctLedgerOpts = ('-F', '"%(date)","%C","%P","%t","%T","%(tag(\'Receipt\'))","%(tag(\'Invoice\'))"\n', '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); open(GL_CSV_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!"; -- cgit v1.2.3 From 71f351d6181ac2b0f3301b7d6a9b1066dcecce5f Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sat, 8 Sep 2012 14:40:30 -0400 Subject: doc/ledger3.info should be ignored. doc/ledger3.info was probably missing from the .gitignore because ledger3.info isn't build automatically yet, but might as well add it to .gitignore for those who are building it by hand at the moment. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 37921df5..50fb20c0 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ doc/.dirstamp doc/html/ doc/latex/ doc/ledger.info +doc/ledger3.info doc/refman.pdf doc/report/ elisp-comp -- cgit v1.2.3 From fa89dc16a63ab30a030311115127e6138a78f0e7 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Mon, 10 Sep 2012 00:08:59 -0400 Subject: Document "Data File Parsing Information" format strings. Based on my reading of src/format.cc and inspection of output on some test data, I believe this is adequate documentation for these format strings. --- doc/ledger3.texi | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 1ea4fd02..bff96adf 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -6691,6 +6691,7 @@ As an example of how flexible the --format strings can be, the default balance f * Quantities and Calculations:: * Dates:: * Text Formatting:: +* Data File Parsing Information:: * Misc:: @end menu @@ -6762,7 +6763,7 @@ The character based formatting ledger can do is limited to the ANSI terminal cha @item @code{value_date } @tab @code{} @tab @end multitable -@node Text Formatting, Misc, Dates, New formatting codes +@node Text Formatting, Data File Parsing Information, Dates, New formatting codes @subsection Text Formatting @subsubsection Summary @multitable @columnfractions .6 .4 @@ -6797,7 +6798,26 @@ Return str surrounded by double quotes, @code{""}. Values can have numerous annotations, such as effective dates and lot prices. @code{strip} removes these annotations. @end table -@node Misc, , Text Formatting, New formatting codes + +@node Data File Parsing Information, Misc, Text Formatting, New formatting codes +@subsection Data File Parsing Information + +The format strings in the table below provide locational metadata +regarding the coordinates of entries in the source data file(s) that +generated the posting. + +@subsubsection Summary +@multitable @columnfractions .3 .2 .5 +@item @strong{Function} @tab @strong{Abbrev.} @tab @strong{Description} +@item @code{filename} @tab S @tab @tab name of ledger data file from whence posting came +@item @code{beg_pos} @tab B @tab character position in @code{filename} where entry for posting begins +@item @code{end_pos} @tab E @tab character position in @code{filename} where entry for posting ends +@item @code{beg_line} @tab b @tab line number in @code{filename} where entry for posting begins +@item @code{end_line} @tab e @tab line number in @code{filename} where posting's entry for posting ends +@end multitable + + +@node Misc, , Data File Parsing Information, New formatting codes @subsection Miscellaneous @multitable @columnfractions .3 .2 .5 @item @strong{Function} @tab @strong{Abbrev.} @tab @strong{Description} -- cgit v1.2.3 From 137183d19f2ae54c030a1f7dcd59e02341f088c6 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Mon, 10 Sep 2012 00:12:51 -0400 Subject: Fixed typo: removed extra @tab. --- doc/ledger3.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index bff96adf..16bf0564 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -6809,7 +6809,7 @@ generated the posting. @subsubsection Summary @multitable @columnfractions .3 .2 .5 @item @strong{Function} @tab @strong{Abbrev.} @tab @strong{Description} -@item @code{filename} @tab S @tab @tab name of ledger data file from whence posting came +@item @code{filename} @tab S @tab name of ledger data file from whence posting came @item @code{beg_pos} @tab B @tab character position in @code{filename} where entry for posting begins @item @code{end_pos} @tab E @tab character position in @code{filename} where entry for posting ends @item @code{beg_line} @tab b @tab line number in @code{filename} where entry for posting begins -- cgit v1.2.3 From ccf10e20604a9fc074c1f7f1f98905be59a0e0b4 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 14 Sep 2012 16:35:46 -0400 Subject: Created Fixated prices node. There was a Fixated prices section, but no Fixated prices node. This of course required an update of nodes and menus throughout chapter. --- doc/ledger3.texi | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 16bf0564..6dc1787d 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -2486,6 +2486,7 @@ kill the report buffer * Virtual posting costs:: * Commodity prices:: * Prices vs. costs:: +* Fixated prices:: * Lot dates:: * Lot notes:: * Lot value expressions:: @@ -3131,7 +3132,7 @@ Plus, it comes with dangers. This works fine: And in cases where the amounts do not divide into whole figure and must be rounded, the capital gains figure could be off by a cent. Use with caution. -@node Prices vs. costs, Lot dates, Commodity prices, Transactions +@node Prices vs. costs, Fixated prices, Commodity prices, Transactions @section Prices vs. costs Because lot pricing provides enough information to infer the cost, the @@ -3151,6 +3152,7 @@ However, note that what you see in some reports may differ, for example in the print report. Functionally, however, there is no difference, and neither the register nor the balance report are sensitive to this difference. +@node Fixated prices, Lot dates, Prices vs. costs, Transactions @section Fixated prices If you buy a stock last year, and ask for its value today, Ledger will consult @@ -3174,7 +3176,7 @@ below) to fix the value of a commodity lot. * Fixated costs:: @end menu -@node Fixated costs, , Prices vs. costs, Prices vs. costs +@node Fixated costs, , Fixated prices, Fixated prices @subsection Fixated costs Since price annotations are costs are largely interchangeable and a matter of @@ -3190,7 +3192,7 @@ of the cost: This is the same as the previous transaction, with the same caveats found in the section ``Prices vs. costs''. -@node Lot dates, Lot notes, Prices vs. costs, Transactions +@node Lot dates, Lot notes, Fixated prices, Transactions @section Lot dates In addition to lot prices, you can specify lot dates and reveal them with -- cgit v1.2.3 From 438806ac71a9a56645d824d2dbebb2bd565155ce Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 14 Sep 2012 16:39:41 -0400 Subject: Documentation for the fixed directive. Based on conversation with johnw on IRC, I believe this text properly documents the intended feature of the fixed directive. --- doc/ledger3.texi | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 6dc1787d..d4c89951 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -2047,6 +2047,37 @@ Closes block commands like @code{tag} or @code{comment}. @item fixed @c instance_t::fixed_directive in textual.cc +A fixed block is used to set fixated prices (@pxref{Fixated prices}) for a series of +transactions. It's purely a typing saver, for use when entering many +transactions with fixated prices. + +Thus, the following: +@smallexample +fixed CAD $0.90 + 2012-04-10 Lunch in Canada + Assets:Wallet -15.50 CAD + Expenses:Food 15.50 CAD + + 2012-04-11 Second day Dinner in Canada + Assets:Wallet -25.75 CAD + Expenses:Food 25.75 CAD +endfixed +@end smallexample +is equivalent to this: +@smallexample + 2012-04-10 Lunch in Canada + Assets:Wallet -15.50 CAD @{=$0.90@} + Expenses:Food 15.50 CAD @{=$0.90@} + + 2012-04-11 Second day Dinner in Canada + Assets:Wallet -25.75 CAD @{=$0.90@} + Expenses:Food 25.75 CAD @{=$0.90@} +@end smallexample + +Note that ending a @samp{fixed} is done differently than other +directives, as @samp{fixed} is closed with an @samp{endfixed} (i.e., +there is @strong{no space} between @samp{end} and @samp{fixed}). + @item include @c instance_t::include_directive in textual.cc Include the stated file as if it were part of the current file. -- cgit v1.2.3 From 06356ebf90bb051b2cfef09dbed646fd4c31a759 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 14 Sep 2012 16:54:12 -0400 Subject: Make reference and link to Bug Report #789 in fixed directive documentation. Due to weirdness that's currently true with the existing next branch of ledger, I believe it's important to tell users in the documentation that there are some discrepancies in the 'fixed' directive behavior. The documentation from my previous commit is written to explain what 'fixed' *should* do; adding the bug report link here is a placeholder to tell users that it may not do what they think it does. Obviously, if someone closes #789, they should remove this paragraph added herein. But, if the bug report is closed, but the documentation lags behind, the worst that happens is some users have to click through to see the bug is closed. --- doc/ledger3.texi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index d4c89951..9a91d79e 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -2078,6 +2078,10 @@ Note that ending a @samp{fixed} is done differently than other directives, as @samp{fixed} is closed with an @samp{endfixed} (i.e., there is @strong{no space} between @samp{end} and @samp{fixed}). +For the moment, users may wish to study +@uref{http://bugs.ledger-cli.org/show_bug.cgi?id=789, Bug Report 789} +before using the @samp{fixed} directive in production. + @item include @c instance_t::include_directive in textual.cc Include the stated file as if it were part of the current file. -- cgit v1.2.3 From 7c288b956d02f7a5157970876697b76fe66aaeae Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 21 Sep 2012 15:12:38 -0500 Subject: Changes for CMake --- acprep | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/acprep b/acprep index 83ff4ab2..c35d09db 100755 --- a/acprep +++ b/acprep @@ -657,11 +657,12 @@ class PrepareBuild(CommandLineApp): ######################################################################### def setup_for_johnw(self): + self.configure_args.append('-GNinja') self.configure_args.append('-DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON') self.configure_args.append('-DBoost_USE_MULTITHREADED:BOOL=OFF') if not self.options.compiler: - self.configure_args.append('-DCMAKE_CXX_COMPILER:PATH=/usr/local/stow/clang-3.1/bin/clang++') + self.configure_args.append('-DCMAKE_CXX_COMPILER:PATH=/usr/local/bin/clang++') self.CXXFLAGS.append('-Qunused-arguments') self.CXXFLAGS.append('-nostdlibinc') @@ -910,7 +911,6 @@ class PrepareBuild(CommandLineApp): if self.options.jobs > 1 and self.current_flavor != 'gcov': make_args.append('-j%d' % self.options.jobs) - make_args.append('ARGS=-j%d' % self.options.jobs) if self.options.verbose: make_args.append('VERBOSE=1') @@ -932,12 +932,11 @@ class PrepareBuild(CommandLineApp): def phase_check(self, *args): self.log.info('Executing phase: update') - self.phase_make(*(['check'] + list(args))) + self.execute(*(['ctest'] + make_args)) def phase_update(self, *args): self.log.info('Executing phase: update') self.phase_pull() - #self.phase_check(*args) self.phase_make(*args) ######################################################################### -- cgit v1.2.3 From 300cefd1a78ebeddb139a32fa7e1478a3f4225b4 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 26 Sep 2012 12:25:26 -0500 Subject: Changes to support using homebrew and ninja --- acprep | 50 ++++++++++++++++---------------------------------- lib/Makefile | 34 +++------------------------------- lib/build.sh | 4 ++-- tools/build.sh | 12 ++++++------ 4 files changed, 27 insertions(+), 73 deletions(-) diff --git a/acprep b/acprep index c35d09db..25f565f3 100755 --- a/acprep +++ b/acprep @@ -659,21 +659,10 @@ class PrepareBuild(CommandLineApp): def setup_for_johnw(self): self.configure_args.append('-GNinja') self.configure_args.append('-DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON') - self.configure_args.append('-DBoost_USE_MULTITHREADED:BOOL=OFF') if not self.options.compiler: self.configure_args.append('-DCMAKE_CXX_COMPILER:PATH=/usr/local/bin/clang++') - self.CXXFLAGS.append('-Qunused-arguments') - self.CXXFLAGS.append('-nostdlibinc') - self.CXXFLAGS.append('-isystem') - self.CXXFLAGS.append('/usr/local/include/c++/v1') - self.CXXFLAGS.append('-isystem') - self.CXXFLAGS.append('/usr/include') - self.CXXFLAGS.append('-stdlib=libc++') - self.CXXFLAGS.append('-Wl,/usr/local/lib/libc++.dylib') - self.CXXFLAGS.append('-Wno-disabled-macro-expansion') - if self.current_flavor == 'opt': self.configure_args.append('-DCMAKE_CXX_FLAGS_RELEASE:STRING=-O4') self.configure_args.append('-DCMAKE_CXX_LINK_FLAGS_RELEASE:STRING=-O4') @@ -681,31 +670,13 @@ class PrepareBuild(CommandLineApp): # self.CXXFLAGS.append('-g -O1 -faddress-sanitizer') # self.LDFLAGS.append('-g -O1 -faddress-sanitizer') - self.configure_args.append('-DCMAKE_INCLUDE_PATH:STRING=/usr/local/include;/opt/local/include') - self.configure_args.append('-DCMAKE_LIBRARY_PATH:STRING=/usr/local/lib;/opt/local/lib') - - self.configure_args.append('-DBOOST_ROOT=/usr/local') - self.configure_args.append('-DBOOST_INCLUDEDIR=/usr/local/include/boost-1_50') - self.configure_args.append('-DBoost_COMPILER=-clang-darwin') - - self.configure_args.append(self.source_dir) - - elif self.options.compiler == "icc": - self.configure_args.append('-DCMAKE_AR:PATH=/opt/intel/bin/xiar') - self.configure_args.append('-DCMAKE_CXX_COMPILER:PATH=/opt/intel/bin/icc') - if self.current_flavor == 'opt': - self.configure_args.append('-DCMAKE_CXX_FLAGS:STRING=-fast') - self.configure_args.append('-DCMAKE_CXX_LINK_FLAGS:STRING=-fast') - self.configure_args.append('-DCMAKE_INCLUDE_PATH:STRING=/opt/local/include') - self.configure_args.append('-DCMAKE_LIBRARY_PATH:STRING=/opt/local/lib') - self.configure_args.append('-DBOOST_ROOT=/opt/local') self.configure_args.append(self.source_dir) else: self.configure_args.append('-DCMAKE_CXX_COMPILER:PATH=' + self.options.compiler) - self.configure_args.append('-DCMAKE_INCLUDE_PATH:STRING=/opt/local/include') - self.configure_args.append('-DCMAKE_LIBRARY_PATH:STRING=/opt/local/lib') - self.configure_args.append('-DBOOST_ROOT=/opt/local') + self.configure_args.append('-DCMAKE_INCLUDE_PATH:STRING=/usr/local/include') + self.configure_args.append('-DCMAKE_LIBRARY_PATH:STRING=/usr/local/lib') + self.configure_args.append('-DBOOST_ROOT=/usr/local') self.configure_args.append(self.source_dir) def setup_for_system(self): @@ -926,13 +897,24 @@ class PrepareBuild(CommandLineApp): self.log.debug('Changing directory to ' + build_dir) os.chdir(build_dir) - self.execute(*(['make'] + make_args)) + self.execute(*(['ninja'] + make_args)) finally: os.chdir(self.source_dir) def phase_check(self, *args): self.log.info('Executing phase: update') - self.execute(*(['ctest'] + make_args)) + build_dir = self.ensure(self.build_directory()) + try: + self.log.debug('Changing directory to ' + build_dir) + os.chdir(build_dir) + + make_args = list(args) + if self.options.jobs > 1: + make_args.append('-j%d' % self.options.jobs) + + self.execute(*(['ctest'] + list(make_args))) + finally: + os.chdir(self.source_dir) def phase_update(self, *args): self.log.info('Executing phase: update') diff --git a/lib/Makefile b/lib/Makefile index 92ec38ce..68755f18 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -2,7 +2,7 @@ # This is only important if you intend to produce a Ledger binary for # installation. -STOW_ROOT = /usr/local/stow +STOW_ROOT = /usr/local/Cellar/boost PRODUCTS = $(HOME)/Products GCC_VERSION = 4.7 @@ -37,14 +37,10 @@ endif BOOST_FLAGS = toolset=$(BOOST_TOOLSET) --layout=versioned \ link=shared threading=single $(BOOST_DEFINES) BOOST_DIR = boost_$(BOOST_VERSION)-$(DIR_SUFFIX) -BOOST_STOW = $(STOW_ROOT)/$(BOOST_DIR) +BOOST_STOW = $(STOW_ROOT)/$(BOOST_VERSION) BOOST_BUILD = $(PRODUCTS)/$(BOOST_DIR) -ICU_FLAGS = -sHAVE_ICU=1 -sICU_PATH=$(STOW_ROOT)/icu-$(DIR_SUFFIX) -BOOST_ICU_DIR = boost_$(BOOST_VERSION)-icu-$(DIR_SUFFIX) -BOOST_ICU_STOW = $(STOW_ROOT)/$(BOOST_ICU_DIR) -BOOST_ICU_BUILD = $(PRODUCTS)/$(BOOST_ICU_DIR) -all: boost-build #icu-build boost-icu-build +all: boost-build prepare-boost: perl -i -pe 's/local command = \[ common\.get-invocation-command darwin : g\+\+ : .*/local command = [ common.get-invocation-command darwin : g++ : $(CXX) ] ;/;' $(BOOST_SOURCE)/tools/build/v2/tools/darwin.jam @@ -56,29 +52,5 @@ boost-build: prepare-boost ./b2 $(OPTJ) debug release --prefix=$(BOOST_STOW) \ --build-dir=$(BOOST_BUILD) $(BOOST_FLAGS) install) -icu-build: - -(cd icu/source; make distclean) - (cd icu/source; sh autogen.sh; \ - ./configure CPPFLAGS="$(CPPFLAGS)" \ - CFLAGS="$(CFLAGS)" \ - LDFLAGS="$(LDFLAGS)" \ - CC="$(CC)" CXX="$(CXX)" LD="$(LD)" \ - --enable-static --enable-debug \ - --prefix=$(STOW_ROOT)/icu-$(DIR_SUFFIX) && \ - make install) - -boost-icu-build: - (cd $(BOOST_SOURCE) && \ - sh bootstrap.sh && \ - ./bjam $(OPTJ) debug --prefix=$(BOOST_ICU_STOW) \ - --build-dir=$(BOOST_ICU_BUILD) \ - $(BOOST_FLAGS) $(ICU_FLAGS) install) - clean: -rm -fr $(BOOST_STOW) $(BOOST_BUILD) - -rm -fr $(BOOST_ICU_STOW) $(BOOST_ICU_BUILD) - -rm -fr $(STOW_ROOT)/icu-$(DIR_SUFFIX) - -(cd icu/source; make distclean) - -lib-clean: - -(cd icu/source; make distclean) diff --git a/lib/build.sh b/lib/build.sh index 4fadccfa..4f3f2e7f 100755 --- a/lib/build.sh +++ b/lib/build.sh @@ -4,7 +4,7 @@ # clang-3.1 from MacPorts. I build my own Boost instead of using MacPorts' # Boost in order to get better debugging support, and to link with libc++. -export PATH=$PATH:/opt/local/lib/openmpi/bin +#export PATH=$PATH:/opt/local/lib/openmpi/bin cat > ~/user-config.jam <-std=c++11 ; @@ -14,4 +14,4 @@ EOF # instead of /usr/local/lib/libc++.1.dylib make CXX=clang++ LD=clang++ CC=clang OPTJ=-j20 \ BOOST_TOOLSET=clang-darwin DIR_SUFFIX=clang31 \ - BOOST_DEFINES="-sHAVE_ICONV=1 -sICONV_PATH=/usr/local -sHAVE_ICU=1 -sICU_PATH=/usr/local cxxflags=\"-g -std=c++11 $* -nostdlibinc -isystem /usr/local/include -isystem /opt/local/include -isystem /usr/local/include/c++/v1 -isystem /usr/include -stdlib=libc++\" linkflags=\"-g $* -L/usr/local/lib -L/opt/local/lib -L/usr/lib /usr/local/lib/libc++.dylib -stdlib=libc++\"" + BOOST_DEFINES="-sHAVE_ICONV=1 -sHAVE_ICU=1 -sICU_PATH=/usr/local/opt/icu4c cxxflags=\"-g -std=c++11 $* -nostdlibinc -isystem /usr/local/include -isystem /usr/local/include/c++/v1 -isystem /usr/include -stdlib=libc++\" linkflags=\"-g $* -L/usr/local/lib -L/usr/lib /usr/local/lib/libc++.dylib -stdlib=libc++\"" diff --git a/tools/build.sh b/tools/build.sh index a37b06f4..2abf70b8 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -6,10 +6,10 @@ shift 1 JOBS=-j$(sysctl -n hw.activecpu) OPTIONS="$flavor --debug --python --doxygen $JOBS" -time ( \ - cd ~/src/ledger ; \ - PATH=/usr/local/bin:/opt/local/bin:$PATH \ - nice -n 20 ./acprep $OPTIONS make "$@" && \ - PATH=/usr/local/bin:/opt/local/bin:$PATH \ - nice -n 20 ./acprep $OPTIONS check "$@" \ +time ( \ + cd ~/src/ledger ; \ + PATH=/usr/local/bin:/opt/local/bin:$PATH \ + nice -n 20 ./acprep $OPTIONS make $JOBS "$@" && \ + PATH=/usr/local/bin:/opt/local/bin:$PATH \ + nice -n 20 ./acprep $OPTIONS check $JOBS "$@" \ ) -- cgit v1.2.3 From a9bd40a1e3959c35f5c72e70825594675b23446c Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 27 Sep 2012 17:40:17 -0500 Subject: Don't use the ninja build command by default --- acprep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acprep b/acprep index 25f565f3..ebf776db 100755 --- a/acprep +++ b/acprep @@ -897,7 +897,7 @@ class PrepareBuild(CommandLineApp): self.log.debug('Changing directory to ' + build_dir) os.chdir(build_dir) - self.execute(*(['ninja'] + make_args)) + self.execute(*(['make'] + make_args)) finally: os.chdir(self.source_dir) -- cgit v1.2.3 From dcd64a67823b2f53cc2e28fe74d5ab2cbcf4e60c Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 27 Sep 2012 17:42:43 -0500 Subject: Added -N/--ninja option to acprep --- acprep | 10 ++++++++-- tools/build.sh | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/acprep b/acprep index ebf776db..26f8d8b2 100755 --- a/acprep +++ b/acprep @@ -300,6 +300,9 @@ class PrepareBuild(CommandLineApp): action="store", dest="compiler", help='Use the Clang C++ compiler') + op.add_option('-N', '--ninja', action='store_true', dest='use_ninja', + default=False, + help='Use ninja to build, rather than make') op.add_option('', '--no-git', action='store_true', dest='no_git', default=False, help='Do not call out to Git; useful for offline builds') @@ -657,7 +660,6 @@ class PrepareBuild(CommandLineApp): ######################################################################### def setup_for_johnw(self): - self.configure_args.append('-GNinja') self.configure_args.append('-DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON') if not self.options.compiler: @@ -690,6 +692,9 @@ class PrepareBuild(CommandLineApp): if self.options.no_python: self.configure_args.remove('-DUSE_PYTHON=1') + if self.options.use_ninja: + self.configure_args.append('-GNinja') + if exists('/Users/johnw/Projects/ledger/plan/TODO'): self.setup_for_johnw() @@ -897,7 +902,8 @@ class PrepareBuild(CommandLineApp): self.log.debug('Changing directory to ' + build_dir) os.chdir(build_dir) - self.execute(*(['make'] + make_args)) + self.execute(*(['ninja' if self.options.use_ninja else 'make'] + + make_args)) finally: os.chdir(self.source_dir) diff --git a/tools/build.sh b/tools/build.sh index 2abf70b8..e79689e3 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -4,7 +4,7 @@ flavor=$1 shift 1 JOBS=-j$(sysctl -n hw.activecpu) -OPTIONS="$flavor --debug --python --doxygen $JOBS" +OPTIONS="$flavor --debug --python --ninja --doxygen $JOBS" time ( \ cd ~/src/ledger ; \ -- cgit v1.2.3 From e56a4ffef07d9731fd6e48ab468fc4780d45945b Mon Sep 17 00:00:00 2001 From: Paolo Capriotti Date: Wed, 9 Mar 2011 10:12:27 -0600 Subject: Running totals on a report including automated transactions are computed with extra precision, resulting in balances differing from the sum of their components. --- test/regress/CAE63F5C-a.test | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 test/regress/CAE63F5C-a.test diff --git a/test/regress/CAE63F5C-a.test b/test/regress/CAE63F5C-a.test new file mode 100644 index 00000000..4465bd2f --- /dev/null +++ b/test/regress/CAE63F5C-a.test @@ -0,0 +1,17 @@ +2011/03/01 test1 + a 4.00 € + b + +2011/03/02 test2 + a 4.00 € + b + +2011/03/03 test2 + a 4.00 € + b + +test reg a +11-Mar-01 test1 a 4.00 € 4.00 € +11-Mar-02 test2 a 4.00 € 8.00 € +11-Mar-03 test2 a 4.00 € 12.00 € +end test -- cgit v1.2.3 From bf7375db116858f387a5aa90da9d659af6a660d2 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 30 Sep 2012 14:53:05 -0400 Subject: Rounding is different for balance totals vs. postings when using posting costs. test/regress/CAE63F5C-b.test and test/regress/CAE63F5C-c.test should both pass, but test/regress/CAE63F5C-c.test does not, because the total line of $6.46 is rounded wrong; it should be $6.45. There seems to be different rounding occurring for totals vs. postings. This seems to be related to Bug #492. --- test/regress/CAE63F5C-b.test | 15 +++++++++++++++ test/regress/CAE63F5C-c.test | 15 +++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 test/regress/CAE63F5C-b.test create mode 100644 test/regress/CAE63F5C-c.test diff --git a/test/regress/CAE63F5C-b.test b/test/regress/CAE63F5C-b.test new file mode 100644 index 00000000..c0b7efd8 --- /dev/null +++ b/test/regress/CAE63F5C-b.test @@ -0,0 +1,15 @@ +2012/08/22 Payment + Accrued €208.00 {=$1.3109} @ $1.2799 + Expenses €4.16 {=$1.2798689} @ $1.2799 + Assets $-271.54 + Income:Currency Conversion $-6.45 + +test bal -X $ + $272.67 Accrued + $-271.54 Assets + $6.45 Equity:Capital Gains + $5.32 Expenses + $-6.45 Income:Currency Conversion +-------------------- + $6.45 +end test diff --git a/test/regress/CAE63F5C-c.test b/test/regress/CAE63F5C-c.test new file mode 100644 index 00000000..ae2d7d10 --- /dev/null +++ b/test/regress/CAE63F5C-c.test @@ -0,0 +1,15 @@ +2012/08/22 Payment + Accrued €208.00 {=$1.3109} @ $1.2798689 + Expenses €4.16 {=$1.2798689} @ $1.2798689 + Assets $-271.54 + Income:Currency Conversion $-6.45 + +test bal -X $ + $272.67 Accrued + $-271.54 Assets + $6.45 Equity:Capital Gains + $5.32 Expenses + $-6.45 Income:Currency Conversion +-------------------- + $6.45 +end test -- cgit v1.2.3 From 1ebc014f55715418ef8f379c1cc7567937dcf8e3 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Wed, 3 Oct 2012 12:23:21 -0700 Subject: correcte --period-sort arguments in section 7.3.1 --- doc/ledger3.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 9a91d79e..4ab27f5f 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -3751,7 +3751,7 @@ The following query makes it easy to see monthly expenses, with each month's expenses sorted by the amount: @example -ledger -M --period-sort t reg ^expenses +ledger -M --period-sort "(amount)" reg ^expenses @end example Now, you might wonder where the money came from to pay for these @@ -3759,7 +3759,7 @@ things. To see that report, add @option{-r}, which shows the ``related account'' postings: @example -ledger -M --period-sort t -r reg ^expenses +ledger -M --period-sort "(amount)" -r reg ^expenses @end example But maybe this prints too much information. You might just want to -- cgit v1.2.3 From ecc91c6b95c7ead18cf4e51e5a5aa72db966aaa6 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 4 Oct 2012 06:25:18 -0700 Subject: Corrected a few missing @ symbols per Jeroen --- doc/ledger3.texi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 4ab27f5f..2d10cb35 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -2984,7 +2984,7 @@ source account. Whenever a commodity is exchanged like this, the commodity moved to the target account is considered "secondary", while the commodity used for purchasing and tracked in the cost is "primary". -Said another way, whenever Ledger sees a posting cost of the form "AMOUNT @ +Said another way, whenever Ledger sees a posting cost of the form "AMOUNT @@ AMOUNT", the commodity used in the second amount is marked "primary". The only meaning a primary commodity has is that -V flag will never convert a @@ -2997,7 +2997,7 @@ Just as you can have amount expressions, you can have posting expressions: @smallexample 2012-03-10 My Broker - Assets:Brokerage 10 AAPL @ ($500.00 / 10) + Assets:Brokerage 10 AAPL @@ ($500.00 / 10) Assets:Brokerage:Cash @end smallexample @@ -3005,7 +3005,7 @@ You can even have both: @smallexample 2012-03-10 My Broker - Assets:Brokerage (5 AAPL * 2) @ ($500.00 / 10) + Assets:Brokerage (5 AAPL * 2) @@ ($500.00 / 10) Assets:Brokerage:Cash @end smallexample @@ -3018,7 +3018,7 @@ instead, use @@@@: @smallexample 2012-03-10 My Broker - Assets:Brokerage 10 AAPL @@@@ $500.00 + Assets:Brokerage 10 AAPL @@ $500.00 Assets:Brokerage:Cash @end smallexample -- cgit v1.2.3 From 8bb5bae7a97dbc2052eb4aa44c1e805b7c07bd5f Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 9 Oct 2012 16:09:09 -0700 Subject: Filled in many blank entries Also reformatted the option lists to be more like the GCC manual --- doc/ledger3.texi | 1241 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 770 insertions(+), 471 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 2d10cb35..ab59f2ae 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -293,8 +293,7 @@ called @file{drewr3.dat} (@pxref{Example Data File}). Copy it someplace convenient and open up a terminal window in that directory. -If you would rather start with your own journal right away please skip -to @xref{Keeping a Journal}. +If you would rather start with your own journal right away please see @ref{Keeping a Journal}. @node Run Some Reports, Command Line Quick Reference, Start a Journal, Ledger Tutorial @section Run a Few Reports @@ -370,11 +369,11 @@ To show all transactions and a running total: ledger -f drewr3.dat register @end smallexample -Ledger will generate: +@noindent Ledger will generate: @smallexample 10-Dec-01 Checking balance Assets:Checking $ 1,000.00 $ 1,000.00 - Equity:Opening Balances $ -1,000.00 0 + Equity:Opening Balances $ -1,000.00 0 10-Dec-20 Organic Co-op Expense:Food:Groceries $ 37.50 $ 37.50 Expense:Food:Groceries $ 37.50 $ 75.00 Expense:Food:Groceries $ 37.50 $ 112.50 @@ -447,7 +446,8 @@ $ ledger -f drewr3.dat register payee "Organic" A very useful report is to show what your obligations are versus what expenditures have actually been recorded. It can take several days for a check to clear, but you should treat it as money spent. The -@samp{cleared} report shows just that: +@samp{cleared} report shows just that (note that the cleared report will +not format correctly for accounts that contain multiple commodities): @smallexample $ ledger -f drewr3.dat cleared @@ -473,7 +473,7 @@ $ ledger -f drewr3.dat cleared $ -243.60 0 @end smallexample -@noindent The first column shows the outstanding balance, the second column show the ``cleared'' balance. +@noindent The first column shows the outstanding balance, the second column shows the ``cleared'' balance. @node Using the Windows command line, , Cleared Report, Run Some Reports @subsection Using the Windows Command Line @cindex windows cmd.exe @@ -482,6 +482,7 @@ Using ledger under the windows command shell has one significant limitation. CMD.exe is limited to standard ASCII characters and as such cannot display any currency symbols other than dollar signs ($). +@page @node Command Line Quick Reference, , Run Some Reports, Ledger Tutorial @section Command Line Quick Reference @@ -588,10 +589,8 @@ cannot display any currency symbols other than dollar signs ($). @item @code{-F STR} @tab @code{--format STR} @tab Set reporting format @item @code{} @tab @code{--balance-format STR} @tab @item @code{} @tab @code{--register-format STR} @tab -@item @code{} @tab @code{--print-format STR} @tab -@item @code{-j register} @tab @code{--plot-amount-format STR} @tab -@item @code{-J register} @tab @code{--plot-total-format STR} @tab -@item @code{} @tab @code{--equity-format STR} @tab +@item @code{-j register} @tab @code{--plot-amount-format STR} @tab format the output of a amount plots +@item @code{-J register} @tab @code{--plot-total-format STR} @tab format the output of a total plot @item @code{} @tab @code{--prices-format STR} @tab @item @code{-w register} @tab @code{--wide-register-format STR} @tab @item @code{} @tab @code{--anon} @tab Print the ledger register with anonymized accounts and payees, useful for filing bug reports @@ -604,7 +603,7 @@ cannot display any currency symbols other than dollar signs ($). @item @code{-P} @tab @code{--by-payee} @tab Group postings by common payee names @item @code{-D} @tab @code{--daily} @tab Group postings by day @item @code{-W} @tab @code{--weekly} @tab Group postings by week -@item @code{-M} @tab @code{--Monthly} @tab Group postings by month +@item @code{-M} @tab @code{--monthly} @tab Group postings by month @item @code{} @tab @code{--quarterly} @tab Group postings by quarter @item @code{-Y} @tab @code{--yearly} @tab Group postings by year @item @code{} @tab @code{--dow} @tab Group by day of weeks @@ -3188,7 +3187,7 @@ print report. Functionally, however, there is no difference, and neither the register nor the balance report are sensitive to this difference. @node Fixated prices, Lot dates, Prices vs. costs, Transactions -@section Fixated prices +@section Fixated prices and costs If you buy a stock last year, and ask for its value today, Ledger will consult its price database to see what the most recent price for that stock is. You @@ -3207,14 +3206,7 @@ else happens to the stock in the meantime. Fixated prices are a special case of using lot valuation expressions (see below) to fix the value of a commodity lot. -@menu -* Fixated costs:: -@end menu - -@node Fixated costs, , Fixated prices, Fixated prices -@subsection Fixated costs - -Since price annotations are costs are largely interchangeable and a matter of +Since price annotations and costs are largely interchangeable and a matter of preference, there is an equivalent syntax for specified fixated prices by way of the cost: @@ -3225,7 +3217,7 @@ of the cost: @end smallexample This is the same as the previous transaction, with the same caveats found in -the section ``Prices vs. costs''. +@ref{Prices vs. costs}. @node Lot dates, Lot notes, Fixated prices, Transactions @section Lot dates @@ -4432,6 +4424,14 @@ examples of more complex operations with a ledger. @node The pricemap Command, The xml Command, Emacs org mode, Reports in other Formats @subsection The @code{pricemap} Command +If you have the graphviz graph visualization package installed, ledger +can generate a graph of the relationship between your various +commodities. The output file is in the ``dot'' format. + +This is probably not very interesting, unless you have many different +commdities valued in terms of each other. For example, multiple +currencies and multiples investments valued in those currencies. + @node The xml Command, prices and pricedb, The pricemap Command, Reports in other Formats @subsection The @code{xml} Command @@ -4810,6 +4810,7 @@ it against a model transaction. Print details of how ledger uses the given formatting description and apply it against a model transaction. @item generate +FIX THIS ENTRY @item parse Print details of how ledger uses the given value expression description and apply it against a model transaction. @@ -4873,6 +4874,7 @@ model transaction: true @end smallexample @item template +FIX THIS ENTRY @end table @node Command-line Syntax, Budgeting and Forecasting, Reporting Commands, Top @@ -4935,7 +4937,6 @@ commands. * Session Options:: * Report Options:: * Report Filtering:: -* Search Terms:: * Output Customization:: * Commodity Reporting:: * Environment Variables:: @@ -4951,50 +4952,49 @@ GUIs, which would make use of the different scopes by keeping an instance of Ledger running in the background and running multiple sessions with multiple reports per session. - -@option{--args-only} Ignore all environment and init-file settings and +@table @code +@item --args-only +Ignore all environment and init-file settings and use only command-line arguments to control Ledger. Useful for debugs or testing small Journal files not associated with you main financial database. - -@option{--help} +@item --help Displays the info page for ledger. -@option{--init-file } +@item --init-file Specifies the location of the init file @file{.ledgerrc} -@option{--options} Display the options in effect for this Ledger -invocation, along with their values and the source of those values, for -example: +@item --options + Display the options in effect for this Ledger invocation, along with +their values and the source of those values, for example: @smallexample 14:15:02 > ledger --options bal --cleared -f ~/ledger/test/input/drewr3.dat =============================================================================== [Global scope options] [Session scope options] - --file = ~/ledger/test/input/drewr3.dat -f - --price-db = ~/FinanceData/PriceDB $price-db + --file = ~/ledger/test/input/drewr3.dat -f + --price-db = ~/FinanceData/PriceDB $price-db [Report scope options] - --cleared --cleared - --color ?normalize - --date-format = %Y/%m/%d $date-format - --limit = cleared --cleared - --prepend-width = 0 ?normalize - --meta-width = 0 ?normalize - --date-width = 10 ?normalize - --payee-width = 21 ?normalize - --account-width = 21 ?normalize - --amount-width = 12 ?normalize - --total-width = 12 ?normalize + --cleared --cleared + --color ?normalize + --date-format = %Y/%m/%d $date-format + --limit = cleared --cleared + --prepend-width = 0 ?normalize + --meta-width = 0 ?normalize + --date-width = 10 ?normalize + --payee-width = 21 ?normalize + --account-width = 21 ?normalize + --amount-width = 12 ?normalize + --total-width = 12 ?normalize =============================================================================== $ 775.00 Assets:Checking $ -1,000.00 Equity:Opening Balances $ 225.00 Expenses:Food:Groceries -------------------- 0 - @end smallexample @noindent For the `source' column, a value starting with a `@code{-}' or `@code{--}' indicated the source was a command line argument. It the @@ -5002,7 +5002,10 @@ entry starts with a `@code{$}', the source was an environment variable. If the source is `@code{?normalize}' the value was set internally by ledger, in a function called @code{normalize_options}. -@option{--script } Execute a ledger script. +@item --script +Execute a ledger script. +@end table + @node Session Options, Report Options, Global Options, Detailed Options Description @subsection Session Options @@ -5013,22 +5016,26 @@ GUIs, which would make use of the different scopes by keeping an instance of Ledger running in the background and running multiple sessions with multiple reports per session. -@option{--decimal-comma} Direct Ledger to parse journals using the -European standard comma as decimal separator, vice a period. +@table @code +@item --decimal-comma +Direct Ledger to parse journals using the European standard comma as +decimal separator, vice a period. -@option{--download} Direct Ledger to download prices using the script -defined in @code{--getquote}. +@item --download +Direct Ledger to download prices using the script defined in +@code{--getquote}. -@option{--file } +@item --file Specify the input file path for this invocation. @cindex getquote @cindex download prices -@option{--getquote } Tells ledger where to find the user defined -script to download prices information. +@item --getquote +Tells ledger where to find the user defined script to download prices +information. -@option{--input-date-format } Specify the input date format -for journal entries. For example, +@item --input-date-format +Specify the input date format for journal entries. For example, @smallexample ledger convert Export.csv --input-date-format "%m/%d/%Y" @end smallexample @@ -5037,8 +5044,8 @@ Would convert the @file{Export.csv} file to ledger format, assuming the the dates in the CSV file are like 12/23/2009 (@pxref{Date and Time Format Codes}). -@option{--master-account } Prepends all account names with the -argument. +@item --master-account +Prepends all account names with the argument. @smallexample 21:51:39 ~/ledger (next)> ledger -f test/input/drewr3.dat bal --master-account HUMBUG 0 HUMBUG @@ -5063,23 +5070,24 @@ argument. $ 200.00 Mortgage:Principal @end smallexample -@option{--price-db } Specify the location of the price entry data -file. +@item --price-db +Specify the location of the price entry data file. -@option{--price-exp INTEGER_MINUTES} Set the expected freshness of price -quotes, in minutes. That is, if the last known quote for any commodity -is older than this value, and if ‘--download’ is being used, then the -Internet will be consulted again for a newer price. Otherwise, the old -price is still considered to be fresh enough. - -@option{--strict} Ledger normally silently accepts any account or -commodity in a posting, even if you have misspelled a common used one. -The option @code{--strict} changes that behavior. While running -@code{--strict}, Ledger interprets all cleared transactions as correct, -and if it finds a new account or commodity (same as a misspelled -commodity or account) it will issue a warning giving you the file and -line number of the problem. +@item --price-exp INTEGER_MINUTES +Set the expected freshness of price quotes, in minutes. That is, if the +last known quote for any commodity is older than this value, and if +@samp{--download} is being used, then the Internet will be consulted again +for a newer price. Otherwise, the old price is still considered to be +fresh enough. +@item --strict +Ledger normally silently accepts any account or commodity in a posting, +even if you have misspelled a common used one. The option +@code{--strict} changes that behavior. While running @code{--strict}, +Ledger interprets all cleared transactions as correct, and if it finds a +new account or commodity (same as a misspelled commodity or account) it +will issue a warning giving you the file and line number of the problem. +@end table @node Report Options, Report Filtering, Session Options, Detailed Options Description @subsection Report Options Options for Ledger report affect three separate scopes of operation: @@ -5088,7 +5096,7 @@ difference between these scopes. Ledger 3.0 contains provisions for GUIs, which would make use of the different scopes by keeping an instance of Ledger running in the background and running multiple sessions with multiple reports per session. -@option{--abbrev-len } Sets the minimum +@code{--abbrev-len } Sets the minimum length an account can be abbreviated to if it doesn't fit inside the @code{account-width}. If @code{abbrev-len} is zero, then the account name will be truncated on the right. If @code{abbrev-len} is greater @@ -5096,40 +5104,52 @@ than @code{account-width} then the account will be truncated on the left, with no shortening of the account names in order to fit into the desired width. -@option{--account } Prepend @code{} to all accounts +@table @code +@item --account +Prepend @code{} to all accounts reported. That is, the option @code{--account Personal} would tack @code{Personal:} to the beginning of every account reported in a balance report or register report. -@option{--account-width } Set the width of the account column in +@item --account-width + Set the width of the account column in the @code{register} report to @code{N} characters. -@option{--actual-dates} Show actual dates of transactions +@item --actual-dates + Show actual dates of transactions (@pxref{Effective Dates}). Also @code{-L}. -@option{--actual} Report only real transactions, with no automated or +@item --actual + Report only real transactions, with no automated or virtual transactions used. -@option{--add-budget} Show only unbudgeted postings. +@item --add-budget + Show only unbudgeted postings. -@option{--amount-data} On a register report print only the dates and +@item --amount-data + On a register report print only the dates and amount of postings. Useful for graphing and spreadsheet applications. -@option{--amount } Apply the given value expression to the posting +@item --amount + Apply the given value expression to the posting amount (@pxref{Value Expressions}). Using @code{--amount} you can apply an arbitrary transformation to the postings. -@option{--amount-width } Set the width in characters of the amount +@item --amount-width + Set the width in characters of the amount column in the register report. -@option{--anon} anonymizes registry output, mostly for sending in bug +@item --anon + anonymizes registry output, mostly for sending in bug reports. -@option{--average} Print average values over the number of transactions +@item --average + Print average values over the number of transactions instead of running totals. -@option{--balance-format } specifies the format to use for the +@item --balance-format + specifies the format to use for the @code{balance} report (@pxref{Format Strings}). The default is: @smallexample "%(justify(scrub(display_total), 20, -1, true, color))" @@ -5139,14 +5159,18 @@ instead of running totals. "--------------------\n" @end smallexample -@option{--base} ASK JOHN +@item --base + ASK JOHN -@option{--basis} Report the cost basis on all posting +@item --basis + Report the cost basis on all posting -@option{--begin } Specify the start date of all calculations. +@item --begin + Specify the start date of all calculations. Transactions before that date will be ignored. -@option{--bold-if } print the entire line in bold if the given +@item --bold-if + print the entire line in bold if the given value expression is true (@pxref{Value Expressions}). @smallexample @@ -5154,7 +5178,8 @@ ledger reg Expenses --begin Dec --bold-if "amount > 100" @end smallexample @noindent list all transactions since the beginning of December and bold any posting greater than $100 -@option{--budget-format } +@item --budget-format + specifies the format to use for the @code{budget} report (@pxref{Format Strings}). The default is: @smallexample "%(justify(scrub(display_total), 20, -1, true, color))" @@ -5164,14 +5189,17 @@ specifies the format to use for the @code{budget} report (@pxref{Format Strings} "--------------------\n" @end smallexample -@option{--budget} only display budgeted items. In a register report this +@item --budget + only display budgeted items. In a register report this displays transaction in the budget, in a balance report this displays accounts in the budget (@pxref{Budgeting and Forecasting}). -@option{--by-payee } +@item --by-payee + group the register report by payee. -@option{--cleared-format } specifies the format to use +@item --cleared-format + specifies the format to use for the @code{cleared} report (@pxref{Format Strings}). The default is: @smallexample @@ -5186,25 +5214,32 @@ for the @code{cleared} report (@pxref{Format Strings}). The default is: "---------------- ---------------- ---------\n" @end smallexample -@option{--cleared} consider only transaction that have been cleared for +@item --cleared + consider only transaction that have been cleared for display and calculation. -@option{--collapse} By default ledger prints all account in an account +@item --collapse + By default ledger prints all account in an account tree. With @code{--collapse} it print only the top level account specified. -@option{--collapse-if-zero} Collapses the account display only if it has +@item --collapse-if-zero + Collapses the account display only if it has a zero balance. -@option{--color} use color is the tty supports it. +@item --color + use color is the tty supports it. -@option{--columns } specify the width of the register report in +@item --columns + specify the width of the register report in characters. -@option{--count} Direct ledger to report the number of items when +@item --count + Direct ledger to report the number of items when appended to the commodities, accounts or payees command. -@option{--csv-format} specifies the format to use for the @code{csv} +@item --csv-format + specifies the format to use for the @code{csv} report (@pxref{Format Strings}). The default is: @smallexample "%(quoted(date))," @@ -5216,25 +5251,32 @@ report (@pxref{Format Strings}). The default is: "%(quoted(cleared ? \"*\" : (pending ? \"!\" : \"\")))," "%(quoted(join(note | xact.note)))\n" @end smallexample -@option{--current} +@item --current + Shorthand for @code{--limit "date <= today"} -@option{--daily} +@item --daily + Shorthand for @code{--period "daily"} -@option{--date-format } specifies format ledger should use +@item --date-format + specifies format ledger should use to print dates (@pxref{Date and Time Format Codes}). -@option{--date } transforms the date of the transaction using +@item --date + transforms the date of the transaction using @code{EXPR} -@option{--date-width } specifies the width, in characters, of the +@item --date-width + specifies the width, in characters, of the date column in the register report. -@option{--datetime-format} +@item --datetime-format + ASK JOHN -@option{--dc} Display register or balance in debit/credit format +@item --dc + Display register or balance in debit/credit format If you use @samp{--dc} with either the register (reg) or balance (bal) commands, you will now get extra columns. The register goes from this: @smallexample @@ -5285,81 +5327,103 @@ For the balance report without @samp{--dc}: @end smallexample -@option{--depth } limit the depth of the account tree. In a balance -report, for example, a @code{--depth 2} statement will print balances -only for account with two levels, i.e. @code{Expenses:Entertainment} but -not @code{Expenses:entertainemnt:Dining}. This is a display predicate, -which means it only affects display, not the total calculations. +@item --depth + limit the depth of the account tree. In a balance report, for example, +a @code{--depth 2} statement will print balances only for account with +two levels, i.e. @code{Expenses:Entertainment} but not +@code{Expenses:entertainemnt:Dining}. This is a display predicate, which +means it only affects display, not the total calculations. -@option{--deviation} reports each posting’s deviation from the - average. It is only mean- ingful in the register and prices reports. +@item --deviation + reports each posting’s deviation from the average. It is only + meaningful in the register and prices reports. -@option{--display-amount } apply a transform to the +@item --display-amount + apply a transform to the @strong{displayed} amount. This occurs after calculations occur. -@option{--display } +@item --display + display lines that satisfy the expression given. -@option{--display-total } apply a transform to the +@item --display-total + apply a transform to the @strong{displayed} total. This occurs after calculations occur. -@option{--dow} +@item --dow + group transactions by the day of the week. @smallexample ledger reg Expenses --dow --collapse @end smallexample @noindent will print all Expenses totalled for each day of the week. -@option{--effective} +@item --effective + use effective dates for all calculations (@pxref{Effective Dates}). -@option{--empty} +@item --empty + include empty accounts in the report. -@option{--end } +@item --end + specify the end date for transaction to be considered in the report. -@option{--equity} related to the @code{equity} command (@pxref{The +@item --equity + related to the @code{equity} command (@pxref{The equity Command}). Gives current account balances in the form of a register report. -@option{--exact} +@item --exact + ASK JOHN -@option{--exchange } display values in terms of the given +@item --exchange + display values in terms of the given commodity. The latest available price is used. -@option{--flat} force the full names of accounts to be used inthe +@item --flat + force the full names of accounts to be used inthe balance report. The balance report will not use an indented tree. -@option{--force-color} output tty color codes even if the tty doesn't +@item --force-color + output tty color codes even if the tty doesn't support them. Ueful for TTY that don't advertise their capabilities correctly. -@option{--force-pager} +@item --force-pager + force Ledger to paginate its output. -@option{forecast-while} +@item --forecast-while + FIX THIS ENTRY -@option{forecast-years} +@item --forecast-years + FIX THIS ENTRY -@option{--format } +@item --format + use the given format string to print output. -@option{--gain} +@item --gain + report on gains using the latest available prices . -@option{generated} +@item --generated + ASK JOHN -@option{--group-by } group transaction together in the register +@item --group-by + group transaction together in the register report. EXPR can be anything, although most common would be @code{"payee"} or @code{"commodity"}. The @code{tags()} function is also useful here. -@option{--group-title-format} sets the format for the headers that +@item --group-title-format + sets the format for the headers that separate reports section of a grouped report. Only has effect with a @code{--group-by} register report. @smallexample @@ -5376,200 +5440,282 @@ ledger reg Expenses --group-by "payee" --group-title-format "------------------- @end smallexample -@option{--head } +@item --head + Print the first INT entries. Opposite of @code{--tail}. -@option{--inject} -See email from John W. +@item --inject +Use @code{Expected} amounts in calculations. In the case that you know +that amount a transaction should be, but the actual transaction has the +wrong value you can use metadata to put in the expected amount: +@smallexample +2012-03-12 Paycheck + Income $-990; Expected:: $-1000.00 + Checking +@end smallexample + +Then using the command @code{ledger reg --inject=Expected Income} would +treat the transaction as iff the ``Expected Value'' was actual. +@item --invert -@option{--invert} Change the sign of all reported values. -@option{--limit } Only transactions that satisfy the expression +@item --limit + Only transactions that satisfy the expression will be considered in the calculation. -@option{--lot-dates} -FIX THIS ENTRY +@item --lot-dates +Report the date on which each commodity in a balance report was purchased. -@option{--lot-prices} -FIX THIS ENTRY +@item --lot-prices -@option{--lot-tags} -FIX THIS ENTRY +Report the price at which each commodity in a balance report was purchased. -@option{--lots-actual} -FIX THIS ENTRY +@item --lot-tags -@option{--lots} -FIX THIS ENTRY +Report the tag attached to each commodity in a balance report. -@option{market} -FIX THIS ENTRY +@item --lots-actual -@option{meta} FIX THIS ENTRY -@option{meta-width} +@item --lots + +Report the date and price at which each commodity was purchased in a balance report. + +@item --market + +Use the latest market value for all commodities. + +@item --meta + FIX THIS ENTRY -@option{--monthly} +@item --meta-width + FIX THIS ENTRY -@option{--no-color} +@item --monthly + +synonymn for @code{--period "monthly"} + +@item --no-color + suppress any color TTY output. -@option{--no-rounding} -FIX THIS ENTRY +@item --no-rounding -@option{--no-titles} FIX THIS ENTRY -@option{--no-total} -FIX THIS ENTRY +@item --no-titles -@option{--now} -FIX THIS ENTRY +Suppress the output of group titles -@option{only} -FIX THIS ENTRY +@item --no-total -@option{--output} -FIX THIS ENTRY +Suppress printing the final total line in a balance report. -@option{--pager} -FIX THIS ENTRY +@item --now -@option{payee} FIX THIS ENTRY -@option{payee-width} +@item --only + FIX THIS ENTRY -@option{--pending} -Use only postings tht are marked pending +@item --output -@option{percent} FIX THIS ENTRY -@option{period} -FIX THIS ENTRY +@item --pager -@option{--pivot} -FIX THIS ENTRY +Specify the pager program to use. -@option{plot-amount-format} -FIX THIS ENTRY +@item --payee -@option{plot-total-format} -FIX THIS ENTRY +Sets a value expression for formatting the payee. In the register report +this prevents the second entry from having a date and payee for each +transaction -@option{prepend-format} -FIX THIS ENTRY +@item --payee-width N -@option{prepend-width} -FIX THIS ENTRY +Set the number of columns dedicated to the payee in the register report. -@option{pricedb-format} -FIX THIS ENTRY +@item --pending -@option{price} -FIX THIS ENTRY +Use only postings that are marked pending -@option{prices-format} -FIX THIS ENTRY +@item --percent +Calculate the percentage value of each account in a blance reports. +Only works for account that have a single commoditiy. + +@item --period + +Define a period expression the sets the time period during which +transactions are to be accounted. For a register report only th +transactions that satisfy the period expression with be displayed. For +a balance report only those transactions will be accounted in the final +balances. + +@item --pivot + +Produce a balance pivot report ``around'' the given tag. For example, +if you have multiple cars and track each fuel purchase in +@code{Expenses:Auto:Fuel} and tag each fuel purchase with a tag +identifying which car the purchase was for @code{; Car: Prius}, then the command: +@smallexample +ledger bal Fuel --pivot "Car" --period "this year" + $ 3491.26 Car + $ 1084.22 M3:Expenses:Auto:Fuel + $ 149.65 MG V11:Expenses:Auto:Fuel + $ 621.89 Prius:Expenses:Auto:Fuel + $ 1635.50 Sienna:Expenses:Auto:Fuel + $ 42.69 Expenses:Auto:Fuel +-------------------- + $ 3533.95 +@end smallexample + +@item --plot-amount-format + +Define the output format for a amount data plot. @xref{Visualizing with Gnuplot}. + +@item --plot-total-format + +Define the output format for a total data plot. @xref{Visualizing with Gnuplot}. + +@item --prepend-format STR + +Prepend STR to every line of the output + +@item --prepend-width N + +Reserve @code{N} spaces at the beginning of each line of the output + + +@item --price -@option{quantity} FIX THIS ENTRY -@option{--quarterly} +@item --quantity + FIX THIS ENTRY -@option{raw} +@item --quarterly + +Synonym for @code{--period "quarterly"}. + +@item --raw + FIX THIS ENTRY -@option{--real} Account using only real transactions ignoring virtual +@item --real + Account using only real transactions ignoring virtual and automatic transactions. -@option{register-format} -FIX THIS ENTRY -@option{related-all} -FIX THIS ENTRY +@item --related-all + +Show all postings in a transaction, similar to @code{--related} but show +both ``sides'' of each transaction. + +@item --related -@option{--related} -In a register report show the related account. +In a register report show the related account. This is the other +``side'' of the transaction. + +@item --revalued-only -@option{--revalued-only} FIX THIS ENTRY -@option{--revalued-total} +@item --revalued-total + FIX THIS ENTRY -@option{--revalued} +@item --revalued + FIX THIS ENTRY -@option{seed} +@item --seed + FIX THIS ENTRY -@option{sort-all} +@item --sort-all + FIX THIS ENTRY -@option{--sort } +@item --sort + Sort the register report based on the value expression given to sort -@option{--sort-xacts} -FIX THIS ENTRY +@item --sort-xacts + +Sort the posting within transactions using the given value expression + +@item --start-of-week +Tell ledger to use a particular day of the week to start its ``weekly'' +summary. @code{--start-of-week=1} specifies Monday as the start of the +week. -@option{--start-of-week } Tell ledger to use a particular day of -the week to start its ``weekly'' summary. @code{--start-of-week=1} -specifies Monday as the start of the week. +@item --subtotal -@option{--subtotal} FIX THIS ENTRY -@option{--tail } +@item --tail + report only the last entries. Only useful ona register report. -@option{total-data} +@item --total-data + FIX THIS ENTRY -@option{total} +@item --total + FIX THIS ENTRY -@option{total-width} +@item --total-width + FIX THIS ENTRY -@option{truncate} +@item --truncate + FIX THIS ENTRY -@option{unbudgeted} +@item --unbudgeted + FIX THIS ENTRY -@option{uncleared} +@item --uncleared + FIX THIS ENTRY -@option{unrealized-gains} +@item --unrealized-gains + FIX THIS ENTRY -@option{unrealized-losses} +@item --unrealized-losses + FIX THIS ENTRY -@option{unrealized} +@item --unrealized + FIX THIS ENTRY -@option{unround} +@item --unround + FIX THIS ENTRY -@option{--weekly} +@item --weekly + synonymn for @code{--period "weekly"} -@option{--wide} lets the register report use 132 columns. Identical to -@code{--columns "132"} +@item --wide +lets the register report use 132 columns. Identical to @code{--columns +"132"} -@option{yearly} +@item --yearly synonymn for @code{--period "yearly"} - +@end table @@ -5579,29 +5725,37 @@ These are the most basic command options. Most likely, the user will want to set them using environment variables (see @ref{Environment Variables}), instead of using actual command-line options: -@option{--help} (@option{-h}) prints a summary of all the options, and -what they are used for. This can be a handy way to remember which -options do what. This help screen is also printed if ledger is run -without a command. - -@option{--version} (@option{-v}) prints the current version of ledger -and exits. This is useful for sending bug reports, to let the author -know which version of ledger you are using. - -@option{--file FILE} (@option{-f FILE}) reads FILE as a ledger file. -This command may be used multiple times. -Typically, the environment variable -@env{LEDGER_FILE} is set, rather than using this command-line option. - -@option{--output FILE} (@option{-o FILE}) redirects output from any -command to @var{FILE}. By default, all output goes to standard -output. - -@option{--init-file FILE} (@option{-i FILE}) causes FILE to be read by -ledger before any other ledger file. This file may not contain any -postings, but it may contain option settings. To specify options -in the init file, use the same syntax as the command-line, but put each -option on it's own line. Here's an example init file: +@table @code +@item --help +@item -h +Prints a summary of all the options, and what they are used for. This +can be a handy way to remember which options do what. This help screen +is also printed if ledger is run without a command. + +@item --version +@item -v +prints the current version of ledger and exits. This is useful for +sending bug reports, to let the author know which version of ledger you +are using. + +@item --file FILE +@item -f FILE +reads FILE as a ledger file. This command may be used multiple times. +Typically, the environment variable @env{LEDGER_FILE} is set, rather +than using this command-line option. + +@item --output FILE +@item -o FILE +redirects output from any command to @var{FILE}. By default, all output +goes to standard output. + +@item --init-file FILE +@item -i FILE +causes FILE to be read by ledger before any other ledger file. This +file may not contain any postings, but it may contain option settings. +To specify options in the init file, use the same syntax as the +command-line, but put each option on it's own line. Here's an example +init file: @smallexample --price-db ~/finance/.pricedb @@ -5613,68 +5767,81 @@ Option settings on the command-line or in the environment always take precedence over settings in the init file. -@option{--account NAME} (@option{-a NAME}) specifies the default -account which QIF file postings are assumed to relate to. +@item --account NAME +@item -a NAME +specifies the default account which QIF file postings are assumed to +relate to. +@end table -@node Report Filtering, Search Terms, Report Options, Detailed Options Description +@node Report Filtering, Output Customization, Report Options, Detailed Options Description @subsection Report filtering These options change which postings affect the outcome of a report, in ways other than just using regular expressions: -@option{--current}(@option{-c}) displays only transactions occurring on or -before the current date. - -@option{--begin DATE} (@option{-b DATE}) constrains the report to -transactions on or after @var{DATE}. Only transactions after that date will be -calculated, which means that the running total in the balance report -will always start at zero with the first matching transaction. (Note: This -is different from using @option{--display} to constrain what is -displayed). - -@option{--end DATE} (@option{-e DATE}) constrains the report so that -transactions on or after @var{DATE} are not considered. The ending date -is inclusive. - -@option{--period STR} (@option{-p STR}) sets the reporting period -to @var{STR}. This will subtotal all matching transactions within each -period separately, making it easy to see weekly, monthly, quarterly, -etc., posting totals. A period string can even specify the -beginning and end of the report range, using simple terms like ``last -June'' or ``next month''. For more using period expressions, see -@ref{Period Expressions}. - -@option{--period-sort EXPR} sorts the postings within each -reporting period using the value expression @var{EXPR}. This is most -often useful when reporting monthly expenses, in order to view the -highest expense categories at the top of each month: +@table @code +@item --current +@item -c +displays only transactions occurring on or before the current date. + +@item --begin DATE +@item -b DATE constrains the report to transactions on or after +@var{DATE}. Only transactions after that date will be calculated, which +means that the running total in the balance report will always start at +zero with the first matching transaction. (Note: This is different from +using @option{--display} to constrain what is displayed). + +@item --end DATE +@item -e DATE +constrains the report so that transactions on or after @var{DATE} are +not considered. The ending date is inclusive. + +@item --period STR +@item -p STR sets the reporting period to @var{STR}. This will subtotal +all matching transactions within each period separately, making it easy +to see weekly, monthly, quarterly, etc., posting totals. A period +string can even specify the beginning and end of the report range, using +simple terms like ``last June'' or ``next month''. For more using +period expressions, see @ref{Period Expressions}. + +@item --period-sort EXPR +sorts the postings within each reporting period using the value +expression @var{EXPR}. This is most often useful when reporting monthly +expenses, in order to view the highest expense categories at the top of +each month: @smallexample ledger -M --period-sort -At reg ^Expenses @end smallexample -@option{--cleared} (@option{-C}) displays only postings whose transaction -has been marked ``cleared'' (by placing an asterisk to the right of the -date). +@item --cleared +@item -C + displays only postings whose transaction has been marked ``cleared'' +(by placing an asterisk to the right of the date). -@option{--uncleared} (@option{-U}) displays only postings whose -transaction has not been marked ``cleared'' (i.e., if there is no asterisk to -the right of the date). +@item --uncleared +@item -U +displays only postings whose transaction has not been marked ``cleared'' +(i.e., if there is no asterisk to the right of the date). -@option{--real} (@option{-R}) displays only real postings, not virtual. -(A virtual posting is indicated by surrounding the account name with -parentheses or brackets; see @ref{Virtual postings} for more -information). +@item --real +@item -R + displays only real postings, not virtual. (A virtual posting is +indicated by surrounding the account name with parentheses or brackets; +see @ref{Virtual postings} for more information). -@option{--actual} (@option{-L}) displays only actual postings, and -not those created due to automated postings. +@item --actual +@item -L +displays only actual postings, and not those created due to automated +postings. -@option{--related} (@option{-r}) displays postings that are -related to whichever postings would otherwise have matched the -filtering criteria. In the register report, this shows where money -went to, or the account it came from. In the balance report, it shows -all the accounts affected by transactions having a related posting. -For example, if a file had this transaction: +@item --related +@item -r +displays postings that are related to whichever postings would otherwise +have matched the filtering criteria. In the register report, this shows +where money went to, or the account it came from. In the balance +report, it shows all the accounts affected by transactions having a +related posting. For example, if a file had this transaction: @smallexample 2004/03/20 Safeway @@ -5697,154 +5864,184 @@ posting that matched: Assets:Checking $85.00 $65.00 @end smallexample -@option{--budget} is useful for displaying how close your postings -meet your budget. @option{--add-budget} also shows un-budgeted -postings, while @option{--unbudgeted} shows only those. -@option{--forecast} is a related option that projects your budget into -the future, showing how it will affect future balances. -@xref{Budgeting and Forecasting}. +@item --budget +is useful for displaying how close your postings meet your budget. +@code{--add-budget} also shows un-budgeted postings, while +@code{--unbudgeted} shows only those. @code{--forecast} is a related +option that projects your budget into the future, showing how it will +affect future balances. @xref{Budgeting and Forecasting}. -@option{--limit EXPR} (@option{-l EXPR}) limits which postings -take part in the calculations of a report. +@item --limit EXPR +@item -l EXPR +limits which postings take part in the calculations of a report. -@option{--amount EXPR} (@option{-t EXPR}) changes the value expression -used to calculate the ``value'' column in the @command{register} -report, the amount used to calculate account totals in the -@command{balance} report, and the values printed in the +@item --amount EXPR +@item -t EXPR +changes the value expression used to calculate the ``value'' column in +the @command{register} report, the amount used to calculate account +totals in the @command{balance} report, and the values printed in the @command{equity} report. @xref{Value Expressions}. -@option{--total EXPR} (@option{-T EXPR}) sets the value expression -used for the ``totals'' column in the @command{register} and -@command{balance} reports. - -@node Search Terms, Output Customization, Report Filtering, Detailed Options Description -@subsection Search Terms - -Valid Ledger invocations look like: -@smallexample - ledger [OPTIONS] -@end smallexample - -Where @samp{COMMAND} is any command verb (@pxref{Reporting Commands}), @samp{OPTIONS} can occur -anywhere, and @samp{SEARCH-TERM} is one or more of the following: - -@smallexample - word search for any account containing 'word' - TERM and TERM boolean AND between terms - TERM or TERM boolean OR between terms - not TERM invert the meaning of the term - payee word search for any payee containing 'word' - @@word shorthand for 'payee word' - desc word alternate for 'payee word' - note word search for any note containing 'word' - &word shorthand for 'note word' - tag word search for any metadata tag containing 'word' - tag word=value search for any metadata tag containing 'word' - whose value contains 'value' - %word shorthand for 'tag word' - %word=value shorthand for 'tag word=value' - meta word alternate for 'tag word' - meta word=value alternate for 'tag word=value' - expr 'EXPR' apply the given value expression as a predicate - '=EXPR' shorthand for 'expr EXPR' - \( TERMS \) group terms; useful if using and/or/not -@end smallexample - -So, to list all transaction that charged to ``food'' but not ``dining'' for any payee other than ``chang'' the following three commands would be equivalent: - -@smallexample - ledger reg food not dining @@chang - ledger reg food and not dining and not payee chang - ledger reg food not dining expr 'payee =~ /chang/' -@end smallexample - -@node Output Customization, Commodity Reporting, Search Terms, Detailed Options Description +@item --total EXPR +@item -T EXPR +sets the value expression used for the ``totals'' column in the +@command{register} and @command{balance} reports. +@end table +@c @node Search Terms, Output Customization, Report Filtering, Detailed Options Description +@c @subsection Search Terms + +@c Valid Ledger invocations look like: +@c @smallexample +@c ledger [OPTIONS] +@c @end smallexample + +@c Where @samp{COMMAND} is any command verb (@pxref{Reporting Commands}), @samp{OPTIONS} can occur +@c anywhere, and @samp{SEARCH-TERM} is one or more of the following: + +@c @smallexample +@c word search for any account containing 'word' +@c TERM and TERM boolean AND between terms +@c TERM or TERM boolean OR between terms +@c not TERM invert the meaning of the term +@c payee word search for any payee containing 'word' +@c @@word shorthand for 'payee word' +@c desc word alternate for 'payee word' +@c note word search for any note containing 'word' +@c &word shorthand for 'note word' +@c tag word search for any metadata tag containing 'word' +@c tag word=value search for any metadata tag containing 'word' +@c whose value contains 'value' +@c %word shorthand for 'tag word' +@c %word=value shorthand for 'tag word=value' +@c meta word alternate for 'tag word' +@c meta word=value alternate for 'tag word=value' +@c expr 'EXPR' apply the given value expression as a predicate +@c '=EXPR' shorthand for 'expr EXPR' +@c \( TERMS \) group terms; useful if using and/or/not +@c @end smallexample + +@c So, to list all transaction that charged to ``food'' but not ``dining'' +@c for any payee other than ``chang'' the following three commands would be +@c equivalent: + +@c @smallexample +@c ledger reg food not dining @@chang +@c ledger reg food and not dining and not payee chang +@c ledger reg food not dining expr 'payee =~ /chang/' +@c @end smallexample + +@node Output Customization, Commodity Reporting, Report Filtering, Detailed Options Description @subsection Output Customization These options affect only the output, but not which postings are used to create it: -@option{--collapse} (@option{-n}) causes transactions in a -@command{register} report with multiple postings to be collapsed +@table @code +@item --collapse +@item -n +causes transactions in a @command{register} report with multiple +postings to be collapsed into a single, subtotaled transaction. + +@item --subtotal +@item -s + causes all transactions in a @command{register} report to be collapsed into a single, subtotaled transaction. -@option{--subtotal} (@option{-s}) causes all transactions in a -@command{register} report to be collapsed into a single, subtotaled -transaction. - -@option{--by-payee} (@option{-P}) reports subtotals by payee. - - -@option{--empty} (@option{-E}) includes even empty accounts in the -@command{balance} report. - -@option{--weekly} (@option{-W}) reports posting totals by the -week. The week begins on whichever day of the week begins the month -containing that posting. To set a specific begin date, use a -period string, such as @samp{weekly from DATE}. @option{--monthly} -(@option{-M}) reports posting totals by month; @option{--yearly} -(@option{-Y}) reports posting totals by year. For more complex -period, using the @option{--period} option described above. - -@option{--dow} reports postings totals for each day of the week. -This is an easy way to see if weekend spending is more than on -weekdays. - -@option{--sort EXPR} (@option{-S EXPR}) sorts a report by comparing -the values determined using the value expression @var{EXPR}. For -example, using @option{-S -UT} in the balance report will sort account -balances from greatest to least, using the absolute value of the -total. For more on how to use value expressions, see @ref{Value -Expressions}. - -@option{--pivot TAG} produces a pivot table around the tag provided. -This requires meta data using valued tags. - -@option{--wide} (@option{-w}) causes the default @command{register} -report to assume 132 columns instead of 80. - -@option{--head} causes only the first N transactions to be printed. This -is different from using the command-line utility @command{head}, which -would limit to the first N postings. @option{--tail} outputs only -the last N transactions. Both options may be used simultaneously. If a -negative amount is given, it will invert the meaning of the flag -(instead of the first five transactions being printed, for example, it -would print all but the first five). - -@option{--pager} tells Ledger to pass its output to the given pager -program---very useful when the output is especially long. This -behavior can be made the default by setting the @env{LEDGER_PAGER} -environment variable. - -@option{--average} (@option{-A}) reports the average posting -value. - -@option{--deviation} (@option{-D}) reports each posting's -deviation from the average. It is only meaningful in the -@command{register} and @command{prices} reports. - -@option{--percent} (@option{-%}) shows account subtotals in the -@command{balance} report as percentages of the parent account. +@item --by-payee +@item -P +reports subtotals by payee. + + +@item --empty +@item -E +includes even empty accounts in the @command{balance} report. + +@item --weekly +@item -W +reports posting totals by the week. The week begins on whichever day of +the week begins the month containing that posting. To set a specific +begin date, use a period string, such as @samp{weekly from DATE}. +@item --monthly +@item -M +reports posting totals by month; +@item --yearly +@item -Y +reports posting totals by year. For more complex period, using the +@item --period +option described above. + +@item --dow +reports postings totals for each day of the week. This is an easy way +to see if weekend spending is more than on weekdays. + +@item --sort EXPR +@item -S EXPR +sorts a report by comparing the values determined using the value +expression @var{EXPR}. For example, using @option{-S -UT} in the +balance report will sort account balances from greatest to least, using +the absolute value of the total. For more on how to use value +expressions, see @ref{Value Expressions}. + +@item --pivot TAG +produces a pivot table around the tag provided. This requires meta data +using valued tags. + +@item --wide +@item -w +causes the default @command{register} report to assume 132 columns +instead of 80. + +@item --head +causes only the first N transactions to be printed. This is different +from using the command-line utility @command{head}, which would limit to +the first N postings. @option{--tail} outputs only the last N +transactions. Both options may be used simultaneously. If a negative +amount is given, it will invert the meaning of the flag (instead of the +first five transactions being printed, for example, it would print all +but the first five). + +@item --pager +tells Ledger to pass its output to the given pager program---very useful +when the output is especially long. This behavior can be made the +default by setting the @env{LEDGER_PAGER} environment variable. + +@item --average +@item -A +reports the average posting value. + +@item --deviation +@item -D +reports each posting's deviation from the average. It is only +meaningful in the @command{register} and @command{prices} reports. + +@item --percent +@item -% +shows account subtotals in the @command{balance} report as percentages +of the parent account. @c @option{--totals} include running total information in the @c @command{xml} report. -@option{--amount-data} (@option{-j}) changes the @command{register} -report so that it outputs nothing but the date and the value column, -and the latter without commodities. This is only meaningful if the -report uses a single commodity. This data can then be fed to other -programs, which could plot the date, analyze it, etc. +@item --amount-data +@item -j +changes the @command{register} report so that it outputs nothing but the +date and the value column, and the latter without commodities. This is +only meaningful if the report uses a single commodity. This data can +then be fed to other programs, which could plot the date, analyze it, +etc. -@option{--total-data} (@option{-J}) changes the @command{register} -report so that it outputs nothing but the date and totals column, -without commodities. +@item --total-data +@item -J +changes the @command{register} report so that it outputs nothing but the +date and totals column, without commodities. -@option{--display EXPR} (@option{-d EXPR}) limits which postings -or accounts or actually displayed in a report. They might still be -calculated, and be part of the running total of a register report, for -example, but they will not be displayed. This is useful for seeing -last month's checking postings, against a running balance which -includes all posting values: +@item --display EXPR +@item -d EXPR +limits which postings or accounts or actually displayed in a report. +They might still be calculated, and be part of the running total of a +register report, for example, but they will not be displayed. This is +useful for seeing last month's checking postings, against a running +balance which includes all posting values: @smallexample ledger -d "d>=[last month]" reg checking @@ -5862,38 +6059,133 @@ Which is more useful depends on what you're looking to know: the total amount for the reporting range (@option{-p}), or simply a display restricted to the reporting range (using @option{-d}). -@option{--date-format STR} (@option{-y STR}) changes the basic date -format used by reports. The default uses a date like 2004/08/01, -which represents the default date format of @samp{%Y/%m/%d}. To -change the way dates are printed in general, the easiest way is to put -@option{--date-format FORMAT} in the Ledger initialization file -@file{~/.ledgerrc} (or the file referred to by @env{LEDGER_INIT}). - -@option{--format STR} (@option{-F STR}) sets the reporting format for -whatever report ledger is about to make. @xref{Format Strings}. -There are also specific format commands for each report type: - -@itemize -@item @option{--balance-format STR} -@item @option{--register-format STR} -@item @option{--print-format STR} -@item @option{--plot-amount-format STR} (-j @command{register}) -@item @option{--plot-total-format STR} (-J @command{register}) -@item @option{--equity-format STR} -@item @option{--prices-format STR} -@item @option{--wide-register-format STR} (-w @command{register}) -@end itemize +@item --date-format STR +@item -y STR +changes the basic date format used by reports. The default uses a date +like 2004/08/01, which represents the default date format of +@samp{%Y/%m/%d}. To change the way dates are printed in general, the +easiest way is to put @option{--date-format FORMAT} in the Ledger +initialization file @file{~/.ledgerrc} (or the file referred to by +@env{LEDGER_INIT}). + +@item --format STR +@item -F STR +sets the reporting format for whatever report ledger is about to make. +@xref{Format Strings}. There are also specific format commands for each +report type: + +@item --balance-format STR +Define the output format for the @code{balance} report. The default (defined in @code{report.h} is: +@smallexample + "%(ansify_if( + justify(scrub(display_total), 20, + 20 + int(prepend_width), true, color), + bold if should_bold)) + %(!options.flat ? depth_spacer : \"\") + %-(ansify_if( + ansify_if(partial_account(options.flat), blue if color), + bold if should_bold))\n%/ + %$1\n%/ + %(prepend_width ? \" \" * int(prepend_width) : \"\") + --------------------\n" +@end smallexample +@item --cleared-format +Defines the format for the cleared report. The default is: +@smallexample + "%(justify(scrub(get_at(display_total, 0)), 16, 16 + int(prepend_width), + true, color)) %(justify(scrub(get_at(display_total, 1)), 18, + 36 + int(prepend_width), true, color)) + %(latest_cleared ? format_date(latest_cleared) : \" \") + %(!options.flat ? depth_spacer : \"\") + %-(ansify_if(partial_account(options.flat), blue if color))\n%/ + %$1 %$2 %$3\n%/ + %(prepend_width ? \" \" * int(prepend_width) : \"\") + ---------------- ---------------- ---------\n" +@end smallexample +@item --register-format STR +Define the output format for the @code{register} report. The default (defined in @code{report.h} is: +@smallexample + "%(ansify_if( + ansify_if(justify(format_date(date), int(date_width)), + green if color and date > today), + bold if should_bold)) + %(ansify_if( + ansify_if(justify(truncated(payee, int(payee_width)), int(payee_width)), + bold if color and !cleared and actual), + bold if should_bold)) + %(ansify_if( + ansify_if(justify(truncated(display_account, int(account_width), + int(abbrev_len)), int(account_width)), + blue if color), + bold if should_bold)) + %(ansify_if( + justify(scrub(display_amount), int(amount_width), + 3 + int(meta_width) + int(date_width) + int(payee_width) + + int(account_width) + int(amount_width) + int(prepend_width), + true, color), + bold if should_bold)) + %(ansify_if( + justify(scrub(display_total), int(total_width), + 4 + int(meta_width) + int(date_width) + int(payee_width) + + int(account_width) + int(amount_width) + int(total_width) + + int(prepend_width), true, color), + bold if should_bold))\n%/ + %(justify(\" \", int(date_width))) + %(ansify_if( + justify(truncated(has_tag(\"Payee\") ? payee : \" \", + int(payee_width)), int(payee_width)), + bold if should_bold)) + %$3 %$4 %$5\n" +@end smallexample +@item --csv-format +Sets the format for @code{csv} reports. The default is: +@smallexample +"%(quoted(date)), + %(quoted(code)), + %(quoted(payee)), + %(quoted(display_account)), + %(quoted(commodity)), + %(quoted(quantity(scrub(display_amount)))), + %(quoted(cleared ? \"*\" : (pending ? \"!\" : \"\"))), + %(quoted(join(note | xact.note)))\n" +@end smallexample +@item --plot-amount-format STR +Sets the format for amount plots, using the @code{-j} option. The default is: +@smallexample +"%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_amount)))\n" +@end smallexample +@item --plot-total-format STR +Sets the format for total plots, using the @code{-J} option. The default is: +@smallexample +"%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_total)))\n" +@end smallexample +@item --pricedb-format STR +Sets the format expected for the histroical price file. The default is +@smallexample +"P %(datetime) %(display_account) %(scrub(display_amount))\n" +@end smallexample + +@item --prices-format STR +Sets the format for the @command{prices} report. The deault is: +@smallexample +"%(date) %-8(display_account) %(justify(scrub(display_amount), 12, + 2 + 9 + 8 + 12, true, color))\n" +@end smallexample +@item --wide-register-format STR +(-w @command{register}) +@end table @node Commodity Reporting, Environment Variables, Output Customization, Detailed Options Description @subsection Commodity Reporting These options affect how commodity values are displayed: - -@option{--price-db FILE} sets the file that is used for recording -downloaded commodity prices. It is always read on start up, to -determine historical prices. Other settings can be placed in this -file manually, to prevent downloading quotes for a specific commodity, for -example. This is done by adding a line like the following: +@table @code +@item --price-db FILE +sets the file that is used for recording downloaded commodity prices. +It is always read on start up, to determine historical prices. Other +settings can be placed in this file manually, to prevent downloading +quotes for a specific commodity, for example. This is done by adding a +line like the following: @smallexample ; Don't download quotes for the dollar, or timelog values @@ -5901,24 +6193,31 @@ N $ N h @end smallexample -Note: Ledger NEVER write output to files. You are responsible for +@noindent Note: Ledger NEVER write output to files. You are responsible for updated the price-db file. The best way is to have your price download script maintain this file. -@option{--price-exp MINS} (@option{-L MINS}) sets the expected -freshness of price quotes, in minutes. That is, if the last known quote -for any commodity is older than this value---and if @option{--download} -is being used---then the Internet will be consulted again for a newer -price. Otherwise, the old price is still considered to be fresh enough. - -@option{--download} (@option{-Q}) causes quotes to be automagically -downloaded, as needed, by running a script named @command{getquote} -and expecting that script to return a value understood by ledger. A -sample implementation of a @command{getquote} script, implemented in -Perl, is provided in the distribution. Downloaded quote price are -then appended to the price database, usually specified using the -environment variable @env{LEDGER_PRICE_DB}. - +The format of the file can be changed by telling ledger to use the +@code{--pricedb-format} you define. + +@item --price-exp MINS +@item -L MINS +sets the expected freshness of price quotes, in minutes. That is, if +the last known quote for any commodity is older than this value---and if +@code{--download} is being used---then the Internet will be consulted +again for a newer price. Otherwise, the old price is still considered +to be fresh enough. + +@item --download +@item -Q +causes quotes to be automagically downloaded, as needed, by running a +script named @command{getquote} and expecting that script to return a +value understood by ledger. A sample implementation of a +@command{getquote} script, implemented in Perl, is provided in the +distribution. Downloaded quote price are then appended to the price +database, usually specified using the environment variable +@env{LEDGER_PRICE_DB}. +@end table There are several different ways that ledger can report the totals it displays. The most flexible way to adjust them is by using value expressions, and the @option{-t} and @option{-T} options. However, @@ -6689,7 +6988,7 @@ minimum amount of state detail is printed. Inserts the ``optimized'' form of a posting's amount. This is used by the print report. In some cases, this inserts nothing; in others, it inserts the posting amount and its cost. It's use is -not recommend unless you are modifying the print report. +not recommended unless you are modifying the print report. @item n Inserts the note associated with a posting, preceded by two spaces -- cgit v1.2.3 From 25f063ab7cb0af91891ed7e0a9948eb2e884be42 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Wed, 10 Oct 2012 07:31:17 -0700 Subject: Fixes bug 801. Replaces "jorunal" with Ledger on line 235 of ledger3.texi --- doc/ledger3.texi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index ab59f2ae..b0373dc2 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -236,7 +236,7 @@ $ ledger -f ledger.dat register Bell An important difference between Ledger and other finance packages is that journal will never alter your input file. You can create and edit -that file in any way you prefer, but journal is only for analyzing the +that file in any way you prefer, but Ledger is only for analyzing the data, not for altering it. @@ -504,7 +504,6 @@ cannot display any currency symbols other than dollar signs ($). @item @code{register} @tab Show all transactions with running total @item @code{csv} @tab Show transactions in csv format, for exporting to other programs @item @code{print} @tab Print transaction in a ledger readable format -@item @code{output} @tab Similar to print without included transactions @item @code{xml} @tab Produce XML output of the register command @item @code{emacs} @tab Produce Emacs lisp output @item @code{equity} @tab Print account balances as transactions -- cgit v1.2.3 From d7a03c471692f508118be7a9d0bb30f49374c1e7 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Wed, 10 Oct 2012 09:43:16 -0700 Subject: Detailed section on the new commodity valuation system. --- doc/ledger3.texi | 485 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 320 insertions(+), 165 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index b0373dc2..08be7551 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -280,7 +280,6 @@ http://groups.google.com/group/ledger-cli @menu * Start a Journal:: * Run Some Reports:: -* Command Line Quick Reference:: @end menu @node Start a Journal, Run Some Reports, Ledger Tutorial , Ledger Tutorial @@ -295,7 +294,7 @@ directory. If you would rather start with your own journal right away please see @ref{Keeping a Journal}. -@node Run Some Reports, Command Line Quick Reference, Start a Journal, Ledger Tutorial +@node Run Some Reports, , Start a Journal, Ledger Tutorial @section Run a Few Reports @menu @@ -482,147 +481,6 @@ Using ledger under the windows command shell has one significant limitation. CMD.exe is limited to standard ASCII characters and as such cannot display any currency symbols other than dollar signs ($). -@page -@node Command Line Quick Reference, , Run Some Reports, Ledger Tutorial -@section Command Line Quick Reference - -@menu -* Reporting Commands Quick Reference:: -* Basic Options Quick Reference:: -* Report Filtering Quick Reference:: -* Error Checking and Calculation Options:: -* Output Customization Quick Reference:: -* Grouping Options:: -* Commodity Reporting Quick Reference:: -@end menu - -@node Reporting Commands Quick Reference, Basic Options Quick Reference, Command Line Quick Reference, Command Line Quick Reference -@subsection Reporting Commands -@multitable @columnfractions .2 .8 -@item @strong{Report} @tab @strong{Description} -@item @code{balance} @tab Show account balances -@item @code{register} @tab Show all transactions with running total -@item @code{csv} @tab Show transactions in csv format, for exporting to other programs -@item @code{print} @tab Print transaction in a ledger readable format -@item @code{xml} @tab Produce XML output of the register command -@item @code{emacs} @tab Produce Emacs lisp output -@item @code{equity} @tab Print account balances as transactions -@item @code{prices} @tab Print price history for matching commodities -@item @code{pricedb} @tab Print price history for matching commodities in ledger readable format -@item @code{xact} @tab Used to generate transactions based on previous postings -@end multitable - -@node Basic Options Quick Reference, Report Filtering Quick Reference, Reporting Commands Quick Reference, Command Line Quick Reference -@subsection Basic Options -@multitable @columnfractions .1 .25 .65 -@item @strong{Short} @tab @strong{Long} @tab @strong{Description} -@item @code{-h} @tab @code{--help} @tab prints summary of all options -@item @code{-v} @tab @code{--version} @tab prints version of ledger executable -@item @code{-f FILE} @tab @code{--file FILE} @tab read @file{FILE} as a ledger file -@item @code{-o FILE} @tab @code{--output FILE} @tab redirects output to @file{FILE} -@item @code{-i FILE} @tab @code{--init-file FILE} @tab specify options file -@item @code{-a NAME} @tab @code{--account NAME} @tab specify default account name for QIF file postings -@end multitable - -@node Report Filtering Quick Reference, Error Checking and Calculation Options, Basic Options Quick Reference, Command Line Quick Reference -@subsection Report Filtering -@multitable @columnfractions .1 .25 .65 -@item @strong{Short} @tab @strong{Long} @tab @strong{Description} -@item @code{-c} @tab @code{--current} @tab Display transaction on or before the current date -@item @code{-b DATE} @tab @code{--begin DATE} @tab Begin reports on or after @code{DATE} -@item @code{-e DATE} @tab @code{--end DATE} @tab Limits end date of transactions for report -@item @code{-p STR} @tab @code{--period} @tab Set report period to STR -@item @code{ } @tab @code{--period-sort} @tab Sort postings within each period -@item @code{-C} @tab @code{--cleared} @tab Display only cleared postings -@item @code{} @tab @code{--dc} @tab Display register or balance in debit/credit format -@item @code{-U} @tab @code{--uncleared} @tab Display only uncleared postings -@item @code{-R} @tab @code{--real} @tab Display only real postings -@item @code{-L} @tab @code{--actual} @tab Displays only actual postings, not automated -@item @code{-r} @tab @code{--related} @tab Display related postings -@item @code{} @tab @code{--budget} @tab Display how close your postings meet your budget -@item @code{} @tab @code{--add-budget} @tab Shows un-budgeted postings -@item @code{} @tab @code{--unbudgeted} @tab Shows only un-budgeted postings -@item @code{} @tab @code{--forecast} @tab Project balances into the future -@item @code{-l EXPR} @tab @code{--limit EXPR} @tab Limits postings in calculations -@item @code{-t EXPR} @tab @code{--amount} @tab Change value expression reported in register report -@item @code{-T EXPR} @tab @code{--total} @tab Change the value expression used for ``totals'' column in register and balance reports -@end multitable - -@node Error Checking and Calculation Options, Output Customization Quick Reference, Report Filtering Quick Reference, Command Line Quick Reference -@subsection Error Checking and Calculation Options - -@multitable @columnfractions .1 .25 .65 -@item @strong{Short} @tab @strong{Long} @tab @strong{Description} -@item @code{} @tab @code{--strict} @tab accounts, tags or commodities not previously declared will cause warnings -@item @code{} @tab @code{--pedantic} @tab accounts, tags or commodities not previously declared will cause errors -@item @code{} @tab @code{--check-payees} @tab enable strict and pedantic checking for payees as well as accounts, commodities and tags. -@item @code{} @tab @code{--immediate} @tab instructs ledger to evaluate calculations immediately rather than lazily -@end multitable - - -@node Output Customization Quick Reference, Grouping Options, Error Checking and Calculation Options, Command Line Quick Reference -@subsection Output Customization -@multitable @columnfractions .15 .4 .45 -@item @strong{Short} @tab @strong{Long} @tab @strong{Description} -@item @code{-n} @tab @code{--collapse} @tab Collapse transactions with multiple postings -@item @code{-s} @tab @code{--subtotal} @tab Report register as a single subtotal -@item @code{-P} @tab @code{--by-payee} @tab Report subtotals by payee -@item @code{-E} @tab @code{--empty} @tab Include empty accounts in report -@item @code{-W} @tab @code{--weekly} @tab Report posting totals by week -@item @code{-Y} @tab @code{--yearly} @tab Report posting totals by year -@item @code{} @tab @code{--dow} @tab report Posting totals by day of week -@item @code{-S EXPR} @tab @code{--sort EXPR} @tab Sorts a report using @code{EXPR} -@item @code{-w} @tab @code{--wide} @tab Assume 132 columns instead of 80 -@item @code{} @tab @code{--head N} @tab Report the first N postings -@item @code{} @tab @code{--tail N} @tab Report the last N postings -@item @code{} @tab @code{--pager prog} @tab Direct output @code{prog} pager program -@item @code{-A} @tab @code{--average} @tab Reports average posting value -@item @code{-D} @tab @code{--deviation} @tab Reports each posting deviation from the average -@item @code{-%} @tab @code{--percent} @tab Show subtotals in the balance report as percentages -@c @item @code{} @tab @code{--totals} @tab Include running total in the @code{xml} report -@item @code{} @tab @code{--pivot TAG} @tab produce a pivot table of the tag type specified -@item @code{-j} @tab @code{--amount-data} @tab Show only date and value column -@item @code{-J} @tab @code{--total-data} @tab Show only dates and totals -@item @code{-d EXPR} @tab @code{--display EXPR} @tab Limit only the display of certain postings -@item @code{-y STR} @tab @code{--date-format STR} @tab Change the basic date format used in reports -@item @code{-F STR} @tab @code{--format STR} @tab Set reporting format -@item @code{} @tab @code{--balance-format STR} @tab -@item @code{} @tab @code{--register-format STR} @tab -@item @code{-j register} @tab @code{--plot-amount-format STR} @tab format the output of a amount plots -@item @code{-J register} @tab @code{--plot-total-format STR} @tab format the output of a total plot -@item @code{} @tab @code{--prices-format STR} @tab -@item @code{-w register} @tab @code{--wide-register-format STR} @tab -@item @code{} @tab @code{--anon} @tab Print the ledger register with anonymized accounts and payees, useful for filing bug reports -@end multitable - -@node Grouping Options, Commodity Reporting Quick Reference, Output Customization Quick Reference, Command Line Quick Reference -@subsection Grouping Options -@multitable @columnfractions .1 .25 .65 -@item @strong{Short} @tab @strong{Long} @tab @strong{Description} -@item @code{-P} @tab @code{--by-payee} @tab Group postings by common payee names -@item @code{-D} @tab @code{--daily} @tab Group postings by day -@item @code{-W} @tab @code{--weekly} @tab Group postings by week -@item @code{-M} @tab @code{--monthly} @tab Group postings by month -@item @code{} @tab @code{--quarterly} @tab Group postings by quarter -@item @code{-Y} @tab @code{--yearly} @tab Group postings by year -@item @code{} @tab @code{--dow} @tab Group by day of weeks -@item @code{-s} @tab @code{--subtotal} @tab Group posting together, similar to balance report -@end multitable - -@node Commodity Reporting Quick Reference, , Grouping Options, Command Line Quick Reference -@subsection Commodity Reporting - -@multitable @columnfractions .1 .25 .65 -@item @strong{Short} @tab @strong{Long} @tab @strong{Description} -@item @code{} @tab @code{--price-db FILE} @tab Use @file{FILE} for retrieving stored commodity prices -@item @code{-L MINS} @tab @code{--price-exp MINS} @tab Set expected freshness of prices in minutes -@item @code{-Q} @tab @code{--download} @tab Download quotes using @code{getquote} -@item @code{} @tab @code{--getquote} @tab Sets path to a user defined script to download commodity prices. -@item @code{-O} @tab @code{--quantity} @tab Report commodity totals without conversion -@item @code{-B} @tab @code{--basis} @tab Report cost basis -@item @code{-V} @tab @code{--market} @tab Report last known market value -@item @code{-G} @tab @code{--gain} @tab Report net gain loss for commodities that have a price history -@end multitable @node Principles of Accounting, Keeping a Journal, Ledger Tutorial , Top @chapter Principles of Accounting with Ledger @@ -1382,6 +1240,7 @@ posting. * Currency and Commodities:: * Keeping it Consistent:: * Journal Format:: +* Converting from other formats:: * Archiving Previous Years :: * Using Emacs:: @end menu @@ -1719,6 +1578,145 @@ its amount is null. @node Complete control over commodity pricing, , Fixing Lot Prices, Currency and Commodities @subsection Complete control over commodity pricing +Ledger allows you to have very detailed control over how your +commodities are valued. You can fine tune the results given using the +@code{--market} or @code{--exchange} options. There are now several +points of interception, you can specify the valuation method: +@enumerate + @item on a commodity itself + @item on a posting, via metadata (affect is largely the same as #1) + @item on an xact, which then applies to all postings in that xact + @item on any posting via an automated transaction + @item on a per-account basis + @item on a per-commodity basis + @item by changing the journal default of @code{market} +@end enumerate + +Fixated pricing (such as @code{@{=$20@})} still plays a role in this scheme. As far as +valuation goes, it's shorthand for writing @code{((s,d,t -> market($20,d,t)))}. + + +A valuation function receives three arguments: + +@table @code +@item source + A string identifying the commodity whose price is being asked for + (example: "EUR") +@item date + The reference date the price should be relative. +@item target +A string identifying the ``target'' commodity, or the commodity the + returned price should be in. This argument is null if @code{--market} + was used instead of @code{--exchange}. +@end table + +The valuation function should return an amount. If you've written your +function in Python, you can return something like @code{Amount("$100")}. If the +function returns an explicit value, that value is always used, regardless +of the commodity, the date, or the desired target commodity. For example, + +@smallexample +define myfunc_seven(s, d, t) = 7 EUR +@end smallexample + +In order to specify a fixed price, but still valuate that price into the +target commodity, use something like this: +@smallexample +define myfunc_five(s, d, t) = market(5 EUR, d, t) +@end smallexample + +The @code{value} directive sets the valuation used for all commodities +used in the rest of the data stream. This is the fallback, if nothing +more specific is found. +@smallexample +value myfunc_seven +@end smallexample + +You can set a specific valuation function on a per-commodity basis. +Instead of defining a function, you can also pass a lambda. +@smallexample +commodity $ + value s, d, t -> 6 EUR +@end smallexample + +Each account can also provide a default valuation function for any +commodities transferred to that account. + +@smallexample +account Expenses:Food5 + value myfunc_five +@end smallexample + +The metadata field @code{Value}, if found, overrides the valuation function +on a transaction-wide or per-posting basis. + +@smallexample += @@XACT and Food + ; Value:: 8 EUR + (Equity) $1 + += @@POST and Dining + (Expenses:Food9) $1 + ; Value:: 9 EUR +@end smallexample + +Lastly, you can specify the valuation function/value for any specific +amount using the @code{(( ))} commodity annotation. + +@smallexample +2012-03-02 KFC + Expenses:Food2 $1 ((2 EUR)) + Assets:Cash2 + +2012-03-03 KFC + Expenses:Food3 $1 + ; Value:: 3 EUR + Assets:Cash3 + +2012-03-04 KFC + ; Value:: 4 EUR + Expenses:Food4 $1 + Assets:Cash4 + +2012-03-05 KFC + Expenses:Food5 $1 + Assets:Cash5 + +2012-03-06 KFC + Expenses:Food6 $1 + Assets:Cash6 + +2012-03-07 KFC + Expenses:Food7 1 CAD + Assets:Cas7 + +2012-03-08 XACT + Expenses:Food8 $1 + Assets:Cash8 + +2012-03-09 POST + Expenses:Dining9 $1 + Assets:Cash9 +@end smallexample + + +@smallexample +ledger reg -V food +12-Mar-02 KFC Expenses:Food2 2 EUR 2 EUR +12-Mar-03 KFC -1 EUR 1 EUR + Expenses:Food3 3 EUR 4 EUR +12-Mar-04 KFC -2 EUR 2 EUR + Expenses:Food4 4 EUR 6 EUR +12-Mar-05 KFC -3 EUR 3 EUR + Expenses:Food5 5 EUR 8 EUR +12-Mar-06 KFC -4 EUR 4 EUR + Expenses:Food6 6 EUR 10 EUR +12-Mar-07 KFC Expenses:Food7 7 EUR 17 EUR +12-Mar-08 XACT Expenses:Food8 8 EUR 25 EUR +12-Mar-09 POST (Expenses:Food9) 9 EUR 34 EUR +@end smallexample + + @node Keeping it Consistent, Journal Format, Currency and Commodities, Keeping a Journal @section Keeping it Consistent @@ -1750,7 +1748,7 @@ ledger accounts >> Accounts.dat @noindent You will have to edit this file to add the @samp{account} directive. -@node Journal Format, Archiving Previous Years , Keeping it Consistent, Keeping a Journal +@node Journal Format, Converting from other formats, Keeping it Consistent, Keeping a Journal @section Journal Format The ledger file format is quite simple, but also very flexible. It @@ -2238,7 +2236,21 @@ timelog files. See the timeclock's documentation for more info on the syntax of its timelog files. @end table -@node Archiving Previous Years , Using Emacs, Journal Format, Keeping a Journal +@node Converting from other formats, Archiving Previous Years , Journal Format, Keeping a Journal +@section Converting from other formats +There are numerous tools to help convert various formats to a Ledger +file. Most banks will generate a commas separated value file that can +easily be parsed into Ledger format using one of those tools. Some of the more popular tools are: +@itemize +@item @code{icsv2ledger} +@item @code{csvToLedger} +@item @code{CSV2Ledger} +@end itemize +@noindent Directly pulling information from banks is outside the scope of Ledger's +function. + + +@node Archiving Previous Years , Using Emacs, Converting from other formats, Keeping a Journal @section Archiving Previous Years @@ -4882,11 +4894,12 @@ FIX THIS ENTRY @menu * Basic Usage:: +* Command Line Quick Reference:: * Detailed Options Description:: * Period Expressions:: @end menu -@node Basic Usage, Detailed Options Description, Command-line Syntax, Command-line Syntax +@node Basic Usage, Command Line Quick Reference, Command-line Syntax, Command-line Syntax @section Basic Usage This chapter describes Ledger's features and options. You may wish to @@ -4927,8 +4940,148 @@ There are many, many command options available with the However, none of them are required to use the basic reporting commands. +@node Command Line Quick Reference, Detailed Options Description, Basic Usage, Command-line Syntax +@section Command Line Quick Reference + +@menu +* Reporting Commands Quick Reference:: +* Basic Options Quick Reference:: +* Report Filtering Quick Reference:: +* Error Checking and Calculation Options:: +* Output Customization Quick Reference:: +* Grouping Options:: +* Commodity Reporting Quick Reference:: +@end menu + +@node Reporting Commands Quick Reference, Basic Options Quick Reference, Command Line Quick Reference, Command Line Quick Reference +@subsection Reporting Commands +@multitable @columnfractions .2 .8 +@item @strong{Report} @tab @strong{Description} +@item @code{balance} @tab Show account balances +@item @code{register} @tab Show all transactions with running total +@item @code{csv} @tab Show transactions in csv format, for exporting to other programs +@item @code{print} @tab Print transaction in a ledger readable format +@item @code{xml} @tab Produce XML output of the register command +@item @code{emacs} @tab Produce Emacs lisp output +@item @code{equity} @tab Print account balances as transactions +@item @code{prices} @tab Print price history for matching commodities +@item @code{pricedb} @tab Print price history for matching commodities in ledger readable format +@item @code{xact} @tab Used to generate transactions based on previous postings +@end multitable + +@node Basic Options Quick Reference, Report Filtering Quick Reference, Reporting Commands Quick Reference, Command Line Quick Reference +@subsection Basic Options +@multitable @columnfractions .1 .25 .65 +@item @strong{Short} @tab @strong{Long} @tab @strong{Description} +@item @code{-h} @tab @code{--help} @tab prints summary of all options +@item @code{-v} @tab @code{--version} @tab prints version of ledger executable +@item @code{-f FILE} @tab @code{--file FILE} @tab read @file{FILE} as a ledger file +@item @code{-o FILE} @tab @code{--output FILE} @tab redirects output to @file{FILE} +@item @code{-i FILE} @tab @code{--init-file FILE} @tab specify options file +@item @code{-a NAME} @tab @code{--account NAME} @tab specify default account name for QIF file postings +@end multitable + +@node Report Filtering Quick Reference, Error Checking and Calculation Options, Basic Options Quick Reference, Command Line Quick Reference +@subsection Report Filtering +@multitable @columnfractions .1 .25 .65 +@item @strong{Short} @tab @strong{Long} @tab @strong{Description} +@item @code{-c} @tab @code{--current} @tab Display transaction on or before the current date +@item @code{-b DATE} @tab @code{--begin DATE} @tab Begin reports on or after @code{DATE} +@item @code{-e DATE} @tab @code{--end DATE} @tab Limits end date of transactions for report +@item @code{-p STR} @tab @code{--period} @tab Set report period to STR +@item @code{ } @tab @code{--period-sort} @tab Sort postings within each period +@item @code{-C} @tab @code{--cleared} @tab Display only cleared postings +@item @code{} @tab @code{--dc} @tab Display register or balance in debit/credit format +@item @code{-U} @tab @code{--uncleared} @tab Display only uncleared postings +@item @code{-R} @tab @code{--real} @tab Display only real postings +@item @code{-L} @tab @code{--actual} @tab Displays only actual postings, not automated +@item @code{-r} @tab @code{--related} @tab Display related postings +@item @code{} @tab @code{--budget} @tab Display how close your postings meet your budget +@item @code{} @tab @code{--add-budget} @tab Shows un-budgeted postings +@item @code{} @tab @code{--unbudgeted} @tab Shows only un-budgeted postings +@item @code{} @tab @code{--forecast} @tab Project balances into the future +@item @code{-l EXPR} @tab @code{--limit EXPR} @tab Limits postings in calculations +@item @code{-t EXPR} @tab @code{--amount} @tab Change value expression reported in register report +@item @code{-T EXPR} @tab @code{--total} @tab Change the value expression used for ``totals'' column in register and balance reports +@end multitable + +@node Error Checking and Calculation Options, Output Customization Quick Reference, Report Filtering Quick Reference, Command Line Quick Reference +@subsection Error Checking and Calculation Options -@node Detailed Options Description, Period Expressions, Basic Usage, Command-line Syntax +@multitable @columnfractions .1 .25 .65 +@item @strong{Short} @tab @strong{Long} @tab @strong{Description} +@item @code{} @tab @code{--strict} @tab accounts, tags or commodities not previously declared will cause warnings +@item @code{} @tab @code{--pedantic} @tab accounts, tags or commodities not previously declared will cause errors +@item @code{} @tab @code{--check-payees} @tab enable strict and pedantic checking for payees as well as accounts, commodities and tags. +@item @code{} @tab @code{--immediate} @tab instructs ledger to evaluate calculations immediately rather than lazily +@end multitable + + +@node Output Customization Quick Reference, Grouping Options, Error Checking and Calculation Options, Command Line Quick Reference +@subsection Output Customization +@multitable @columnfractions .15 .4 .45 +@item @strong{Short} @tab @strong{Long} @tab @strong{Description} +@item @code{-n} @tab @code{--collapse} @tab Collapse transactions with multiple postings +@item @code{-s} @tab @code{--subtotal} @tab Report register as a single subtotal +@item @code{-P} @tab @code{--by-payee} @tab Report subtotals by payee +@item @code{-E} @tab @code{--empty} @tab Include empty accounts in report +@item @code{-W} @tab @code{--weekly} @tab Report posting totals by week +@item @code{-Y} @tab @code{--yearly} @tab Report posting totals by year +@item @code{} @tab @code{--dow} @tab report Posting totals by day of week +@item @code{-S EXPR} @tab @code{--sort EXPR} @tab Sorts a report using @code{EXPR} +@item @code{-w} @tab @code{--wide} @tab Assume 132 columns instead of 80 +@item @code{} @tab @code{--head N} @tab Report the first N postings +@item @code{} @tab @code{--tail N} @tab Report the last N postings +@item @code{} @tab @code{--pager prog} @tab Direct output @code{prog} pager program +@item @code{-A} @tab @code{--average} @tab Reports average posting value +@item @code{-D} @tab @code{--deviation} @tab Reports each posting deviation from the average +@item @code{-%} @tab @code{--percent} @tab Show subtotals in the balance report as percentages +@c @item @code{} @tab @code{--totals} @tab Include running total in the @code{xml} report +@item @code{} @tab @code{--pivot TAG} @tab produce a pivot table of the tag type specified +@item @code{-j} @tab @code{--amount-data} @tab Show only date and value column +@item @code{-J} @tab @code{--total-data} @tab Show only dates and totals +@item @code{-d EXPR} @tab @code{--display EXPR} @tab Limit only the display of certain postings +@item @code{-y STR} @tab @code{--date-format STR} @tab Change the basic date format used in reports +@item @code{-F STR} @tab @code{--format STR} @tab Set reporting format +@item @code{} @tab @code{--balance-format STR} @tab +@item @code{} @tab @code{--register-format STR} @tab +@item @code{-j register} @tab @code{--plot-amount-format STR} @tab format the output of a amount plots +@item @code{-J register} @tab @code{--plot-total-format STR} @tab format the output of a total plot +@item @code{} @tab @code{--prices-format STR} @tab +@item @code{-w register} @tab @code{--wide-register-format STR} @tab +@item @code{} @tab @code{--anon} @tab Print the ledger register with anonymized accounts and payees, useful for filing bug reports +@end multitable + +@node Grouping Options, Commodity Reporting Quick Reference, Output Customization Quick Reference, Command Line Quick Reference +@subsection Grouping Options +@multitable @columnfractions .1 .25 .65 +@item @strong{Short} @tab @strong{Long} @tab @strong{Description} +@item @code{-P} @tab @code{--by-payee} @tab Group postings by common payee names +@item @code{-D} @tab @code{--daily} @tab Group postings by day +@item @code{-W} @tab @code{--weekly} @tab Group postings by week +@item @code{-M} @tab @code{--monthly} @tab Group postings by month +@item @code{} @tab @code{--quarterly} @tab Group postings by quarter +@item @code{-Y} @tab @code{--yearly} @tab Group postings by year +@item @code{} @tab @code{--dow} @tab Group by day of weeks +@item @code{-s} @tab @code{--subtotal} @tab Group posting together, similar to balance report +@end multitable + +@node Commodity Reporting Quick Reference, , Grouping Options, Command Line Quick Reference +@subsection Commodity Reporting + +@multitable @columnfractions .1 .25 .65 +@item @strong{Short} @tab @strong{Long} @tab @strong{Description} +@item @code{} @tab @code{--price-db FILE} @tab Use @file{FILE} for retrieving stored commodity prices +@item @code{-L MINS} @tab @code{--price-exp MINS} @tab Set expected freshness of prices in minutes +@item @code{-Q} @tab @code{--download} @tab Download quotes using @code{getquote} +@item @code{} @tab @code{--getquote} @tab Sets path to a user defined script to download commodity prices. +@item @code{-O} @tab @code{--quantity} @tab Report commodity totals without conversion +@item @code{-B} @tab @code{--basis} @tab Report cost basis +@item @code{-V} @tab @code{--market} @tab Report last known market value +@item @code{-G} @tab @code{--gain} @tab Report net gain loss for commodities that have a price history +@end multitable + +@node Detailed Options Description, Period Expressions, Command Line Quick Reference, Command-line Syntax @section Detailed Option Description @menu @@ -4962,7 +5115,7 @@ database. Displays the info page for ledger. @item --init-file -Specifies the location of the init file @file{.ledgerrc} +Specifies the location of the init file. The default is @file{~/.ledgerrc} @item --options Display the options in effect for this Ledger invocation, along with @@ -5095,15 +5248,16 @@ difference between these scopes. Ledger 3.0 contains provisions for GUIs, which would make use of the different scopes by keeping an instance of Ledger running in the background and running multiple sessions with multiple reports per session. -@code{--abbrev-len } Sets the minimum + +@table @code +@item --abbrev-len +Sets the minimum length an account can be abbreviated to if it doesn't fit inside the @code{account-width}. If @code{abbrev-len} is zero, then the account name will be truncated on the right. If @code{abbrev-len} is greater than @code{account-width} then the account will be truncated on the left, with no shortening of the account names in order to fit into the desired width. - -@table @code @item --account Prepend @code{} to all accounts reported. That is, the option @code{--account Personal} would tack @@ -5515,16 +5669,14 @@ Suppress the output of group titles Suppress printing the final total line in a balance report. @item --now - -FIX THIS ENTRY +Define the current date in case to you to do calculate in the past or future using @code{--current} @item --only FIX THIS ENTRY -@item --output - -FIX THIS ENTRY +@item --output +Redriect the output of ledger to the file defined in @file{PATH}. @item --pager @@ -5667,13 +5819,11 @@ report only the last entries. Only useful ona register report. FIX THIS ENTRY -@item --total - -FIX THIS ENTRY +@item --total +Define a vlaue expression used to calulate the total in reports. @item --total-width - -FIX THIS ENTRY +Set the width of the total field in the register report. @item --truncate @@ -5685,7 +5835,7 @@ FIX THIS ENTRY @item --uncleared -FIX THIS ENTRY +Use only uncleared transactions in calculations and reports. @item --unrealized-gains @@ -5700,8 +5850,7 @@ FIX THIS ENTRY FIX THIS ENTRY @item --unround - -FIX THIS ENTRY +Perform all calculations without rounding and display results to full precision. @item --weekly @@ -7938,11 +8087,16 @@ need to create sums of multiple commodities, use a Balance. For example: @node Major Changes from version 2.6, Example Data File, Extending with Python, Top @chapter Major Changes from version 2.6 +@itemize +@item OFX support has been removed from Ledger 3.0 +@item single character value expressions are deprecated and should be changed to the new value expressions available in 3.0 +@end itemize + @node Example Data File, Miscellaneous Notes, Major Changes from version 2.6, Top @appendix Example Journal File: drewr.dat The following journal file is included with the source distribution of ledger. It is called @file{drewr.dat} and exhibits many ledger - features, include automatic and virtual transactions, + features, include automatic and virtual transactions, @smallexample ; -*- ledger -*- @@ -8045,6 +8199,7 @@ ledger register Checking --sort d -d 'd>[2011/04/01]' until 2011/05/25 (Liabilities:Tithe Owed) -1.0 @end smallexample + @node Concept Index, Command Index, Miscellaneous Notes, Top @unnumbered Concept Index -- cgit v1.2.3 From 8c7ac50fd8e29a0c2edf172f4bfa020aebdd2f7b Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Wed, 10 Oct 2012 21:21:00 -0700 Subject: formatting and grammar cleanup --- doc/ledger3.texi | 184 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 100 insertions(+), 84 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 08be7551..4cc28f43 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -4054,19 +4054,19 @@ file whose formatting has gotten out of hand. @node The csv command, The convert command, Comma Separated Variable files, Comma Separated Variable files @subsubsection The @code{csv} command -The csv command will output print out the desired ledger transactions in -a csv format suitable for import into other programs. You can determine -the transaction to print using all the normal limiting and searching +The @command{csv} command will output print out the desired ledger transactions in +a csv format suitable for import into other programs. You can specify +the transactions to print using all the normal limiting and searching functions. @cindex csv conversion @cindex reading csv @cindex comma separated variable file reading @node The convert command, , The csv command, Comma Separated Variable files @subsubsection The @code{convert} command -Convert reads your Ledger journal then parses a comma separated value -(csv) file into Ledger transactions. Many banks offer csv file -downloads. Unfortunately the file formats, aside form the commas, are -all different. The ledger convert command tried to help as much as it +The @code{convert} command parses a comma separated value +(csv) file and outputs Ledger transactions. Many banks offer csv file +downloads. Unfortunately the file formats, aside the from commas, are +all different. The ledger @code{convert} command tries to help as much as it can. Your banks csv files will have fields in different orders from other @@ -4277,12 +4277,12 @@ financial state. Eventually, babel will support passing arguments to currently. Instead, we can use the concepts of literary programming, as implemented by the noweb features of babel, to help us. -@subsubheading Multiple Ledger source blocks with noweb +@subsubheading Multiple Ledger source blocks with @command{noweb} -The noweb feature of babel allows us to expand references to other code -blocks within a code block. For Ledger, this can be used to group -transactions according to type, say, and then bring various sets of -transactions together to generate reports. +The @command{noweb} feature of babel allows us to expand references to +other code blocks within a code block. For Ledger, this can be used to +group transactions according to type, say, and then bring various sets +of transactions together to generate reports. Using the same transactions used above, we could consider splitting these into expenses and income, as follows: @@ -4342,9 +4342,9 @@ transactions. The overall balance of your account and expenditure with a breakdown according to category is specified by passing the :cmdline bal argument -to Ledger. This code block can now be evaluated (C-c C-c) and the +to Ledger. This code block can now be evaluated (@code{C-c C-c}) and the results generated by incorporating the transactions referred to by the -<> and <>= lines. +@code{<>} and @code{<>} lines. @smallexample #+name: balance #+begin_src ledger :cmdline bal :noweb yes @@ -4359,7 +4359,7 @@ results generated by incorporating the transactions referred to by the @end smallexample If you want a more detailed breakdown of where your money is and where -it has been spent, you can specify the -s flag (i.e. :cmdline -s bal) to +it has been spent, you can specify the -s flag (i.e. @code{:cmdline -s bal}) to tell Ledger to include sub-accounts in the report. @smallexample @@ -4384,7 +4384,7 @@ tell Ledger to include sub-accounts in the report. You can also generate a monthly register (the reg command) by executing the following src block. This presents a summary of transactions for -each monthly period (the -M argument) with a running total in the final +each monthly period (the @code{-M} argument) with a running total in the final column (which should be 0 at the end if all the entries are correct). @smallexample @@ -4435,12 +4435,12 @@ examples of more complex operations with a ledger. @node The pricemap Command, The xml Command, Emacs org mode, Reports in other Formats @subsection The @code{pricemap} Command -If you have the graphviz graph visualization package installed, ledger +If you have the @code{graphviz} graph visualization package installed, ledger can generate a graph of the relationship between your various commodities. The output file is in the ``dot'' format. This is probably not very interesting, unless you have many different -commdities valued in terms of each other. For example, multiple +commodities valued in terms of each other. For example, multiple currencies and multiples investments valued in those currencies. @node The xml Command, prices and pricedb, The pricemap Command, Reports in other Formats @@ -4595,7 +4595,7 @@ the same data. @node prices and pricedb, , The xml Command, Reports in other Formats -@subsection prices and pricedb +@subsection @code{prices} and @code{pricedb} The @command{prices} command displays the price history for matching commodities. The @option{-A} flag is useful with this report, to @@ -4619,7 +4619,7 @@ database files. @end menu @node accounts, commodities, Reports about your Journals, Reports about your Journals -@subsection accounts +@subsection @code{accounts} The @command{accounts} reports all of the accounts in the journal. Following the command with a regular expression will limit the output to @@ -4627,12 +4627,12 @@ accounts matching the regex. @node commodities, entry and xact, accounts, Reports about your Journals -@subsection commodities +@subsection @command{commodities} Report all commodities present in the journals under consideration. @node entry and xact, payees, commodities, Reports about your Journals -@subsection entry and xact +@subsection @command{entry} and @command{xact} The @code{entry} and @command{xact} commands simplify the creation of new transactions. It works on the principle that 80% of all postings @@ -4686,7 +4686,7 @@ ledger xact 4/9 viva dining "DM 11.50" backwards compatibility with Ledger 2.X. @node payees, , entry and xact, Reports about your Journals -@subsection payees +@subsection @code{payees} The @command{payees} reports all of the unique payees in the journal. To filter the payees displayed you must use the prefix: @smallexample @@ -4711,18 +4711,18 @@ macbook-2:$ @end menu @node echo, reload, Developer Commands, Developer Commands -@subsection echo +@subsection @command{echo} This command simply echos its argument back to the output. @node reload, source, echo, Developer Commands -@subsection reload +@subsection @command{reload} Forces ledger to reload any journal files. This function exists to support external programs controlling a running ledger process and does nothing for a command line user. @node source, Debug Options, reload, Developer Commands -@subsection source +@subsection @command{source} The @code{source} command take a journal file as an argument and parses it checking for errors, no other reports are generated, and no other arguments are necessary. Ledger will return success if no errors are @@ -4734,16 +4734,19 @@ found. These options are primarily for Ledger developers, but may be of some use to a user trying something new. - @option{--args-only} ignore init +@table @code + @item --args-only +ignore init files and environment variables for the ledger run. -@option{--verify} enable additional assertions during run-time. This -causes a significant slowdown. When combined with @option{--debug} -ledger will produce memory trace information. +@item --verify +enable additional assertions during run-time. This causes a significant +slowdown. When combined with @code{--debug} ledger will produce +memory trace information. -@option{--debug "argument"} If Ledger has been built with debug options -this will provide extra data during the run. The following are the -available arguments to debug: +@item --debug "argument" +If Ledger has been built with debug options this will provide extra data +during the run. The following are the available arguments to debug: @multitable @columnfractions .32 .43 .27 @item @code{account.display} @tab @code{expr.calc.when} @tab @code{org.next_amount} @@ -4772,7 +4775,7 @@ available arguments to debug: @item @code{expr.calc} @tab @code{option.names} @end multitable -@option{--trace INTEGER_TRACE_LEVEL} +@item --trace INTEGER_TRACE_LEVEL Enable tracing. The integer specifies the level of trace desired: @multitable @columnfractions .3 .7 @item @code{LOG_OFF} @tab 0 @@ -4789,15 +4792,16 @@ Enable tracing. The integer specifies the level of trace desired: @item @code{LOG_ALL} @tab 11 @end multitable -@option{--verbose} +@item --verbose Print detailed information on the execution of Ledger. -@option{--version} +@item --version Print version information and exit. +@end table @node Pre-commands, , Debug Options, Developer Commands @subsection Pre-Commands -Pre-commands are useful when you aren't sure how a command or option +Pre-commands are useful when you aren't sure how a command or option will work. @table @code @item args @@ -4821,7 +4825,8 @@ it against a model transaction. Print details of how ledger uses the given formatting description and apply it against a model transaction. @item generate -FIX THIS ENTRY +Randomly generates syntactically valid Ledger data from a seed. Used by the +GenerateTests harness for development testing @item parse Print details of how ledger uses the given value expression description and apply it against a model transaction. @@ -4885,7 +4890,8 @@ model transaction: true @end smallexample @item template -FIX THIS ENTRY +Shows the insertion template that a "draft" or "xact" sub-command generates. +This is a debugging command. @end table @node Command-line Syntax, Budgeting and Forecasting, Reporting Commands, Top @@ -5032,21 +5038,21 @@ commands. @item @code{-w} @tab @code{--wide} @tab Assume 132 columns instead of 80 @item @code{} @tab @code{--head N} @tab Report the first N postings @item @code{} @tab @code{--tail N} @tab Report the last N postings -@item @code{} @tab @code{--pager prog} @tab Direct output @code{prog} pager program +@item @code{} @tab @code{--pager PATH} @tab Direct output to @code{PATH} pager program @item @code{-A} @tab @code{--average} @tab Reports average posting value @item @code{-D} @tab @code{--deviation} @tab Reports each posting deviation from the average @item @code{-%} @tab @code{--percent} @tab Show subtotals in the balance report as percentages @c @item @code{} @tab @code{--totals} @tab Include running total in the @code{xml} report @item @code{} @tab @code{--pivot TAG} @tab produce a pivot table of the tag type specified -@item @code{-j} @tab @code{--amount-data} @tab Show only date and value column -@item @code{-J} @tab @code{--total-data} @tab Show only dates and totals -@item @code{-d EXPR} @tab @code{--display EXPR} @tab Limit only the display of certain postings +@item @code{-j} @tab @code{--amount-data} @tab Show only date and value column to format the output for plots +@item @tab @code{--plot-amount-format STR} @tab specify the format for the plot output +@item @code{-J} @tab @code{--total-data} @tab Show only dates and totals to format the output for plots +@item @tab @code{--plot-total-format STR} @tab specify the format for the plot output +@item @code{-d EXPR} @tab @code{--display EXPR} @tab Display only posting that meet the criteris in the EXPR @item @code{-y STR} @tab @code{--date-format STR} @tab Change the basic date format used in reports @item @code{-F STR} @tab @code{--format STR} @tab Set reporting format @item @code{} @tab @code{--balance-format STR} @tab @item @code{} @tab @code{--register-format STR} @tab -@item @code{-j register} @tab @code{--plot-amount-format STR} @tab format the output of a amount plots -@item @code{-J register} @tab @code{--plot-total-format STR} @tab format the output of a total plot @item @code{} @tab @code{--prices-format STR} @tab @item @code{-w register} @tab @code{--wide-register-format STR} @tab @item @code{} @tab @code{--anon} @tab Print the ledger register with anonymized accounts and payees, useful for filing bug reports @@ -5196,7 +5202,7 @@ Would convert the @file{Export.csv} file to ledger format, assuming the the dates in the CSV file are like 12/23/2009 (@pxref{Date and Time Format Codes}). -@item --master-account +@item --master-account Prepends all account names with the argument. @smallexample 21:51:39 ~/ledger (next)> ledger -f test/input/drewr3.dat bal --master-account HUMBUG @@ -5549,13 +5555,11 @@ correctly. force Ledger to paginate its output. -@item --forecast-while - -FIX THIS ENTRY - -@item --forecast-years +@item --forecast-while +Continue forecasting while @code{} is true. -FIX THIS ENTRY +@item --forecast-years +Forecast at most @code{N} years in the future. @item --format @@ -5563,11 +5567,12 @@ use the given format string to print output. @item --gain -report on gains using the latest available prices . +report on gains using the latest available prices. @item --generated - -ASK JOHN +Include auto-generated postings (such as those from automated transactions) +in the report, in cases where you normally wouldn't want +them. @item --group-by group transaction together in the register @@ -5640,13 +5645,13 @@ Report the date and price at which each commodity was purchased in a balance rep Use the latest market value for all commodities. -@item --meta +@item --meta -FIX THIS ENTRY +In the register report, prepend the transaction with the value of the given tag. @item --meta-width -FIX THIS ENTRY +Specify the width of the Meta column used for the @code{--meta} options. @item --monthly @@ -5657,8 +5662,8 @@ synonymn for @code{--period "monthly"} suppress any color TTY output. @item --no-rounding - -FIX THIS ENTRY +Don't output postings. Note that this will cause the running total +to often not add up! It's main use is for @code{-j} and @code{-J} reports. @item --no-titles @@ -5673,7 +5678,8 @@ Define the current date in case to you to do calculate in the past or future usi @item --only -FIX THIS ENTRY +This is a postings predicate that applies after certain +transforms have been executed, such as periodic gathering. @item --output Redriect the output of ledger to the file defined in @file{PATH}. @@ -5700,7 +5706,7 @@ Use only postings that are marked pending Calculate the percentage value of each account in a blance reports. Only works for account that have a single commoditiy. -@item --period +@item --period Define a period expression the sets the time period during which transactions are to be accounted. For a register report only th @@ -5708,7 +5714,7 @@ transactions that satisfy the period expression with be displayed. For a balance report only those transactions will be accounted in the final balances. -@item --pivot +@item --pivot Produce a balance pivot report ``around'' the given tag. For example, if you have multiple cars and track each fuel purchase in @@ -5726,6 +5732,7 @@ ledger bal Fuel --pivot "Car" --period "this year" $ 3533.95 @end smallexample +@xref{Metadata values}. @item --plot-amount-format Define the output format for a amount data plot. @xref{Visualizing with Gnuplot}. @@ -5744,8 +5751,7 @@ Reserve @code{N} spaces at the beginning of each line of the output @item --price - -FIX THIS ENTRY +use the price of the commodity purchase for performing calculations @item --quantity @@ -5757,7 +5763,10 @@ Synonym for @code{--period "quarterly"}. @item --raw -FIX THIS ENTRY +In the print report, show transactions using the exact same syntax as +specified by the user in their data file. Don't do any massaging or +interpreting. Can be useful for minor cleanups, like just aligning +amounts. @item --real Account using only real transactions ignoring virtual @@ -5788,7 +5797,7 @@ FIX THIS ENTRY @item --seed -FIX THIS ENTRY +Sets the random seed for the @code{generate} command. Used as part of development testing. @item --sort-all @@ -5826,8 +5835,11 @@ Define a vlaue expression used to calulate the total in reports. Set the width of the total field in the register report. @item --truncate - -FIX THIS ENTRY +Indicates how truncation should happen when the contents of columns +exceed their width. Valid arguments are @code{leading}, @code{middle}, +and @code{trailing}. The default is smarter than any of these three, as +it considers sub-names within the account name (that style is called +``abbreviate''. @item --unbudgeted @@ -5933,7 +5945,8 @@ report, in ways other than just using regular expressions: displays only transactions occurring on or before the current date. @item --begin DATE -@item -b DATE constrains the report to transactions on or after +@item -b DATE +constrains the report to transactions on or after @var{DATE}. Only transactions after that date will be calculated, which means that the running total in the balance report will always start at zero with the first matching transaction. (Note: This is different from @@ -5945,7 +5958,8 @@ constrains the report so that transactions on or after @var{DATE} are not considered. The ending date is inclusive. @item --period STR -@item -p STR sets the reporting period to @var{STR}. This will subtotal +@item -p STR +sets the reporting period to @var{STR}. This will subtotal all matching transactions within each period separately, making it easy to see weekly, monthly, quarterly, etc., posting totals. A period string can even specify the beginning and end of the report range, using @@ -6723,8 +6737,8 @@ ledger --forecast "d<[2010]" bal ^assets ^liabilities @node Value Expressions, Format Strings, Budgeting and Forecasting, Top @chapter Value Expressions -Value expressions are an expression language used by Ledger to -calculate values used by the program for many different purposes: +Ledger uses value expressions to make +calculations for many different purposes: @enumerate @item @@ -6739,19 +6753,21 @@ In the matching criteria used by automated postings. @end enumerate Value expressions support most simple math and logic operators, in -addition to a set of one letter functions and variables. A function's -argument is whatever follows it. The following is a display predicate -that I use with the @command{balance} command: +addition to a set of functions and variables. -@smallexample -ledger -d /^Liabilities/?T<0:UT>100 balance -@end smallexample +@c A function's +@c argument is whatever follows it. The following is a display predicate +@c that I use with the @command{balance} command: + +@c @smallexample +@c ledger -d /^Liabilities/?T<0:UT>100 balance +@c @end smallexample -The effect is that account totals are displayed only if: 1) A -Liabilities account has a total less than zero; or 2) the absolute -value of the account's total exceeds 100 units of whatever commodity -contains. If it contains multiple commodities, only one of them must -exceed 100 units. +@c The effect is that account totals are displayed only if: 1) A +@c Liabilities account has a total less than zero; or 2) the absolute +@c value of the account's total exceeds 100 units of whatever commodity +@c contains. If it contains multiple commodities, only one of them must +@c exceed 100 units. Display predicates are also very handy with register reports, to constrain which transactions are printed. For example, the following -- cgit v1.2.3 From f1c459b80c43de1d2e1a8ab51f2d91c33b9bd03b Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 12 Oct 2012 06:56:21 -0700 Subject: Fixed several typos and cleaned up formatting --- doc/ledger3.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 4cc28f43..84f32857 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -235,7 +235,7 @@ $ ledger -f ledger.dat register Bell @end smallexample An important difference between Ledger and other finance packages is -that journal will never alter your input file. You can create and edit +that Ledger will never alter your input file. You can create and edit that file in any way you prefer, but Ledger is only for analyzing the data, not for altering it. -- cgit v1.2.3 From 0d90de44b62274ae761b8d81c754f2c78cd44f56 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sat, 13 Oct 2012 07:48:00 -0700 Subject: Added more details to the convert command as provide by Johan Klahn --- doc/ledger3.texi | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 84f32857..b429d27e 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -4098,7 +4098,7 @@ line of the file. The fields ledger can recognize are called Delete the account description lines at the top, and replace the first line in the data above with: @smallexample -date,payee,note,amount,,,code, +,date,payee,note,amount,,,code, @end smallexample Then execute ledger like this: @@ -4110,6 +4110,49 @@ Where the @code{--input-date-format} option tells ledger how to interpret the dates. Importing csv files is a lot of work, and but is very amenable to scripting. + +If there are columns in the bank data you would like to keep in your +ledger data, besides the primary fileds described above, you can name +them in the field descriptor list and Ledger will include them in the +transaction as meta data if it doesn't recognize the field name. For +example, if you want to capture the bank transaction number and it +occurs in the first column of the data use: + + +@smallexample +transid,date,payee,note,amount,,,code, +@end smallexample + +Ledger will include @code{; transid: 767718} in the first transaction is +fromthe file above. + +The @code{convert} command accepts three options, the most important +ones are @code{--invert} which inverts the amount field, and +@code{--account NAME} which you can use to specify the account to +balance against and @code{--rich-data}. When using the rich-data switch +additional metadata is stored as tags. There is, for example, a UUID field. If +an entry with the same UUID tag is already included in the normal ledger +file (specified via -f or $LEDGER_FILE) this entry will not be printed +again. + +You can also use @code{convert} with @code{payee} and @code{account} +directives. First, you can use the @code{payee} and @code{alias} +directive to rewrite the @code{payee} field based on some rules. Then you can +use the account and its @code{payee} directive to specify the account. I use it +like this, for example: + +@smallexample +payee Aldi + alias ^ALDI SUED SAGT DANKE +account Aufwand:Einkauf:Lebensmittel + payee ^(Aldi|Alnatura|Kaufland|REWE)$ +@end smallexample + +Note that it may be necessary for the output of 'ledger convert' to be +passed through 'ledger print' a second time if you want to match on the +new payee field. During the 'ledger convert' run only the original payee +name as specified in the csv data seems to be used. + @node Emacs, Emacs org mode, Comma Separated Variable files, Reports in other Formats @subsection Emacs -- cgit v1.2.3 From c51ad98a6636b054fae1a8b2eca009ed516ee158 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sat, 13 Oct 2012 08:16:39 -0700 Subject: Fixe emacs command chapter heading --- doc/ledger3.texi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index b429d27e..aabb9445 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -4038,14 +4038,14 @@ file whose formatting has gotten out of hand. @section Reports in other Formats @menu * Comma Separated Variable files:: -* Emacs:: +* The emacs command:: * Emacs org mode:: * The pricemap Command:: * The xml Command:: * prices and pricedb:: @end menu -@node Comma Separated Variable files, Emacs, Reports in other Formats, Reports in other Formats +@node Comma Separated Variable files, The emacs command, Reports in other Formats, Reports in other Formats @subsection Comma Separated Variable files @menu * The csv command:: @@ -4153,8 +4153,8 @@ passed through 'ledger print' a second time if you want to match on the new payee field. During the 'ledger convert' run only the original payee name as specified in the csv data seems to be used. -@node Emacs, Emacs org mode, Comma Separated Variable files, Reports in other Formats -@subsection Emacs +@node The emacs command, Emacs org mode, Comma Separated Variable files, Reports in other Formats +@subsection The @code{emacs} command The @command{emacs} command outputs results in a form that can be read directly by Emacs Lisp. The format of the @code{sexp} is: @@ -4165,7 +4165,7 @@ directly by Emacs Lisp. The format of the @code{sexp} is: ...) ; list of transactions @end smallexample -@node Emacs org mode, The pricemap Command, Emacs, Reports in other Formats +@node Emacs org mode, The pricemap Command, The emacs command, Reports in other Formats @subsection Emacs @code{org} Mode The @code{org} command produces a journal file suitable for use in the Emacs org mode. More details on using org mode can be found at -- cgit v1.2.3 From 7b11dad404b4e689393a5725c93ea84507fc2221 Mon Sep 17 00:00:00 2001 From: adamsrl Date: Sun, 14 Oct 2012 16:43:56 -0500 Subject: Added back my patches for johns ldg-mode --- lisp/ldg-report.el | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index f9c6afca..e0744100 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -259,15 +259,16 @@ the default." (insert (format "Report: %s\n" ledger-report-name) (format "Command: %s\n" cmd) (make-string (- (window-width) 1) ?=) - "\n") - (let ((register-report (string-match " reg\\(ister\\)? " cmd)) + "\n\n") + (let ((data-pos (point)) + (register-report (string-match " reg\\(ister\\)? " cmd)) files-in-report) (shell-command (if register-report (concat cmd " --prepend-format='%(filename):%(beg_line):'") cmd) t nil) (when register-report - (goto-char (point-min)) + (goto-char data-pos) (while (re-search-forward "^\\([^:]+\\)?:\\([0-9]+\\)?:" nil t) (let ((file (match-string 1)) (line (string-to-number (match-string 2)))) @@ -283,20 +284,30 @@ the default." ledger-report-patch-alist)) (add-to-list 'files-in-report fullpath))) - (dolist (path files-in-report) - (let ((buf (get-file-buffer path))) - (if (and buf (buffer-live-p buf)) - (ledger-report-patch-reports buf)))))))) + ;; Disable john's "monkey patching" because it didn't work + ;; (dolist (path files-in-report) + ;; (let ((buf (get-file-buffer path))) + ;; (if (and buf (buffer-live-p buf)) + ;; (ledger-report-patch-reports buf)))))))) + ) + (goto-char data-pos) ))) (defun ledger-report-visit-source () (interactive) (let ((prop (get-text-property (point) 'ledger-source))) (destructuring-bind (file . line-or-marker) prop (find-file-other-window file) + (widen) (if (markerp line-or-marker) (goto-char line-or-marker) (goto-char (point-min)) - (forward-line (1- line-or-marker)))))) + (forward-line (1- line-or-marker)) + (re-search-backward "^[0-9]+") + (beginning-of-line) + (let ((start-of-txn (point))) + (forward-paragraph) + (narrow-to-region start-of-txn (point)) + (backward-paragraph)))))) (defun ledger-report-goto () "Goto the ledger report buffer." -- cgit v1.2.3 From 6094c202c152b282098de1002be54b3bcd7ab50c Mon Sep 17 00:00:00 2001 From: adamsrl Date: Mon, 15 Oct 2012 11:47:29 -0500 Subject: Adding goto EOL to fix issue where re-search-forward was including ledger report data in the text properties. --- lisp/ldg-report.el | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index e0744100..9fdf55d2 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -275,6 +275,7 @@ the default." (delete-region (match-beginning 0) (match-end 0)) (set-text-properties (line-beginning-position) (line-end-position) (list 'ledger-source (cons file line))) + (end-of-line) (let* ((fullpath (expand-file-name file)) (entry (assoc fullpath ledger-report-patch-alist))) (if entry @@ -282,15 +283,13 @@ the default." (push (cons (expand-file-name file) (list (current-buffer))) ledger-report-patch-alist)) - (add-to-list 'files-in-report fullpath))) - - ;; Disable john's "monkey patching" because it didn't work - ;; (dolist (path files-in-report) - ;; (let ((buf (get-file-buffer path))) - ;; (if (and buf (buffer-live-p buf)) - ;; (ledger-report-patch-reports buf)))))))) - ) - (goto-char data-pos) ))) + (add-to-list 'files-in-report fullpath)))) + (dolist (path files-in-report) + (let ((buf (get-file-buffer path))) + (if (and buf (buffer-live-p buf)) + (ledger-report-patch-reports buf))))) + (goto-char data-pos))) + (defun ledger-report-visit-source () (interactive) -- cgit v1.2.3 From 9173190a8f1d93bebf14ff795bee46b619fd845a Mon Sep 17 00:00:00 2001 From: adamsrl Date: Mon, 15 Oct 2012 13:29:22 -0500 Subject: Made marker logic for jumping from hyperlinked reports to source files work by simplifying. --- lisp/ldg-report.el | 46 +++++++++------------------------------------- 1 file changed, 9 insertions(+), 37 deletions(-) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 9fdf55d2..9a964195 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -231,28 +231,6 @@ the default." (ledger-reports-custom-save)) report-cmd)) -(defvar ledger-report-patch-alist nil) - -(defun ledger-report-patch-reports (buf) - (when ledger-report-patch-alist - (let ((entry (assoc (expand-file-name (buffer-file-name buf)) - ledger-report-patch-alist))) - (when entry - (dolist (b (cdr entry)) - (if (buffer-live-p b) - (with-current-buffer b - (save-excursion - (goto-char (point-min)) - (while (not (eobp)) - (let ((record (get-text-property (point) 'ledger-source))) - (if (and record (not (markerp (cdr record)))) - (setcdr record (with-current-buffer buf - (save-excursion - (goto-char (point-min)) - (forward-line (cdr record)) - (point-marker)))))) - (forward-line 1)))))))))) - (defun ledger-do-report (cmd) "Run a report command line." (goto-char (point-min)) @@ -271,23 +249,17 @@ the default." (goto-char data-pos) (while (re-search-forward "^\\([^:]+\\)?:\\([0-9]+\\)?:" nil t) (let ((file (match-string 1)) - (line (string-to-number (match-string 2)))) + (line (string-to-number (match-string 2)))) (delete-region (match-beginning 0) (match-end 0)) (set-text-properties (line-beginning-position) (line-end-position) - (list 'ledger-source (cons file line))) - (end-of-line) - (let* ((fullpath (expand-file-name file)) - (entry (assoc fullpath ledger-report-patch-alist))) - (if entry - (nconc (cdr entry) (list (current-buffer))) - (push (cons (expand-file-name file) - (list (current-buffer))) - ledger-report-patch-alist)) - (add-to-list 'files-in-report fullpath)))) - (dolist (path files-in-report) - (let ((buf (get-file-buffer path))) - (if (and buf (buffer-live-p buf)) - (ledger-report-patch-reports buf))))) + (list 'ledger-source (cons file (save-window-excursion + (save-excursion + (find-file file) + (widen) + (goto-char (point-min)) + (forward-line (1- line)) + (point-marker)))))) + (end-of-line)))) (goto-char data-pos))) -- cgit v1.2.3 From 2b7f7b7f90e182b52219a5fb824e3463a3b8a220 Mon Sep 17 00:00:00 2001 From: adamsrl Date: Mon, 15 Oct 2012 13:41:20 -0500 Subject: Moved over some shortcut functions --- contrib/raw/ledger-matching.el | 142 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 136 insertions(+), 6 deletions(-) diff --git a/contrib/raw/ledger-matching.el b/contrib/raw/ledger-matching.el index d12c3937..7c568126 100644 --- a/contrib/raw/ledger-matching.el +++ b/contrib/raw/ledger-matching.el @@ -145,11 +145,12 @@ (backward-paragraph) (beginning-of-line) - ;; Update the ER and Project while I'm there - (save-excursion - (search-forward "; ER:") - (kill-line nil) - (insert " " *ledger-expense-shortcut-ER*)) + ;; ;; Update the ER and Project while I'm there + ;; (save-excursion + ;; (search-forward "; ER:") + ;; (kill-line nil) + ;; (insert " " *ledger-expense-shortcut-ER*)) + ;; Just do the project for now. (save-excursion (search-forward "; PROJECT:") (kill-line nil) @@ -192,7 +193,9 @@ ledger-matching-image-name)) ;; Update the receipt screen - (ledger-matching-update-current-image) )) + (ledger-matching-update-current-image) + + (message "Filed %s to project %s" ledger-matching-image-name ledger-matching-project))) @@ -207,6 +210,133 @@ ;; Update the receipt screen at the same offset (ledger-matching-update-current-image)) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Items below are speed entry macros, and should eventually migrate to their own file. + +(defvar *ledger-expense-shortcut-ER* + "Current expense report number, just last four digits (ie: 1234 results in AISER1234).") + +(defvar *ledger-expense-shortcut-split-ER* + "Split (ie: internal) expense report number, just last four digits (ie: 1234 results in AISER1234).") + +(defvar *ledger-expense-shortcut-Proj* "" + "Current export report project code (ie: AGIL1292)") + +(defun ledger-expense-shortcut-ER-format-specifier () *ledger-expense-shortcut-ER*) + +(defun ledger-expense-shortcut-Project-format-specifier () *ledger-expense-shortcut-Proj*) + +(defun ledger-expense-shortcut-setup (ER Split Proj) + "Sets the variables expanded into the transaction." + (interactive "MER Number (ER or IN and 4 digit number only): \nMSplit ER Number (ER or IN and 4 digit number only): \nMProject: ") + (setq *ledger-expense-shortcut-ER* + (concatenate 'string "AIS" ER)) + (setq *ledger-expense-shortcut-split-ER* + (concatenate 'string "AIS" Split)) + (setq *ledger-expense-shortcut-Proj* Proj) + (setq ledger-matching-project Proj) + (message "Set Proj to %s and ER to %s, split to %s" + *ledger-expense-shortcut-Proj* + *ledger-expense-shortcut-ER* + *ledger-expense-shortcut-split-ER*)) + +(defun ledger-expense-shortcut () + "Updates the ER and Project metadata with the current values of the shortcut variables." + (interactive) + (when (eq major-mode 'ledger-mode) + (if (or (eql *ledger-expense-shortcut-ER* "") + (eql *ledger-expense-shortcut-Proj* "")) + (message "Run ledger-expense-shortcut-setup first.") + (save-excursion + (search-forward "; ER:") + (kill-line nil) + (insert " " *ledger-expense-shortcut-ER*)) + (save-excursion + (search-forward "; PROJECT:") + (kill-line nil) + (insert " " *ledger-expense-shortcut-Proj*))))) + +(defun ledger-expense-split () + "Splits the current transaction between internal and projects." + (interactive) + (when (eq major-mode 'ledger-mode) ; I made this local now, should only trigger in ldg-mode + (save-excursion + (end-of-line) + (re-search-backward "^[0-9]\\{4\\}/") + (re-search-forward "^ +Dest:Projects") + (move-beginning-of-line nil) + (let ((begin (point)) + (end (re-search-forward "^$"))) + (goto-char end) + (insert (buffer-substring begin end)) + (goto-char end) + (re-search-forward "^ Dest:Projects") + (replace-match " Dest:Internal") + (re-search-forward "; ER: +[A-Za-z0-9]+") + (replace-match (concat "; ER: " *ledger-expense-shortcut-split-ER*) t) + (when (re-search-forward "; CATEGORY: Meals" (save-excursion (re-search-forward "^$")) t) + (replace-match "; CATEGORY: Travel" t)))) + (re-search-backward "^[0-9]\\{4\\}/") + (re-search-forward "^ +Dest:Projects") + (insert-string " $") )) + +(defun ledger-expense-internal () + "Makes the expense an internal one." + (interactive) + (when (eq major-mode 'ledger-mode) ; I made this local now, should only trigger in ldg-mode + (save-excursion + (end-of-line) + (re-search-backward "^[0-9]\\{4\\}/") + (let ((begin (point)) + (end (save-excursion (re-search-forward "^$")))) + (when (re-search-forward "^ Dest:Projects" end t) + (replace-match " Dest:Internal") ) + (when (re-search-forward "; CATEGORY: Meals" (save-excursion (re-search-forward "^$")) t) + (replace-match "; CATEGORY: Travel" t)))))) + +(defun ledger-expense-personal () + "Makes the expense an personal one, eliminating metadata and receipts." + (interactive) + (when (eq major-mode 'ledger-mode) ; I made this local now, should only trigger in ldg-mode + (save-excursion + (end-of-line) + (re-search-backward "^[0-9]\\{4\\}/") + (let ((begin (point)) + (end (save-excursion (re-search-forward "^$")))) + (when (re-search-forward "^ Dest:Projects" end t) + (replace-match " Other:Personal")) + (goto-char begin) + (save-excursion + (when (re-search-forward "^ +; ER:" end t) + (beginning-of-line) + (kill-line 1))) + (save-excursion + (when (re-search-forward "^ +; PROJECT:" end t) + (beginning-of-line) + (kill-line 1))) + (save-excursion + (when (re-search-forward "^ +; CATEGORY:" end t) + (beginning-of-line) + (kill-line 1))) + (save-excursion + (when (re-search-forward "^ +; RECEIPT:" end t) + (beginning-of-line) + (kill-line 1))) + (ledger-toggle-current-entry))))) + +(defun ledger-expense-show-receipt () + "Uses the Receipt buffer to show the receipt of the txn we're on." + (when (eq major-mode 'ledger-mode) ; I made this local now, should only trigger in ldg-mode + (save-excursion + (end-of-line) + (re-search-backward "^[0-9]\\{4\\}/") + (let ((begin (point)) + (end (save-excursion (re-search-forward "^$")))) + (save-excursion + (when (re-search-forward "^\\( +; RECEIPT: +\\)\\([^,]+?.jpg\\).*$" end t) + (ledger-matching-display-image + (concat "/home/adamsrl/AdamsInfoServ/BusinessDocuments/Ledger/AdamsRussell/" + (match-string 2))) )))))) (provide 'ledger-matching) -- cgit v1.2.3 From 49b02614a39ad86bb499df8b410232a5948247d7 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Sat, 13 Oct 2012 15:17:09 +0200 Subject: fix account mapping in csv conversion By using payees_for_unknown_accounts instead of account_mappings in csv.cc ledger will have the same behaviour as in `ledger -f - print` in that it uses payee fields in account directives to rewrite the account. --- src/csv.cc | 2 +- test/baseline/feat-convert-with-diretives.dat | 3 +++ test/baseline/feat-convert-with-diretives.test | 28 ++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 test/baseline/feat-convert-with-diretives.dat create mode 100644 test/baseline/feat-convert-with-diretives.test diff --git a/src/csv.cc b/src/csv.cc index 71b6516a..dbd2dbfe 100644 --- a/src/csv.cc +++ b/src/csv.cc @@ -243,7 +243,7 @@ xact_t * csv_reader::read_xact(bool rich_data) // Translate the account name, if we have enough information to do so - foreach (account_mapping_t& value, context.journal->account_mappings) { + foreach (account_mapping_t& value, context.journal->payees_for_unknown_accounts) { if (value.first.match(xact->payee)) { post->account = value.second; break; diff --git a/test/baseline/feat-convert-with-diretives.dat b/test/baseline/feat-convert-with-diretives.dat new file mode 100644 index 00000000..ac13ff81 --- /dev/null +++ b/test/baseline/feat-convert-with-diretives.dat @@ -0,0 +1,3 @@ +date,payee,amount +2012/01/01,KFC,$10 +2012/01/02,"REWE SAGT DANKE 123454321",10€ diff --git a/test/baseline/feat-convert-with-diretives.test b/test/baseline/feat-convert-with-diretives.test new file mode 100644 index 00000000..2f6e0102 --- /dev/null +++ b/test/baseline/feat-convert-with-diretives.test @@ -0,0 +1,28 @@ +account Expenses:Food + payee KFC + payee REWE + +payee REWE + alias REWE SAGT DANKE + +# When reading csv file without directives: +test -f /dev/null convert test/baseline/feat-convert-with-diretives.dat +2012/01/01 * KFC + Expenses:Unknown $10 + Equity:Unknown + +2012/01/02 * REWE SAGT DANKE 123454321 + Expenses:Unknown 10€ + Equity:Unknown +end test + +# When reading csv file with directives: +test --account "Assets:Cash" convert test/baseline/feat-convert-with-diretives.dat +2012/01/01 * KFC + Expenses:Food $10 + Assets:Cash + +2012/01/02 * REWE + Expenses:Food 10€ + Assets:Cash +end test -- cgit v1.2.3 From 08033e6d50dbe659b8393464eab119b00d8ba44a Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Sat, 13 Oct 2012 15:06:48 +0200 Subject: fix test runner if filename is specified If the command line switch "-f" is used the test runner will not pass the file name of the test file to ledger. The line "test -f /dev/null" as used in test/baseline/cmd-convert.test did not work as intended before this. Also using "-f - " did not work as "$ledger" was noti prepended to the command. --- test/RegressTests.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/RegressTests.py b/test/RegressTests.py index 7d67eb21..1094d0d5 100755 --- a/test/RegressTests.py +++ b/test/RegressTests.py @@ -98,8 +98,10 @@ class RegressFile(object): def run_test(self, test): use_stdin = False - if test['command'].find("-f - ") != -1: - use_stdin = True + if test['command'].find("-f ") != -1: + test['command'] = '$ledger ' + test['command'] + if test['command'].find("-f - ") != -1: + use_stdin = True else: test['command'] = (('$ledger -f "%s" ' % os.path.abspath(self.filename)) + -- cgit v1.2.3 From 6b5fb0da7372d7f5e48607b3885b8f9b01afa99c Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 19 Oct 2012 04:00:13 +0200 Subject: Reformatted tables and moved date formatting code section --- doc/ledger3.texi | 1093 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 568 insertions(+), 525 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index aabb9445..531a0870 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -261,7 +261,7 @@ enter these commands: Ledger has a complete online help system based on GNU Info. This manual can be searched directly from the command line using the following options: -@option{ledger --help} bring up this entire manual in your tty. +@code{ledger --help} bring up this entire manual in your tty. If you need help on how to use Ledger, or run into problems, you can join the Ledger mailing list at the following Web address: @@ -270,8 +270,8 @@ join the Ledger mailing list at the following Web address: http://groups.google.com/group/ledger-cli @end smallexample -@noindent You can also find help at the @samp{#ledger} channel on the IRC server -@samp{irc.freenode.net}. +@noindent You can also find help at the @code{#ledger} channel on the IRC server +@code{irc.freenode.net}. @cindex tutorial @node Ledger Tutorial , Principles of Accounting, Introduction to Ledger, Top @@ -419,14 +419,14 @@ $ ledger -f drewr3.dat register Groceries 11-Jan-19 Grocery Store Expense:Food:Groceries $ 44.00 $ 334.00 @end smallexample -@noindent Which matches the balance reported for the @samp{Groceries} account: +@noindent Which matches the balance reported for the @code{Groceries} account: @smallexample $ ledger -f drewr3.dat balance Groceries $ 334.00 Expenses:Food:Groceries @end smallexample -@noindent If you would like to find transaction to only a certain payee use @samp{payee} or @@: +@noindent If you would like to find transaction to only a certain payee use @code{payee} or @@: @smallexample $ ledger -f drewr3.dat register payee "Organic" 10-Dec-20 Organic Co-op Expense:Food:Groceries $ 37.50 $ 37.50 @@ -445,7 +445,7 @@ $ ledger -f drewr3.dat register payee "Organic" A very useful report is to show what your obligations are versus what expenditures have actually been recorded. It can take several days for a check to clear, but you should treat it as money spent. The -@samp{cleared} report shows just that (note that the cleared report will +@code{cleared} report shows just that (note that the cleared report will not format correctly for accounts that contain multiple commodities): @smallexample @@ -626,7 +626,7 @@ ledger -M register expenses:auto @end example This assumes, of course, that you use account names like -@samp{Expenses:Auto:Gas} and @samp{Expenses:Auto:Repair}. +@code{Expenses:Auto:Gas} and @code{Expenses:Auto:Repair}. @menu * Tracking reimbursable expenses:: @@ -728,8 +728,8 @@ It's easier shown than said: And now the reimbursements account is paid off, accounts payable is paid off, and $100.00 has been effectively transferred from the company's checking account to your personal checking account. The -money simply ``waited''---in both @samp{Assets:Reimbursements:Company -XYZ}, and @samp{Company XYZ:Accounts Payable:Your Name}---until such +money simply ``waited''---in both @code{Assets:Reimbursements:Company +XYZ}, and @code{Company XYZ:Accounts Payable:Your Name}---until such time as it could be paid off. The value of tracking expenses from both sides like that is that you @@ -773,7 +773,7 @@ apply account Company XYZ end apply account @end smallexample -(Note: The @samp{apply account} above means that all accounts mentioned in +(Note: The @code{apply account} above means that all accounts mentioned in the file are children of that account. In this case it means that all activity in the file relates to Company XYZ). @@ -839,8 +839,8 @@ P 2004/06/21 02:18:02 AAPL $32.91 P 2004/06/21 02:18:02 AU $400.00 @end smallexample -Specify the price history to use with the @option{--price-db} option, -with the @option{-V} option to report in terms of current market +Specify the price history to use with the @code{--price-db} option, +with the @code{-V} option to report in terms of current market value: @example @@ -910,7 +910,7 @@ or days, it should be possible to convert between the various forms. Doing this requires the use of commodity equivalencies. For example, you might have the following two postings, one which -transfers an hour of time into a @samp{Billable} account, and another +transfers an hour of time into a @code{Billable} account, and another which decreases the same account by ten minutes. The resulting report will indicate that fifty minutes remain: @@ -944,13 +944,13 @@ C 1.00 Gb = 1024 Mb C 1.00 Tb = 1024 Gb @end smallexample -Each of these definitions correlates a commodity (such as @samp{Kb}) +Each of these definitions correlates a commodity (such as @code{Kb}) and a default precision, with a certain quantity of another commodity. In the above example, kilobytes are reported with two decimal places of precision and each kilobyte is equal to 1024 bytes. Equivalency chains can be as long as desired. Whenever a commodity -would report as a decimal amount (less than @samp{1.00}), the next +would report as a decimal amount (less than @code{1.00}), the next smallest commodity is used. If a commodity could be reported in terms of a higher commodity without resulting to a partial fraction, then the larger commodity is used. @@ -975,8 +975,8 @@ EverQuest account: Now your EverQuest:Inventory has 3 apples and 5 steaks in it. The amounts are negative, because you are taking @emph{from} Black's Tavern in order to add to your Inventory account. Note that you don't -have to use @samp{Places:Black's Tavern} as the source account. You -could use @samp{EverQuest:System} to represent the fact that you +have to use @code{Places:Black's Tavern} as the source account. You +could use @code{EverQuest:System} to represent the fact that you acquired them online. The only purpose for choosing one kind of source account over another is for generate more informative reports later on. The more you know, the better analysis you can perform. @@ -1029,7 +1029,7 @@ assets is greater than the absolute value of your starting equity, it means you are making money. Clear as mud? Keep thinking about it. Until you figure it out, put -@samp{-Equity} at the end of your balance command, to remove the +@code{-Equity} at the end of your balance command, to remove the confusing figure from the total. @node Dealing with Petty Cash, Working with multiple funds and accounts, Understanding Equity, Principles of Accounting @@ -1042,7 +1042,7 @@ a few large ones, as with checks. One solution is: don't bother. Move your spending to a debit card, but in general ignore cash. Once you withdraw it from the ATM, mark -it as already spent to an @samp{Expenses:Cash} category: +it as already spent to an @code{Expenses:Cash} category: @smallexample 2004/03/15 ATM @@ -1051,7 +1051,7 @@ it as already spent to an @samp{Expenses:Cash} category: @end smallexample If at some point you make a large cash expense that you want to track, -just ``move'' the amount of the expense from @samp{Expenses:Cash} into +just ``move'' the amount of the expense from @code{Expenses:Cash} into the target account: @smallexample @@ -1091,8 +1091,8 @@ reserves resources for later: The problem with this kind of setup is that when you spend money, it comes from two or more places at once: the account and the fund. And yet, the correlation of amounts between funds and accounts is rarely -one-to-one. What if the school fund has @samp{$500.00}, but -@samp{$400.00} of that comes from Checking, and @samp{$100.00} from +one-to-one. What if the school fund has @code{$500.00}, but +@code{$400.00} of that comes from Checking, and @code{$100.00} from Savings? Traditional finance packages require that the money reside in only one @@ -1130,14 +1130,14 @@ account: When reports are generated, by default they'll appear in terms of the funds. In this case, you will likely want to mask out your -@samp{Assets} account, because otherwise the balance won't make much +@code{Assets} account, because otherwise the balance won't make much sense: @example ledger bal -^Assets @end example -If the @option{--real} option is used, the report will be in terms of +If the @code{--real} option is used, the report will be in terms of the real accounts: @example @@ -1159,7 +1159,7 @@ The second way of tracking funds is to use transaction codes. In this respect the codes become like virtual accounts that embrace the entire set of postings. Basically, we are associating a transaction with a fund by setting its code. Here are two transactions that deposit money -into, and spend money from, the @samp{Funds:School} fund: +into, and spend money from, the @code{Funds:School} fund: @smallexample 2004/03/25 (Funds:School) Donations @@ -1176,10 +1176,10 @@ balance or registers reports will reflect this. That the transactions relate to a particular fund is kept only in the code. How does this become a fund report? By using the -@option{--code-as-payee} option, you can generate a register report +@code{--code-as-payee} option, you can generate a register report where the payee for each posting shows the code. Alone, this is not terribly interesting; but when combined with the -@option{--by-payee} option, you will now see account subtotals for any +@code{--by-payee} option, you will now see account subtotals for any postings related to a specific fund. So, to see the current monetary balances of all funds, the command would be: @@ -1187,7 +1187,7 @@ monetary balances of all funds, the command would be: ledger --code-as-payee -P reg ^Assets @end smallexample -Or to see a particular funds expenses, the @samp{School} fund in this +Or to see a particular funds expenses, the @code{School} fund in this case: @smallexample @@ -1270,7 +1270,7 @@ balanced amount, if it is the same as the first line: @end smallexample For this transaction, Ledger will figure out that $-23.00 must come from -@samp{Assets:Checking} in order to balance the transaction. +@code{Assets:Checking} in order to balance the transaction. Also note the structure of the account entries. There is an implied hierarchy established by separating with colons (see @pxref{Structuring @@ -1733,7 +1733,7 @@ account Expenses account Expenses:Utilities ... @end smallexample -Using the @samp{--strict} option will cause Ledger to complain if any accounts are not previously defined: +Using the @code{--strict} option will cause Ledger to complain if any accounts are not previously defined: @smallexample 15:27:39 ~/ledger (next) > ledger bal --strict Warning: "FinanceData/Master.dat", line 6: Unknown account 'Liabilities:Tithe Owed' @@ -1741,12 +1741,12 @@ Warning: "FinanceData/Master.dat", line 8: Unknown account 'Liabilities:Tithe Ow Warning: "FinanceData/Master.dat", line 15: Unknown account 'Allocation:Equities:Domestic' @end smallexample -If you have a large Ledger register already created use the @samp{accounts} command to get started: +If you have a large Ledger register already created use the @code{accounts} command to get started: @smallexample ledger accounts >> Accounts.dat @end smallexample -@noindent You will have to edit this file to add the @samp{account} directive. +@noindent You will have to edit this file to add the @code{account} directive. @node Journal Format, Converting from other formats, Keeping it Consistent, Keeping a Journal @section Journal Format @@ -1775,11 +1775,11 @@ transaction's account postings. The format of the first line is: DATE[=EDATE] [*|!] [(CODE)] DESC @end smallexample -If @samp{*} appears after the date (with optional effective date), it +If @code{*} appears after the date (with optional effective date), it indicates the transaction is ``cleared'', which can mean whatever the user -wants it to mean. If @samp{!} appears after the date, it indicates d +wants it to mean. If @code{!} appears after the date, it indicates d the transaction is ``pending''; i.e., tentatively cleared from the user's -point of view, but not yet actually cleared. If a @samp{CODE} appears +point of view, but not yet actually cleared. If a @code{CODE} appears in parentheses, it may be used to indicate a check number, or the type of the posting. Following these is the payee, or a description of the posting. @@ -1790,18 +1790,18 @@ The format of each following posting is: ACCOUNT AMOUNT [; NOTE] @end smallexample -The @samp{ACCOUNT} may be surrounded by parentheses if it is a virtual +The @code{ACCOUNT} may be surrounded by parentheses if it is a virtual posting, or square brackets if it is a virtual posting that -must balance. The @samp{AMOUNT} can be followed by a per-unit -posting cost, by specifying @samp{@@ AMOUNT}, or a complete -posting cost with @samp{@@@@ AMOUNT}. Lastly, the @samp{NOTE} may +must balance. The @code{AMOUNT} can be followed by a per-unit +posting cost, by specifying @code{@@ AMOUNT}, or a complete +posting cost with @code{@@@@ AMOUNT}. Lastly, the @code{NOTE} may specify an actual and/or effective date for the posting by using -the syntax @samp{[ACTUAL_DATE]} or @samp{[=EFFECTIVE_DATE]} or -@samp{[ACTUAL_DATE=EFFECTIVE_DATE]}.(See @pxref{Virtual postings}) +the syntax @code{[ACTUAL_DATE]} or @code{[=EFFECTIVE_DATE]} or +@code{[ACTUAL_DATE=EFFECTIVE_DATE]}.(See @pxref{Virtual postings}) @item P Specifies a historical price for a commodity. These are usually found -in a pricing history file (see the @option{-Q} option). The syntax +in a pricing history file (see the @code{-Q} option). The syntax is: @smallexample P DATE SYMBOL PRICE @@ -1844,8 +1844,8 @@ Command directives must occur at the beginning of a line. Use of ! and @item account Pre-declare valid account names. This only has effect if -@samp{--strict} or @samp{--pedantic} is used (see below). The -@samp{account} directive supports several optional sub-directives, if +@code{--strict} or @code{--pedantic} is used (see below). The +@code{account} directive supports several optional sub-directives, if they immediately follow the account directive and if they begin with whitespace: @@ -1860,14 +1860,14 @@ whitespace: default @end smallexample -The @samp{note} sub-directive associates a textual note with the account. This can -be accessed later using the @samp{note} valexpr function in any account context. +The @code{note} sub-directive associates a textual note with the account. This can +be accessed later using the @code{note} valexpr function in any account context. -The @samp{alias} sub-directive, which can occur multiple times, allows the alias to +The @code{alias} sub-directive, which can occur multiple times, allows the alias to be used in place of the full account name anywhere that account names are allowed. -The @samp{payee} sub-directive, which can occur multiple times, provides regexps +The @code{payee} sub-directive, which can occur multiple times, provides regexps that identify the account if that payee is encountered and an account within its transaction ends in the name "Unknown". Example: @@ -1877,13 +1877,13 @@ its transaction ends in the name "Unknown". Example: Assets:Cash @end smallexample -The @samp{check} and @samp{assert} directives warn or error (respectively) if the given +The @code{check} and @code{assert} directives warn or error (respectively) if the given value expression evaluates to false within the context of any posting. -The @samp{eval} directive evaluates the value expression in the context of the +The @code{eval} directive evaluates the value expression in the context of the account at the time of definition. At the moment this has little value. -The @samp{default} directive specifies that this account should be used as the +The @code{default} directive specifies that this account should be used as the ``balancing account'' for any future transactions that contain only a single posting. @@ -1992,13 +1992,13 @@ check Start a block comment, closed by @code{end comment}. @item commodity -Pre-declare commodity names. This only has effect if @samp{--strict} or -@samp{--pedantic} is used (see below). +Pre-declare commodity names. This only has effect if @code{--strict} or +@code{--pedantic} is used (see below). commodity $ commodity CAD -The @samp{commodity} directive supports several optional sub-directives, if they +The @code{commodity} directive supports several optional sub-directives, if they immediately follow the commodity directive and if they begin with whitespace: @smallexample @@ -2009,18 +2009,18 @@ immediately follow the commodity directive and if they begin with whitespace: default @end smallexample -The @samp{note} sub-directive associates a textual note with the commodity. At +The @code{note} sub-directive associates a textual note with the commodity. At present this has no value other than documentation. -The @samp{format} directive gives you a way to tell Ledger how to format this +The @code{format} directive gives you a way to tell Ledger how to format this commodity. In future using this directive will disable Ledger's observation of other ways that commodity is used, and will provide the ``canonical'' representation. -The @samp{nomarket} directive states that the commodity's price should never be +The @code{nomarket} directive states that the commodity's price should never be auto-downloaded. -The @samp{default} directive marks this as the ``default'' commodity. +The @code{default} directive marks this as the ``default'' commodity. @item define @c instance_t::define_directive in textual.cc @@ -2070,13 +2070,13 @@ is equivalent to this: Expenses:Food 25.75 CAD @{=$0.90@} @end smallexample -Note that ending a @samp{fixed} is done differently than other -directives, as @samp{fixed} is closed with an @samp{endfixed} (i.e., -there is @strong{no space} between @samp{end} and @samp{fixed}). +Note that ending a @code{fixed} is done differently than other +directives, as @code{fixed} is closed with an @code{endfixed} (i.e., +there is @strong{no space} between @code{end} and @code{fixed}). For the moment, users may wish to study @uref{http://bugs.ledger-cli.org/show_bug.cgi?id=789, Bug Report 789} -before using the @samp{fixed} directive in production. +before using the @code{fixed} directive in production. @item include @c instance_t::include_directive in textual.cc @@ -2084,7 +2084,7 @@ Include the stated file as if it were part of the current file. @item payee @c instance_t::payee_mapping_directive in textual.cc -The @samp{payee} directive supports one optional sub-directive, if it immediately +The @code{payee} directive supports one optional sub-directive, if it immediately follows the payee directive and if it begins with whitespace: @smallexample @@ -2092,7 +2092,7 @@ follows the payee directive and if it begins with whitespace: alias KENTUCKY FRIED CHICKEN @end smallexample -The @samp{alias} directive provides a regexp which, if it matches a parsed payee, +The @code{alias} directive provides a regexp which, if it matches a parsed payee, the declared payee name is substituted: @smallexample @@ -2152,8 +2152,8 @@ Note that anything following ``@code{end tag}'' is ignored. placing the name of the tag that is being closed is a simple way to keep track. @item tag -Pre-declares tag names. This only has effect if @samp{--strict} or -@samp{--pedantic} is used (see below). +Pre-declares tag names. This only has effect if @code{--strict} or +@code{--pedantic} is used (see below). @smallexample tag Receipt @@ -2169,7 +2169,7 @@ follow the tag directive and if they begin with whitespace: assert value != "foobar" @end smallexample -The @samp{check} and @samp{assert} directives warn or error (respectively) if the given +The @code{check} and @code{assert} directives warn or error (respectively) if the given value expression evaluates to false within the context of any use of the related tag. In such a context, ``value'' is bound to the value of the tag (which may not be a string if typed-metadata is used!). Such checks or @@ -2183,7 +2183,7 @@ This is a synonym for @code{comment} and must be closed by and @code{end} tag. @c instance_t::year_directive in textual.cc Denotes the year used for all subsequent transactions that give a date without a year. The year should appear immediately after the Y, for -example: @samp{year 2004}. This is useful at the beginning of a file, to +example: @code{year 2004}. This is useful at the beginning of a file, to specify the year for that file. If all transactions specify a year, however, this command has no effect. @@ -2408,8 +2408,8 @@ save typing and improve accuracy. Ledger doesn't leave you hanging, Type a portion of the payee and hit , and @code{ledger-mode} will suggest a completion. When filling in the account type the first few letters followed by a and the account will be filled in. For -example typing @samp{ExAuF} would yield -@samp{Expenses:Auto:Fuel} if you had previously used that account in +example typing @code{ExAuF} would yield +@code{Expenses:Auto:Fuel} if you had previously used that account in this journal. If there are more than one account with similar starting, hitting multiple times will iterate through them. This is a good habit to get in to prevent misspellings of accounts. Remember Ledger @@ -2434,7 +2434,7 @@ payee. For example, if your journal contains an entry Expenses:Tips $2.55 Liabilities:MasterCard $-15.00 @end smallexample -@noindent and you type @samp{C-c C-a}, the mini-buffer will appear showing the +@noindent and you type @code{C-c C-a}, the mini-buffer will appear showing the current year and month. If you complete the mini-buffer entry by typing @smallexample Entry: 2011/11/28 viva food 34 tip 7 @@ -2470,7 +2470,7 @@ your bank (or whatever else you want the concept to mean) @end smallexample If, for some reason you need to clear a specific posting in the -transaction you can type @samp{C-c C-c} and the posting at point will be +transaction you can type @code{C-c C-c} and the posting at point will be toggled. @node Reconciling accounts, Generating Reports, Working with entries, Using Emacs @@ -2817,7 +2817,7 @@ there are some tricks up Ledger's sleeve... You can use virtual accounts to transfer amounts to an account on the sly, bypassing the balancing requirement. The trick is that these postings are not -considered ``real'', and can be removed from all reports using @samp{--real}. +considered ``real'', and can be removed from all reports using @code{--real}. To specify a virtual account, surround the account name with parentheses: @@ -3060,7 +3060,7 @@ of an exceptional transaction, surround the @@ or @@@@ with parentheses: When a transaction occurs that exchange one commodity for another, Ledger records that commodity price not only within its internal price database, but also attached to the commodity itself. Usually this fact remains invisible to -the user, unless you turn on @samp{--lot-prices} to show these hidden price figures. +the user, unless you turn on @code{--lot-prices} to show these hidden price figures. For example, consider the stock sale given above: @@ -3234,7 +3234,7 @@ This is the same as the previous transaction, with the same caveats found in @section Lot dates In addition to lot prices, you can specify lot dates and reveal them with -@samp{--lot-dates}. Other than that, however, they have no special meaning to +@code{--lot-dates}. Other than that, however, they have no special meaning to Ledger. They are specified after the amount in square brackets (the same way that dates are parsed in value expressions): @@ -3262,7 +3262,7 @@ cannot begin with an @ character, as that would indicate a virtual cost: You can any combination of lot prices, dates or notes, in any order. They are all optional. -To show all lot information in a report, use @samp{--lots}. +To show all lot information in a report, use @code{--lots}. @node Lot value expressions, Automated transactions, Lot notes, Transactions @section Lot value expressions @@ -3602,7 +3602,7 @@ really knows that it debited $225 this month. A periodic transaction starts with a ~ followed by a period expression. Periodic transactions are used for budgeting and forecasting only, they -have no effect without the @samp{--budget} option specified. +have no effect without the @code{--budget} option specified. See @ref{Budgeting and Forecasting} for examples and details. @@ -3680,7 +3680,7 @@ command. $ 5,480.00 20:39:21 ~/ledger/test/input > @end smallexample -@noindent note the implicit logical and between @samp{Auto} and @samp{Mastercard}. +@noindent note the implicit logical and between @code{Auto} and @code{Mastercard}. If you want the entire contents of a branch of your account tree, use the highest common name in the branch: @@ -3703,7 +3703,7 @@ You can use general regular expressions in nearly anyplace Ledger needs a string The first example looks for any account starting with ``Bo'', of which there are none. The second looks for any account with ``Bo'', which is -@samp{Expenses:Books}. +@code{Expenses:Books}. @cindex limit by payees If you want to know exactly how much you have spent in a particular @@ -3758,7 +3758,7 @@ ledger -M --period-sort "(amount)" reg ^expenses @end example Now, you might wonder where the money came from to pay for these -things. To see that report, add @option{-r}, which shows the +things. To see that report, add @code{-r}, which shows the ``related account'' postings: @example @@ -3768,8 +3768,8 @@ ledger -M --period-sort "(amount)" -r reg ^expenses But maybe this prints too much information. You might just want to see how much you're spending with your MasterCard. That kind of query requires the use of a display predicate, since the postings -calculated must match @samp{^expenses}, while the postings -displayed must match @samp{mastercard}. The command would be: +calculated must match @code{^expenses}, while the postings +displayed must match @code{mastercard}. The command would be: @example ledger -M -r --display "account =~ /mastercard/" reg ^expenses @@ -3777,8 +3777,8 @@ ledger -M -r --display "account =~ /mastercard/" reg ^expenses This query says: Report monthly subtotals; report the ``related account'' postings; display only related postings whose -account matches @samp{mastercard}, and base the calculation on -postings matching @samp{^expenses}. +account matches @code{mastercard}, and base the calculation on +postings matching @code{^expenses}. This works just as well for report the overall total, too: @@ -3786,7 +3786,7 @@ This works just as well for report the overall total, too: ledger -s -r --display "account =~ /mastercard/"/ reg ^expenses @end example -The @option{-s} option subtotals all postings, just as @option{-M} +The @code{-s} option subtotals all postings, just as @code{-M} subtotaled by the month. The running total in both cases is off, however, since a display expression is being used. @@ -3922,8 +3922,8 @@ register reports. The script to do this is included in the ledger distribution, and is named @file{contrib/report}. Install @file{report} anywhere along your @env{PATH}, and then use @command{report} instead of @command{ledger} when doing a register report. The only thing to keep -in mind is that you must specify @option{-j (--amount-data)} or -@option{-J (--total-data)} to indicate whether Gnuplot should plot the +in mind is that you must specify @code{-j (--amount-data)} or +@code{-J (--total-data)} to indicate whether Gnuplot should plot the amount, or the running total. For example, this command plots total monthly expenses made on your MasterCard. @@ -3954,8 +3954,8 @@ report -J -l "Ua>=@{\$0.01@}" reg ^assets ^liab report -J -l "Ua>=@{\$0.01@}" -d "d>=[last feb]" reg ^assets ^liab @end smallexample -The last report uses both a calculation predicate (@option{-l}) and a -display predicate (@option{-d}). The calculation predicates limits +The last report uses both a calculation predicate (@code{-l}) and a +display predicate (@code{-d}). The calculation predicates limits the report to postings whose amount is greater than $1 (which can only happen if the posting amount is in dollars). The display predicate limits the transactions @emph{displayed} to just those since last @@ -4018,7 +4018,7 @@ always be the same as the current balance of that account. If you have Gnuplot installed, you may plot the amount or running total of any register by using the script @file{report}, which is included in the Ledger distribution. The only requirement is that you -add either @option{-j} or @option{-J} to your register command, in +add either @code{-j} or @code{-J} to your register command, in order to plot either the amount or total column, respectively. @node The print Command, , The register Command, Primary Financial Reports @@ -4132,7 +4132,7 @@ ones are @code{--invert} which inverts the amount field, and balance against and @code{--rich-data}. When using the rich-data switch additional metadata is stored as tags. There is, for example, a UUID field. If an entry with the same UUID tag is already included in the normal ledger -file (specified via -f or $LEDGER_FILE) this entry will not be printed +file (specified via @code{-f} or @code{$LEDGER_FILE}) this entry will not be printed again. You can also use @code{convert} with @code{payee} and @code{account} @@ -4148,9 +4148,9 @@ account Aufwand:Einkauf:Lebensmittel payee ^(Aldi|Alnatura|Kaufland|REWE)$ @end smallexample -Note that it may be necessary for the output of 'ledger convert' to be -passed through 'ledger print' a second time if you want to match on the -new payee field. During the 'ledger convert' run only the original payee +Note that it may be necessary for the output of @code{ledger convert} to be +passed through @code{ledger print} a second time if you want to match on the +new payee field. During the @code{ledger convert} run only the original payee name as specified in the csv data seems to be used. @node The emacs command, Emacs org mode, Comma Separated Variable files, Reports in other Formats @@ -4171,18 +4171,18 @@ The @code{org} command produces a journal file suitable for use in the Emacs org mode. More details on using org mode can be found at @url{http://www.orgmode.org}. -Org mode has a sub-system known as babel which allows for literate +Org mode has a sub-system known as Babel which allows for literate programming. This allows you to mix text and code within the same document and automatically execute code which may generate results which will then appear in the text. -One of the languages supported by org+babel is ledger so that you can +One of the languages supported by @code{org+babel} is Ledger, so that you can have ledger commands embedded in a text file and have the output of ledger commands also appear in the text file. The output can be updated whenever any new ledger entries are added. For instance, the following org mode text document snippet illustrates a -very naive but still useful of the org+babel system: +very naive but still useful of the @code{org+babel} system: @smallexample * A simple test of ledger in an org file @@ -4316,7 +4316,7 @@ Evaluating the code block again would generate a different report. Having to change the actual directive on the code block and re-evaluate makes it difficult to have more than one view of your transactions and financial state. Eventually, babel will support passing arguments to -#+call evaluations of code blocks but this support is missing +@code{#+call} evaluations of code blocks but this support is missing currently. Instead, we can use the concepts of literary programming, as implemented by the noweb features of babel, to help us. @@ -4377,7 +4377,7 @@ have been done individually. Given the ledger entries defined above in the income and expenses code blocks, we can now refer to these using the noweb expansion directives, -<>. We can now define different code blocks to generate specific +@code{<>}. We can now define different code blocks to generate specific reports for those transactions. Below are two examples, one to generate a balance report and one to generate a register report of all transactions. @@ -4402,7 +4402,7 @@ results generated by incorporating the transactions referred to by the @end smallexample If you want a more detailed breakdown of where your money is and where -it has been spent, you can specify the -s flag (i.e. @code{:cmdline -s bal}) to +it has been spent, you can specify the @code{-s} flag (i.e. @code{:cmdline -s bal}) to tell Ledger to include sub-accounts in the report. @smallexample @@ -4505,8 +4505,8 @@ The general format used for Ledger data is: @end smallexample -The data stream is enclosed in a @samp{ledger} tag, which contains a -series of one or more transactions. Each @samp{xact} describes the +The data stream is enclosed in a @code{ledger} tag, which contains a +series of one or more transactions. Each @code{xact} describes the transaction and contains a series of one or more postings: @smallexample @@ -4523,19 +4523,19 @@ transaction and contains a series of one or more postings: @end smallexample -The date format for @samp{en:date} is always @samp{YYYY/MM/DD}. The -@samp{en:cleared} tag is optional, and indicates whether the posting has -been cleared or not. There is also an @samp{en:pending} tag, for -marking pending postings. The @samp{en:code} and @samp{en:payee} tags +The date format for @code{en:date} is always @code{YYYY/MM/DD}. The +@code{en:cleared} tag is optional, and indicates whether the posting has +been cleared or not. There is also an @code{en:pending} tag, for +marking pending postings. The @code{en:code} and @code{en:payee} tags both contain whatever text the user wishes. After the initial transaction data, there must follow a set of postings -marked with @samp{en:postings}. Typically these postings will all +marked with @code{en:postings}. Typically these postings will all balance each other, but if not they will be automatically balanced into -an account named @samp{}. +an account named @code{}. -Within the @samp{en:postings} tag is a series of one or more -@samp{posting}'s, which have the following form: +Within the @code{en:postings} tag is a series of one or more +@code{posting}'s, which have the following form: @smallexample @@ -4552,13 +4552,13 @@ Within the @samp{en:postings} tag is a series of one or more @end smallexample This is a basic posting. It may also be begin with -@samp{tr:virtual} and/or @samp{tr:generated} tags, to indicate virtual -and auto-generated postings. Then follows the @samp{tr:account} +@code{tr:virtual} and/or @code{tr:generated} tags, to indicate virtual +and auto-generated postings. Then follows the @code{tr:account} tag, which contains the full name of the account the posting is related to. Colons separate parent from child in an account name. Lastly follows the amount of the posting, indicated by -@samp{tr:amount}. Within this tag is a @samp{value} tag, of which +@code{tr:amount}. Within this tag is a @code{value} tag, of which there are four different kinds, each with its own format: @enumerate @@ -4568,15 +4568,15 @@ there are four different kinds, each with its own format: @item balance @end enumerate -The format of a Boolean value is @samp{true} or @samp{false} -surrounded by a @samp{boolean} tag, for example: +The format of a Boolean value is @code{true} or @code{false} +surrounded by a @code{boolean} tag, for example: @smallexample true @end smallexample The format of an integer value is the numerical value surrounded by an -@samp{integer} tag, for example: +@code{integer} tag, for example: @smallexample 12036 @@ -4641,8 +4641,8 @@ the same data. @subsection @code{prices} and @code{pricedb} The @command{prices} command displays the price history for matching -commodities. The @option{-A} flag is useful with this report, to -display the running average price, or @option{-D} to show each price's +commodities. The @code{-A} flag is useful with this report, to +display the running average price, or @code{-D} to show each price's deviation from that average. There is also a @command{pricedb} command which outputs the same @@ -4690,7 +4690,7 @@ Say you currently have this posting in your ledger file: Liabilities:MasterCard $-15.00 @end smallexample -Now it's @samp{2004/4/9}, and you've just eating at @samp{Viva +Now it's @code{2004/4/9}, and you've just eating at @code{Viva Italiano} again. The exact amounts are different, but the overall form is the same. With the @command{xact} command you can type: @@ -4708,10 +4708,10 @@ This produces the following output: @end smallexample It works by finding a past posting matching the regular expression -@samp{viva}, and assuming that any accounts or amounts specified will +@code{viva}, and assuming that any accounts or amounts specified will be similar to that earlier posting. If Ledger does not succeed in generating a new transaction, an error is printed and the exit code is set -to @samp{1}. +to @code{1}. Here are a few more examples of the @command{xact} command, assuming the above journal transaction: @@ -4933,7 +4933,7 @@ model transaction: true @end smallexample @item template -Shows the insertion template that a "draft" or "xact" sub-command generates. +Shows the insertion template that a @code{draft} or @code{xact} sub-command generates. This is a debugging command. @end table @@ -4972,7 +4972,7 @@ meaning, described below. The regular expressions arguments always match the account name that a posting refers to. To match on the payee of the transaction instead, -precede the regular expression with @samp{payee} or @@. For example, the +precede the regular expression with @code{payee} or @@. For example, the following balance command reports account totals for rent, food and movies, but only those whose payee matches Freddie: @@ -5197,10 +5197,10 @@ their values and the source of those values, for example: -------------------- 0 @end smallexample -@noindent For the `source' column, a value starting with a `@code{-}' or -`@code{--}' indicated the source was a command line argument. It the -entry starts with a `@code{$}', the source was an environment -variable. If the source is `@code{?normalize}' the value was set +@noindent For the source column, a value starting with a @code{-} or +@code{--} indicated the source was a command line argument. It the +entry starts with a @code{$}, the source was an environment +variable. If the source is @code{?normalize} the value was set internally by ledger, in a function called @code{normalize_options}. @item --script @@ -5277,7 +5277,7 @@ Specify the location of the price entry data file. @item --price-exp INTEGER_MINUTES Set the expected freshness of price quotes, in minutes. That is, if the last known quote for any commodity is older than this value, and if -@samp{--download} is being used, then the Internet will be consulted again +@code{--download} is being used, then the Internet will be consulted again for a newer price. Otherwise, the old price is still considered to be fresh enough. @@ -5479,7 +5479,7 @@ ASK JOHN @item --dc Display register or balance in debit/credit format -If you use @samp{--dc} with either the register (reg) or balance (bal) commands, you +If you use @code{--dc} with either the register (reg) or balance (bal) commands, you will now get extra columns. The register goes from this: @smallexample 12-Mar-10 Employer Assets:Cash $100 $100 @@ -5508,7 +5508,7 @@ will now get extra columns. The register goes from this: @noindent Where the first column is debits, the second is credits, and the third is the running total. Only the running total may contain negative values. -For the balance report without @samp{--dc}: +For the balance report without @code{--dc}: @smallexample $70 Assets:Cash @@ -5518,7 +5518,7 @@ For the balance report without @samp{--dc}: 0 @end smallexample -@noindent And with @samp{--dc} it becomes this: +@noindent And with @code{--dc} it becomes this: @smallexample $105 $35 $70 Assets:Cash @@ -5619,8 +5619,8 @@ them. @item --group-by group transaction together in the register -report. EXPR can be anything, although most common would be -@code{"payee"} or @code{"commodity"}. The @code{tags()} function is +report. @code{EXPR} can be anything, although most common would be +@code{payee} or @code{commodity}. The @code{tags()} function is also useful here. @item --group-title-format @@ -5643,7 +5643,7 @@ ledger reg Expenses --group-by "payee" --group-title-format "------------------- @item --head -Print the first INT entries. Opposite of @code{--tail}. +Print the first @code{INT} entries. Opposite of @code{--tail}. @item --inject Use @code{Expected} amounts in calculations. In the case that you know @@ -5656,14 +5656,14 @@ wrong value you can use metadata to put in the expected amount: @end smallexample Then using the command @code{ledger reg --inject=Expected Income} would -treat the transaction as iff the ``Expected Value'' was actual. +treat the transaction as if the ``Expected Value'' was actual. @item --invert Change the sign of all reported values. @item --limit - Only transactions that satisfy the expression -will be considered in the calculation. + Only transactions that satisfy the expression will be considered in the +calculation. @item --lot-dates Report the date on which each commodity in a balance report was purchased. @@ -5717,12 +5717,13 @@ Suppress the output of group titles Suppress printing the final total line in a balance report. @item --now -Define the current date in case to you to do calculate in the past or future using @code{--current} +Define the current date in case to you to do calculate in the past or +future using @code{--current} @item --only -This is a postings predicate that applies after certain -transforms have been executed, such as periodic gathering. +This is a postings predicate that applies after certain transforms have +been executed, such as periodic gathering. @item --output Redriect the output of ledger to the file defined in @file{PATH}. @@ -5752,7 +5753,7 @@ Only works for account that have a single commoditiy. @item --period Define a period expression the sets the time period during which -transactions are to be accounted. For a register report only th +transactions are to be accounted. For a register report only the transactions that satisfy the period expression with be displayed. For a balance report only those transactions will be accounted in the final balances. @@ -5812,8 +5813,8 @@ interpreting. Can be useful for minor cleanups, like just aligning amounts. @item --real - Account using only real transactions ignoring virtual -and automatic transactions. +Account using only real transactions ignoring virtual and automatic +transactions. @item --related-all @@ -5865,7 +5866,7 @@ FIX THIS ENTRY @item --tail -report only the last entries. Only useful ona register report. +report only the last @code{INT} entries. Only useful ona register report. @item --total-data @@ -5882,7 +5883,7 @@ Indicates how truncation should happen when the contents of columns exceed their width. Valid arguments are @code{leading}, @code{middle}, and @code{trailing}. The default is smarter than any of these three, as it considers sub-names within the account name (that style is called -``abbreviate''. +``abbreviate''). @item --unbudgeted @@ -5954,7 +5955,7 @@ goes to standard output. @item --init-file FILE @item -i FILE -causes FILE to be read by ledger before any other ledger file. This +causes @code{FILE} to be read by ledger before any other ledger file. This file may not contain any postings, but it may contain option settings. To specify options in the init file, use the same syntax as the command-line, but put each option on it's own line. Here's an example @@ -5989,11 +5990,11 @@ displays only transactions occurring on or before the current date. @item --begin DATE @item -b DATE -constrains the report to transactions on or after -@var{DATE}. Only transactions after that date will be calculated, which -means that the running total in the balance report will always start at -zero with the first matching transaction. (Note: This is different from -using @option{--display} to constrain what is displayed). +constrains the report to transactions on or after @var{DATE}. Only +transactions after that date will be calculated, which means that the +running total in the balance report will always start at zero with the +first matching transaction. (Note: This is different from using +@code{--display} to constrain what is displayed). @item --end DATE @item -e DATE @@ -6002,12 +6003,12 @@ not considered. The ending date is inclusive. @item --period STR @item -p STR -sets the reporting period to @var{STR}. This will subtotal -all matching transactions within each period separately, making it easy -to see weekly, monthly, quarterly, etc., posting totals. A period -string can even specify the beginning and end of the report range, using -simple terms like ``last June'' or ``next month''. For more using -period expressions, see @ref{Period Expressions}. +sets the reporting period to @var{STR}. This will subtotal all matching +transactions within each period separately, making it easy to see +weekly, monthly, quarterly, etc., posting totals. A period string can +even specify the beginning and end of the report range, using simple +terms like ``last June'' or ``next month''. For more using period +expressions, see @ref{Period Expressions}. @item --period-sort EXPR sorts the postings within each reporting period using the value @@ -6100,8 +6101,8 @@ sets the value expression used for the ``totals'' column in the @c ledger [OPTIONS] @c @end smallexample -@c Where @samp{COMMAND} is any command verb (@pxref{Reporting Commands}), @samp{OPTIONS} can occur -@c anywhere, and @samp{SEARCH-TERM} is one or more of the following: +@c Where @code{COMMAND} is any command verb (@pxref{Reporting Commands}), @code{OPTIONS} can occur +@c anywhere, and @code{SEARCH-TERM} is one or more of the following: @c @smallexample @c word search for any account containing 'word' @@ -6149,7 +6150,7 @@ postings to be collapsed into a single, subtotaled transaction. @item --subtotal @item -s - causes all transactions in a @command{register} report to be collapsed +causes all transactions in a @command{register} report to be collapsed into a single, subtotaled transaction. @item --by-payee @@ -6165,7 +6166,7 @@ includes even empty accounts in the @command{balance} report. @item -W reports posting totals by the week. The week begins on whichever day of the week begins the month containing that posting. To set a specific -begin date, use a period string, such as @samp{weekly from DATE}. +begin date, use a period string, such as @code{weekly from DATE}. @item --monthly @item -M reports posting totals by month; @@ -6182,7 +6183,7 @@ to see if weekend spending is more than on weekdays. @item --sort EXPR @item -S EXPR sorts a report by comparing the values determined using the value -expression @var{EXPR}. For example, using @option{-S -UT} in the +expression @var{EXPR}. For example, using @code{-S -UT} in the balance report will sort account balances from greatest to least, using the absolute value of the total. For more on how to use value expressions, see @ref{Value Expressions}. @@ -6197,16 +6198,16 @@ causes the default @command{register} report to assume 132 columns instead of 80. @item --head -causes only the first N transactions to be printed. This is different +causes only the first @code{N} transactions to be printed. This is different from using the command-line utility @command{head}, which would limit to -the first N postings. @option{--tail} outputs only the last N +the first N postings. @code{--tail} outputs only the last @code{N} transactions. Both options may be used simultaneously. If a negative amount is given, it will invert the meaning of the flag (instead of the first five transactions being printed, for example, it would print all but the first five). @item --pager -tells Ledger to pass its output to the given pager program---very useful +tells Ledger to pass its output to the given pager program; very useful when the output is especially long. This behavior can be made the default by setting the @env{LEDGER_PAGER} environment variable. @@ -6224,7 +6225,7 @@ meaningful in the @command{register} and @command{prices} reports. shows account subtotals in the @command{balance} report as percentages of the parent account. -@c @option{--totals} include running total information in the +@c @code{--totals} include running total information in the @c @command{xml} report. @item --amount-data @@ -6261,15 +6262,15 @@ ledger -p "last month" reg checking @end smallexample Which is more useful depends on what you're looking to know: the total -amount for the reporting range (@option{-p}), or simply a display -restricted to the reporting range (using @option{-d}). +amount for the reporting range (@code{-p}), or simply a display +restricted to the reporting range (using @code{-d}). @item --date-format STR @item -y STR changes the basic date format used by reports. The default uses a date -like 2004/08/01, which represents the default date format of -@samp{%Y/%m/%d}. To change the way dates are printed in general, the -easiest way is to put @option{--date-format FORMAT} in the Ledger +like @code{2004/08/01}, which represents the default date format of +@code{%Y/%m/%d}. To change the way dates are printed in general, the +easiest way is to put @code{--date-format FORMAT} in the Ledger initialization file @file{~/.ledgerrc} (or the file referred to by @env{LEDGER_INIT}). @@ -6398,8 +6399,8 @@ N $ N h @end smallexample -@noindent Note: Ledger NEVER write output to files. You are responsible for -updated the price-db file. The best way is to have your price download +@noindent Note: Ledger NEVER writes output to files. You are responsible for +updating the price-db file. The best way is to have your price download script maintain this file. The format of the file can be changed by telling ledger to use the @@ -6408,8 +6409,8 @@ The format of the file can be changed by telling ledger to use the @item --price-exp MINS @item -L MINS sets the expected freshness of price quotes, in minutes. That is, if -the last known quote for any commodity is older than this value---and if -@code{--download} is being used---then the Internet will be consulted +the last known quote for any commodity is older than this value, and if +@code{--download} is being used, then the Internet will be consulted again for a newer price. Otherwise, the old price is still considered to be fresh enough. @@ -6425,7 +6426,7 @@ database, usually specified using the environment variable @end table There are several different ways that ledger can report the totals it displays. The most flexible way to adjust them is by using value -expressions, and the @option{-t} and @option{-T} options. However, +expressions, and the @code{-t} and @code{-T} options. However, there are also several ``default'' reports, which will satisfy most users basic reporting needs: @@ -6453,10 +6454,10 @@ commodity can mean different things to different people, depending on the accounts involved, the commodities, the nature of the transactions, etc. -When you specify @samp{-V}, or @samp{-X COMM}, you are requesting that +When you specify @code{-V}, or @code{-X COMM}, you are requesting that some or all of the commodities be valuated as of today (or whatever -@samp{--now} is set to). But what does such a valuation mean? This -meaning is governed by the presence of a @samp{VALUE} meta-data property, +@code{--now} is set to). But what does such a valuation mean? This +meaning is governed by the presence of a @code{VALUE} meta-data property, whose content is an expression used to compute that value. If no VALUE property is specified, each posting is assumed to have a @@ -6467,9 +6468,9 @@ follows: = expr true ; VALUE:: market(amount, date, exchange) @end smallexample -This definition emulates the present day behavior of @samp{-V} and @samp{-X} (in the -case of @samp{-X}, the requested commodity is passed via the string 'exchange' -above). +This definition emulates the present day behavior of @code{-V} and +@code{-X} (in the case of @code{-X}, the requested commodity is passed +via the string 'exchange' above). @cindex Euro conversion One thing many people have wanted to do is to fixate the valuation of @@ -6481,8 +6482,8 @@ old European currencies in terms of the Euro after a certain date: ; VALUE:: date < [Jun 2008] ? market(amount, date, exchange) : 1.44 EUR @end smallexample -This says: If @samp{--now} is some old date, use market prices as they -were at that time; but if @samp{--now} is past June 2008, use a fixed +This says: If @code{--now} is some old date, use market prices as they +were at that time; but if @code{--now} is past June 2008, use a fixed price for converting Deutsch Mark to Euro. Or how about never re-valuating commodities used in Expenses, since they @@ -6495,7 +6496,7 @@ cannot have a different future value: This says the future valuation is the same as the valuation at the time of posting. post.date equals the posting's date, while just 'date' is -the value of @samp{--now} (defaults to today). +the value of @code{--now} (defaults to today). Or how about valuating miles based on a reimbursement rate during a specific time period: @@ -6507,7 +6508,7 @@ specific time period: @end smallexample In this case, miles driven in 2007 will always be valuated at $1.05 -each. If you use @samp{-X EUR} to expressly request all amounts in +each. If you use @code{-X EUR} to expressly request all amounts in Euro, Ledger shall convert $1.05 to Euro by whatever means are appropriate for dollars. @@ -6547,16 +6548,16 @@ another currency. For example: Ledger presently has no way of handling such things as FIFO and LIFO. If you specify an unadorned commodity name, like AAPL, it will balance -against itself. If @samp{--lots} are not being displayed, then it will +against itself. If @code{--lots} are not being displayed, then it will appear to balance against any lot of AAPL. @cindex adorned commodity If you specify an adorned commodity, like AAPL @{$10.00@}, it will also -balance against itself, and against any AAPL if @samp{--lots} is not -specified. But if you do specify @samp{--lot-prices}, for example, then +balance against itself, and against any AAPL if @code{--lots} is not +specified. But if you do specify @code{--lot-prices}, for example, then it will balance against that specific price for AAPL. -Normally when you use @samp{-X } to request that amounts be reported in a +Normally when you use @code{-X } to request that amounts be reported in a specific commodity, Ledger uses these values: @itemize @@ -6569,16 +6570,17 @@ specific commodity, Ledger uses these values: For the balance report, use the value of that commodity as of today. @end itemize -You can now specify -H to ask that all valuations for any amount be done +You can now specify @code{-H} to ask that all valuations for any amount be done relative to the date that amount was encountered. -You can also now use -X (and -H) in conjunction with -B and -I, to see -valuation reports of just your basis costs or lot prices. +You can also now use @code{-X} (and @code{-H}) in conjunction with +@code{-B} and @code{-I}, to see valuation reports of just your basis +costs or lot prices. @node Environment Variables, , Commodity Reporting, Detailed Options Description @subsection Environment variables Every option to ledger may be set using an environment variable. If -an option has a long name such @option{--this-option}, setting the +an option has a long name such @code{--this-option}, setting the environment variable @env{LEDGER_THIS_OPTION} will have the same affect as specifying that option on the command-line. Options on the command-line always take precedence over environment variable @@ -6655,7 +6657,7 @@ last week The beginning and ending can be given at the same time, if it spans a single period. In that case, just use @var{SPEC} by itself. In that -case, the period @samp{oct}, for example, will cover all the days in +case, the period @code{oct}, for example, will cover all the days in October. The possible forms are: @smallexample @@ -6729,7 +6731,7 @@ ledger -p "this year" --monthly --average --subtotal balance ^expenses The reported totals are the current year's average for each account. Once these period transactions are defined, creating a budget report is as -easy as adding @option{--budget} to the command-line. For example, a +easy as adding @code{--budget} to the command-line. For example, a typical monthly expense report would be: @example @@ -6744,8 +6746,8 @@ ledger --budget --monthly register ^expenses A budget report includes only those accounts that appear in the budget. To see all expenses balanced against the budget, use -@option{--add-budget}. You can even see only the un-budgeted expenses -using @option{--unbudgeted}: +@code{--add-budget}. You can even see only the un-budgeted expenses +using @code{--unbudgeted}: @example ledger --unbudgeted --monthly register ^expenses @@ -6780,15 +6782,15 @@ ledger --forecast "d<[2010]" bal ^assets ^liabilities @node Value Expressions, Format Strings, Budgeting and Forecasting, Top @chapter Value Expressions -Ledger uses value expressions to make -calculations for many different purposes: +Ledger uses value expressions to make calculations for many different +purposes: @enumerate @item The values displayed in reports @item For predicates (where truth is anything non-zero), to determine which -postings are calculated (@option{-l}) or displayed (@option{-d}). +postings are calculated (@code{-l}) or displayed (@code{-d}). @item For sorting criteria, to yield the sort key. @item @@ -6822,8 +6824,8 @@ ledger -d "d>[this month]" register checking @end smallexample This advantage to this command's complexity is that it prints the -running total in terms of all transactions in the register. The following, -simpler command is similar, but totals only the displayed +running total in terms of all transactions in the register. The +following, simpler command is similar, but totals only the displayed postings: @smallexample @@ -6844,20 +6846,20 @@ Below are the one letter variables available in any value expression. For the register and print commands, these variables relate to individual postings, and sometimes the account affected by a posting. For the balance command, these variables relate to -accounts---often with a subtle difference in meaning. The use of each +accounts, often with a subtle difference in meaning. The use of each variable for both is specified. @table @code @item t -This maps to whatever the user specified with @option{-t}. In a -register report, @option{-t} changes the value column; in a balance -report, it has no meaning by default. If @option{-t} was not +This maps to whatever the user specified with @code{-t}. In a +register report, @code{-t} changes the value column; in a balance +report, it has no meaning by default. If @code{-t} was not specified, the current report style's value expression is used. @item T -This maps to whatever the user specified with @option{-T}. In a -register report, @option{-T} changes the totals column; in a balance -report, this is the value given for each account. If @option{-T} was +This maps to whatever the user specified with @code{-T}. In a +register report, @code{-T} changes the totals column; in a balance +report, this is the value given for each account. If @code{-T} was not specified, the current report style's value expression is used. @item m @@ -6884,7 +6886,7 @@ The market value of a posting, or an account without its children. @item g The net gain (market value minus cost basis), for a posting or an -account without its children. It is the same as @samp{v-b}. +account without its children. It is the same as @code{v-b}. @item l The depth (``level'') of an account. If an account has one parent, @@ -6926,7 +6928,7 @@ all its children. @item G The total net gain (market value minus cost basis), for a series of postings, or an account and its children. It is the same as -@samp{V-B}. +@code{V-B}. @end table @node Functions, Operators, Variables, Value Expressions @@ -6945,12 +6947,12 @@ The absolute (unsigned) value of the argument. Strips the commodity from the argument. @item A -The arithmetic mean of the argument; @samp{Ax} is the same as -@samp{x/n}. +The arithmetic mean of the argument; @code{Ax} is the same as +@code{x/n}. @item P -The present market value of the argument. The syntax @samp{P(x,d)} is -supported, which yields the market value at time @samp{d}. If no date +The present market value of the argument. The syntax @code{P(x,d)} is +supported, which yields the market value at time @code{d}. If no date is given, then the current moment is used. @end table @@ -6960,10 +6962,10 @@ is given, then the current moment is used. The binary and ternary operators, in order of precedence, are: @enumerate -@item @samp{* /} -@item @samp{+ -} -@item @samp{! < > =} -@item @samp{& | ?:} +@item @code{* /} +@item @code{+ -} +@item @code{! < > =} +@item @code{& | ?:} @end enumerate @menu @@ -7045,177 +7047,235 @@ precedence order of operators. @item [DATE] Useful specifying a date in plain terms. For example, you could say -@samp{[2004/06/01]}. +@code{[2004/06/01]}. @end table +@menu +* Misc:: +@end menu + +@node Misc, , Complex Expressions, Complex Expressions +@subsection Miscellaneous +@multitable @columnfractions .3 .2 .5 +@item @strong{Function} @tab @strong{Abbrev.} @tab @strong{Description} +@item @code{amount_expr } @tab @code{} @tab +@item @code{abs } @tab @code{} @tab --> U +@item @code{code} @tab @code{} @tab returns the transaction code, the string between the parenthesis after the date. +@item @code{commodity } @tab @code{} @tab +@item @code{display_amount } @tab @code{} @tab --> t +@item @code{display_total } @tab @code{} @tab --> T +@item @code{date } @tab @code{} @tab +@item @code{format_date } @tab @code{} @tab +@item @code{format } @tab @code{} @tab +@item @code{floor } @tab @code{} @tab +@item @code{get_at } @tab @code{} @tab +@item @code{is_seq } @tab @code{} @tab +@item @code{justify } @tab @code{} @tab +@item @code{join } @tab @code{} @tab +@item @code{market --> P } @tab @code{} @tab +@item @code{null } @tab @code{} @tab +@item @code{now --> d m } @tab @code{} @tab +@item @code{options } @tab @code{} @tab +@item @code{post } @tab @code{} @tab +@item @code{percent } @tab @code{} @tab +@item @code{price } @tab @code{} @tab +@item @code{print } @tab @code{} @tab +@item @code{quoted } @tab @code{} @tab +@item @code{quantity } @tab @code{} @tab +@item @code{rounded } @tab @code{} @tab +@item @code{scrub } @tab @code{} @tab +@item @code{strip --> S } @tab @code{} @tab +@item @code{should_bold } @tab @code{} @tab +@item @code{truncated } @tab @code{} @tab +@item @code{total_expr } @tab @code{} @tab +@item @code{today } @tab @code{} @tab +@item @code{top_amount } @tab @code{} @tab +@item @code{to_boolean } @tab @code{} @tab +@item @code{to_int } @tab @code{} @tab +@item @code{to_datetime } @tab @code{} @tab +@item @code{to_date } @tab @code{} @tab +@item @code{to_amount } @tab @code{} @tab +@item @code{to_balance } @tab @code{} @tab +@item @code{to_spring } @tab @code{} @tab +@item @code{to_mask } @tab @code{} @tab +@item @code{to_sequence } @tab @code{} @tab +@item @code{unrounded } @tab @code{} @tab +@item @code{value_date } @tab @code{} @tab +@end multitable @node Format Strings, Ledger for Developers, Value Expressions, Top @chapter Format Strings @menu * Basics:: +* Format String Structure:: * Format Expressions:: * --balance-format:: -* New formatting codes:: -* Date and Time Format Codes:: +* Formatting codes:: @end menu -@node Basics, Format Expressions, Format Strings, Format Strings +@node Basics, Format String Structure, Format Strings, Format Strings @section Format String Basics -Format strings may be used to change the output format of reports. -They are specified by passing a formatting string to the -@option{--format} (@option{-F}) option. Within that string, -constructs are allowed which make it possible to display the various -parts of an account or posting in custom ways. +Format strings may be used to change the output format of reports. They +are specified by passing a formatting string to the @code{--format} +(@code{-F}) option. Within that string, constructs are allowed which +make it possible to display the various parts of an account or posting +in custom ways. +There are several additional flags that allow you to define formats for +specific reports. These are useful to define in your configuration file +and will allow you to run ledger reports from the command line without +having to enter a new format for each command. + +@itemize +@item @code{--balance-report} +@item @code{--cleared-report} +@item @code{--register-report} +@item @code{--csv-report} +@item @code{--plot-amount-report} +@item @code{--plot-total-report} +@item @code{--pricedb-report} +@item @code{--prices-report} +@item @code{--wide-register-report} +@end itemize + +@node Format String Structure, Format Expressions, Basics, Format Strings +@section Format String Structure Within a format string, a substitution is specified using a percent -character (@samp{%}). The basic format of all substitutions is: +character (@code{%}). The basic format of all substitutions is: @smallexample %[-][MIN WIDTH][.MAX WIDTH](VALEXPR) @end smallexample -If the optional minus sign (@samp{-}) follows the percent character, +If the optional minus sign (@code{-}) follows the percent character, whatever is substituted will be left justified. The default is right -justified. If a minimum width is given next, the substituted text -will be at least that wide, perhaps wider. If a period and a maximum -width is given, the substituted text will never be wider than this, -and will be truncated to fit. Here are some examples: +justified. If a minimum width is given next, the substituted text will +be at least that wide, perhaps wider. If a period and a maximum width +is given, the substituted text will never be wider than this, and will +be truncated to fit. Here are some examples: -@smallexample -%-P a transaction's payee, left justified -%20P The same, right justified, at least 20 chars wide -%.20P The same, no more than 20 chars wide -%-.20P Left justified, maximum twenty chars wide -@end smallexample +@table @code +@item %-20P +a transaction's payee, left justified and padded to 20 characters wide. +@item %20P +The same, right justified, at least 20 chars wide +@item %.20P +The same, no more than 20 chars wide +@end table -The expression following the format constraints can be a single -letter, or an expression enclosed in parentheses or brackets. +The expression following the format constraints can be a single letter, +or an expression enclosed in parentheses or brackets. -@node Format Expressions, --balance-format, Basics, Format Strings +@node Format Expressions, --balance-format, Format String Structure, Format Strings @section Format Expressions - The -allowable expressions are: + The allowable expressions are: @table @code @item % Inserts a percent sign. @item t -Inserts the results of the value expression specified by @option{-t}. -If @option{-t} was not specified, the current report style's value +Inserts the results of the value expression specified by @code{-t}. +If @code{-t} was not specified, the current report style's value expression is used. @item T -Inserts the results of the value expression specified by @option{-T}. -If @option{-T} was not specified, the current report style's value +Inserts the results of the value expression specified by @code{-T}. +If @code{-T} was not specified, the current report style's value expression is used. -@item | -Inserts a single space. This is useful if a width is specified, for -inserting a certain number of spaces. - -@item _ -Inserts a space for each level of an account's depth. That is, if an -account has two parents, this construct will insert two spaces. If a -minimum width is specified, that much space is inserted for each level -of depth. Thus @samp{%5_}, for an account with four parents, will -insert twenty spaces. - @item (EXPR) Inserts the amount resulting from the value expression given in parentheses. To insert five times the total value of an account, for -example, one could say @samp{%12(5*O)}. Note: It's important to put -the five first in that expression, so that the commodity doesn't get +example, one could say @code{%12(5*O)}. Note: It's important to put the +five first in that expression, so that the commodity doesn't get stripped from the total. @item [DATEFMT] Inserts the result of formatting a posting's date with a date format string, exactly like those supported by @code{strftime}. For -example: @samp{%[%Y/%m/%d %H:%M:%S]}. +example: @code{%[%Y/%m/%d %H:%M:%S]}. @item S -Insert the pathname of the file from which the transaction's data was read. +Insert the pathname of the file from which the transaction's data was +read. Only sensible in a register report. @item B -Inserts the beginning character position of that transaction within the file. +Inserts the beginning character position of that transaction within the +file. @item b Inserts the beginning line of that transaction within the file. @item E -Inserts the ending character position of that transaction within the file. +Inserts the ending character position of that transaction within the +file. @item e Inserts the ending line of that transaction within the file. -@item D -By default, this is the same as @samp{%[%Y/%m%/d]}. The date format -used can be changed at any time with the @option{-y} flag, however. -Using @samp{%D} gives the user more control over the way dates are -output. +@c @item D +@c By default, this is the same as @code{%[%Y/%m%/d]}. The date format +@c used can be changed at any time with the @code{-y} flag, however. Using +@c @code{%D} gives the user more control over the way dates are output. @item d -This is the same as the @samp{%D} option, unless the transaction has an -effective date, in which case it prints -@samp{[ACTUAL_DATE=EFFECTIVE_DATE]}. +Returns the data accoridng to the default format. If the transaction +has an effective date, it prints @code{[ACTUAL_DATE=EFFECTIVE_DATE]}. @item X -If a posting has been cleared, this inserts @samp{*} followed by a -space; otherwise nothing is inserted. +If a posting has been cleared, this returns a 1, otherwise returns 0. @item Y -This is the same as @samp{%X}, except that it only displays a state +This is the same as @code{%X}, except that it only displays a state character if all of the member postings have the same state. @item C -Inserts the checking number for a transaction, in parentheses, followed by -a space; if none was specified, nothing is inserted. +Inserts the transaction type. This is the value specified between +parenthesis on the first line of the transaction. @item P Inserts the payee related to a posting. -@item a -Inserts the optimal short name for an account. This is normally used -in balance reports. It prints a parent account's name if that name -has not been printed yet, otherwise it just prints the account's name. +@c @item a +@c Inserts the optimal short name for an account. This is normally used in +@c balance reports. It prints a parent account's name if that name has not +@c been printed yet, otherwise it just prints the account's name. @item A Inserts the full name of an account. -@item W -This is the same as @samp{%A}, except that it first displays the -posting's state @emph{if the transaction's posting states are not -all the same}, followed by the full account name. This is offered as -a printing optimization, so that combined with @samp{%Y}, only the -minimum amount of state detail is printed. +@c @item W +@c This is the same as @code{%A}, except that it first displays the +@c posting's state @emph{if the transaction's posting states are not all +@c the same}, followed by the full account name. This is offered as a +@c printing optimization, so that combined with @code{%Y}, only the minimum +@c amount of state detail is printed. -@item o -Inserts the ``optimized'' form of a posting's amount. This is -used by the print report. In some cases, this inserts nothing; in -others, it inserts the posting amount and its cost. It's use is -not recommended unless you are modifying the print report. +@c @item o +@c Inserts the ``optimized'' form of a posting's amount. This is used by +@c the print report. In some cases, this inserts nothing; in others, it +@c inserts the posting amount and its cost. It's use is not recommended +@c unless you are modifying the print report. -@item n -Inserts the note associated with a posting, preceded by two spaces -and a semi-colon, if it exists. Thus, no none becomes an empty -string, while the note @samp{foo} is substituted as @samp{ ; foo}. @item N Inserts the note associated with a posting, if one exists. @item / -The @samp{%/} construct is special. It separates a format string +The @code{%/} construct is special. It separates a format string between what is printed for the first posting of a transaction, and what is printed for all subsequent postings. If not used, the same format string is used for all postings. @end table -@node --balance-format, New formatting codes, Format Expressions, Format Strings +@node --balance-format, Formatting codes, Format Expressions, Format Strings @section --balance-format -As an example of how flexible the --format strings can be, the default balance format looks like this: +As an example of how flexible the @code{--format} strings can be, the default +balance format looks like this (the various functions are descirbed later): @smallexample "%(justify(scrub(display_total), 20, -1, true, color))" @@ -7225,34 +7285,37 @@ As an example of how flexible the --format strings can be, the default balance f "--------------------\n" @end smallexample -@node New formatting codes, Date and Time Format Codes, --balance-format, Format Strings -@section New Formatting Codes +@node Formatting codes, , --balance-format, Format Strings +@section Formatting Functions and Codes @menu * Field Widths:: * Colors:: * Quantities and Calculations:: * Dates:: +* Date and Time Format Codes:: * Text Formatting:: * Data File Parsing Information:: -* Misc:: @end menu -@node Field Widths, Colors, New formatting codes, New formatting codes +@node Field Widths, Colors, Formatting codes, Formatting codes @subsection Field Widths -@multitable @columnfractions .3 .2 .5 -@item @strong{Function} @tab @strong{Abbrev.} @tab @strong{Description} +The following codes return the width allocated for the specific fields. +The defaults can be changed using the corresponding command line +options: +@itemize @item @code{date_width} @item @code{payee_width} @item @code{account_width} @item @code{amount_width} @item @code{total_width} -@end multitable +@end itemize -@node Colors, Quantities and Calculations, Field Widths, New formatting codes +@node Colors, Quantities and Calculations, Field Widths, Formatting codes @subsection Colors -The character based formatting ledger can do is limited to the ANSI terminal character colors and font highlight in a normal TTY session. +The character based formatting ledger can do is limited to the ANSI +terminal character colors and font highlights in a normal TTY session. @multitable @columnfractions .3 .3 .3 @item @code{red} @tab @code{magenta} @tab @code{bold} @item @code{green } @tab @code{cyan} @tab @code{underline} @@ -7262,231 +7325,211 @@ The character based formatting ledger can do is limited to the ANSI terminal cha -@node Quantities and Calculations, Dates, Colors, New formatting codes +@node Quantities and Calculations, Dates, Colors, Formatting codes @subsection Quantities and Calculations -@multitable @columnfractions .3 .2 .5 -@item @strong{Function} @tab @strong{Abbrev.} @tab @strong{Description} -@item @code{amount_expr } @tab @code{} @tab -@item @code{abs} @tab @code{U} @tab -@item @code{commodity } @tab @code{} @tab -@item @code{display_amount } @tab @code{t} @tab -@item @code{display_total } @tab @code{T} @tab -@item @code{floor } @tab @code{} @tab -@item @code{get_at } @tab @code{} @tab -@item @code{is_seq } @tab @code{} @tab -@item @code{market } @tab @code{P} @tab -@item @code{percent } @tab @code{} @tab -@item @code{price } @tab @code{} @tab -@item @code{quantity } @tab @code{} @tab -@item @code{rounded } @tab @code{} @tab -@item @code{truncated } @tab @code{} @tab -@item @code{total_expr } @tab @code{} @tab -@item @code{top_amount } @tab @code{} @tab -@item @code{to_boolean } @tab @code{} @tab -@item @code{to_int } @tab @code{} @tab -@item @code{to_amount } @tab @code{} @tab -@item @code{to_balance } @tab @code{} @tab -@item @code{unrounded } @tab @code{} @tab -@end multitable +@table @code +@item amount_expr +@item abs +@item commodity +@item display_amount +@item display_total +@item floor +@item get_at +@item is_seq +@item market +@item percent +@item price +@item quantity +@item rounded +@item truncated +@item total_expr +@item top_amount +@item to_boolean +@item to_int +@item to_amount +@item to_balance +@item unrounded +@end table -@node Dates, Text Formatting, Quantities and Calculations, New formatting codes -@subsection Dates - -@multitable @columnfractions .3 .2 .5 -@item @strong{Function} @tab @strong{Abbrev.} @tab @strong{Description} -@item @code{date } @tab @code{} @tab -@item @code{format_date } @tab @code{} @tab -@item @code{now } @tab @code{} @tab --> d m -@item @code{today } @tab @code{} @tab -@item @code{to_datetime } @tab @code{} @tab -@item @code{to_date } @tab @code{} @tab -@item @code{value_date } @tab @code{} @tab -@end multitable - -@node Text Formatting, Data File Parsing Information, Dates, New formatting codes -@subsection Text Formatting -@subsubsection Summary -@multitable @columnfractions .6 .4 -@item @strong{Function} @tab @strong{Description} -@item @code{ansify_if(str,color) } @tab Colorize the string -@item @code{justify(str, fwidth, lwidth, right, colorize) } @tab Right or left justify the string. -@item @code{join(str) } @tab Remove line feeds from the input string. Mainly used internally for org-mode output -@item @code{quoted(str) } @tab Returns @code{""}. -@item @code{strip } @tab @code{Removes additional annotations from values.} -@item @code{scrub } @tab @code{S} -@item @code{should_bold } @tab @code{} -@end multitable -@subsubsection Detailed Descriptions +@node Dates, Date and Time Format Codes, Quantities and Calculations, Formatting codes +@subsection Date Functions +The following functions allow you to manipulate and format dates. @table @code -@item ansify_if(value, color) -Surrounds the string representing value with ANSI codes to give it -@code{color} on an TTY display. Has no effect if directed to a file. -@item justify(value, first_width, latter_width, right_justify, colorize) -Right or left justify the string representing @code{value}. The width -of the field in the first line is given by @code{first_width}. For -subsequent lines the width is given by @code{latterwidth}. If -@code{latter_width=-1}, then @code{first_width} is use for all lines. -If @code{right_justify=true} then the field is right justify within the -width of the field. If it is @code{false}, then the field is left -justified and padded to the full width of the field. If @code{colorize} -is true then ledger will honor color settings. -@item join(str) -Replaces line feeds in str with @code{\n}. -@item quoted(str) -Return str surrounded by double quotes, @code{""}. -@item strip(value) -Values can have numerous annotations, such as effective dates and lot -prices. @code{strip} removes these annotations. +@item date +Returns the date of the current transaction +@item format_date(date, "FORMAT STRING") +formats the date using the given format string. +@item now +Returns the current date and time. If the @code{--now} option is +defined it will return that value. +@item today +Returns the current date. If the @code{--now} option is +defined it will return that value. +@item to_datetime +convert a string to a date-time value +@item to_date +convert a string to date value +@item value_date @end table -@node Data File Parsing Information, Misc, Text Formatting, New formatting codes -@subsection Data File Parsing Information - -The format strings in the table below provide locational metadata -regarding the coordinates of entries in the source data file(s) that -generated the posting. - -@subsubsection Summary -@multitable @columnfractions .3 .2 .5 -@item @strong{Function} @tab @strong{Abbrev.} @tab @strong{Description} -@item @code{filename} @tab S @tab name of ledger data file from whence posting came -@item @code{beg_pos} @tab B @tab character position in @code{filename} where entry for posting begins -@item @code{end_pos} @tab E @tab character position in @code{filename} where entry for posting ends -@item @code{beg_line} @tab b @tab line number in @code{filename} where entry for posting begins -@item @code{end_line} @tab e @tab line number in @code{filename} where posting's entry for posting ends -@end multitable - - -@node Misc, , Data File Parsing Information, New formatting codes -@subsection Miscellaneous -@multitable @columnfractions .3 .2 .5 -@item @strong{Function} @tab @strong{Abbrev.} @tab @strong{Description} -@item @code{amount_expr } @tab @code{} @tab -@item @code{abs } @tab @code{} @tab --> U -@item @code{code} @tab @code{} @tab returns the transaction code, the string between the parenthesis after the date. -@item @code{commodity } @tab @code{} @tab -@item @code{display_amount } @tab @code{} @tab --> t -@item @code{display_total } @tab @code{} @tab --> T -@item @code{date } @tab @code{} @tab -@item @code{format_date } @tab @code{} @tab -@item @code{format } @tab @code{} @tab -@item @code{floor } @tab @code{} @tab -@item @code{get_at } @tab @code{} @tab -@item @code{is_seq } @tab @code{} @tab -@item @code{justify } @tab @code{} @tab -@item @code{join } @tab @code{} @tab -@item @code{market --> P } @tab @code{} @tab -@item @code{null } @tab @code{} @tab -@item @code{now --> d m } @tab @code{} @tab -@item @code{options } @tab @code{} @tab -@item @code{post } @tab @code{} @tab -@item @code{percent } @tab @code{} @tab -@item @code{price } @tab @code{} @tab -@item @code{print } @tab @code{} @tab -@item @code{quoted } @tab @code{} @tab -@item @code{quantity } @tab @code{} @tab -@item @code{rounded } @tab @code{} @tab -@item @code{scrub } @tab @code{} @tab -@item @code{strip --> S } @tab @code{} @tab -@item @code{should_bold } @tab @code{} @tab -@item @code{truncated } @tab @code{} @tab -@item @code{total_expr } @tab @code{} @tab -@item @code{today } @tab @code{} @tab -@item @code{top_amount } @tab @code{} @tab -@item @code{to_boolean } @tab @code{} @tab -@item @code{to_int } @tab @code{} @tab -@item @code{to_datetime } @tab @code{} @tab -@item @code{to_date } @tab @code{} @tab -@item @code{to_amount } @tab @code{} @tab -@item @code{to_balance } @tab @code{} @tab -@item @code{to_spring } @tab @code{} @tab -@item @code{to_mask } @tab @code{} @tab -@item @code{to_sequence } @tab @code{} @tab -@item @code{unrounded } @tab @code{} @tab -@item @code{value_date } @tab @code{} @tab -@end multitable +@menu +* Date and Time Format Codes:: +@end menu -@node Date and Time Format Codes, , New formatting codes, Format Strings -@section Date and Time Format Codes +@node Date and Time Format Codes, Text Formatting, Dates, Formatting codes +@subsection Date and Time Format Codes Date and time format are specified as strings of single letter codes preceded by percent signs. Any separator, or no separator can be specified. -@subsection Dates +@subsubsection Days Dates are formed from a combination of day, month and year codes, in whatever order you prefer: -@option{%Y} is keyword for four digit year +@table @code +@item %Y +Four digit year -@option{%y} is keyword for two digit year +@item %y +Two digit year -@option{%m} is keyword for two digit month +@item %m +Two digit month -@option{%d} is keyword for two digit date +@item %d +Two digit date +@end table -@noindent So @code{"%Y%m%d"} yields @code{20111214} which provides a date that is simple to sort. +@noindent So @code{"%Y%m%d"} yields @code{20111214} which provides a date that is simple to sort on. -@subsection Weekdays +@subsubsection Weekdays You can have additional weekday information in your date with @code{%A} as -@option{%m-%d-%Y %A} yields @code{02-10-2010 Wednesday} - -@option{%A %m-%d-%Y} yields @code{Wednesday 02-10-2010} +@table @code +@item %m-%d-%Y %A +yields @code{02-10-2010 Wednesday} +@item %A %m-%d-%Y +yields @code{Wednesday 02-10-2010} +@end table @noindent These are options you can select for weekday -@option{%a} weekday, abbreviated Wed - -@option{%A} weekday, full Wednesday - -@option{%d} day of the month (dd), zero padded 10 - -@option{%e} day of the month (dd) 10 - -@option{%j} day of year, zero padded 000-366 - -@option{%u} day of week starting with Monday (1), i.e. @code{mtwtfss} 3 - -@option{%w} day of week starting with Sunday (0), i.e. @code{smtwtfs} 3 - -@subsection Month +@table @code +@item %a +weekday, abbreviated Wed +@item %A +weekday, full Wednesday +@item %d +day of the month (dd), zero padded 10 +@item %e +day of the month (dd) 10 +@item %j +day of year, zero padded 000-366 +@item %u +day of week starting with Monday (1), i.e. @code{mtwtfss} 3 +@item %w +day of week starting with Sunday (0), i.e. @code{smtwtfs} 3 +@end table +@subsubsection Month You can have additional month information in your date with @code{%B} as +@table @code +@item %m-%d-%Y %B +yields @code{ 02-10-2010 Februrary} -@option{%m-%d-%Y %B} yields @code{ 02-10-2010 Februrary} - -@option{%B %m-%d-%Y} yields @code{February 02-10-2010} - +@item %B %m-%d-%Y +yields @code{February 02-10-2010} +@end table @noindent These are options you can select for month +@table @code +@item %m +@code{mm} month as two digits -@option{%m} @code{mm} month as two digits +@item %b +Locale’s abbreviated month, for example @code{02} might be abbreviated as @code{Feb} -@option{%b} @code{Mon}, locale’s abbreviated Feb +@item %B +Locale’s full month, variable length February +@end table -@option{%B} locale’s full month, variable length February +@subsubsection Miscellaneous Date Codes +Additional date format parameters which can be used : +@table @code +@item %U +week number Sunday as first day of week 01–53 +@item %W +week number Monday as first day of week 01–53 +@item %V +week of the year 01–53 +@item %C +@code{cc} century 00–99 +@item %D +yields @code{mm/dd/yy 02/10/10} +@item %x +locale’s date representation @code{02/10/2010} for the U.S. +@item %F +yields @code{%Y-%m-%d 2010-02-10} +@end table +@menu +* Text Formatting:: +* Data File Parsing Information:: +* Misc:: +@end menu -@subsection Miscellaneous Date Codes -Additional date format parameters which can be used : +@node Text Formatting, Data File Parsing Information, Date and Time Format Codes, Formatting codes +@subsection Text Formatting +The following format functions allow you limited formatting of text: +@table @code +@item ansify_if(value, color) +Surrounds the string representing value with ANSI codes to give it +@code{color} on an TTY display. Has no effect if directed to a file. +@item justify(value, first_width, latter_width, right_justify, colorize) +Right or left justify the string representing @code{value}. The width +of the field in the first line is given by @code{first_width}. For +subsequent lines the width is given by @code{latterwidth}. If +@code{latter_width=-1}, then @code{first_width} is use for all lines. +If @code{right_justify=true} then the field is right justify within the +width of the field. If it is @code{false}, then the field is left +justified and padded to the full width of the field. If @code{colorize} +is true then ledger will honor color settings. +@item join(STR) +Replaces line feeds in @code{STR} with @code{\n}. +@item quoted(STR) +Return @code{STR} surrounded by double quotes, @code{"STR"}. +@item strip(value) +Values can have numerous annotations, such as effective dates and lot +prices. @code{strip} removes these annotations. +@end table -@option{%U} week number Sunday as first day of week 01–53 +@node Data File Parsing Information, , Text Formatting, Formatting codes +@subsection Data File Parsing Information -@option{%W} week number Monday as first day of week 01–53 +The following format strings provide locational metadata +regarding the coordinates of entries in the source data file(s) that +generated the posting. -@option{%V} week of the year 01–53 +@table @code +@item filename +name of ledger data file from whence posting came, abbreviated @code{S} +@item beg_pos +character position in @code{filename} where entry for posting begins, abbreviated @code{B} +@item end_pos +character position in @code{filename} where entry for posting ends, abbreviated @code{E} +@item beg_line +line number in @code{filename} where entry for posting begins, abbreviated @code{b} +@item end_line +line number in @code{filename} where posting's entry for posting ends, abbreviated @code{e} +@end table -@option{%C} @code{cc} century 00–99 -@option{%D} yields @code{mm/dd/yy 02/10/10} -@option{%x} locale’s date representation @code{02/10/2010} for the U.S. -@option{%F} yields @code{%Y-%m-%d 2010-02-10} @node Ledger for Developers, Extending with Python, Format Strings, Top @@ -7547,7 +7590,7 @@ Those tiers are: strings, etc. If you try to apply an operation between two values that makes no sense (like dividing an amount by a balance), an error occurs at runtime, rather than at compile-time (as would happen if you actually tried - to divide an amount_t by a balance_t). + to divide an @code{amount_t} by a @code{balance_t}). This is the core data type for the value expression language. @@ -7566,9 +7609,9 @@ Those tiers are: @item Query expressions Expressions can be onerous to type at the command-line, so there's a - shorthand for reporting called "query expressions". These add no + shorthand for reporting called ``query expressions''. These add no functionality of there own, but are purely translated from the input string - (cash) down to the corresponding value expression (account =~ /cash/). + (cash) down to the corresponding value expression @code{(account =~ /cash/)}. This is a convenience layer. @item Format strings @@ -7576,7 +7619,7 @@ Those tiers are: Format strings let you interpolate value expressions into string, with the requirement that any interpolated value have a string representation. Really all this does is calculate the value expression in the current - report context, call the resulting value's "to_string()" method, and stuffs + report context, call the resulting value's @code{to_string()} method, and stuffs the result into the output string. It also provides printf-like behavior, such as min/max width, right/left justification, etc. @@ -7609,19 +7652,19 @@ Those tiers are: @item The Journal object Finally, all transactions with their postings, and all accounts, are owned - by a journal_t object. This is the go-to object for querying ad reporting + by a @code{journal_t} object. This is the go-to object for querying ad reporting on your data. @item Textual journal parser There is a textual parser, wholly contained in textual.cc, which knows how - to parse text into journal objects, which then get "finalized" and added to + to parse text into journal objects, which then get ``finalized'' and added to the journal. Finalization is the step that enforces the double-entry guarantee. @item Iterators - Every journal object is "iterable", and these iterators are defined in + Every journal object is ``iterable'', and these iterators are defined in iterators.h and iterators.cc. This iteration logic is kept out of the basic journal objects themselves for the sake of modularity. @@ -7629,12 +7672,12 @@ Those tiers are: Another abstraction isolated to its own layer, this class encapsulating the comparison of journal objects, based on whatever value expression the user - passed to --sort. + passed to @code{--sort}. @item Temporaries Many reports bring pseudo-journal objects into existence, like postings - which report totals in a "" account. These objects are created and + which report totals in a @code{} account. These objects are created and managed by a temporaries_t object, which gets used in many places by the reporting filters. @@ -7666,7 +7709,7 @@ Those tiers are: iterator depends on the type of report. This iterator is then walked, and every object yielded from the iterator is - passed to an "item handler", whose type is directly related to the type of + passed to an ``item handler'', whose type is directly related to the type of the iterator. There are many, many item handlers, which can be chained together. Each @@ -7675,22 +7718,22 @@ Those tiers are: filters which compute the running totals; that queue and sort all the input items before playing them back out in a new order; that filter out items which fail to match a predicate, etc. Almost every reporting feature in - Ledger is related to one or more filters. Looking at filters.h, I see over + Ledger is related to one or more filters. Looking at @code{filters.h}, I see over 25 of them defined currently. @item The filter chain How filters get wired up, and in what order, is a complex process based on all the various options specified by the user. This is the job of the - chain logic, found entirely in chain.cc. It took a really long time to get + chain logic, found entirely in @code{chain.cc}. It took a really long time to get this logic exactly write, which is why I haven't exposed this layer to the Python bridge yet. @item Output modules Although filters are great and all, in the end you want to see stuff. This - is the job of special "leaf" filters call output modules. They are - implemented just like a regular filter, but they don't have a "next" filter + is the job of special ``leaf'' filters call output modules. They are + implemented just like a regular filter, but they don't have a ``next'' filter to pass the time on down to. Instead, they are the end of the line and must do something with the item that results in the user seeing something on their screen or in a file. @@ -7714,7 +7757,7 @@ Those tiers are: This creates the global scope object, performs error reporting, and handles command-line options which must precede even the creation of the global - scope, such as --debug. + scope, such as @code{--debug}. @end itemize And that's Ledger in a nutshell. All the rest are details, such as which @@ -7755,7 +7798,7 @@ 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 +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: @@ -7779,7 +7822,7 @@ amount of the first posting is typically positive. Consider: @node Comments and meta-data, Specifying Amounts, Journal File Format, Journal File Format @subsection Comments and meta-data -Comments are generally started using a ';'. However, in order to +Comments are generally started using a @code{;}. However, in order to increase compatibility with other text manipulation programs and methods three additional comment characters are valid if used at the beginning of a line: @code{#}, @code{|}, and @code{*}. @@ -7822,13 +7865,13 @@ 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}. +case of @code{1000.00} above, the internal value is @code{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} +arises: How should they be displayed? A number like @code{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? +about when the number @code{1/1} is divided by three? How should one +print @code{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 @@ -7839,11 +7882,11 @@ 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 +@code{1/3} be printed as @code{0.33} or @code{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}. +is six. Thus, @code{1/3} is printed back as @code{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 @@ -7866,10 +7909,10 @@ characters are allowed in a commodity name, except for the following: @itemize @bullet @item Any kind of white-space @item Numerical digits -@item Punctuation: @samp{.,;:?!} -@item Mathematical and logical operators: @samp{-+*/^&|=} -@item Bracketing characters: @samp{<>[]()}@{@} -@item The at symbol: @samp{@@} +@item Punctuation: @code{.,;:?!} +@item Mathematical and logical operators: @code{-+*/^&|=} +@item Bracketing characters: @code{<>[]()}@{@} +@item The at symbol: @code{@@} @end itemize And yet, any of these may appear in a commodity name if it is @@ -7885,9 +7928,9 @@ 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}. +@code{$100}, they will print the same; likewise with @code{100 $} or +@code{$100.000}. You may even use decimal commas, such as +@code{$100,00}, or thousand-marks, as in @code{$10,000.00}. These display characteristics become associated with the commodity, with the result being that all amounts of the same commodity are reported @@ -7951,7 +7994,7 @@ postings are involved: Assets:Checking @end smallexample -Here the implied cost is @samp{$57.00}, which is entered into the null +Here the implied cost is @code{$57.00}, which is entered into the null posting automatically so that the transaction balances. @node Primary commodities, , Posting costs, Journal File Format @@ -7979,7 +8022,7 @@ on the placement of the commodity in the transaction: @end smallexample The only case where knowledge of primary versus secondary comes into -play is in reports that use the @option{-V} or @option{-B} options. +play is in reports that use the @code{-V} or @code{-B} options. With these, only primary commodities are shown. If a transaction uses only one commodity, this commodity is also @@ -8010,7 +8053,7 @@ interface functions. The Session is where objects live like the Commodity's that Amount's refer to. The make a Session useful, you must read a Journal into it, using the function -`@samp{read_journal}`. This reads Ledger data from the given file, populates a +`@code{read_journal}`. This reads Ledger data from the given file, populates a Journal object within the current Session, and returns a reference to that Journal object. -- cgit v1.2.3 From 12c7ac7a4b7ce02e85ca4e2a7f6b2980d6940778 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 19 Oct 2012 18:43:03 +0200 Subject: Added --quiet options to clean up the texi2pdt output --- tools/gendocs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gendocs.sh b/tools/gendocs.sh index 55933b13..9126a406 100755 --- a/tools/gendocs.sh +++ b/tools/gendocs.sh @@ -2,4 +2,4 @@ echo "===================================== Making Info..." makeinfo ledger3.texi echo "===================================== Making PDF..." -texi2pdf ledger3.texi +texi2pdf --quiet --batch ledger3.texi -- cgit v1.2.3 From 9a2f44049634e8fa62f832f15dab0cef2d0eb6a3 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Mon, 22 Oct 2012 10:11:56 +0200 Subject: provide immediate feedback in test runner --- test/LedgerHarness.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/LedgerHarness.py b/test/LedgerHarness.py index b8900971..39a31286 100755 --- a/test/LedgerHarness.py +++ b/test/LedgerHarness.py @@ -116,12 +116,14 @@ class LedgerHarness: def success(self): sys.stdout.write(".") + sys.stdout.flush() self.succeeded += 1 def failure(self, name=None): sys.stdout.write("E") if name: sys.stdout.write("[%s]" % name) + sys.stdout.flush() self.failed += 1 def exit(self): -- cgit v1.2.3 From e824070b4ac098010f993dbdbcdff9a4bf1a3ba6 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Tue, 23 Oct 2012 12:13:22 +0200 Subject: fix bucket directive (bug 765) This was caused by both 'A' and 'bucket' using default_account_directive. This function was still stripping the 'A' directive, so the first character of the account name used with 'bucket' was cut off. Maybe the code for the other directives should be changed accordingly for consistency (put line + 1 in call instead of function). --- src/textual.cc | 8 ++++---- test/regress/0161EB1E.test | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 test/regress/0161EB1E.test diff --git a/src/textual.cc b/src/textual.cc index 0ead9232..7f2f2a69 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -148,7 +148,7 @@ namespace { void account_value_directive(account_t * account, string expr_str); void account_default_directive(account_t * account); - void default_account_directive(char * line); + void default_account_directive(char * args); void alias_directive(char * line); void payee_directive(char * line); @@ -397,7 +397,7 @@ void instance_t::read_next_directive(bool& error_flag) #endif // TIMELOG_SUPPORT case 'A': // a default account for unbalanced posts - default_account_directive(line); + default_account_directive(line + 1); break; case 'C': // a set of conversions price_conversion_directive(line); @@ -490,9 +490,9 @@ void instance_t::default_commodity_directive(char * line) amt.commodity().add_flags(COMMODITY_KNOWN); } -void instance_t::default_account_directive(char * line) +void instance_t::default_account_directive(char * args) { - context.journal->bucket = top_account()->find_account(skip_ws(line + 1)); + context.journal->bucket = top_account()->find_account(skip_ws(name)); context.journal->bucket->add_flags(ACCOUNT_KNOWN); } diff --git a/test/regress/0161EB1E.test b/test/regress/0161EB1E.test new file mode 100644 index 00000000..93498ad5 --- /dev/null +++ b/test/regress/0161EB1E.test @@ -0,0 +1,15 @@ +bucket Assets:Checking +2011/04/25 Tom's Used Cars + Auto $ 5,500.00 + ; :nobudget: + +A Assets:Checking +2011/04/27 Book Store + Books $20.00 + +test reg +11-Apr-25 Tom's Used Cars Auto $ 5,500.00 $ 5,500.00 + Assets:Checking $ -5,500.00 0 +11-Apr-27 Book Store Books $ 20.00 $ 20.00 + Assets:Checking $ -20.00 0 +end test -- cgit v1.2.3 From 3dc538189e64c4bc0c3428e8784fdb1f593304df Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 23 Oct 2012 12:04:07 -0700 Subject: Formatting cleanup --- doc/ledger3.texi | 87 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 531a0870..e377f02d 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -1225,7 +1225,7 @@ For example, you do not need to tell Ledger about the accounts you use. Any time Ledger sees a posting involving an account it knows nothing about, it will create it@footnote{This also means if you misspell an account it will end up getting counted separately from what -you intended. The provided Emacs major mode provides for automatically +you intended. The provided EMACS major mode provides for automatically filling in account names.}. If you use a commodity that is new to Ledger, it will create that commodity, and determine its display characteristics (placement of the symbol before or after the amount, @@ -1242,7 +1242,7 @@ posting. * Journal Format:: * Converting from other formats:: * Archiving Previous Years :: -* Using Emacs:: +* Using EMACS:: @end menu @node Most Basic Entry, Starting up, Keeping a Journal, Keeping a Journal @@ -2250,7 +2250,7 @@ easily be parsed into Ledger format using one of those tools. Some of the more function. -@node Archiving Previous Years , Using Emacs, Converting from other formats, Keeping a Journal +@node Archiving Previous Years , Using EMACS, Converting from other formats, Keeping a Journal @section Archiving Previous Years @@ -2299,7 +2299,7 @@ they were before the data was split. How often should you split your ledger? You never need to, if you don't want to. Even eighty years of data will not slow down ledger -much---and that's just using present day hardware! Or, you can keep +much, and that's just using present day hardware! Or, you can keep the previous and current year in one file, and each year before that in its own file. It's really up to you, and how you want to organize your finances. For those who also keep an accurate paper trail, it @@ -2309,45 +2309,52 @@ any electronic statements received during the year. In the arena of organization, just keep in mind this maxim: Do whatever keeps you doing it. -@node Using Emacs, , Archiving Previous Years , Keeping a Journal -@section Using Emacs to Maintain Your Journal -@cindex Emacs +@node Using EMACS, , Archiving Previous Years , Keeping a Journal +@section Using EMACS to Maintain Your Journal +@cindex EMACS @menu -* running ledger-mode:: +* Running ledger-mode:: * Working with entries:: * Reconciling accounts:: * Generating Reports:: @end menu -@node running ledger-mode, Working with entries, Using Emacs, Using Emacs -@subsection Running ledger-mode +@node Running ledger-mode, Working with entries, Using EMACS, Using EMACS +@subsection Running ledger-mode in EMACS Journal files are simple free text files easily modified by any text -editor. A special mode for Emacs is included with the source +editor. A special mode for EMACS is included with the source distribution. -@cindex Emacs .emacs file -To use the Emacs mode, copy the several lisp files from the source lisp -directory your your @file{site-lisp} directory and add the following line -to your @file{.emacs} (or equivalent, @file{~/Aquamacs/Preferences.el} -for Aquamacs on Mac OS X) +@cindex EMACS .emacs file + +Add the following line to your @file{.emacs} (or equivalent, +@file{~/Aquamacs/Preferences.el} for Aquamacs on Mac OS X) +@smallexample +(load "ldg-new") +@end smallexample + +Copy the several lisp files from the source lisp directory your your +@file{site-lisp} directory, or add the ledger lisp source directory to +your EMACS load path by adding: @smallexample -(load "ledger") +(add-to-list 'load-path "~/ledger/lisp") @end smallexample +@noindent to your @file{.emacs} file. To trigger ledger mode when you visit a journal file, the first line of each of your journal files should be: @smallexample ; -*-ledger-*- @end smallexample -To enter ledger-mode on a new file, type M-x ledger-mode. +To enter ledger-mode on a new file, type @command{M-x ledger-mode}. -Once you have loaded a Journal file into Emacs, you have several +Once you have loaded a Journal file into EMACS, you have several commands available to make entering, clearing and reconciling transactions and producing reports: -@cindex Emacs commands +@cindex EMACS commands @table @code @item C-i or auto complete entry @@ -2387,7 +2394,7 @@ kill the ledger report buffer * Generating Reports:: @end menu -@node Working with entries, Reconciling accounts, running ledger-mode, Using Emacs +@node Working with entries, Reconciling accounts, Running ledger-mode, Using EMACS @subsection Working with entries @menu * Manual Entry Support:: @@ -2405,13 +2412,13 @@ kill the ledger report buffer In most financial programs, some sort of auto-completion is available to save typing and improve accuracy. Ledger doesn't leave you hanging, @code{ledger-mode} provides tab completion on all portions of an entry. -Type a portion of the payee and hit , and @code{ledger-mode} will +Type a portion of the payee and hit @code{}, and @code{ledger-mode} will suggest a completion. When filling in the account type the first few -letters followed by a and the account will be filled in. For +letters followed by a @code{} and the account will be filled in. For example typing @code{ExAuF} would yield @code{Expenses:Auto:Fuel} if you had previously used that account in this journal. If there are more than one account with similar starting, -hitting multiple times will iterate through them. This is a good +hitting @code{} multiple times will iterate through them. This is a good habit to get in to prevent misspellings of accounts. Remember Ledger does not validate the names of payees or account so a misspelled account will be interpreted as a new account by ledger. @@ -2419,10 +2426,10 @@ will be interpreted as a new account by ledger. @node Automagically Adding new entries, Clearing Transactions, Manual Entry Support, Working with entries @subsubsection Automagically Adding new entries -@cindex new transactions in Emacs -@cindex Emacs, adding new transactions +@cindex new transactions in EMACS +@cindex EMACS, adding new transactions @code{C-c C-a} will run the @code{ledger entry} command (@pxref{entry -and xact}) from within Emacs. When typed, the mini-buffer will appear +and xact}) from within EMACS. When typed, the mini-buffer will appear with the current year and month, waiting for you to enter the day and the payee. Ledger will generate a new entry based on the most recent entry for that payee, using the amount and accounts from that @@ -2439,7 +2446,7 @@ current year and month. If you complete the mini-buffer entry by typing @smallexample Entry: 2011/11/28 viva food 34 tip 7 @end smallexample -@noindent Emacs will add the following entry to your journal: +@noindent EMACS will add the following entry to your journal: @smallexample 2011/11/30 Viva Italiano Expenses:Food $34.00 @@ -2450,8 +2457,8 @@ Entry: 2011/11/28 viva food 34 tip 7 ordered by date, not necessarily at the bottom of the file. @node Clearing Transactions, , Automagically Adding new entries, Working with entries @subsubsection Clearing Transactions and Postings -@cindex clearing transactions in Emacs -@cindex Emacs, clear transaction +@cindex clearing transactions in EMACS +@cindex EMACS, clear transaction @code{C-c C-e} will place an asterisk after the date in the current transaction. The tells ledger the transaction has been cleared through your bank (or whatever else you want the concept to mean) @@ -2473,13 +2480,13 @@ If, for some reason you need to clear a specific posting in the transaction you can type @code{C-c C-c} and the posting at point will be toggled. -@node Reconciling accounts, Generating Reports, Working with entries, Using Emacs +@node Reconciling accounts, Generating Reports, Working with entries, Using EMACS @subsection Reconciling accounts In the reconcile buffer, use SPACE to toggle the cleared status of a transaction, C-x C-s to save changes (to the ledger file as well). -@node Generating Reports, , Reconciling accounts, Using Emacs +@node Generating Reports, , Reconciling accounts, Using EMACS @subsection Generating Reports The ledger reports command asks the user to select a report to run then @@ -4039,7 +4046,7 @@ file whose formatting has gotten out of hand. @menu * Comma Separated Variable files:: * The emacs command:: -* Emacs org mode:: +* EMACS org mode:: * The pricemap Command:: * The xml Command:: * prices and pricedb:: @@ -4153,11 +4160,11 @@ passed through @code{ledger print} a second time if you want to match on the new payee field. During the @code{ledger convert} run only the original payee name as specified in the csv data seems to be used. -@node The emacs command, Emacs org mode, Comma Separated Variable files, Reports in other Formats +@node The emacs command, EMACS org mode, Comma Separated Variable files, Reports in other Formats @subsection The @code{emacs} command The @command{emacs} command outputs results in a form that can be read -directly by Emacs Lisp. The format of the @code{sexp} is: +directly by EMACS Lisp. The format of the @code{sexp} is: @smallexample ((BEG-POS CLEARED DATE CODE PAYEE @@ -4165,10 +4172,10 @@ directly by Emacs Lisp. The format of the @code{sexp} is: ...) ; list of transactions @end smallexample -@node Emacs org mode, The pricemap Command, The emacs command, Reports in other Formats -@subsection Emacs @code{org} Mode +@node EMACS org mode, The pricemap Command, The emacs command, Reports in other Formats +@subsection EMACS @code{org} Mode The @code{org} command produces a journal file suitable for use in the -Emacs org mode. More details on using org mode can be found at +EMACS org mode. More details on using org mode can be found at @url{http://www.orgmode.org}. Org mode has a sub-system known as Babel which allows for literate @@ -4475,7 +4482,7 @@ file and manipulated using Babel. However, only simple Ledger features have been illustrated; please refer to the Ledger documentation for examples of more complex operations with a ledger. -@node The pricemap Command, The xml Command, Emacs org mode, Reports in other Formats +@node The pricemap Command, The xml Command, EMACS org mode, Reports in other Formats @subsection The @code{pricemap} Command If you have the @code{graphviz} graph visualization package installed, ledger @@ -5011,7 +5018,7 @@ commands. @item @code{csv} @tab Show transactions in csv format, for exporting to other programs @item @code{print} @tab Print transaction in a ledger readable format @item @code{xml} @tab Produce XML output of the register command -@item @code{emacs} @tab Produce Emacs lisp output +@item @code{emacs} @tab Produce EMACS lisp output @item @code{equity} @tab Print account balances as transactions @item @code{prices} @tab Print price history for matching commodities @item @code{pricedb} @tab Print price history for matching commodities in ledger readable format -- cgit v1.2.3 From 14dcb277778568b9c5b60612e4f696363db4de11 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 23 Oct 2012 13:07:39 -0700 Subject: Implemented Bug551 Automatic Transactions are cleared base on parent --- src/xact.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/xact.cc b/src/xact.cc index a54da81a..ec1d372c 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -780,6 +780,14 @@ void auto_xact_t::extend_xact(xact_base_t& xact, parse_context_t& context) // the automated xact's one. post_t * new_post = new post_t(account, amt); new_post->copy_details(*post); + + // A Cleared transaction implies all of its automatic posting are cleared + // CPR 2012/10/23 + if(xact.state() == item_t::CLEARED){ + DEBUG("xact.extend.cleared", "CLEARED"); + new_post->set_state(item_t::CLEARED); + } + new_post->add_flags(ITEM_GENERATED); new_post->account = journal->register_account(account->fullname(), new_post, -- cgit v1.2.3 From 41cc9a7f3cb9cd4b1857b0209c59ef66929edf03 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 23 Oct 2012 14:10:19 -0700 Subject: Added filebase and filepath values 'filename' returns the complete path/filename of the file containg the current xact. This is inconvenient for some displays. filebase returns only the base name. For completeness added filepath as well. --- src/item.cc | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/item.cc b/src/item.cc index 0630043b..24d03ba1 100644 --- a/src/item.cc +++ b/src/item.cc @@ -330,6 +330,21 @@ namespace { return NULL_VALUE; } + value_t get_filebase(item_t& item) { + if (item.pos) + return string_value(item.pos->pathname.filename().string()); + else + return NULL_VALUE; + } + + value_t get_filepath(item_t& item) { + if (item.pos) + return string_value(item.pos->pathname.parent_path().string()); + else + return NULL_VALUE; + } + + value_t get_beg_pos(item_t& item) { return item.pos ? long(item.pos->beg_pos) : 0L; } @@ -456,7 +471,12 @@ expr_t::ptr_op_t item_t::lookup(const symbol_t::kind_t kind, case 'f': if (name == "filename") return WRAP_FUNCTOR(get_wrapper<&get_pathname>); - break; + else if (name == "filebase") + return WRAP_FUNCTOR(get_wrapper<&get_filebase>); + else if (name == "filepath") + return WRAP_FUNCTOR(get_wrapper<&get_filepath>); + break; + break; case 'h': if (name == "has_tag") -- cgit v1.2.3 From 4b261f99bc56853b3468a8a1bb5b4af39ed67af5 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 25 Oct 2012 10:39:48 -0700 Subject: Fixes Bug 695, ledger ignores --init-file Handle --init-file as a special command option like the debug options. That wway we can have the argument captured before teh global scope is created. --- src/global.cc | 7 +++++++ src/global.h | 14 ++++++++++---- src/main.cc | 1 + 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/global.cc b/src/global.cc index a718d6cb..3e83ba04 100644 --- a/src/global.cc +++ b/src/global.cc @@ -44,6 +44,7 @@ namespace ledger { static bool args_only = false; +std::string _init_file; global_scope_t::global_scope_t(char ** envp) { @@ -126,6 +127,8 @@ void global_scope_t::read_init() } TRACE_FINISH(init, 1); + } else { + throw_(parse_error, _f("Could not find specified init file %1%") % init_file); } } } @@ -473,6 +476,10 @@ void handle_debug_options(int argc, char * argv[]) _log_level = LOG_INFO; #endif } + else if (i + 1 < argc && std::strcmp(argv[i], "--init-file") == 0) { + _init_file = argv[i + 1]; + i++; + } else if (i + 1 < argc && std::strcmp(argv[i], "--debug") == 0) { #if DEBUG_ON _log_level = LOG_DEBUG; diff --git a/src/global.h b/src/global.h index f797ba01..d37043fc 100644 --- a/src/global.h +++ b/src/global.h @@ -46,6 +46,8 @@ namespace ledger { class session_t; class report_t; +extern std::string _init_file; + class global_scope_t : public noncopyable, public scope_t { shared_ptr session_ptr; @@ -151,10 +153,14 @@ See LICENSE file included with the distribution for details and disclaimer."); OPTION__ (global_scope_t, init_file_, // -i CTOR(global_scope_t, init_file_) { - if (const char * home_var = std::getenv("HOME")) - on(none, (path(home_var) / ".ledgerrc").string()); - else - on(none, path("./.ledgerrc").string()); + if(!_init_file.empty()) + // _init_file is filled during handle_debug_options + on(none, _init_file); + else + if (const char * home_var = std::getenv("HOME")) + on(none, (path(home_var) / ".ledgerrc").string()); + else + on(none, path("./.ledgerrc").string()); }); OPTION(global_scope_t, options); diff --git a/src/main.cc b/src/main.cc index a1ac0339..124efb5e 100644 --- a/src/main.cc +++ b/src/main.cc @@ -59,6 +59,7 @@ int main(int argc, char * argv[], char * envp[]) // --debug CATEGORY ; turns on debug logging // --trace LEVEL ; turns on trace logging // --memory ; turns on memory usage tracing + // --init-file ; directs ledger to use a different init file handle_debug_options(argc, argv); #if VERIFY_ON IF_VERIFY() initialize_memory_tracing(); -- cgit v1.2.3 From b044a74bd34afdc27baf6241fe398690ff5e043a Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 25 Oct 2012 22:28:26 -0700 Subject: Bug 634 and 488, Corrected behavior of floor, and added ceiling This is only a partial fix for 634, since rounding is not fixed. --- src/amount.cc | 23 ++++++++++++++++++++--- src/amount.h | 9 +++++++++ src/balance.h | 11 +++++++++++ src/report.cc | 7 +++++++ src/report.h | 1 + src/value.cc | 23 +++++++++++++++++++++++ src/value.h | 7 +++++++ 7 files changed, 78 insertions(+), 3 deletions(-) diff --git a/src/amount.cc b/src/amount.cc index 6ecb3558..4e658212 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -670,10 +670,27 @@ void amount_t::in_place_floor() _dup(); - std::ostringstream out; - stream_out_mpq(out, MP(quantity), precision_t(0), -1, GMP_RNDZ); + mpz_t quot; + mpz_init(quot); + mpz_fdiv_q(quot, mpq_numref(MP(quantity)), mpq_denref(MP(quantity))); + mpq_clear(MP(quantity)); + mpq_init(MP(quantity)); + mpq_set_num(MP(quantity), quot); +} + +void amount_t::in_place_ceiling() +{ + if (! quantity) + throw_(amount_error, _("Cannot ceiling an uninitialized amount")); - mpq_set_str(MP(quantity), out.str().c_str(), 10); + _dup(); + + mpz_t quot; + mpz_init(quot); + mpz_cdiv_q(quot, mpq_numref(MP(quantity)), mpq_denref(MP(quantity))); + mpq_clear(MP(quantity)); + mpq_init(MP(quantity)); + mpq_set_num(MP(quantity), quot); } void amount_t::in_place_unround() diff --git a/src/amount.h b/src/amount.h index 49027bb7..1b7d2101 100644 --- a/src/amount.h +++ b/src/amount.h @@ -364,6 +364,15 @@ public: } void in_place_floor(); + /** Yields an amount which has lost all of its extra precision, beyond what + the display precision of the commodity would have printed. */ + amount_t ceilinged() const { + amount_t temp(*this); + temp.in_place_ceiling(); + return temp; + } + void in_place_ceiling(); + /** Yields an amount whose display precision is never truncated, even though its commodity normally displays only rounded values. */ amount_t unrounded() const { diff --git a/src/balance.h b/src/balance.h index 230a4e2c..9635742d 100644 --- a/src/balance.h +++ b/src/balance.h @@ -345,6 +345,17 @@ public: pair.second.in_place_floor(); } + balance_t ceilinged() const { + balance_t temp(*this); + temp.in_place_ceiling(); + return temp; + } + void in_place_ceiling() { + foreach (amounts_map::value_type& pair, amounts) + pair.second.in_place_ceiling(); + } + + balance_t unrounded() const { balance_t temp(*this); temp.in_place_unround(); diff --git a/src/report.cc b/src/report.cc index 662386a4..dc5a0704 100644 --- a/src/report.cc +++ b/src/report.cc @@ -681,6 +681,11 @@ value_t report_t::fn_floor(call_scope_t& args) return args[0].floored(); } +value_t report_t::fn_ceiling(call_scope_t& args) +{ + return args[0].ceilinged(); +} + value_t report_t::fn_round(call_scope_t& args) { return args[0].rounded(); @@ -1335,6 +1340,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, return WRAP_FUNCTOR(fn_cyan); else if (is_eq(p, "commodity")) return MAKE_FUNCTOR(report_t::fn_commodity); + else if (is_eq(p, "ceiling")) + return MAKE_FUNCTOR(report_t::fn_ceiling); break; case 'd': diff --git a/src/report.h b/src/report.h index 4a02843e..2eac61fe 100644 --- a/src/report.h +++ b/src/report.h @@ -174,6 +174,7 @@ public: value_t fn_unrounded(call_scope_t& scope); value_t fn_truncated(call_scope_t& scope); value_t fn_floor(call_scope_t& scope); + value_t fn_ceiling(call_scope_t& scope); value_t fn_round(call_scope_t& scope); value_t fn_unround(call_scope_t& scope); value_t fn_abs(call_scope_t& scope); diff --git a/src/value.cc b/src/value.cc index 1921d5a3..c57cff78 100644 --- a/src/value.cc +++ b/src/value.cc @@ -1658,6 +1658,29 @@ void value_t::in_place_floor() throw_(value_error, _f("Cannot floor %1%") % label()); } +void value_t::in_place_ceiling() +{ + switch (type()) { + case INTEGER: + return; + case AMOUNT: + as_amount_lval().in_place_ceiling(); + return; + case BALANCE: + as_balance_lval().in_place_ceiling(); + return; + case SEQUENCE: + foreach (value_t& value, as_sequence_lval()) + value.in_place_ceiling(); + return; + default: + break; + } + + add_error_context(_f("While ceiling %1%:") % *this); + throw_(value_error, _f("Cannot ceiling %1%") % label()); +} + void value_t::in_place_unround() { switch (type()) { diff --git a/src/value.h b/src/value.h index ee3d414d..249f3d7f 100644 --- a/src/value.h +++ b/src/value.h @@ -457,6 +457,13 @@ public: } void in_place_floor(); + value_t ceilinged() const { + value_t temp(*this); + temp.in_place_ceiling(); + return temp; + } + void in_place_ceiling(); + value_t unrounded() const { value_t temp(*this); temp.in_place_unround(); -- cgit v1.2.3 From e3cd1045d5bd055633f661a232f0784badbe2eb4 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 26 Oct 2012 09:59:20 -0700 Subject: Bugs 726 and 727. Remove reference to draft and lisp commands in man page --- doc/ledger.1 | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/doc/ledger.1 b/doc/ledger.1 index b96e4a7d..659d3fbb 100644 --- a/doc/ledger.1 +++ b/doc/ledger.1 @@ -92,29 +92,23 @@ Report of postings matching the .Ar report-query in CSV format (comma-separated values). Useful for exporting data to a spreadsheet for further analysis or charting. -.It Nm draft Oo Ar draft-template Oc +.It Nm entry Oo Ar entry-template Oc Generate and display a new, properly formatted Ledger transaction by comparing the -.Ar draft-template +.Ar entry-template to the transactions in your data file(s). For more information on draft templates and using this command to quickly create new transactions, see the section -.Sx DRAFTS . +.Sx ENTRIES . .Pp -The synonyms -.Nm entry -and +The synonym .Nm xact -are also accepted. +is also accepted. .It Nm emacs Oo Ar query Oc Outputs posting and transaction data in a format readily consumed by the Emacs editor, in a series of Lisp forms. This is used by the .Li ledger.el Emacs mode to process reporting data from Ledger. -.Pp -The synonym -.Nm lisp -is also accepted. .It Nm equity Oo Ar report-query Oc Prints a series of transactions that balance current totals for accounts matching the @@ -586,9 +580,9 @@ for example: .It Nm xact .El .Pp -.Sh DRAFTS +.Sh ENTRIES .Pp -.Sh FORMATS +.Sh FORMATS .Pp .Sh DEBUG COMMANDS In addition to the regular reporting commands, Ledger also accepts several -- cgit v1.2.3 From bd3c13e2a2962930a4d06f4832ec0b1e2b8a845a Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 26 Oct 2012 10:49:22 -0700 Subject: Documented removal of draft and lisp commands in the 2.6 changes chapter --- doc/ledger3.texi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index e377f02d..ecd4947f 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -8199,6 +8199,8 @@ need to create sums of multiple commodities, use a Balance. For example: @itemize @item OFX support has been removed from Ledger 3.0 @item single character value expressions are deprecated and should be changed to the new value expressions available in 3.0 +@item @code{draft} command is no longer supported, use @code{entry} or @code{exact} +@item @code{lisp} command is no longer supported, use @code{emacs}. @end itemize @node Example Data File, Miscellaneous Notes, Major Changes from version 2.6, Top -- cgit v1.2.3 From 10180f0fffd5dcb14df06617c17b1607a5818bfe Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 26 Oct 2012 13:33:27 -0700 Subject: Added "draft" and "lisp" command synonyms --- src/report.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/report.cc b/src/report.cc index dc5a0704..9e085a98 100644 --- a/src/report.cc +++ b/src/report.cc @@ -1592,7 +1592,10 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, return POSTS_REPORTER(new report_commodities(*this)); } break; - + case 'd': + if (is_eq(p, "draft")) { + return WRAP_FUNCTOR(xact_command); + } case 'e': if (is_eq(p, "equity")) { HANDLER(generated).on("#equity"); @@ -1614,7 +1617,10 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, return POSTS_REPORTER(new format_ptree(*this, format_ptree::FORMAT_JSON)); break; - + case 'l': + if (is_eq(p, "lisp")) + return POSTS_REPORTER(new format_emacs_posts(output_stream)); + break; case 'o': if (is_eq(p, "org")) return POSTS_REPORTER(new posts_to_org_table -- cgit v1.2.3 From 5c5c6463c74549cac0c5548ee9f5e314751f8e92 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 26 Oct 2012 15:46:10 -0700 Subject: Added missing break; statement in report.cc --- src/report.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/report.cc b/src/report.cc index 9e085a98..08365a6b 100644 --- a/src/report.cc +++ b/src/report.cc @@ -1596,6 +1596,7 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, if (is_eq(p, "draft")) { return WRAP_FUNCTOR(xact_command); } + break; case 'e': if (is_eq(p, "equity")) { HANDLER(generated).on("#equity"); -- cgit v1.2.3 From 0ff33003e8ea5e6278c5c7aec29e812d44485944 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 26 Oct 2012 20:13:20 -0700 Subject: Minor grammatical fixes --- doc/ledger3.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index ecd4947f..b60a0f5c 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -7800,7 +7800,7 @@ 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 +be the inverse of the first. This guarantees 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. -- cgit v1.2.3 From 3b9b2cf908c27dff7b85511e9283119485f9439e Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 31 Oct 2012 00:14:47 -0500 Subject: Corrected a typo --- src/textual.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/textual.cc b/src/textual.cc index 7f2f2a69..8a055251 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -490,9 +490,9 @@ void instance_t::default_commodity_directive(char * line) amt.commodity().add_flags(COMMODITY_KNOWN); } -void instance_t::default_account_directive(char * args) +void instance_t::default_account_directive(char * line) { - context.journal->bucket = top_account()->find_account(skip_ws(name)); + context.journal->bucket = top_account()->find_account(skip_ws(line)); context.journal->bucket->add_flags(ACCOUNT_KNOWN); } -- cgit v1.2.3 From c5a15a556a6cd34f7afabaffbe76c26d18a7d81f Mon Sep 17 00:00:00 2001 From: Karl Fogel Date: Wed, 31 Oct 2012 14:54:55 -0400 Subject: Add some material to README-1ST, along with a couple of formatting changes. Give an early pointer to where to look if 'acprep update' fails. Clarify a few things in the first section. Give sections clearer headers, so they can be more easily referred to. Add a FAQ entry about what to do if './acprep update' gives errors. Update FAQ entry about MPFR library to refer to above new entry. --- README-1ST | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/README-1ST b/README-1ST index 45e9800a..b92b2f6a 100644 --- a/README-1ST +++ b/README-1ST @@ -5,9 +5,12 @@ To build this code after doing a Git clone, run: $ ./acprep update -If you try to configure and build on your own, you are almost certainly going -to run into problems. In future, you can run this command again and again, -and it will keep you updated to the very latest version. +If anything goes wrong, see "COMMON CONFIGURE/BUILD PROBLEMS" below. + +If you try to configure and build without running acprep first, you are +almost certainly going to run into problems. In future, you can run +'acprep update' again and again, and it will keep you updated to the +very latest version. I further recommend building both debug and optimized versions of Ledger, in a subdirectory of your source tree named 'build' (which acprep will manage for @@ -21,8 +24,8 @@ Now install the optimized version, but know that you have 'build/debug/ledger' available for testing and more useful bug reports. =============================================================================== - - IF YOU HAVE CONFIGURE OR BUILD PROBLEMS +COMMON CONFIGURE/BUILD PROBLEMS: +=============================================================================== To build and install Ledger requires several dependencies on various platforms. You can install these dependencies very simply for most of them @@ -40,9 +43,10 @@ down easily: With the contents of config.log, and the output from acprep --debug update, it's usually fairly obvious where things have gone astray. +=============================================================================== +F.A.Q.: =============================================================================== - F.A.Q. - Q: The build fails saying it can't find utf8.h @@ -50,6 +54,29 @@ it's usually fairly obvious where things have gone astray. ---------------------------------------------------------------------- + - Q: './acprep update' gives errors + + A: You're probably missing some dependency libraries. Did you run + './acprep dependencies'? If you tried that too and it didn't + work, then you may need to install dependencies by hand. On a + Debian GNU/Linux system (or Debian-based system such as Ubuntu), + something this should work (as root): + + # aptitude update + # for name in \ + cmake libboost-dev libboost-date-time-dev libboost-doc \ + libboost-dbg libboost-filesystem-dev libboost-graph-dev \ + libboost-iostreams-dev libboost-program-options-dev \ + libboost-python-dev libboost-regex-dev \ + libboost-serialization-dev libboost-signals-dev \ + libboost-test-dev libboost-thread-dev libboost-wave-dev \ + libmpfr-dev libmpfr-dbg libmpfr-doc; \ + do \ + aptitude install ${name}; \ + done + + ---------------------------------------------------------------------- + - Q: Configure fails saying it can't find boost_regex A: Look in config.log and search for "boost_regex", then scroll down a bit @@ -68,7 +95,9 @@ it's usually fairly obvious where things have gone astray. - Q: Configure fails saying it can't find MPFR A: You need MPFR version 2.4.0 or higher. This version does not come with - most Debian distributions, so you will need to build it. + most Debian distributions, so you will need to build it. The + relevant packages are 'libmpfr-dev' and 'libmpfr-dbg'. See also + the question above about "'./acprep update' gives errors". ---------------------------------------------------------------------- -- cgit v1.2.3 From 4203cf4e9149bd49ce62d5bac0bdd0d7ef0b5fad Mon Sep 17 00:00:00 2001 From: Karl Fogel Date: Wed, 31 Oct 2012 15:07:59 -0400 Subject: Improve wording from commit c5a15a556a6cd34f7afabaffbe76c26d18a7d81f. --- README-1ST | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README-1ST b/README-1ST index b92b2f6a..337bf7f2 100644 --- a/README-1ST +++ b/README-1ST @@ -54,13 +54,13 @@ F.A.Q.: ---------------------------------------------------------------------- - - Q: './acprep update' gives errors + - Q: './acprep update' gives errors or './acprep dependencies' fails - A: You're probably missing some dependency libraries. Did you run - './acprep dependencies'? If you tried that too and it didn't - work, then you may need to install dependencies by hand. On a - Debian GNU/Linux system (or Debian-based system such as Ubuntu), - something this should work (as root): + A: You're probably missing some dependency libraries. If you tried + './acprep dependencies' already and that didn't solve the problem, + then you may need to install dependencies by hand. On a Debian + GNU/Linux system (or Debian-based system such as Ubuntu), something + like this should work (as root): # aptitude update # for name in \ @@ -97,7 +97,8 @@ F.A.Q.: A: You need MPFR version 2.4.0 or higher. This version does not come with most Debian distributions, so you will need to build it. The relevant packages are 'libmpfr-dev' and 'libmpfr-dbg'. See also - the question above about "'./acprep update' gives errors". + the question above about what to do if './acprep update' gives + errors or './acprep dependencies' fails. ---------------------------------------------------------------------- -- cgit v1.2.3 From f89c84e200e6d51c3b59b9658710fb8601f9e6f5 Mon Sep 17 00:00:00 2001 From: Karl Fogel Date: Wed, 31 Oct 2012 15:27:26 -0400 Subject: Fix path to debug build given in README-1ST. --- README-1ST | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-1ST b/README-1ST index 337bf7f2..84fc753f 100644 --- a/README-1ST +++ b/README-1ST @@ -20,7 +20,7 @@ you, you simply need to create it): $ ./acprep opt make $ ./acprep debug make -Now install the optimized version, but know that you have 'build/debug/ledger' +Now install the optimized version, but know that you have 'build/ledger/debug' available for testing and more useful bug reports. =============================================================================== -- cgit v1.2.3 From 1ad1f349619243f47e1fc76388e710726845851f Mon Sep 17 00:00:00 2001 From: Karl Fogel Date: Wed, 31 Oct 2012 15:32:15 -0400 Subject: Give explicit installation command in README-1ST. --- README-1ST | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README-1ST b/README-1ST index 84fc753f..56aa2314 100644 --- a/README-1ST +++ b/README-1ST @@ -20,8 +20,13 @@ you, you simply need to create it): $ ./acprep opt make $ ./acprep debug make -Now install the optimized version, but know that you have 'build/ledger/debug' -available for testing and more useful bug reports. +Now install the optimized version: + + $ cd build/ledger/opt + $ sudo make install + +but know that you have 'build/ledger/debug' available for testing and +for more useful bug reports. =============================================================================== COMMON CONFIGURE/BUILD PROBLEMS: -- cgit v1.2.3 From ae5325f0a9aea13025d3fa6e6229f0b27171bd8c Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 31 Oct 2012 14:57:02 -0500 Subject: Guard against global_scope being NULL --- src/main.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cc b/src/main.cc index 124efb5e..a44506c9 100644 --- a/src/main.cc +++ b/src/main.cc @@ -214,7 +214,8 @@ int main(int argc, char * argv[], char * envp[]) } else #endif { - global_scope->quick_close(); + if (global_scope) + global_scope->quick_close(); INFO("Ledger ended"); // let global_scope leak! } -- cgit v1.2.3 From 71ecd4ef792549af652431550e7b8b2f4fe93d50 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 1 Nov 2012 16:03:58 -0700 Subject: re-fixed draft and lisp command documentation --- doc/ledger3.texi | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index b60a0f5c..891cc1af 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -4045,14 +4045,14 @@ file whose formatting has gotten out of hand. @section Reports in other Formats @menu * Comma Separated Variable files:: -* The emacs command:: +* The lisp command:: * EMACS org mode:: * The pricemap Command:: * The xml Command:: * prices and pricedb:: @end menu -@node Comma Separated Variable files, The emacs command, Reports in other Formats, Reports in other Formats +@node Comma Separated Variable files, The lisp command, Reports in other Formats, Reports in other Formats @subsection Comma Separated Variable files @menu * The csv command:: @@ -4160,10 +4160,10 @@ passed through @code{ledger print} a second time if you want to match on the new payee field. During the @code{ledger convert} run only the original payee name as specified in the csv data seems to be used. -@node The emacs command, EMACS org mode, Comma Separated Variable files, Reports in other Formats -@subsection The @code{emacs} command +@node The lisp command, EMACS org mode, Comma Separated Variable files, Reports in other Formats +@subsection The @code{lisp} command -The @command{emacs} command outputs results in a form that can be read +The @command{lisp} command outputs results in a form that can be read directly by EMACS Lisp. The format of the @code{sexp} is: @smallexample @@ -4172,7 +4172,9 @@ directly by EMACS Lisp. The format of the @code{sexp} is: ...) ; list of transactions @end smallexample -@node EMACS org mode, The pricemap Command, The emacs command, Reports in other Formats +@noindent @code{emacs{ can also be used as asynonym for @code{lisp} + +@node EMACS org mode, The pricemap Command, The lisp command, Reports in other Formats @subsection EMACS @code{org} Mode The @code{org} command produces a journal file suitable for use in the EMACS org mode. More details on using org mode can be found at @@ -4682,11 +4684,11 @@ Report all commodities present in the journals under consideration. @node entry and xact, payees, commodities, Reports about your Journals -@subsection @command{entry} and @command{xact} +@subsection @command{draft}, @command{entry} and @command{xact} -The @code{entry} and @command{xact} commands simplify the creation of -new transactions. It works on the principle that 80% of all postings -are variants of earlier postings. Here's how it works: +The @code{draft}, @code{entry} and @command{xact} commands simplify the +creation of new transactions. It works on the principle that 80% of all +postings are variants of earlier postings. Here's how it works: Say you currently have this posting in your ledger file: @@ -8199,8 +8201,6 @@ need to create sums of multiple commodities, use a Balance. For example: @itemize @item OFX support has been removed from Ledger 3.0 @item single character value expressions are deprecated and should be changed to the new value expressions available in 3.0 -@item @code{draft} command is no longer supported, use @code{entry} or @code{exact} -@item @code{lisp} command is no longer supported, use @code{emacs}. @end itemize @node Example Data File, Miscellaneous Notes, Major Changes from version 2.6, Top -- cgit v1.2.3 From ab887ad7d7e9ebaa1f874862b1649329a7019cd1 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 2 Nov 2012 14:09:27 -0500 Subject: README-1ST changes --- README-1ST | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/README-1ST b/README-1ST index 56aa2314..87e41257 100644 --- a/README-1ST +++ b/README-1ST @@ -29,7 +29,7 @@ but know that you have 'build/ledger/debug' available for testing and for more useful bug reports. =============================================================================== -COMMON CONFIGURE/BUILD PROBLEMS: + COMMON CONFIGURE/BUILD PROBLEMS =============================================================================== To build and install Ledger requires several dependencies on various @@ -49,7 +49,7 @@ With the contents of config.log, and the output from acprep --debug update, it's usually fairly obvious where things have gone astray. =============================================================================== -F.A.Q.: + F.A.Q. =============================================================================== @@ -152,16 +152,15 @@ F.A.Q.: ---------------------------------------------------------------------- - - Q: My distribution has a versions of Boost and/or CMake that are too - old for Ledger. How do I build my own Boost and/or CMake binaries - that will work properly with Ledger? Thereafter, how do I configure - Ledger properly to use those newly built verisons of Boost and/or - CMake? + - Q: My distribution has versions of Boost and/or CMake that are too old for + Ledger. How do I build my own Boost and/or CMake binaries that will + work properly with Ledger? Thereafter, how do I configure Ledger + properly to use those newly built verisons of Boost and/or CMake? - A: Here's commands that one user used to make this work, for Boost - 1.51.0 on Debian GNU/Linux 6.0.x (aka Debian squeeze). It's likely - to work ok for other versions of Boost as well. YMMV on other - distributions and/or other Debian distribution versions, though. + A: Here's commands that one user used to make this work, for Boost 1.51.0 + on Debian GNU/Linux 6.0.x (aka Debian squeeze). It's likely to work ok + for other versions of Boost as well. YMMV on other distributions and/or + other Debian distribution versions, though. # Preparing and building Boost 1.51.0 -- cgit v1.2.3 From 8214a69e20aa6d5ef2dbb86ca670a02b013db0f1 Mon Sep 17 00:00:00 2001 From: Christophe Rhodes Date: Tue, 6 Nov 2012 11:56:43 +0000 Subject: fix comment in display_filter_posts::output_rounding(post_t) slightly more detail in the case of zero display_amount and --empty not specified. --- src/filters.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/filters.cc b/src/filters.cc index f5694133..5e2bf983 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -530,9 +530,11 @@ bool display_filter_posts::output_rounding(post_t& post) } // Allow the posting to be displayed if: - // 1. It's display_amount would display as non-zero - // 2. The --empty option was specified - // 3. The account of the posting is + // 1. Its display_amount would display as non-zero, or + // 2. The --empty option was specified, or + // 3. a) The account of the posting is , and + // b) the revalued option is specified, and + // c) the --no-rounding option is not specified. if (post.account == revalued_account) { if (show_rounding) -- cgit v1.2.3 From a6d40ada1f33ebce5ed55ddd2d54a187a1f70c59 Mon Sep 17 00:00:00 2001 From: Christophe Rhodes Date: Tue, 6 Nov 2012 12:01:16 +0000 Subject: right-justify amount_expr text in print report where possible --- src/print.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/print.cc b/src/print.cc index 79d83161..a4a0bc6f 100644 --- a/src/print.cc +++ b/src/print.cc @@ -203,9 +203,15 @@ namespace { (static_cast(account_width) - static_cast(name.length())); + std::size_t amount_width = + (report.HANDLED(amount_width_) ? + lexical_cast(report.HANDLER(amount_width_).str()) : + 12); string amt; if (post->amount_expr) { - amt = post->amount_expr->text(); + std::ostringstream amt_str; + justify(amt_str, post->amount_expr->text(), amount_width, true); + amt = amt_str.str(); } else if (count == 2 && index == 2 && post_has_simple_amount(*post) && @@ -218,11 +224,6 @@ namespace { // first. } else { - std::size_t amount_width = - (report.HANDLED(amount_width_) ? - lexical_cast(report.HANDLER(amount_width_).str()) : - 12); - std::ostringstream amt_str; value_t(post->amount).print(amt_str, static_cast(amount_width), -1, AMOUNT_PRINT_RIGHT_JUSTIFY | -- cgit v1.2.3 From dc24ea721758b4a0121c78c4737492041a8dd093 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 6 Nov 2012 14:03:49 -0700 Subject: Fixe } bug --- doc/ledger3.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 891cc1af..52f6b79f 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -2177,7 +2177,7 @@ assertions are not called if no value is given. @item test @c instance_t::comment_directive in textual.cc -This is a synonym for @code{comment} and must be closed by and @code{end} tag. +This is a synonym for @code{comment} and must be closed by an @code{end} tag. @item year @c instance_t::year_directive in textual.cc @@ -4172,7 +4172,7 @@ directly by EMACS Lisp. The format of the @code{sexp} is: ...) ; list of transactions @end smallexample -@noindent @code{emacs{ can also be used as asynonym for @code{lisp} +@noindent @code{emacs} can also be used as asynonym for @code{lisp} @node EMACS org mode, The pricemap Command, The lisp command, Reports in other Formats @subsection EMACS @code{org} Mode -- cgit v1.2.3 From 49983e2870b6f39a6de1bbb1b8914035a79ac737 Mon Sep 17 00:00:00 2001 From: Alexis Hildebrandt Date: Sat, 10 Nov 2012 11:57:34 +0100 Subject: Correct typos --- doc/ledger3.texi | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 52f6b79f..f99504f0 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -4119,7 +4119,7 @@ interpret the dates. Importing csv files is a lot of work, and but is very amenable to scripting. If there are columns in the bank data you would like to keep in your -ledger data, besides the primary fileds described above, you can name +ledger data, besides the primary fields described above, you can name them in the field descriptor list and Ledger will include them in the transaction as meta data if it doesn't recognize the field name. For example, if you want to capture the bank transaction number and it @@ -4131,7 +4131,7 @@ transid,date,payee,note,amount,,,code, @end smallexample Ledger will include @code{; transid: 767718} in the first transaction is -fromthe file above. +from the file above. The @code{convert} command accepts three options, the most important ones are @code{--invert} which inverts the amount field, and @@ -4172,7 +4172,7 @@ directly by EMACS Lisp. The format of the @code{sexp} is: ...) ; list of transactions @end smallexample -@noindent @code{emacs} can also be used as asynonym for @code{lisp} +@noindent @code{emacs} can also be used as a synonym for @code{lisp} @node EMACS org mode, The pricemap Command, The lisp command, Reports in other Formats @subsection EMACS @code{org} Mode @@ -5595,12 +5595,12 @@ ASK JOHN commodity. The latest available price is used. @item --flat - force the full names of accounts to be used inthe + force the full names of accounts to be used in the balance report. The balance report will not use an indented tree. @item --force-color output tty color codes even if the tty doesn't -support them. Ueful for TTY that don't advertise their capabilities +support them. Useful for TTY that don't advertise their capabilities correctly. @item --force-pager @@ -5707,7 +5707,7 @@ Specify the width of the Meta column used for the @code{--meta} options. @item --monthly -synonymn for @code{--period "monthly"} +synonym for @code{--period "monthly"} @item --no-color @@ -5735,7 +5735,7 @@ This is a postings predicate that applies after certain transforms have been executed, such as periodic gathering. @item --output -Redriect the output of ledger to the file defined in @file{PATH}. +Redirect the output of ledger to the file defined in @file{PATH}. @item --pager @@ -5756,8 +5756,8 @@ Set the number of columns dedicated to the payee in the register report. Use only postings that are marked pending @item --percent -Calculate the percentage value of each account in a blance reports. -Only works for account that have a single commoditiy. +Calculate the percentage value of each account in a balance reports. +Only works for account that have a single commodity. @item --period @@ -5875,14 +5875,14 @@ FIX THIS ENTRY @item --tail -report only the last @code{INT} entries. Only useful ona register report. +report only the last @code{INT} entries. Only useful on a register report. @item --total-data FIX THIS ENTRY @item --total -Define a vlaue expression used to calulate the total in reports. +Define a value expression used to calculate the total in reports. @item --total-width Set the width of the total field in the register report. @@ -5919,14 +5919,14 @@ Perform all calculations without rounding and display results to full precision. @item --weekly -synonymn for @code{--period "weekly"} +synonym for @code{--period "weekly"} @item --wide lets the register report use 132 columns. Identical to @code{--columns "132"} @item --yearly -synonymn for @code{--period "yearly"} +synonym for @code{--period "yearly"} @end table @@ -6375,13 +6375,13 @@ Sets the format for total plots, using the @code{-J} option. The default is: "%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_total)))\n" @end smallexample @item --pricedb-format STR -Sets the format expected for the histroical price file. The default is +Sets the format expected for the historical price file. The default is @smallexample "P %(datetime) %(display_account) %(scrub(display_amount))\n" @end smallexample @item --prices-format STR -Sets the format for the @command{prices} report. The deault is: +Sets the format for the @command{prices} report. The default is: @smallexample "%(date) %-8(display_account) %(justify(scrub(display_amount), 12, 2 + 9 + 8 + 12, true, color))\n" @@ -7231,7 +7231,7 @@ Inserts the ending line of that transaction within the file. @c @code{%D} gives the user more control over the way dates are output. @item d -Returns the data accoridng to the default format. If the transaction +Returns the data according to the default format. If the transaction has an effective date, it prints @code{[ACTUAL_DATE=EFFECTIVE_DATE]}. @item X @@ -7284,7 +7284,7 @@ same format string is used for all postings. @section --balance-format As an example of how flexible the @code{--format} strings can be, the default -balance format looks like this (the various functions are descirbed later): +balance format looks like this (the various functions are described later): @smallexample "%(justify(scrub(display_total), 20, -1, true, color))" -- cgit v1.2.3 From 36f87f49d86e931bb99a226cd47721219ccd6301 Mon Sep 17 00:00:00 2001 From: Alexis Hildebrandt Date: Mon, 6 Sep 2010 15:01:09 +0200 Subject: Add --time-colon option The --time-colon option will display the value for a seconds based commodity as real hours and minutes. For example 8100 seconds by default will be displayed as 2.25 whereas with the --time-colon option they will be displayed as 2:15. --- src/amount.cc | 23 +++++++++++++++++++++-- src/commodity.cc | 1 + src/commodity.h | 2 ++ src/session.cc | 4 +++- src/session.h | 5 +++++ 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/amount.cc b/src/amount.cc index 4e658212..671215c2 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -195,7 +195,10 @@ namespace { for (const char * p = buf; *p; p++) { if (*p == '.') { - if (commodity_t::decimal_comma_by_default || + if (commodity_t::time_colon_by_default || + (comm && comm->has_flags(COMMODITY_STYLE_TIME_COLON))) + out << ':'; + else if (commodity_t::decimal_comma_by_default || (comm && comm->has_flags(COMMODITY_STYLE_DECIMAL_COMMA))) out << ','; else @@ -209,7 +212,10 @@ namespace { out << *p; if (integer_digits > 3 && --integer_digits % 3 == 0) { - if (commodity_t::decimal_comma_by_default || + if (commodity_t::time_colon_by_default || + (comm && comm->has_flags(COMMODITY_STYLE_TIME_COLON))) + out << ':'; + else if (commodity_t::decimal_comma_by_default || (comm && comm->has_flags(COMMODITY_STYLE_DECIMAL_COMMA))) out << '.'; else @@ -737,6 +743,16 @@ void amount_t::in_place_unreduce() } if (shifted) { + if ("h" == comm->symbol() && commodity_t::time_colon_by_default) { + amount_t floored = tmp.floored(); + amount_t precision = tmp - floored; + if (precision < 0.0) { + precision += 1.0; + floored -= 1.0; + } + tmp = floored + (precision * (comm->smaller()->number() / 100.0)); + } + *this = tmp; commodity_ = comm; } @@ -1090,6 +1106,9 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags) bool decimal_comma_style = (commodity_t::decimal_comma_by_default || commodity().has_flags(COMMODITY_STYLE_DECIMAL_COMMA)); + bool time_colon_style + = (commodity_t::time_colon_by_default || + commodity().has_flags(COMMODITY_STYLE_TIME_COLON)); new_quantity->prec = 0; diff --git a/src/commodity.cc b/src/commodity.cc index 05d465ca..ffeac10d 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -40,6 +40,7 @@ namespace ledger { bool commodity_t::decimal_comma_by_default = false; +bool commodity_t::time_colon_by_default = false; void commodity_t::add_price(const datetime_t& date, const amount_t& price, const bool reflexive) diff --git a/src/commodity.h b/src/commodity.h index ab496850..1d69b689 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -107,6 +107,7 @@ protected: #define COMMODITY_SAW_ANNOTATED 0x200 #define COMMODITY_SAW_ANN_PRICE_FLOAT 0x400 #define COMMODITY_SAW_ANN_PRICE_FIXATED 0x800 +#define COMMODITY_STYLE_TIME_COLON 0x1000 string symbol; optional graph_index; @@ -176,6 +177,7 @@ protected: public: static bool decimal_comma_by_default; + static bool time_colon_by_default; virtual ~commodity_t() { TRACE_DTOR(commodity_t); diff --git a/src/session.cc b/src/session.cc index b6153203..7072fb09 100644 --- a/src/session.cc +++ b/src/session.cc @@ -348,9 +348,11 @@ option_t * session_t::lookup_option(const char * p) case 's': OPT(strict); break; + case 't': + OPT(time_colon); + break; case 'v': OPT(value_expr_); - break; } return NULL; } diff --git a/src/session.h b/src/session.h index a0aba91b..74aeab5f 100644 --- a/src/session.h +++ b/src/session.h @@ -100,6 +100,7 @@ public: HANDLER(day_break).report(out); HANDLER(download).report(out); HANDLER(decimal_comma).report(out); + HANDLER(time_colon).report(out); HANDLER(file_).report(out); HANDLER(input_date_format_).report(out); HANDLER(explicit).report(out); @@ -130,6 +131,10 @@ public: commodity_t::decimal_comma_by_default = true; }); + OPTION_(session_t, time_colon, DO() { + commodity_t::time_colon_by_default = true; + }); + OPTION__ (session_t, price_exp_, // -Z CTOR(session_t, price_exp_) { value = "24"; }); -- cgit v1.2.3 From 29359f3a878c6017bb00f2aa8fcac91a2af5ddc5 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 12 Nov 2012 01:37:14 -0600 Subject: Account names in auto-xacts can be format strings --- src/xact.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/xact.cc b/src/xact.cc index ec1d372c..cac19a02 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -36,6 +36,7 @@ #include "account.h" #include "journal.h" #include "context.h" +#include "format.h" #include "pool.h" namespace ledger { @@ -775,6 +776,14 @@ void auto_xact_t::extend_xact(xact_base_t& xact, parse_context_t& context) account = account->parent; account = account->find_account(fullname); } + else if (contains(fullname, "%")) { + format_t account_name(fullname); + std::ostringstream buf; + buf << account_name(bound_scope); + while (account->parent) + account = account->parent; + account = account->find_account(buf.str()); + } // Copy over details so that the resulting post is a mirror of // the automated xact's one. -- cgit v1.2.3 From 484e54c2b38e373adfa2c7956f804ca1f7414a0e Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 12 Nov 2012 01:37:22 -0600 Subject: Fixed a regression test --- test/regress/25A099C9.test | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/regress/25A099C9.test b/test/regress/25A099C9.test index d4eab662..fb362a4b 100644 --- a/test/regress/25A099C9.test +++ b/test/regress/25A099C9.test @@ -20,24 +20,24 @@ While parsing file "$sourcepath/src/amount.h", line 121: Error: Unexpected whitespace at beginning of line While parsing file "$sourcepath/src/amount.h", line 132: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 702: +While parsing file "$sourcepath/src/amount.h", line 711: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 732: +While parsing file "$sourcepath/src/amount.h", line 741: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 740: +While parsing file "$sourcepath/src/amount.h", line 749: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 743: +While parsing file "$sourcepath/src/amount.h", line 752: Error: Invalid date/time: line amount_t amoun -While parsing file "$sourcepath/src/amount.h", line 749: +While parsing file "$sourcepath/src/amount.h", line 758: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 755: +While parsing file "$sourcepath/src/amount.h", line 764: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 761: +While parsing file "$sourcepath/src/amount.h", line 770: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 767: +While parsing file "$sourcepath/src/amount.h", line 776: Error: Invalid date/time: line std::ostream& -While parsing file "$sourcepath/src/amount.h", line 774: +While parsing file "$sourcepath/src/amount.h", line 783: Error: Invalid date/time: line std::istream& -While parsing file "$sourcepath/src/amount.h", line 780: +While parsing file "$sourcepath/src/amount.h", line 789: Error: Unexpected whitespace at beginning of line end test -- cgit v1.2.3 From 63712728e1e39557aa8ec35e1a4cf4e56c83e121 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 12 Nov 2012 02:29:10 -0600 Subject: Properly handle metadata tags on auto-postings --- src/textual.cc | 2 +- src/xact.cc | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/textual.cc b/src/textual.cc index 8a055251..6106914f 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -575,7 +575,7 @@ void instance_t::automated_xact_directive(char * line) item = ae.get(); // This is a trailing note, and possibly a metadata info tag - item->append_note(p + 1, *context.scope, true); + ae->append_note(p + 1, *context.scope, true); item->add_flags(ITEM_NOTE_ON_NEXT_LINE); item->pos->end_pos = context.curr_pos; item->pos->end_line++; diff --git a/src/xact.cc b/src/xact.cc index cac19a02..7888dadf 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -645,6 +645,18 @@ namespace { } } +static string apply_format(const string& str, scope_t& scope) +{ + if (contains(str, "%(")) { + format_t str_format(str); + std::ostringstream buf; + buf << str_format(scope); + return buf.str(); + } else { + return str; + } +} + void auto_xact_t::extend_xact(xact_base_t& xact, parse_context_t& context) { posts_list initial_posts(xact.posts.begin(), xact.posts.end()); @@ -696,8 +708,9 @@ void auto_xact_t::extend_xact(xact_base_t& xact, parse_context_t& context) if (deferred_notes) { foreach (deferred_tag_data_t& data, *deferred_notes) { if (data.apply_to_post == NULL) - initial_post->parse_tags(data.tag_data.c_str(), bound_scope, - data.overwrite_existing); + initial_post->append_note( + apply_format(data.tag_data, bound_scope).c_str(), + bound_scope, data.overwrite_existing); } } @@ -776,7 +789,7 @@ void auto_xact_t::extend_xact(xact_base_t& xact, parse_context_t& context) account = account->parent; account = account->find_account(fullname); } - else if (contains(fullname, "%")) { + else if (contains(fullname, "%(")) { format_t account_name(fullname); std::ostringstream buf; buf << account_name(bound_scope); @@ -804,9 +817,11 @@ void auto_xact_t::extend_xact(xact_base_t& xact, parse_context_t& context) if (deferred_notes) { foreach (deferred_tag_data_t& data, *deferred_notes) { - if (! data.apply_to_post || data.apply_to_post == post) - new_post->parse_tags(data.tag_data.c_str(), bound_scope, - data.overwrite_existing); + if (! data.apply_to_post || data.apply_to_post == post) { + new_post->append_note( + apply_format(data.tag_data, bound_scope).c_str(), + bound_scope, data.overwrite_existing); + } } } -- cgit v1.2.3 From 6a5d6a88cd626ee563b344657faec2ceb62b7f59 Mon Sep 17 00:00:00 2001 From: Alexis Hildebrandt Date: Mon, 19 Nov 2012 23:00:58 +0100 Subject: Fix crash when accessing the transaction code via post.xact.code using python ledger would abort with the following error message: TypeError: No Python class registered for C++ class boost::optional The changes pass a CallPolicy to make_getter when adding the transaction code property for python, so that the correct to_python conversion is made. For details see: http://www.boost.org/doc/libs/1_52_0/libs/python/doc/v2/faq.html#topythonconversionfailed --- src/py_xact.cc | 6 ++++-- test/regress/xact_code.dat | 3 +++ test/regress/xact_code.py | 4 ++++ test/regress/xact_code_py.test | 3 +++ 4 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 test/regress/xact_code.dat create mode 100644 test/regress/xact_code.py create mode 100644 test/regress/xact_code_py.test diff --git a/src/py_xact.cc b/src/py_xact.cc index 3d792c7b..96674207 100644 --- a/src/py_xact.cc +++ b/src/py_xact.cc @@ -119,8 +119,8 @@ void export_xact() .def("__str__", py_xact_to_string) .add_property("code", - make_getter(&xact_t::code), - make_setter(&xact_t::code)) + make_getter(&xact_t::code, return_value_policy()), + make_setter(&xact_t::code, return_value_policy())) .add_property("payee", make_getter(&xact_t::payee), make_setter(&xact_t::payee)) @@ -157,6 +157,8 @@ void export_xact() make_getter(&period_xact_t::period_string), make_setter(&period_xact_t::period_string)) ; + + register_optional_to_python(); } } // namespace ledger diff --git a/test/regress/xact_code.dat b/test/regress/xact_code.dat new file mode 100644 index 00000000..60956a23 --- /dev/null +++ b/test/regress/xact_code.dat @@ -0,0 +1,3 @@ +2012-11-10 (C0-d3) Payee + Assets:Checking € -12,45 + Expenses:Expenditure diff --git a/test/regress/xact_code.py b/test/regress/xact_code.py new file mode 100644 index 00000000..64abb17d --- /dev/null +++ b/test/regress/xact_code.py @@ -0,0 +1,4 @@ +import ledger + +for post in ledger.read_journal('test/regress/xact_code.dat').query('expenses'): + print post.xact.code diff --git a/test/regress/xact_code_py.test b/test/regress/xact_code_py.test new file mode 100644 index 00000000..c22158e0 --- /dev/null +++ b/test/regress/xact_code_py.test @@ -0,0 +1,3 @@ +test python test/regress/xact_code.py +C0-d3 +end test -- cgit v1.2.3 From 2ac996d9165f87754077a937eb69d765e139c05b Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 23 Nov 2012 16:54:03 -0600 Subject: Shorten debug comment --- src/post.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/post.h b/src/post.h index a9a44a79..c9aec6b2 100644 --- a/src/post.h +++ b/src/post.h @@ -83,7 +83,7 @@ public: const optional& _note = none) : item_t(_flags, _note), xact(NULL), account(_account), amount(_amount) { - TRACE_CTOR(post_t, "account_t *, const amount_t&, flags_t, const optional&"); + TRACE_CTOR(post_t, "account_t *, amount_t, flags_t, optional"); } post_t(const post_t& post) : item_t(post), -- cgit v1.2.3 From 62bd8d635457a2762cf432187a58c3e3a2c817c4 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 26 Nov 2012 12:54:23 -0600 Subject: Update utfcpp submodule reference to ledger/utfcpp --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 26e5425c..ff480831 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "lib/utfcpp"] path = lib/utfcpp - url = http://github.com/jwiegley/utfcpp.git + url = http://github.com/ledger/utfcpp.git -- cgit v1.2.3 From 287a756ab6c7072349dee8818e9775d67c8847be Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Wed, 21 Nov 2012 13:08:26 -0500 Subject: New test data for increasing the set of possible tags. I use more tags than just Invoice and Receipt, so I'd like this to support more than just two. Here's some test data showing other tags that I use. --- .../tests/Financial/BankStuff/bank-statement.pdf | Bin 0 -> 3257 bytes .../tests/Projects/Foo/earmark-record.txt | 1 + .../tests/non-profit-test-data.ledger | 4 +++- 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 contrib/non-profit-audit-reports/tests/Financial/BankStuff/bank-statement.pdf create mode 100644 contrib/non-profit-audit-reports/tests/Projects/Foo/earmark-record.txt diff --git a/contrib/non-profit-audit-reports/tests/Financial/BankStuff/bank-statement.pdf b/contrib/non-profit-audit-reports/tests/Financial/BankStuff/bank-statement.pdf new file mode 100644 index 00000000..27b40353 Binary files /dev/null and b/contrib/non-profit-audit-reports/tests/Financial/BankStuff/bank-statement.pdf differ diff --git a/contrib/non-profit-audit-reports/tests/Projects/Foo/earmark-record.txt b/contrib/non-profit-audit-reports/tests/Projects/Foo/earmark-record.txt new file mode 100644 index 00000000..c5ac98ac --- /dev/null +++ b/contrib/non-profit-audit-reports/tests/Projects/Foo/earmark-record.txt @@ -0,0 +1 @@ +I, Another J. Donor, would like $400 to be earmarked for Foo! diff --git a/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger b/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger index 69aeb571..fb6134ff 100644 --- a/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger +++ b/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger @@ -5,8 +5,9 @@ Assets:Checking $100.00 -2011/03/15 A Later Donation to Project Foo +2011/03/15 Another J. Donor Income:Foo:Donation $-400.00 + ;Approval: Projects/Foo/earmark-record.txt Assets:Checking $400.00 2011/04/20 (1) Baz Hosting Services, LLC @@ -24,3 +25,4 @@ ;Receipt: Projects/Blah/Expenses/hosting/AprilHostingReceipt.pdf ;Invoice: Projects/Blah/Expenses/hosting/april-invoice.pdf Assets:Checking $-250.00 + ;Statement: Financial/BankStuff/bank-statement.pdf -- cgit v1.2.3 From 01dc0416b9262905e66887b29ccef31d2867b9df Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Wed, 21 Nov 2012 13:09:55 -0500 Subject: Support a broader set of possible tags to be placed into the spreadsheet. I've now made a hard-coded list of potential tags that are supported and will be linked to in the general ledger spreadsheet. This list should probably be in a configuration file of some sort eventually, rather than hard coded. Indeed, note that the hard-coding goes into two different scripts, and thus the lists could easily get out of sync. --- contrib/non-profit-audit-reports/csv2ods.py | 5 ++++- contrib/non-profit-audit-reports/general-ledger-report.plx | 12 ++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/contrib/non-profit-audit-reports/csv2ods.py b/contrib/non-profit-audit-reports/csv2ods.py index f6150158..59571280 100755 --- a/contrib/non-profit-audit-reports/csv2ods.py +++ b/contrib/non-profit-audit-reports/csv2ods.py @@ -24,6 +24,9 @@ import sys, os, os.path, optparse import csv import ooolib2 +file_fields = [ 'Receipt', 'Invoice', 'Statement', 'Contract', 'PurchaseOrder', + 'Approval', 'Check', 'IncomeDistributionAnalysis', 'CurrencyRate' ] + def err(msg): print 'error: %s' % msg sys.exit(1) @@ -56,7 +59,7 @@ def csv2ods(csvname, odsname, verbose = False): if len(val) > 0 and val[0] == '$': doc.set_cell_value(col + 1, row, 'currency', val[1:]) else: - if ( (col == 5) and (val != 'Receipt') and len(val) > 0) or ( (col == 6) and (val != 'Invoice') and len(val) > 0): + if ((col >= 5) and (not val in file_fields) and len(val) > 0): linkrel = '../' + val # ../ means remove the name of the *.ods linkname = os.path.basename(val) # name is just the last component doc.set_cell_value(col + 1, row, 'link', (linkrel, linkname)) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 5286d625..1c293db9 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -107,8 +107,16 @@ foreach my $acct (@sortedAccounts) { close(GL_TEXT_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; print GL_CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; - print GL_CSV_OUT '"DATE","CHECK NUM","NAME","TRANSACTION AMT","RUNNING TOTAL","Receipt","Invoice"', "\n"; - @acctLedgerOpts = ('-F', '"%(date)","%C","%P","%t","%T","%(tag(\'Receipt\'))","%(tag(\'Invoice\'))"\n', '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); + print GL_CSV_OUT '"DATE","CHECK NUM","NAME","TRANSACTION AMT","RUNNING TOTAL"'; + my $formatString = '"%(date)","%C","%P","%t","%T"'; + foreach my $tagField (qw/Receipt Invoice Statement Contract PurchaseOrder Approval Check IncomeDistributionAnalysis CurrencyRate/) { + print GL_CSV_OUT ',"', $tagField, '"'; + $formatString .= ',"%(tag(\'' . $tagField . '\'))"'; + } + $formatString .= "\n"; + print GL_CSV_OUT "\n"; + + @acctLedgerOpts = ('-F', $formatString, '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); open(GL_CSV_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!"; -- cgit v1.2.3 From b5316132d44a91ff664b39c194710f5f88051d74 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Wed, 21 Nov 2012 13:34:55 -0500 Subject: MANIFEST output file that indicates which files are mentioned in general-ledger. Due to reporting options given to ledger, not every file will be referenced by the general-ledger spreadsheet. The generated MANIFEST file now indicates which files were actually referenced in the general-ledger. The demo.sh script now uses this MANIFEST to create a zip file that contains only those files. --- contrib/non-profit-audit-reports/demo.sh | 4 +++- contrib/non-profit-audit-reports/general-ledger-report.plx | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/contrib/non-profit-audit-reports/demo.sh b/contrib/non-profit-audit-reports/demo.sh index 6a9dcadf..a4b837a6 100755 --- a/contrib/non-profit-audit-reports/demo.sh +++ b/contrib/non-profit-audit-reports/demo.sh @@ -32,11 +32,13 @@ else exit 1 fi +echo general-ledger.ods >> MANIFEST + # create a portable zip file with the spreadsheet # and the linked artifacts echo creating portable zipfile... -zip -r ../general-ledger.zip general-ledger.ods Financial Projects -x '*.txt' +cat MANIFEST | zip -@ ../general-ledger.zip echo " " echo "created general-ledger.zip" diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 1c293db9..07f0b9da 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -44,6 +44,7 @@ if (@ARGV < 3) { print STDERR "usage: $0 \n"; exit 1; } +open(MANIFEST, ">", "MANIFEST") or die "Unable to open MANIFEST for writing: $!"; my($beginDate, $endDate, @otherLedgerOpts) = @ARGV; @@ -53,8 +54,6 @@ my(@chartOfAccountsOpts) = ('-F', "%150A\n", '-w', '-s', open(CHART_DATA, "-|", $LEDGER_CMD, @chartOfAccountsOpts) or die "Unable to run $LEDGER_CMD @chartOfAccountsOpts: $!"; -open(CHART_OUTPUT, ">", "chart-of-accounts.txt") or die "unable to write chart-of-accounts.txt: $!"; - my @accounts; while (my $line = ) { chomp $line; @@ -65,6 +64,7 @@ while (my $line = ) { close(CHART_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; open(CHART_OUTPUT, ">", "chart-of-accounts.txt") or die "unable to write chart-of-accounts.txt: $!"; +print MANIFEST "chart-of-accounts.txt\n"; my @sortedAccounts; foreach my $acct ( @@ -91,7 +91,9 @@ $formattedEndDate = $formattedEndDate->calc($oneDayLess); $formattedEndDate = $formattedEndDate->printf("%Y/%m/%d"); open(GL_TEXT_OUT, ">", "general-ledger.txt") or die "unable to write general-ledger.txt: $!"; +print MANIFEST "general-ledger.txt\n"; open(GL_CSV_OUT, ">", "general-ledger.csv") or die "unable to write general-ledger.csv: $!"; +print MANIFEST "general-ledger.csv\n"; foreach my $acct (@sortedAccounts) { print GL_TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; @@ -122,6 +124,14 @@ foreach my $acct (@sortedAccounts) { foreach my $line () { print GL_CSV_OUT $line; + next if $line =~ /ACCOUNT:.*PERIOD/; # Skip column header lines + $line =~ s/^"[^"]*","[^"]*","[^"]*","[^"]*","[^"]*",//; + while ($line =~ s/^"([^"]*)"(,|$)//) { + my $file = $1; + next if $file =~ /^\s*$/; + warn "$file does not exist and/or is not readable" unless -r $file; + print MANIFEST "$file\n"; + } } close(GL_CSV_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; } -- cgit v1.2.3 From 6a3b25f85bd31ae8d7fdd55dd7f9a83a95d96e0d Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 1 Nov 2011 12:13:31 -0400 Subject: Began fund-report.plx, which started as a copy of trial-balance-report.plx. The revision history of trial-balance-report.plx can be found in the following location: http://gitorious.org/bkuhn/small-hacks/blobs/history/master/trial-balance-report.plx --- contrib/non-profit-audit-reports/fund-report.plx | 135 +++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100755 contrib/non-profit-audit-reports/fund-report.plx diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx new file mode 100755 index 00000000..e690b13b --- /dev/null +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -0,0 +1,135 @@ +#!/usr/bin/perl +# fund-report.plx -*- Perl -*- +# +# Script to generate a Trial Balance report for a ledger. +# +# Copyright (C) 2011, Bradley M. Kuhn +# +# This program gives you software freedom; you can copy, modify, convey, +# and/or redistribute it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program in a file called 'GPLv3'. If not, write to the: +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor +# Boston, MA 02110-1301, USA. + +use strict; +use warnings; + +use Math::BigFloat; + +my $LEDGER_CMD = "/usr/bin/ledger"; + +my $ACCT_WIDTH = 70; + +sub ParseNumber($) { + $_[0] =~ s/,//g; + return Math::BigFloat->new($_[0]); +} +Math::BigFloat->precision(-2); +my $ZERO = Math::BigFloat->new("0.00"); + +if (@ARGV < 2) { + print STDERR "usage: $0 \n"; + exit 1; +} + +my($startDate, $endDate, @mainLedgerOptions) = @ARGV; + +# First, get fund list from ending balance +my(@ledgerOptions) = (@mainLedgerOptions, + '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', + '-e', $endDate, 'reg', '^Funds:Restricted:'); + + +my %funds; + +open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) + or die "Unable to run $LEDGER_CMD for funds: $!"; + +while (my $fundLine = ) { + die "Unable to parse output line from funds command: $fundLine" + unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; + $funds{$account}{ending} = $amount; +} +close LEDGER_FUNDS; + +# First, get fund list from ending balance +@ledgerOptions = (@mainLedgerOptions, + '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', + '-e', $startDate, 'reg', '^Funds:Restricted:'); + +open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) + or die "Unable to run $LEDGER_CMD for funds: $!"; + +while (my $fundLine = ) { + die "Unable to parse output line from funds command: $fundLine" + unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; + $funds{$account}{starting} = $amount; +} +close LEDGER_FUNDS; + + +foreach my $fund (keys %funds) { + $funds{$fund}{starting} = $ZERO if not defined $funds{$fund}{starting}; +} + +@ledgerOptions = (@mainLedgerOptions, + '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', + '-b', $startDate, '-e', $endDate, 'reg'); + +foreach my $type ('Income', 'Expenses') { + foreach my $fund (keys %funds) { + open(LEDGER_INCOME, "-|", $LEDGER_CMD, @ledgerOptions, "^${type}:$fund") + or die "Unable to run $LEDGER_CMD for funds: $!"; + $funds{$fund}{$type} = $ZERO; + while (my $line = ) { + die "Unable to parse output line from $type line command: $line" + unless $line =~ /^\s*([^\$]+)\s+\$\s*\s*([\-\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $funds{$fund}{$type} += $amount; + } + close LEDGER_INCOME; + } +} + +my($totStart, $totEnd) = ($ZERO, $ZERO); + +foreach my $fund (sort keys %funds) { + print "Fund: $fund\n"; + print " Balance as of $startDate: ", sprintf("\$%15.2f\n\n", $funds{$fund}{starting}); + print " Income during period: ", sprintf("\$%15.2f\n", $funds{$fund}{Income}); + print " Expenses during period: ", sprintf("\$%15.2f\n\n", $funds{$fund}{Expenses}); + print " Balance as of $endDate: ", sprintf("\$%15.2f\n", $funds{$fund}{ending}); + print "\n\n"; + # Santity check: + if ($funds{$fund}{ending} != + ( ($funds{$fund}{starting} - $funds{$fund}{Income}) - $funds{$fund}{Expenses})) { + print "$fund FAILED SANITY CHECK\n\n\n"; + die "$fund FAILED SANITY CHECK"; + } + $totStart += $funds{$fund}{starting}; + $totEnd += $funds{$fund}{ending}; +} +print "\n\n\nTotal Restricted Funds as of $startDate: ", sprintf("\$%15.2f\n", $totStart); +print "\nTotal Restricted Funds as of $endDate: ", sprintf("\$%15.2f\n", $totEnd); +############################################################################### +# +# Local variables: +# compile-command: "perl -c fund-report.plx" +# End: + -- cgit v1.2.3 From 55227e4d2c30923da7014826f9f02a21facbacfa Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 1 Nov 2011 12:15:25 -0400 Subject: Fix ledger options and be sure starting is set to zero for new funds. --- contrib/non-profit-audit-reports/fund-report.plx | 44 ++++-------------------- 1 file changed, 6 insertions(+), 38 deletions(-) diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index e690b13b..22373eb8 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -59,7 +59,7 @@ while (my $fundLine = ) { unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); - $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; + $account =~ s/^\s+Funds:Restricted://; $account =~ s/\s+$//; $funds{$account}{ending} = $amount; } close LEDGER_FUNDS; @@ -77,56 +77,24 @@ while (my $fundLine = ) { unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); - $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; + $account =~ s/^\s+Funds:Restricted://; $account =~ s/\s+$//; $funds{$account}{starting} = $amount; } close LEDGER_FUNDS; - foreach my $fund (keys %funds) { $funds{$fund}{starting} = $ZERO if not defined $funds{$fund}{starting}; } -@ledgerOptions = (@mainLedgerOptions, - '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', - '-b', $startDate, '-e', $endDate, 'reg'); - -foreach my $type ('Income', 'Expenses') { - foreach my $fund (keys %funds) { - open(LEDGER_INCOME, "-|", $LEDGER_CMD, @ledgerOptions, "^${type}:$fund") - or die "Unable to run $LEDGER_CMD for funds: $!"; - $funds{$fund}{$type} = $ZERO; - while (my $line = ) { - die "Unable to parse output line from $type line command: $line" - unless $line =~ /^\s*([^\$]+)\s+\$\s*\s*([\-\d\.\,]+)/; - my($account, $amount) = ($1, $2); - $amount = ParseNumber($amount); - $funds{$fund}{$type} += $amount; - } - close LEDGER_INCOME; - } -} - -my($totStart, $totEnd) = ($ZERO, $ZERO); +my $format = "%-${ACCT_WIDTH}.${ACCT_WIDTH}s \$%11.2f \$%11.2f\n"; +my($totDeb, $totCred) = ($ZERO, $ZERO); foreach my $fund (sort keys %funds) { print "Fund: $fund\n"; - print " Balance as of $startDate: ", sprintf("\$%15.2f\n\n", $funds{$fund}{starting}); - print " Income during period: ", sprintf("\$%15.2f\n", $funds{$fund}{Income}); - print " Expenses during period: ", sprintf("\$%15.2f\n\n", $funds{$fund}{Expenses}); - print " Balance as of $endDate: ", sprintf("\$%15.2f\n", $funds{$fund}{ending}); + print " Balance as of $startDate: ", sprintf("\$%11.2f\n", $funds{$fund}{starting}); + print " Balance as of $endDate: ", sprintf("\$%11.2f\n", $funds{$fund}{ending}); print "\n\n"; - # Santity check: - if ($funds{$fund}{ending} != - ( ($funds{$fund}{starting} - $funds{$fund}{Income}) - $funds{$fund}{Expenses})) { - print "$fund FAILED SANITY CHECK\n\n\n"; - die "$fund FAILED SANITY CHECK"; - } - $totStart += $funds{$fund}{starting}; - $totEnd += $funds{$fund}{ending}; } -print "\n\n\nTotal Restricted Funds as of $startDate: ", sprintf("\$%15.2f\n", $totStart); -print "\nTotal Restricted Funds as of $endDate: ", sprintf("\$%15.2f\n", $totEnd); ############################################################################### # # Local variables: -- cgit v1.2.3 From daad6e5700141bfbed6bb6a984ad99f76e7ac09d Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 1 Nov 2011 12:24:19 -0400 Subject: Added income/expense summing. --- contrib/non-profit-audit-reports/fund-report.plx | 29 +++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index 22373eb8..35463fe3 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -59,7 +59,7 @@ while (my $fundLine = ) { unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); - $account =~ s/^\s+Funds:Restricted://; $account =~ s/\s+$//; + $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; $funds{$account}{ending} = $amount; } close LEDGER_FUNDS; @@ -77,21 +77,44 @@ while (my $fundLine = ) { unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); - $account =~ s/^\s+Funds:Restricted://; $account =~ s/\s+$//; + $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; $funds{$account}{starting} = $amount; } close LEDGER_FUNDS; + foreach my $fund (keys %funds) { $funds{$fund}{starting} = $ZERO if not defined $funds{$fund}{starting}; } +@ledgerOptions = (@mainLedgerOptions, + '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', + '-b', $startDate, '-e', $endDate, 'reg'); + +foreach my $type ('Income', 'Expenses') { + foreach my $fund (keys %funds) { + open(LEDGER_INCOME, "-|", $LEDGER_CMD, @ledgerOptions, "^${type}:$fund") + or die "Unable to run $LEDGER_CMD for funds: $!"; + $funds{$fund}{$type} = $ZERO; + while (my $line = ) { + die "Unable to parse output line from $type line command: $line" + unless $line =~ /^\s*([^\$]+)\s+\$\s*\s*([\-\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $funds{$fund}{$type} += $amount; + } + close LEDGER_INCOME; + } +} + my $format = "%-${ACCT_WIDTH}.${ACCT_WIDTH}s \$%11.2f \$%11.2f\n"; my($totDeb, $totCred) = ($ZERO, $ZERO); foreach my $fund (sort keys %funds) { print "Fund: $fund\n"; - print " Balance as of $startDate: ", sprintf("\$%11.2f\n", $funds{$fund}{starting}); + print " Balance as of $startDate: ", sprintf("\$%11.2f\n\n", $funds{$fund}{starting}); + print " Income during period: ", sprintf("\$%11.2f\n", $funds{$fund}{Income}); + print " Expenses during period: ", sprintf("\$%11.2f\n", $funds{$fund}{Expenses}); print " Balance as of $endDate: ", sprintf("\$%11.2f\n", $funds{$fund}{ending}); print "\n\n"; } -- cgit v1.2.3 From 9051804fb17bde5d33394747ea38000f26318edd Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 1 Nov 2011 12:28:01 -0400 Subject: Fixed formatting and added sanity check code. --- contrib/non-profit-audit-reports/fund-report.plx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index 35463fe3..9d6a31b3 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -114,9 +114,15 @@ foreach my $fund (sort keys %funds) { print "Fund: $fund\n"; print " Balance as of $startDate: ", sprintf("\$%11.2f\n\n", $funds{$fund}{starting}); print " Income during period: ", sprintf("\$%11.2f\n", $funds{$fund}{Income}); - print " Expenses during period: ", sprintf("\$%11.2f\n", $funds{$fund}{Expenses}); + print " Expenses during period: ", sprintf("\$%11.2f\n\n", $funds{$fund}{Expenses}); print " Balance as of $endDate: ", sprintf("\$%11.2f\n", $funds{$fund}{ending}); print "\n\n"; + # Santity check: + if ($funds{$fund}{ending} == + ($funds{$fund}{starting} + $funds{$fund}{Income} + $funds{$fund}{Expenses})) { + print "$fund FAILED SANITY CHECK\n\n\n"; + die "$fund FAILED SANITY CHECK"; + } } ############################################################################### # -- cgit v1.2.3 From cf969fcbb4cf1cdf0b76124b44e549ca03e8590e Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 1 Nov 2011 12:41:15 -0400 Subject: Formatting changes, and added total for restricted funds. --- contrib/non-profit-audit-reports/fund-report.plx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index 9d6a31b3..e690b13b 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -107,23 +107,26 @@ foreach my $type ('Income', 'Expenses') { } } -my $format = "%-${ACCT_WIDTH}.${ACCT_WIDTH}s \$%11.2f \$%11.2f\n"; -my($totDeb, $totCred) = ($ZERO, $ZERO); +my($totStart, $totEnd) = ($ZERO, $ZERO); foreach my $fund (sort keys %funds) { print "Fund: $fund\n"; - print " Balance as of $startDate: ", sprintf("\$%11.2f\n\n", $funds{$fund}{starting}); - print " Income during period: ", sprintf("\$%11.2f\n", $funds{$fund}{Income}); - print " Expenses during period: ", sprintf("\$%11.2f\n\n", $funds{$fund}{Expenses}); - print " Balance as of $endDate: ", sprintf("\$%11.2f\n", $funds{$fund}{ending}); + print " Balance as of $startDate: ", sprintf("\$%15.2f\n\n", $funds{$fund}{starting}); + print " Income during period: ", sprintf("\$%15.2f\n", $funds{$fund}{Income}); + print " Expenses during period: ", sprintf("\$%15.2f\n\n", $funds{$fund}{Expenses}); + print " Balance as of $endDate: ", sprintf("\$%15.2f\n", $funds{$fund}{ending}); print "\n\n"; # Santity check: - if ($funds{$fund}{ending} == - ($funds{$fund}{starting} + $funds{$fund}{Income} + $funds{$fund}{Expenses})) { + if ($funds{$fund}{ending} != + ( ($funds{$fund}{starting} - $funds{$fund}{Income}) - $funds{$fund}{Expenses})) { print "$fund FAILED SANITY CHECK\n\n\n"; die "$fund FAILED SANITY CHECK"; } + $totStart += $funds{$fund}{starting}; + $totEnd += $funds{$fund}{ending}; } +print "\n\n\nTotal Restricted Funds as of $startDate: ", sprintf("\$%15.2f\n", $totStart); +print "\nTotal Restricted Funds as of $endDate: ", sprintf("\$%15.2f\n", $totEnd); ############################################################################### # # Local variables: -- cgit v1.2.3 From 5305642e4dafcd662c3c6842a383aaf4b27938d4 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Wed, 21 Nov 2012 14:00:58 -0500 Subject: Formatting adaptations for Ledger 3. This includes addition of currency-forcing options such as -V and -X $, as well as corrections to the formatting string options for Ledger 3. --- contrib/non-profit-audit-reports/fund-report.plx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index e690b13b..673263d7 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -25,7 +25,7 @@ use warnings; use Math::BigFloat; -my $LEDGER_CMD = "/usr/bin/ledger"; +my $LEDGER_CMD = "/usr/local/bin/ledger"; my $ACCT_WIDTH = 70; @@ -45,8 +45,8 @@ my($startDate, $endDate, @mainLedgerOptions) = @ARGV; # First, get fund list from ending balance my(@ledgerOptions) = (@mainLedgerOptions, - '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', - '-e', $endDate, 'reg', '^Funds:Restricted:'); + '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-s', + '-e', $endDate, 'reg', '/^Funds:Restricted:/'); my %funds; @@ -55,7 +55,7 @@ open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) or die "Unable to run $LEDGER_CMD for funds: $!"; while (my $fundLine = ) { - die "Unable to parse output line from funds command: $fundLine" + die "Unable to parse output line from funds command: \"$fundLine\"" unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); @@ -66,7 +66,7 @@ close LEDGER_FUNDS; # First, get fund list from ending balance @ledgerOptions = (@mainLedgerOptions, - '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', + '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-w', '-s', '-e', $startDate, 'reg', '^Funds:Restricted:'); open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) @@ -88,7 +88,7 @@ foreach my $fund (keys %funds) { } @ledgerOptions = (@mainLedgerOptions, - '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', + '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-w', '-s', '-b', $startDate, '-e', $endDate, 'reg'); foreach my $type ('Income', 'Expenses') { -- cgit v1.2.3 From 60f45c3e2cff809f6c9356e9853cf38070bd3ec6 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Wed, 21 Nov 2012 14:52:39 -0500 Subject: Ignore entries in the report. With the advent of multi-currency in accounts, lines can be generated in reports. I don't know if there's a way to turn these off on the Ledger command line or not at the moment, but if they're there, they clearly should be ignored by this script. --- contrib/non-profit-audit-reports/fund-report.plx | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index 673263d7..a463bccf 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -40,26 +40,26 @@ if (@ARGV < 2) { print STDERR "usage: $0 \n"; exit 1; } - my($startDate, $endDate, @mainLedgerOptions) = @ARGV; # First, get fund list from ending balance my(@ledgerOptions) = (@mainLedgerOptions, '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-s', '-e', $endDate, 'reg', '/^Funds:Restricted:/'); - - my %funds; open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) or die "Unable to run $LEDGER_CMD for funds: $!"; while (my $fundLine = ) { - die "Unable to parse output line from funds command: \"$fundLine\"" - unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; + die "Unable to parse output line from first funds command: \"$fundLine\"" + unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\-\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); - $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; + $account =~ s/\s+$//; + next if $account =~ /\/ and (abs($amount) <= 0.02); + die "Weird account found, $account with amount of $amount in first funds command\n" + unless $account =~ s/^\s*Funds:Restricted://; $funds{$account}{ending} = $amount; } close LEDGER_FUNDS; @@ -73,11 +73,14 @@ open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) or die "Unable to run $LEDGER_CMD for funds: $!"; while (my $fundLine = ) { - die "Unable to parse output line from funds command: $fundLine" - unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; + die "Unable to parse output line from second funds command: $fundLine" + unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*([\-\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); - $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; + $account =~ s/\s+$//; + next if $account =~ /\/ and (abs($amount) <= 0.02); + die "Weird account found, $account with amount of $amount in first second command\n" + unless $account =~ s/^\s*Funds:Restricted://; $funds{$account}{starting} = $amount; } close LEDGER_FUNDS; -- cgit v1.2.3 From 7772e33720db8234d12640996033bcba8ca98e7f Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 22 Nov 2012 16:45:59 -0500 Subject: Include all types of totals that need to be considered when generating fund report. --- contrib/non-profit-audit-reports/fund-report.plx | 26 ++++++++++++++++-------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index a463bccf..764080d0 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -64,7 +64,7 @@ while (my $fundLine = ) { } close LEDGER_FUNDS; -# First, get fund list from ending balance +# First, get fund list from starting balance @ledgerOptions = (@mainLedgerOptions, '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-w', '-s', '-e', $startDate, 'reg', '^Funds:Restricted:'); @@ -94,7 +94,10 @@ foreach my $fund (keys %funds) { '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-w', '-s', '-b', $startDate, '-e', $endDate, 'reg'); -foreach my $type ('Income', 'Expenses') { +my @possibleTypes = ('Unearned Income', 'Retained Earnings', 'Retained Costs', + 'Accrued:Accounts Payable', 'Accrued:Accounts Receivable'); + +foreach my $type ('Income', 'Expenses', @possibleTypes) { foreach my $fund (keys %funds) { open(LEDGER_INCOME, "-|", $LEDGER_CMD, @ledgerOptions, "^${type}:$fund") or die "Unable to run $LEDGER_CMD for funds: $!"; @@ -113,15 +116,20 @@ foreach my $type ('Income', 'Expenses') { my($totStart, $totEnd) = ($ZERO, $ZERO); foreach my $fund (sort keys %funds) { - print "Fund: $fund\n"; - print " Balance as of $startDate: ", sprintf("\$%15.2f\n\n", $funds{$fund}{starting}); - print " Income during period: ", sprintf("\$%15.2f\n", $funds{$fund}{Income}); - print " Expenses during period: ", sprintf("\$%15.2f\n\n", $funds{$fund}{Expenses}); - print " Balance as of $endDate: ", sprintf("\$%15.2f\n", $funds{$fund}{ending}); - print "\n\n"; + my $sanityTotal = $funds{$fund}{starting}; + print "Fund: $fund\n", sprintf("%-35s\$%26.2f\n\n", "Balance as of $startDate:", + $funds{$fund}{starting}); + foreach my $type ('Income', 'Expenses', @possibleTypes) { + my $formattedType = $type; $formattedType =~ s/^Accrued://; + next if $type ne 'Income' and $type ne 'Expenses' and $funds{$fund}{$type} == $ZERO; + print sprintf("%19s during period: \$%26.2f\n", $formattedType, $funds{$fund}{$type}); + } + print sprintf("\n%-35s\$%26.2f\n", "Balance as of $endDate:", + $funds{$fund}{ending}), "\n\n"; # Santity check: if ($funds{$fund}{ending} != - ( ($funds{$fund}{starting} - $funds{$fund}{Income}) - $funds{$fund}{Expenses})) { + ($funds{$fund}{starting} + - $funds{$fund}{Income} - $funds{$fund}{'Unearned Income'} - $funds{$fund}{Expenses})) { print "$fund FAILED SANITY CHECK\n\n\n"; die "$fund FAILED SANITY CHECK"; } -- cgit v1.2.3 From 530fa76beab2e5e16603d0bf554308056edd1c98 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 22 Nov 2012 16:46:42 -0500 Subject: Update copyright year, I've made changes. --- contrib/non-profit-audit-reports/fund-report.plx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index 764080d0..5b74a606 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -3,7 +3,7 @@ # # Script to generate a Trial Balance report for a ledger. # -# Copyright (C) 2011, Bradley M. Kuhn +# Copyright (C) 2011, 2012, Bradley M. Kuhn # # This program gives you software freedom; you can copy, modify, convey, # and/or redistribute it under the terms of the GNU General Public License -- cgit v1.2.3 From 7ed4d20d87868d5e3918b5d2cccf6558e2849ca6 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 22 Nov 2012 19:40:36 -0500 Subject: Began summary reports script, starting with a basic balance sheet. --- .../non-profit-audit-reports/summary-reports.plx | 168 +++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100755 contrib/non-profit-audit-reports/summary-reports.plx diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx new file mode 100755 index 00000000..1b9bc734 --- /dev/null +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -0,0 +1,168 @@ +#!/usr/bin/perl +# fund-report.plx -*- Perl -*- +# +# Script to generate end-of-year summary reports. +# +# Copyright (C) 2011, 2012, Bradley M. Kuhn +# +# This program gives you software freedom; you can copy, modify, convey, +# and/or redistribute it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program in a file called 'GPLv3'. If not, write to the: +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor +# Boston, MA 02110-1301, USA. + +use strict; +use warnings; + +use Math::BigFloat; + +my $VERBOSE = 0; +my $DEBUG = 0; + +my $LEDGER_BIN = "/usr/local/bin/ledger"; + +my $ACCT_WIDTH = 70; + +sub Commify ($) { + my $text = reverse $_[0]; + $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g; + return scalar reverse $text; +} + +sub ParseNumber($) { + $_[0] =~ s/,//g; + return Math::BigFloat->new($_[0]); +} +Math::BigFloat->precision(-2); +my $ZERO = Math::BigFloat->new("0.00"); + +if (@ARGV < 2) { + print STDERR "usage: $0 \n"; + exit 1; +} +my($startDate, $endDate, @mainLedgerOptions) = @ARGV; + +# First, get fund list from ending balance +my(@ledgerOptions) = (@mainLedgerOptions, + '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-S', 'T', '-s', + 'd', 'T', '-e', $endDate, 'bal', '/^Assets/'); + +my %reportFields = + ('Cash' => { args => [ '-e', $endDate, 'bal', '/^Assets/' ] }, + 'Accounts Receivable' => {args => [ '-e', $endDate, 'bal', '/^Accrued:Accounts Receivable/' ]}, + 'Accounts Payable' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Accounts Payable/' ]}, + 'Accrued Expenses' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Expenses/' ]}, + 'Unearned Income, Conference Registration' => {args => [ '-e', $endDate, 'bal', + '/^Unearned Income.*Conf.*Reg/' ]}, + 'Unearned Income, Other' => {args => [ '-e', $endDate, 'bal', '/^Unearned Income/', 'and', 'not', + '/^Unearned Income.*Conf.*Reg/' ]}, + 'Unrestricted Net Assets' => {args => [ '-e', $endDate, 'bal', '/^(Income|Expenses):Conservancy/' ]}, + 'Temporarily Restricted Net Assets' => {args => [ '-e', $endDate, 'bal', '/^(Income|Expenses)/', + 'and', 'not', '/^(Unearned Income|(Income|Expenses):Conservancy)/' ]}, + 'Total Net Assets' => {args => [ '-e', $endDate, 'bal', '/^(Income|Expenses)/' ]}, + +); +foreach my $item (keys %reportFields) { + my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, + '-V', '-S', 'T', '-s', '-d', 'T', @{$reportFields{$item}{args}}); + open(FILE, "-|", @fullCommand) + or die "unable to run command ledger command: @fullCommand: $!"; + + my $foundBalance; + my $seenTotalLine = 0; + + print STDERR ($VERBOSE ? "Running: @fullCommand\n" : "."); + print STDERR " Output of @fullCommand\n" if $DEBUG; + + while (my $line = ) { + print STDERR $line if ($DEBUG); + + $seenTotalLine = 1 if $line =~ /^\s*\-+\s*/; # Skip lines until the total line + $foundBalance = $1 + if (not $seenTotalLine and $line =~ /^\s*[^0-9\-]+\s*([\-\d,\.]+)\s+/); + + if ($line =~ /^\s*\$\s*([\-\d,\.]+)\s*$/) { + $foundBalance = $1; + last; + } + } + close FILE; + die "problem running ledger command: @fullCommand: $!" unless ($? == 0); + if (not defined $foundBalance) { + $foundBalance = $ZERO; + } else { + $foundBalance =~ s/,//g; + $foundBalance = Math::BigFloat->new($foundBalance); + } + $foundBalance = $ZERO if not defined $foundBalance; + $reportFields{$item}{total} = abs($foundBalance); + print STDERR "$item: $reportFields{$item}{total}\n" if $VERBOSE; +} + +die "Cash+accounts receivable total does not equal net assets and liabilities total" + if ( ($reportFields{'Cash'}{total} + $reportFields{'Accounts Receivable'}{total}) != + ($reportFields{'Accounts Payable'}{total} + + $reportFields{'Accrued Expenses'}{total} + + $reportFields{'Unearned Income, Conference Registration'}{total} + + $reportFields{'Unearned Income, Other'}{total} + + $reportFields{'Total Net Assets'}{total})); + +die "Total net assets doesn't equal sum of restricted and unrestricted ones!" + if ($reportFields{'Total Net Assets'}{total} != + $reportFields{'Unrestricted Net Assets'}{total} + + $reportFields{'Temporarily Restricted Net Assets'}{total}); + +open(ASSETS, ">", "assets-and-liabilities.txt") + or die "unable to open assets-and-liabilities.txt for writing: $!"; + +print ASSETS "ASSETS\n\n"; + +my $formatStr = " %-42s \$%18s\n"; +my $formatStrTotal = "%-45s \$%12s\n"; +my $tot = $ZERO; +foreach my $item ('Cash', 'Accounts Receivable') { + next if $reportFields{$item}{total} == $ZERO; + print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); + $tot += $reportFields{$item}{total}; +} +print ASSETS "\n", sprintf($formatStrTotal, "TOTAL ASSETS", Commify($tot)), "\n\nLIABILITIES\n\n"; + +my $totLiabilities = $ZERO; +foreach my $item ('Accounts Payable', 'Accrued Expenses', + 'Unearned Income, Conference Registration', 'Unearned Income, Other') { + next if $reportFields{$item}{total} == $ZERO; + print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); + $totLiabilities += $reportFields{$item}{total}; +} +print ASSETS "\n", sprintf($formatStr, "TOTAL LIABILTIES", Commify($totLiabilities)), + "\n\nNET ASSETS\n\n"; + +my $totNetAssets = $ZERO; +foreach my $item ('Unrestricted Net Assets', 'Temporarily Restricted Net Assets') { + next if $reportFields{$item}{total} == $ZERO; + print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); + $totNetAssets += $reportFields{$item}{total}; +} +print ASSETS "\n", sprintf($formatStr, "TOTAL NET ASSETS", Commify($totNetAssets)), "\n\n", + sprintf($formatStrTotal, "TOTAL LIABILITIES AND NET ASSETS", + Commify($totNetAssets + $totLiabilities)); + +close ASSETS; +print STDERR "\n"; +die "unable to write to Assets-and-liabilities.txt: $!" unless ($? == 0); + +############################################################################### +# +# Local variables: +# compile-command: "perl -c summary-reports.plx" +# End: + -- cgit v1.2.3 From f0ee16a373412e3654120e3847430a1a94ea8d23 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 08:35:38 -0500 Subject: Add Loans. --- contrib/non-profit-audit-reports/summary-reports.plx | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 1b9bc734..a175f5ba 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -59,6 +59,7 @@ my(@ledgerOptions) = (@mainLedgerOptions, my %reportFields = ('Cash' => { args => [ '-e', $endDate, 'bal', '/^Assets/' ] }, 'Accounts Receivable' => {args => [ '-e', $endDate, 'bal', '/^Accrued:Accounts Receivable/' ]}, + 'Loans Receivable' => {args => [ '-e', $endDate, 'bal', '/^Accrued:Loans Receivable/' ]}, 'Accounts Payable' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Accounts Payable/' ]}, 'Accrued Expenses' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Expenses/' ]}, 'Unearned Income, Conference Registration' => {args => [ '-e', $endDate, 'bal', -- cgit v1.2.3 From 7b0e4c48067296d15c6f350948cbf29d7aec5787 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 08:35:45 -0500 Subject: Add -X $. --- contrib/non-profit-audit-reports/summary-reports.plx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index a175f5ba..c0731322 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -74,7 +74,7 @@ my %reportFields = ); foreach my $item (keys %reportFields) { my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, - '-V', '-S', 'T', '-s', '-d', 'T', @{$reportFields{$item}{args}}); + '-V', '-X', '$', '-S', 'T', '-s', '-d', 'T', @{$reportFields{$item}{args}}); open(FILE, "-|", @fullCommand) or die "unable to run command ledger command: @fullCommand: $!"; -- cgit v1.2.3 From cba448b28bbc26a03a5b590818ff8668ac162681 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 08:36:11 -0500 Subject: Move sanity checks to the bottom, after report is generated. Also, fix formatting. --- .../non-profit-audit-reports/summary-reports.plx | 33 +++++++++++----------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index c0731322..0f0e09ee 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -109,28 +109,15 @@ foreach my $item (keys %reportFields) { print STDERR "$item: $reportFields{$item}{total}\n" if $VERBOSE; } -die "Cash+accounts receivable total does not equal net assets and liabilities total" - if ( ($reportFields{'Cash'}{total} + $reportFields{'Accounts Receivable'}{total}) != - ($reportFields{'Accounts Payable'}{total} + - $reportFields{'Accrued Expenses'}{total} + - $reportFields{'Unearned Income, Conference Registration'}{total} + - $reportFields{'Unearned Income, Other'}{total} + - $reportFields{'Total Net Assets'}{total})); - -die "Total net assets doesn't equal sum of restricted and unrestricted ones!" - if ($reportFields{'Total Net Assets'}{total} != - $reportFields{'Unrestricted Net Assets'}{total} + - $reportFields{'Temporarily Restricted Net Assets'}{total}); - open(ASSETS, ">", "assets-and-liabilities.txt") or die "unable to open assets-and-liabilities.txt for writing: $!"; print ASSETS "ASSETS\n\n"; -my $formatStr = " %-42s \$%18s\n"; -my $formatStrTotal = "%-45s \$%12s\n"; +my $formatStr = " %-42s \$%13s\n"; +my $formatStrTotal = "%-45s \$%13s\n"; my $tot = $ZERO; -foreach my $item ('Cash', 'Accounts Receivable') { +foreach my $item ('Cash', 'Accounts Receivable', 'Loans Receivable') { next if $reportFields{$item}{total} == $ZERO; print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); $tot += $reportFields{$item}{total}; @@ -161,6 +148,20 @@ close ASSETS; print STDERR "\n"; die "unable to write to Assets-and-liabilities.txt: $!" unless ($? == 0); +die "Cash+accounts receivable total does not equal net assets and liabilities total" + if ( ($reportFields{'Cash'}{total} + $reportFields{'Accounts Receivable'}{total} + + $reportFields{'Loans Receivable'}{total}) != + ($reportFields{'Accounts Payable'}{total} + + $reportFields{'Accrued Expenses'}{total} + + $reportFields{'Unearned Income, Conference Registration'}{total} + + $reportFields{'Unearned Income, Other'}{total} + + $reportFields{'Total Net Assets'}{total})); + +die "Total net assets doesn't equal sum of restricted and unrestricted ones!" + if ($reportFields{'Total Net Assets'}{total} != + $reportFields{'Unrestricted Net Assets'}{total} + + $reportFields{'Temporarily Restricted Net Assets'}{total}); + ############################################################################### # # Local variables: -- cgit v1.2.3 From 46b13e8e550fb05a3e863e913cf6cd359ef42272 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 08:44:53 -0500 Subject: Include credit card balances in the Liabilities list. --- contrib/non-profit-audit-reports/summary-reports.plx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 0f0e09ee..04923de8 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -62,6 +62,7 @@ my %reportFields = 'Loans Receivable' => {args => [ '-e', $endDate, 'bal', '/^Accrued:Loans Receivable/' ]}, 'Accounts Payable' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Accounts Payable/' ]}, 'Accrued Expenses' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Expenses/' ]}, + 'Liabilities, Credit Cards' => {args => [ '-e', $endDate, 'bal', '/^Liabilities:Credit Card/' ]}, 'Unearned Income, Conference Registration' => {args => [ '-e', $endDate, 'bal', '/^Unearned Income.*Conf.*Reg/' ]}, 'Unearned Income, Other' => {args => [ '-e', $endDate, 'bal', '/^Unearned Income/', 'and', 'not', @@ -125,7 +126,7 @@ foreach my $item ('Cash', 'Accounts Receivable', 'Loans Receivable') { print ASSETS "\n", sprintf($formatStrTotal, "TOTAL ASSETS", Commify($tot)), "\n\nLIABILITIES\n\n"; my $totLiabilities = $ZERO; -foreach my $item ('Accounts Payable', 'Accrued Expenses', +foreach my $item ('Accounts Payable', 'Liabilities, Credit Cards', 'Accrued Expenses', 'Unearned Income, Conference Registration', 'Unearned Income, Other') { next if $reportFields{$item}{total} == $ZERO; print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); @@ -155,6 +156,7 @@ die "Cash+accounts receivable total does not equal net assets and liabilities to $reportFields{'Accrued Expenses'}{total} + $reportFields{'Unearned Income, Conference Registration'}{total} + $reportFields{'Unearned Income, Other'}{total} + + $reportFields{'Liabilities, Credit Cards'}{total} + $reportFields{'Total Net Assets'}{total})); die "Total net assets doesn't equal sum of restricted and unrestricted ones!" -- cgit v1.2.3 From ccd5d06c04576bbd3911d4ce0c9ccb8c4ec4cfc5 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 08:45:52 -0500 Subject: Include any other liabilities that aren't credit cards. --- contrib/non-profit-audit-reports/summary-reports.plx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 04923de8..14923a42 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -63,6 +63,8 @@ my %reportFields = 'Accounts Payable' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Accounts Payable/' ]}, 'Accrued Expenses' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Expenses/' ]}, 'Liabilities, Credit Cards' => {args => [ '-e', $endDate, 'bal', '/^Liabilities:Credit Card/' ]}, + 'Liabilities, Other' => {args => [ '-e', $endDate, 'bal', '/^Liabilities/', + 'and', 'not', '/^Liabilities:Credit Card/']}, 'Unearned Income, Conference Registration' => {args => [ '-e', $endDate, 'bal', '/^Unearned Income.*Conf.*Reg/' ]}, 'Unearned Income, Other' => {args => [ '-e', $endDate, 'bal', '/^Unearned Income/', 'and', 'not', @@ -126,7 +128,8 @@ foreach my $item ('Cash', 'Accounts Receivable', 'Loans Receivable') { print ASSETS "\n", sprintf($formatStrTotal, "TOTAL ASSETS", Commify($tot)), "\n\nLIABILITIES\n\n"; my $totLiabilities = $ZERO; -foreach my $item ('Accounts Payable', 'Liabilities, Credit Cards', 'Accrued Expenses', +foreach my $item ('Accounts Payable', 'Accrued Expenses', + 'Liabilities, Credit Cards', 'Liabilities, Other', 'Unearned Income, Conference Registration', 'Unearned Income, Other') { next if $reportFields{$item}{total} == $ZERO; print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); @@ -157,6 +160,7 @@ die "Cash+accounts receivable total does not equal net assets and liabilities to $reportFields{'Unearned Income, Conference Registration'}{total} + $reportFields{'Unearned Income, Other'}{total} + $reportFields{'Liabilities, Credit Cards'}{total} + + $reportFields{'Liabilities, Other'}{total} + $reportFields{'Total Net Assets'}{total})); die "Total net assets doesn't equal sum of restricted and unrestricted ones!" -- cgit v1.2.3 From 23dd0899f2634cad221b1859f127a0a6c96d62a2 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 08:48:32 -0500 Subject: Allow for one penny margin of error on totals. --- contrib/non-profit-audit-reports/summary-reports.plx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 14923a42..875f89be 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -44,6 +44,7 @@ sub ParseNumber($) { } Math::BigFloat->precision(-2); my $ZERO = Math::BigFloat->new("0.00"); +my $ONE_PENNY = Math::BigFloat->new("0.01"); if (@ARGV < 2) { print STDERR "usage: $0 \n"; @@ -153,20 +154,20 @@ print STDERR "\n"; die "unable to write to Assets-and-liabilities.txt: $!" unless ($? == 0); die "Cash+accounts receivable total does not equal net assets and liabilities total" - if ( ($reportFields{'Cash'}{total} + $reportFields{'Accounts Receivable'}{total} - + $reportFields{'Loans Receivable'}{total}) != - ($reportFields{'Accounts Payable'}{total} + + if (abs( ($reportFields{'Cash'}{total} + $reportFields{'Accounts Receivable'}{total} + + $reportFields{'Loans Receivable'}{total})) - + abs($reportFields{'Accounts Payable'}{total} + $reportFields{'Accrued Expenses'}{total} + $reportFields{'Unearned Income, Conference Registration'}{total} + $reportFields{'Unearned Income, Other'}{total} + $reportFields{'Liabilities, Credit Cards'}{total} + $reportFields{'Liabilities, Other'}{total} + - $reportFields{'Total Net Assets'}{total})); + $reportFields{'Total Net Assets'}{total}) > $ONE_PENNY); die "Total net assets doesn't equal sum of restricted and unrestricted ones!" - if ($reportFields{'Total Net Assets'}{total} != - $reportFields{'Unrestricted Net Assets'}{total} + - $reportFields{'Temporarily Restricted Net Assets'}{total}); + if (abs($reportFields{'Total Net Assets'}{total}) - + abs($reportFields{'Unrestricted Net Assets'}{total} + + $reportFields{'Temporarily Restricted Net Assets'}{total}) > $ONE_PENNY); ############################################################################### # -- cgit v1.2.3 From e0df353ca37e4601921341a692300754186c8e6e Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 08:53:02 -0500 Subject: Call a Balance Sheet, a Balance Sheet. :) --- contrib/non-profit-audit-reports/summary-reports.plx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 875f89be..27a8d210 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -113,43 +113,43 @@ foreach my $item (keys %reportFields) { print STDERR "$item: $reportFields{$item}{total}\n" if $VERBOSE; } -open(ASSETS, ">", "assets-and-liabilities.txt") - or die "unable to open assets-and-liabilities.txt for writing: $!"; +open(BALANCE_SHEET, ">", "balance-sheet.txt") + or die "unable to open balance-sheet.txt for writing: $!"; -print ASSETS "ASSETS\n\n"; +print BALANCE_SHEET "ASSETS\n\n"; my $formatStr = " %-42s \$%13s\n"; my $formatStrTotal = "%-45s \$%13s\n"; my $tot = $ZERO; foreach my $item ('Cash', 'Accounts Receivable', 'Loans Receivable') { next if $reportFields{$item}{total} == $ZERO; - print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); + print BALANCE_SHEET sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); $tot += $reportFields{$item}{total}; } -print ASSETS "\n", sprintf($formatStrTotal, "TOTAL ASSETS", Commify($tot)), "\n\nLIABILITIES\n\n"; +print BALANCE_SHEET "\n", sprintf($formatStrTotal, "TOTAL ASSETS", Commify($tot)), "\n\nLIABILITIES\n\n"; my $totLiabilities = $ZERO; foreach my $item ('Accounts Payable', 'Accrued Expenses', 'Liabilities, Credit Cards', 'Liabilities, Other', 'Unearned Income, Conference Registration', 'Unearned Income, Other') { next if $reportFields{$item}{total} == $ZERO; - print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); + print BALANCE_SHEET sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); $totLiabilities += $reportFields{$item}{total}; } -print ASSETS "\n", sprintf($formatStr, "TOTAL LIABILTIES", Commify($totLiabilities)), +print BALANCE_SHEET "\n", sprintf($formatStr, "TOTAL LIABILTIES", Commify($totLiabilities)), "\n\nNET ASSETS\n\n"; my $totNetAssets = $ZERO; foreach my $item ('Unrestricted Net Assets', 'Temporarily Restricted Net Assets') { next if $reportFields{$item}{total} == $ZERO; - print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); + print BALANCE_SHEET sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); $totNetAssets += $reportFields{$item}{total}; } -print ASSETS "\n", sprintf($formatStr, "TOTAL NET ASSETS", Commify($totNetAssets)), "\n\n", +print BALANCE_SHEET "\n", sprintf($formatStr, "TOTAL NET ASSETS", Commify($totNetAssets)), "\n\n", sprintf($formatStrTotal, "TOTAL LIABILITIES AND NET ASSETS", Commify($totNetAssets + $totLiabilities)); -close ASSETS; +close BALANCE_SHEET; print STDERR "\n"; die "unable to write to Assets-and-liabilities.txt: $!" unless ($? == 0); -- cgit v1.2.3 From 239df56cfba6ad715f4fc63f9fde6dd968e973cd Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 09:01:19 -0500 Subject: Output should include a heading and an ending date. --- contrib/non-profit-audit-reports/summary-reports.plx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 27a8d210..c41fee50 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -24,6 +24,7 @@ use strict; use warnings; use Math::BigFloat; +use Date::Manip; my $VERBOSE = 0; my $DEBUG = 0; @@ -113,10 +114,16 @@ foreach my $item (keys %reportFields) { print STDERR "$item: $reportFields{$item}{total}\n" if $VERBOSE; } +my $err; open(BALANCE_SHEET, ">", "balance-sheet.txt") or die "unable to open balance-sheet.txt for writing: $!"; -print BALANCE_SHEET "ASSETS\n\n"; +print BALANCE_SHEET " BALANCE SHEET\n", + " Ending ", + UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 day"), \$err), + "%B %e, %Y\n"), + "\n\nASSETS\n\n"; +die "Date calculation error" if ($err); my $formatStr = " %-42s \$%13s\n"; my $formatStrTotal = "%-45s \$%13s\n"; -- cgit v1.2.3 From fe608b12e2a3b774bc7e56b40d95444bcf0d476e Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 09:02:35 -0500 Subject: Remove cruft cut-and-pasted from another script. --- contrib/non-profit-audit-reports/summary-reports.plx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index c41fee50..154662f1 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -53,11 +53,6 @@ if (@ARGV < 2) { } my($startDate, $endDate, @mainLedgerOptions) = @ARGV; -# First, get fund list from ending balance -my(@ledgerOptions) = (@mainLedgerOptions, - '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-S', 'T', '-s', - 'd', 'T', '-e', $endDate, 'bal', '/^Assets/'); - my %reportFields = ('Cash' => { args => [ '-e', $endDate, 'bal', '/^Assets/' ] }, 'Accounts Receivable' => {args => [ '-e', $endDate, 'bal', '/^Accrued:Accounts Receivable/' ]}, -- cgit v1.2.3 From 76292d08d92365a10964255a01a60ee1f6aa7448 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 09:07:12 -0500 Subject: Calculate dates in a reusable way throughout script. --- contrib/non-profit-audit-reports/summary-reports.plx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 154662f1..b49e6bdd 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -53,6 +53,14 @@ if (@ARGV < 2) { } my($startDate, $endDate, @mainLedgerOptions) = @ARGV; +my $err; +my $formattedEndDate = UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 day"), \$err), + "%B %e, %Y"); +die "Date calculation error on $endDate" if ($err); + +my $formattedStartDate = UnixDate(ParseDate($endDate), "%B %e, %Y"), +die "Date calculation error on $startDate" if ($err); + my %reportFields = ('Cash' => { args => [ '-e', $endDate, 'bal', '/^Assets/' ] }, 'Accounts Receivable' => {args => [ '-e', $endDate, 'bal', '/^Accrued:Accounts Receivable/' ]}, @@ -109,16 +117,12 @@ foreach my $item (keys %reportFields) { print STDERR "$item: $reportFields{$item}{total}\n" if $VERBOSE; } -my $err; open(BALANCE_SHEET, ">", "balance-sheet.txt") or die "unable to open balance-sheet.txt for writing: $!"; print BALANCE_SHEET " BALANCE SHEET\n", - " Ending ", - UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 day"), \$err), - "%B %e, %Y\n"), + " Ending ", $formattedEndDate, "\n", "\n\nASSETS\n\n"; -die "Date calculation error" if ($err); my $formatStr = " %-42s \$%13s\n"; my $formatStrTotal = "%-45s \$%13s\n"; -- cgit v1.2.3 From 13c8a1fb569ddd83a65645e40c7f0c83b3a725eb Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 09:53:05 -0500 Subject: Beginnings of income report. --- contrib/non-profit-audit-reports/summary-reports.plx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index b49e6bdd..9cb2aece 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -175,9 +175,26 @@ die "Total net assets doesn't equal sum of restricted and unrestricted ones!" abs($reportFields{'Unrestricted Net Assets'}{total} + $reportFields{'Temporarily Restricted Net Assets'}{total}) > $ONE_PENNY); + +my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', + '-b', $startDate, '-e', $endDate, + '-F', '%-.80A %22.108t\n', '-s', + 'reg', '^Income'); + +open(FILE, "-|", @fullCommand) + or die "unable to run command ledger command: @fullCommand: $!"; + +open(INCOME, ">", "income.txt") + or die "unable to open balance-sheet.txt for writing: $!"; + +print INCOME " INCOME\n", + " Between $formattedStartDate and $formattedEndDate\n\n"; + +foreach my $line () { print INCOME $line; } +close INCOME; +die "unable to write to income.txt: $!" unless ($? == 0); ############################################################################### # # Local variables: # compile-command: "perl -c summary-reports.plx" # End: - -- cgit v1.2.3 From 7467917c7b93a39bbd90ccb059a9b55fdfbe52c4 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sat, 24 Nov 2012 13:57:06 -0500 Subject: Generate income report. --- .../non-profit-audit-reports/summary-reports.plx | 81 ++++++++++++++++++---- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 9cb2aece..a30868d5 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -57,8 +57,7 @@ my $err; my $formattedEndDate = UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 day"), \$err), "%B %e, %Y"); die "Date calculation error on $endDate" if ($err); - -my $formattedStartDate = UnixDate(ParseDate($endDate), "%B %e, %Y"), +my $formattedStartDate = UnixDate(ParseDate($startDate), "%B %e, %Y"); die "Date calculation error on $startDate" if ($err); my %reportFields = @@ -157,7 +156,7 @@ print BALANCE_SHEET "\n", sprintf($formatStr, "TOTAL NET ASSETS", Commify($totNe close BALANCE_SHEET; print STDERR "\n"; -die "unable to write to Assets-and-liabilities.txt: $!" unless ($? == 0); +die "unable to write to balance-sheet.txt: $!" unless ($? == 0); die "Cash+accounts receivable total does not equal net assets and liabilities total" if (abs( ($reportFields{'Cash'}{total} + $reportFields{'Accounts Receivable'}{total} @@ -176,23 +175,77 @@ die "Total net assets doesn't equal sum of restricted and unrestricted ones!" $reportFields{'Temporarily Restricted Net Assets'}{total}) > $ONE_PENNY); -my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', - '-b', $startDate, '-e', $endDate, - '-F', '%-.80A %22.108t\n', '-s', - 'reg', '^Income'); +my %incomeGroups = ('INTEREST INCOME' => { args => ['/^Income.*Interest/' ] }, + 'DONATIONS' => { args => [ '/^Income.*Donation/' ] }, + 'BOOK ROYALTIES & AFFILIATE PROGRAMS' => + { args => [ '/^Income.*(Royalt|Affilate)/' ] }, + 'CONFERENCES, REGISTRATION' => {args => [ '/^Income.*Conf.*Reg/' ] }, + 'CONFERENCES, RELATED BUSINESS INCOME' => { args => [ '/^Income.*(Booth|RBI)/'] }, + 'LICENSE ENFORCEMENT' => { args => [ '/^Income.*Enforce/' ]}, + 'TRADEMARKS' => {args => [ '/^Income.*Trademark/' ]}, + 'ADVERSITING' => {args => [ '/^Income.*Advertising/' ]}); + +my @otherArgs; +foreach my $type (keys %incomeGroups) { + @otherArgs = ("/^Income/") if @otherArgs == 0; + push(@otherArgs, 'and', 'not', @{$incomeGroups{$type}{args}}); +} +$incomeGroups{"OTHER"}{args} = \@otherArgs; +$incomeGroups{"TOTAL"}{args} = ['/^Income/']; + +open(INCOME, ">", "income.txt") or die "unable to open income.txt for writing: $!"; -open(FILE, "-|", @fullCommand) - or die "unable to run command ledger command: @fullCommand: $!"; +foreach my $type (keys %incomeGroups) { + my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', + '-b', $startDate, '-e', $endDate, + '-F', '%-.80A %22.108t\n', '-s', + 'reg', @{$incomeGroups{$type}{args}}); -open(INCOME, ">", "income.txt") - or die "unable to open balance-sheet.txt for writing: $!"; + open(FILE, "-|", @fullCommand) + or die "unable to run command ledger command: @fullCommand: $!"; + + print STDERR ($VERBOSE ? "Running: @fullCommand\n" : "."); + $incomeGroups{$type}{total} = $ZERO; + $incomeGroups{$type}{output} = ""; + + foreach my $line () { + die "Unable to parse output line from second funds command: $line" + unless $line =~ /^\s*([^\$]+)\s+\$\s*([\-\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $account =~ s/\s+$//; + next if $account =~ /\/ and (abs($amount) <= 0.02); + die "Weird account found, $account with amount of $amount in income command\n" + unless $account =~ s/^\s*Income://; + + $incomeGroups{$type}{total} += $amount; + $incomeGroups{$type}{output} .= " $line"; + } +} print INCOME " INCOME\n", " Between $formattedStartDate and $formattedEndDate\n\n"; -foreach my $line () { print INCOME $line; } -close INCOME; -die "unable to write to income.txt: $!" unless ($? == 0); + +my $overallTotal = $ZERO; + +$formatStrTotal = "%-90s \$%14s\n"; +foreach my $type ('DONATIONS', 'LICENSE ENFORCEMENT', + 'CONFERENCES, REGISTRATION', 'CONFERENCES, RELATED BUSINESS INCOME', + 'BOOK ROYALTIES & AFFILIATE PROGRAMS', 'ADVERSITING', + 'TRADEMARKS', 'INTEREST INCOME', 'OTHER') { + print INCOME "\n$type\n", + $incomeGroups{$type}{output}, "\n", + sprintf($formatStrTotal, "TOTAL $type:", Commify($incomeGroups{$type}{total})); + $overallTotal += $incomeGroups{$type}{total}; +} +print INCOME "\n\n\n", sprintf($formatStrTotal, "OVERALL TOTAL:", Commify($overallTotal)); + +close INCOME; die "unable to write to income.txt: $!" unless ($? == 0); + +die "calculated total of $overallTotal does equal $incomeGroups{TOTAL}{total}" + if (abs($overallTotal) - abs($incomeGroups{TOTAL}{total}) > $ONE_PENNY); + ############################################################################### # # Local variables: -- cgit v1.2.3 From 470ed356be4b92bb2967eab281d187f03691ad48 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 08:41:14 -0500 Subject: Expenses report completed. --- .../non-profit-audit-reports/summary-reports.plx | 101 +++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index a30868d5..7b521ccb 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -234,6 +234,7 @@ foreach my $type ('DONATIONS', 'LICENSE ENFORCEMENT', 'CONFERENCES, REGISTRATION', 'CONFERENCES, RELATED BUSINESS INCOME', 'BOOK ROYALTIES & AFFILIATE PROGRAMS', 'ADVERSITING', 'TRADEMARKS', 'INTEREST INCOME', 'OTHER') { + next if ($incomeGroups{$type}{output} =~ /^\s*$/ and $incomeGroups{$type}{total} == $ZERO); print INCOME "\n$type\n", $incomeGroups{$type}{output}, "\n", sprintf($formatStrTotal, "TOTAL $type:", Commify($incomeGroups{$type}{total})); @@ -246,6 +247,106 @@ close INCOME; die "unable to write to income.txt: $!" unless ($? == 0); die "calculated total of $overallTotal does equal $incomeGroups{TOTAL}{total}" if (abs($overallTotal) - abs($incomeGroups{TOTAL}{total}) > $ONE_PENNY); +print STDERR "\n"; + +my %expenseGroups = ('BANKING FEES' => { regex => '^Expenses.*(Banking Fees|Currency Conversion)' }, + 'COMPUTING, HOSTING AND EQUIPMENT' => { regex => '^Expenses.*(Hosting|Computer Equipment)' }, + 'CONFERENCES' => { regex => '^Expenses.*(Conferences|Sprint)' }, + 'DEVELOPER MENTORING' => {regex => '^Expenses.*Mentor' }, + 'LICENSE ENFORCEMENT' => { regex => '^Expenses.*Enforce' }, + 'ACCOUNTING' => { regex => '^Expenses.*(Accounting|Annual Audit)' }, + 'PAYROLL' => { regex => '^Expenses.*Payroll' }, + 'OFFICE' => { regex => '^Expenses.*(Office|Phones)' }, + 'RENT' => { regex => '^Expenses.*Rent' }, + 'SOFTWARE DEVELOPMENT' => { regex => '^Expenses.*Development' }, + 'OTHER PROGRAM ACTIVITY' => {regex => '^Expenses.*Gould' }, + 'ADVOCACY AND PROMOTION' => {regex => '^Expenses.*(Slipstream|Advocacy Merchandise|Promotional)' }, + 'ADVERSITING' => {regex => '^Expenses.*Advertising' }); + +foreach my $type (keys %expenseGroups, 'TRAVEL') { + $expenseGroups{$type}{total} = $ZERO; + $expenseGroups{$type}{output} = ""; +} + +open(EXPENSE, ">", "expense.txt") or die "unable to open expense.txt for writing: $!"; + +my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', + '-b', $startDate, '-e', $endDate, + '-F', '%-.80A %22.108t\n', '-s', + 'reg', '/^Expenses/'); + +open(FILE, "-|", @fullCommand) + or die "unable to run command ledger command: @fullCommand: $!"; + +print STDERR ($VERBOSE ? "Running: @fullCommand\n" : "."); + +my $firstTotal = $ZERO; +foreach my $line () { + die "Unable to parse output line from second funds command: $line" + unless $line =~ /^\s*([^\$]+)\s+\$\s*([\-\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $account =~ s/\s+$//; + next if $account =~ /\/ and (abs($amount) <= 0.02); + die "Weird account found, $account, with amount of $amount in expenses command\n" + unless $account =~ /^\s*Expenses:/; + + if ($account =~ /Travel/) { + $expenseGroups{'TRAVEL'}{total} += $amount; + $expenseGroups{'TRAVEL'}{output} .= " $line"; + } else { + my $taken = 0; + foreach my $type (keys %expenseGroups) { + last if $taken; + next if $type eq 'TRAVEL' or $type eq 'OTHER'; + next unless $line =~ /$expenseGroups{$type}{regex}/; + $taken = 1; + $expenseGroups{$type}{total} += $amount; + $expenseGroups{$type}{output} .= " $line"; + } + if (not $taken) { + $expenseGroups{'OTHER'}{total} += $amount; + $expenseGroups{'OTHER'}{output} .= " $line"; + } + } + $firstTotal += $amount; +} +print EXPENSE " EXPENSES\n", + " Between $formattedStartDate and $formattedEndDate\n\n"; +$overallTotal = $ZERO; +$formatStrTotal = "%-90s \$%14s\n"; + +my %verifyAllGroups; +foreach my $key (keys %expenseGroups) { + $verifyAllGroups{$key} = 1; +} +foreach my $type ('PAYROLL', 'SOFTWARE DEVELOPMENT', 'LICENSE ENFORCEMENT', 'CONFERENCES', + 'DEVELOPER MENTORING', 'TRAVEL', 'BANKING FEES', 'ADVOCACY AND PROMOTION', + 'COMPUTING, HOSTING AND EQUIPMENT', 'ACCOUNTING', + 'OFFICE', 'RENT', 'ADVERSITING', 'OTHER PROGRAM ACTIVITY', 'OTHER') { + delete $verifyAllGroups{$type}; + + die "$type is not defined!" if not defined $expenseGroups{$type}; + next if ($expenseGroups{$type}{output} =~ /^\s*$/ and $expenseGroups{$type}{total} == $ZERO); + + print EXPENSE "\n$type\n", + $expenseGroups{$type}{output}, "\n", + sprintf($formatStrTotal, "TOTAL $type:", Commify($expenseGroups{$type}{total})); + $overallTotal += $expenseGroups{$type}{total}; +} + +print EXPENSE "\n\n\n", sprintf($formatStrTotal, "OVERALL TOTAL:", Commify($overallTotal)); + +close EXPENSE; die "unable to write to expense.txt: $!" unless ($? == 0); + +die "GROUPS NOT INCLUDED : ", join(keys(%verifyAllGroups), ", "), "\n" + unless (keys %verifyAllGroups == 0); + +die "calculated total of $overallTotal does equal $firstTotal" + if (abs($overallTotal) - abs($firstTotal) > $ONE_PENNY); + +print STDERR "\n"; + ############################################################################### # # Local variables: -- cgit v1.2.3 From ca359f0606d80160e075100a290e8d05312ac7c9 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 4 Dec 2011 19:47:30 -0500 Subject: First attempt at this cash-receipts-and-disbursments-journals.plx script, based on general-ledger-report.plx The general-ledger-report.plx was originally found in this repository: http://gitorious.org/bkuhn/small-hacks/blobs/master/general-ledger-report.plx And these early commits on cash-receipts-and-disbursments-journals.plx were fro that repository as well, in: http://gitorious.org/bkuhn/small-hacks/blobs/master/cash-receipts-and-disbursments-journals.plx --- .../cash-receipts-and-disbursments-journals.plx | 131 +++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx new file mode 100644 index 00000000..6b704c08 --- /dev/null +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -0,0 +1,131 @@ +#!/usr/bin/perl +# cash-receipts-and-disbursments-journals -*- Perl -*- +# +# Script to generate a General Ledger report that accountants like +# using Ledger. +# +# Copyright (C) 2011, Bradley M. Kuhn +# +# This program gives you software freedom; you can copy, modify, convey, +# and/or redistribute it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program in a file called 'GPLv3'. If not, write to the: +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor +# Boston, MA 02110-1301, USA. + +use strict; +use warnings; + +use Math::BigFloat; +use Date::Manip; + +my $LEDGER_CMD = "/usr/bin/ledger"; + +my $ACCT_WIDTH = 75; + +sub ParseNumber($) { + $_[0] =~ s/,//g; + return Math::BigFloat->new($_[0]); +} + +sub LedgerAcctToFilename($) { + $_[0] =~ s/ /-/g; + $_[0] =~ s/:/-/g; + returen $_[0]; +} + +Math::BigFloat->precision(-2); +my $ZERO = Math::BigFloat->new("0.00"); + +if (@ARGV < 2) { + print STDERR "usage: $0 \n"; + exit 1; +} + +my($beginDate, $endDate, @otherLedgerOpts) = @ARGV; + +my(@chartOfAccountsOpts) = ('--wide-register-format', "%150A\n", '-w', '-s', + '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg'); + +open(CHART_DATA, "-|", $LEDGER_CMD, @chartOfAccountsOpts) + or die "Unable to run $LEDGER_CMD @chartOfAccountsOpts: $!"; + +my @accounts; +while (my $line = ) { + chomp $line; + $line =~ s/^\s*//; $line =~ s/\s*$//; + push(@accounts, $line); + +} +close(CHART_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; + +my $formattedEndDate = new Date::Manip::Date; +die "badly formatted end date, $endDate" if $formattedEndDate->parse($endDate); +my $oneDayLess = new Date::Manip::Delta; +die "bad one day less" if $oneDayLess->parse("- 1 day"); +$formattedEndDate = $formattedEndDate->calc($oneDayLess); +$formattedEndDate = $formattedEndDate->printf("%Y/%m/%d"); + +foreach my $acct (@accounts) { + next unless ($acct =~ /^(?:Assets|Liabilities)/); + + my $acctFilename = LedgerAcctToFilename($acct); + + foreach my $typeData ({ name => 'disbursements', query => 'a<=0' }, + { name => 'receipts', query => 'a>0' }) { + my $fileNameBase = $acctFilename . '-' . $typeData->{name}; + + print TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; + print CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; + print CSV_OUT '"DATE","CHECK NUM","NAME","ACCOUNT","AMOUNT"', "\n"; + my @entryLedgerOpts = ('-l', $typeData->{query}, + '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'print', $acct); + + open(ENTRY_DATA, "-|", $LEDGER_CMD, @entryLedgerOpts) + or die "Unable to run $LEDGER_CMD @entryLedgerOpts: $!"; + + my $tempFile = "tmp$$"; + + open(ENTRY_OUT, ">", $tempFile) or die "Unable to write $tempFile: $!"; + + while (my $line = ) { print ENTRY_OUT $line; } + close(ENTRY_DATA); die "Error reading ledger output for entries: $!" unless $? == 0; + close(ENTRY_OUT); die "Error writing ledger output for entries to temp file, $tempFile: $!" unless $? == 0; + + my @txtRegLedgerOpts = ('-f', $tempFile, '--wide-register-format', + "%D %-.70P %-.10C %-.80A %18t\n%/%68|%15|%-.80A %18t\n", '-w', '--sort', 'd', + '-b', $beginDate, '-e', $endDate, 'reg'); + + my @csvRegLedgerOpts = ('-f', $tempFile, '--wide-register-format', + '"%D","%C","%P",%A","%t"\n%/|"","","","%A","%t"\n"', '-w', '--sort', 'd', + '-b', $beginDate, '-e', $endDate, 'reg'); + + open(TXT_DATA, "-|", $LEDGER_CMD, @txtRegLedgerOpts) + or die "unable to run ledger command for $fileNameBase.txt: $!"; + + while (my $line = ) { print TEXT_OUT $line; } + close(TXT_DATA); die "Error read from txt ledger command $!" unless $? == 0; + close(TEXT_OUT); die "Error read write text out to $fileNameBase.txt: $!" unless $? == 0; + + open(CSV_DATA, "-|", $LEDGER_CMD, @csvRegLedgerOpts) + or die "unable to run ledger command for $fileNameBase.csv: $!"; + + while (my $line = ) { print CSV_OUT $line; } + close(CSV_DATA); die "Error read from csv ledger command $!" unless $? == 0; + close(CSV_OUT); die "Error read write csv out to $fileNameBase.csv: $!" unless $? == 0; + } +} +############################################################################### +# +# Local variables: +# compile-command: "perl -c cash-receipts-and-disbursments-journals.plx" +# End: + -- cgit v1.2.3 From d817000b828c8ce1808d95cb7fae259fe05630ec Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 4 Dec 2011 20:06:32 -0500 Subject: Various changes to get the script working. --- .../cash-receipts-and-disbursments-journals.plx | 30 ++++++++++++++-------- 1 file changed, 20 insertions(+), 10 deletions(-) mode change 100644 => 100755 contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx old mode 100644 new mode 100755 index 6b704c08..5dbe7033 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -26,6 +26,7 @@ use warnings; use Math::BigFloat; use Date::Manip; +use File::Temp qw/tempfile/; my $LEDGER_CMD = "/usr/bin/ledger"; @@ -37,9 +38,10 @@ sub ParseNumber($) { } sub LedgerAcctToFilename($) { - $_[0] =~ s/ /-/g; - $_[0] =~ s/:/-/g; - returen $_[0]; + my $x = $_[0]; + $x =~ s/ /-/g; + $x =~ s/:/-/g; + return $x; } Math::BigFloat->precision(-2); @@ -83,36 +85,40 @@ foreach my $acct (@accounts) { { name => 'receipts', query => 'a>0' }) { my $fileNameBase = $acctFilename . '-' . $typeData->{name}; + open(TEXT_OUT, ">", "$fileNameBase.txt") or die "unable to open $fileNameBase.txt: $!"; + open(CSV_OUT, ">", "$fileNameBase.csv") or die "unable to open $fileNameBase.csv: $!"; + print TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; print CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; print CSV_OUT '"DATE","CHECK NUM","NAME","ACCOUNT","AMOUNT"', "\n"; + my @entryLedgerOpts = ('-l', $typeData->{query}, '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'print', $acct); open(ENTRY_DATA, "-|", $LEDGER_CMD, @entryLedgerOpts) or die "Unable to run $LEDGER_CMD @entryLedgerOpts: $!"; - my $tempFile = "tmp$$"; + my($tempFH, $tempFile) = tempfile("cashreportsXXXXXXXX", TMPDIR => 1); - open(ENTRY_OUT, ">", $tempFile) or die "Unable to write $tempFile: $!"; - - while (my $line = ) { print ENTRY_OUT $line; } + while (my $line = ) { print $tempFH $line; } close(ENTRY_DATA); die "Error reading ledger output for entries: $!" unless $? == 0; - close(ENTRY_OUT); die "Error writing ledger output for entries to temp file, $tempFile: $!" unless $? == 0; + $tempFH->close() or die "Error writing ledger output for entries to temp file, $tempFile: $!"; + + goto SKIP_REGISTER_COMMANDS if (-z $tempFile); my @txtRegLedgerOpts = ('-f', $tempFile, '--wide-register-format', "%D %-.70P %-.10C %-.80A %18t\n%/%68|%15|%-.80A %18t\n", '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, 'reg'); my @csvRegLedgerOpts = ('-f', $tempFile, '--wide-register-format', - '"%D","%C","%P",%A","%t"\n%/|"","","","%A","%t"\n"', '-w', '--sort', 'd', + '"%D","%C","%P",%A","%t"\n%/"","","","%A","%t"\n', '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, 'reg'); + open(TXT_DATA, "-|", $LEDGER_CMD, @txtRegLedgerOpts) or die "unable to run ledger command for $fileNameBase.txt: $!"; while (my $line = ) { print TEXT_OUT $line; } - close(TXT_DATA); die "Error read from txt ledger command $!" unless $? == 0; close(TEXT_OUT); die "Error read write text out to $fileNameBase.txt: $!" unless $? == 0; open(CSV_DATA, "-|", $LEDGER_CMD, @csvRegLedgerOpts) @@ -120,7 +126,11 @@ foreach my $acct (@accounts) { while (my $line = ) { print CSV_OUT $line; } close(CSV_DATA); die "Error read from csv ledger command $!" unless $? == 0; + + SKIP_REGISTER_COMMANDS: + close(TXT_DATA); die "Error read from txt ledger command $!" unless $? == 0; close(CSV_OUT); die "Error read write csv out to $fileNameBase.csv: $!" unless $? == 0; + unlink($tempFile); } } ############################################################################### -- cgit v1.2.3 From c7a798be8e7f2ac4c10c70b732cdc20f768eb3c2 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 6 Dec 2011 09:19:58 -0500 Subject: Fixed output. --- .../cash-receipts-and-disbursments-journals.plx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx index 5dbe7033..c1c8d833 100755 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -111,7 +111,7 @@ foreach my $acct (@accounts) { '-b', $beginDate, '-e', $endDate, 'reg'); my @csvRegLedgerOpts = ('-f', $tempFile, '--wide-register-format', - '"%D","%C","%P",%A","%t"\n%/"","","","%A","%t"\n', '-w', '--sort', 'd', + '\n"%D","%C","%P","%A","%t"\n%/"","","","%A","%t"\n', '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, 'reg'); -- cgit v1.2.3 From 586c4eb3b3b93faf048df2e31c339c7459e3df9e Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 12:18:26 -0500 Subject: Use -V to normalize currencies in general-ledger report. --- contrib/non-profit-audit-reports/general-ledger-report.plx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 07f0b9da..dc48a509 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -48,7 +48,7 @@ open(MANIFEST, ">", "MANIFEST") or die "Unable to open MANIFEST for writing: $!" my($beginDate, $endDate, @otherLedgerOpts) = @ARGV; -my(@chartOfAccountsOpts) = ('-F', "%150A\n", '-w', '-s', +my(@chartOfAccountsOpts) = ('-V', '-F', "%150A\n", '-w', '-s', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg'); open(CHART_DATA, "-|", $LEDGER_CMD, @chartOfAccountsOpts) @@ -97,7 +97,7 @@ print MANIFEST "general-ledger.csv\n"; foreach my $acct (@sortedAccounts) { print GL_TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; - my @acctLedgerOpts = ('-F', + my @acctLedgerOpts = ('-V', '-F', "%(date) %-.10C %-.80P %-.80N %18t %18T\n", '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); open(GL_TEXT_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) @@ -118,7 +118,7 @@ foreach my $acct (@sortedAccounts) { $formatString .= "\n"; print GL_CSV_OUT "\n"; - @acctLedgerOpts = ('-F', $formatString, '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); + @acctLedgerOpts = ('-V', '-F', $formatString, '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); open(GL_CSV_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!"; -- cgit v1.2.3 From 3e634b6d45ef1991350141df22ed038bae8de07e Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 12:18:58 -0500 Subject: Ignore accounts. --- contrib/non-profit-audit-reports/general-ledger-report.plx | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index dc48a509..192be350 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -57,6 +57,7 @@ open(CHART_DATA, "-|", $LEDGER_CMD, @chartOfAccountsOpts) my @accounts; while (my $line = ) { chomp $line; + next if $line =~ /^\s*\<\s*Adjustment\s*\>\s*$/; $line =~ s/^\s*//; $line =~ s/\s*$//; push(@accounts, $line); -- cgit v1.2.3 From 4318c11fd9b94a3508fac7cd7724407f2f7f6645 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 12:19:44 -0500 Subject: Expense report favors Conferences first, then takes Travel as if it were an Other category only after categories have been handled. --- .../non-profit-audit-reports/summary-reports.plx | 29 +++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 7b521ccb..7d2267d6 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -291,20 +291,21 @@ foreach my $line () { die "Weird account found, $account, with amount of $amount in expenses command\n" unless $account =~ /^\s*Expenses:/; - if ($account =~ /Travel/) { - $expenseGroups{'TRAVEL'}{total} += $amount; - $expenseGroups{'TRAVEL'}{output} .= " $line"; - } else { - my $taken = 0; - foreach my $type (keys %expenseGroups) { - last if $taken; - next if $type eq 'TRAVEL' or $type eq 'OTHER'; - next unless $line =~ /$expenseGroups{$type}{regex}/; - $taken = 1; - $expenseGroups{$type}{total} += $amount; - $expenseGroups{$type}{output} .= " $line"; - } - if (not $taken) { + my $taken = 0; + # Note: Prioritize to put things under conference expenses if they were for a conference. + foreach my $type ('CONFERENCES', keys %expenseGroups) { + last if $taken; + next if $type eq 'TRAVEL' or $type eq 'OTHER'; + next unless $line =~ /$expenseGroups{$type}{regex}/; + $taken = 1; + $expenseGroups{$type}{total} += $amount; + $expenseGroups{$type}{output} .= " $line"; + } + if (not $taken) { + if ($account =~ /Travel/) { + $expenseGroups{'TRAVEL'}{total} += $amount; + $expenseGroups{'TRAVEL'}{output} .= " $line"; + } else { $expenseGroups{'OTHER'}{total} += $amount; $expenseGroups{'OTHER'}{output} .= " $line"; } -- cgit v1.2.3 From 4f8ea18fec539c6b2e48fa7125bceaa795e899de Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 13:26:01 -0500 Subject: Support selection of string encoding. Allow command line option that permits specification of string encoding, passed to Python's unicode() function. --- contrib/non-profit-audit-reports/csv2ods.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/contrib/non-profit-audit-reports/csv2ods.py b/contrib/non-profit-audit-reports/csv2ods.py index 59571280..2b3024d4 100755 --- a/contrib/non-profit-audit-reports/csv2ods.py +++ b/contrib/non-profit-audit-reports/csv2ods.py @@ -31,7 +31,7 @@ def err(msg): print 'error: %s' % msg sys.exit(1) -def csv2ods(csvname, odsname, verbose = False): +def csv2ods(csvname, odsname, encoding='', verbose = False): if verbose: print 'converting from %s to %s' % (csvname, odsname) doc = ooolib2.Calc() @@ -56,6 +56,8 @@ def csv2ods(csvname, odsname, verbose = False): if len(fields) > 0: for col in range(len(fields)): val = fields[col] + if encoding != '': + val = unicode(val, 'utf8') if len(val) > 0 and val[0] == '$': doc.set_cell_value(col + 1, row, 'currency', val[1:]) else: @@ -92,6 +94,8 @@ def main(): help='csv file to process') parser.add_option('-o', '--ods', action='store', help='ods output filename') + parser.add_option('-e', '--encoding', action='store', + help='unicode character encoding type') (options, args) = parser.parse_args() if len(args) != 0: parser.error("not expecting extra args") @@ -104,7 +108,8 @@ def main(): print '%s: verbose mode on' % program print 'csv:', options.csv print 'ods:', options.ods - csv2ods(options.csv, options.ods, options.verbose) + print 'ods:', options.encoding + csv2ods(options.csv, options.ods, options.verbose, options.encoding) if __name__ == '__main__': main() -- cgit v1.2.3 From df6428f549a3a82d52bb18b1e71b468e35b2c444 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 13:26:27 -0500 Subject: Adapted for use with Ledger 3. Includes forcing of -V so all currency is in default. --- .../cash-receipts-and-disbursments-journals.plx | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx index c1c8d833..346e4064 100755 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -4,7 +4,7 @@ # Script to generate a General Ledger report that accountants like # using Ledger. # -# Copyright (C) 2011, Bradley M. Kuhn +# Copyright (C) 2011, 2012 Bradley M. Kuhn # # This program gives you software freedom; you can copy, modify, convey, # and/or redistribute it under the terms of the GNU General Public License @@ -28,7 +28,7 @@ use Math::BigFloat; use Date::Manip; use File::Temp qw/tempfile/; -my $LEDGER_CMD = "/usr/bin/ledger"; +my $LEDGER_CMD = "/usr/local/bin/ledger"; my $ACCT_WIDTH = 75; @@ -54,7 +54,7 @@ if (@ARGV < 2) { my($beginDate, $endDate, @otherLedgerOpts) = @ARGV; -my(@chartOfAccountsOpts) = ('--wide-register-format', "%150A\n", '-w', '-s', +my(@chartOfAccountsOpts) = ('-V', '-F', "%150A\n", '-w', '-s', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg'); open(CHART_DATA, "-|", $LEDGER_CMD, @chartOfAccountsOpts) @@ -90,7 +90,7 @@ foreach my $acct (@accounts) { print TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; print CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; - print CSV_OUT '"DATE","CHECK NUM","NAME","ACCOUNT","AMOUNT"', "\n"; + print CSV_OUT '"DATE","CHECK NUM","NAME","ACCOUNT","AMOUNT"'; my @entryLedgerOpts = ('-l', $typeData->{query}, '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'print', $acct); @@ -106,12 +106,18 @@ foreach my $acct (@accounts) { goto SKIP_REGISTER_COMMANDS if (-z $tempFile); - my @txtRegLedgerOpts = ('-f', $tempFile, '--wide-register-format', - "%D %-.70P %-.10C %-.80A %18t\n%/%68|%15|%-.80A %18t\n", '-w', '--sort', 'd', + my @txtRegLedgerOpts = ('-f', $tempFile, '-V', '-F', + "%(date) %-.70P %-.10C %-.80A %18t\n", '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, 'reg'); - my @csvRegLedgerOpts = ('-f', $tempFile, '--wide-register-format', - '\n"%D","%C","%P","%A","%t"\n%/"","","","%A","%t"\n', '-w', '--sort', 'd', + my $formatString = '\n"%(date)","%C","%P","%A","%t"\n%/"","","","%A","%t"'; + foreach my $tagField (qw/Receipt Invoice Statement Contract PurchaseOrder Approval Check IncomeDistributionAnalysis CurrencyRate/) { + print CSV_OUT ',"', $tagField, '"'; + $formatString .= ',"%(tag(\'' . $tagField . '\'))"'; + } + $formatString .= "\n"; + print CSV_OUT "\n"; + my @csvRegLedgerOpts = ('-f', $tempFile, '-V', '-F', $formatString, '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, 'reg'); -- cgit v1.2.3 From 10d3f5593302b07897f88d7b9c771558af4a2738 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 14:33:53 -0500 Subject: Print date in a more friendly format. Includes issue of "ends on" date being correct for mere mortals as opposed to being right for Ledger only. --- contrib/non-profit-audit-reports/fund-report.plx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index 5b74a606..0c03d009 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -24,6 +24,7 @@ use strict; use warnings; use Math::BigFloat; +use Date::Manip; my $LEDGER_CMD = "/usr/local/bin/ledger"; @@ -42,6 +43,13 @@ if (@ARGV < 2) { } my($startDate, $endDate, @mainLedgerOptions) = @ARGV; +my $err; +my $formattedEndDate = UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 day"), \$err), + "%B %e, %Y"); +die "Date calculation error on $endDate" if ($err); +my $formattedStartDate = UnixDate(ParseDate($startDate), "%B %e, %Y"); +die "Date calculation error on $startDate" if ($err); + # First, get fund list from ending balance my(@ledgerOptions) = (@mainLedgerOptions, '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-s', @@ -117,14 +125,14 @@ my($totStart, $totEnd) = ($ZERO, $ZERO); foreach my $fund (sort keys %funds) { my $sanityTotal = $funds{$fund}{starting}; - print "Fund: $fund\n", sprintf("%-35s\$%26.2f\n\n", "Balance as of $startDate:", + print "Fund: $fund\n", sprintf("%-35s\$%26.2f\n\n", "Balance as of $formattedStartDate:", $funds{$fund}{starting}); foreach my $type ('Income', 'Expenses', @possibleTypes) { my $formattedType = $type; $formattedType =~ s/^Accrued://; next if $type ne 'Income' and $type ne 'Expenses' and $funds{$fund}{$type} == $ZERO; print sprintf("%19s during period: \$%26.2f\n", $formattedType, $funds{$fund}{$type}); } - print sprintf("\n%-35s\$%26.2f\n", "Balance as of $endDate:", + print sprintf("\n%-35s\$%26.2f\n", "Balance as of $formattedEndDate:", $funds{$fund}{ending}), "\n\n"; # Santity check: if ($funds{$fund}{ending} != @@ -136,8 +144,8 @@ foreach my $fund (sort keys %funds) { $totStart += $funds{$fund}{starting}; $totEnd += $funds{$fund}{ending}; } -print "\n\n\nTotal Restricted Funds as of $startDate: ", sprintf("\$%15.2f\n", $totStart); -print "\nTotal Restricted Funds as of $endDate: ", sprintf("\$%15.2f\n", $totEnd); +print "\n\n\nTotal Restricted Funds as of $formattedStartDate: ", sprintf("\$%15.2f\n", $totStart); +print "\nTotal Restricted Funds as of $formattedStartDate: ", sprintf("\$%15.2f\n", $totEnd); ############################################################################### # # Local variables: -- cgit v1.2.3 From 32e51f65a19d030363f9c5d29472c59b2df0cccd Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 14:36:29 -0500 Subject: Verify that files are not duplicated in the MANIFEST. Keep a hash so that file output to the MANIFEST file doesn't have duplicates of the same file name in it. --- contrib/non-profit-audit-reports/general-ledger-report.plx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 192be350..d1c92975 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -96,6 +96,7 @@ print MANIFEST "general-ledger.txt\n"; open(GL_CSV_OUT, ">", "general-ledger.csv") or die "unable to write general-ledger.csv: $!"; print MANIFEST "general-ledger.csv\n"; +my %manifest; foreach my $acct (@sortedAccounts) { print GL_TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; my @acctLedgerOpts = ('-V', '-F', @@ -131,7 +132,8 @@ foreach my $acct (@sortedAccounts) { my $file = $1; next if $file =~ /^\s*$/; warn "$file does not exist and/or is not readable" unless -r $file; - print MANIFEST "$file\n"; + print MANIFEST "$file\n" if not defined $manifest{$file}; + $manifest{$file} = $line; } } close(GL_CSV_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; -- cgit v1.2.3 From 2823c99107c5ea90b70350571d03fc566021e5a1 Mon Sep 17 00:00:00 2001 From: Karl Fogel Date: Sun, 16 Dec 2012 15:31:32 -0600 Subject: Update obsolete wording in documentation for 'year' command directive. --- doc/ledger3.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index f99504f0..1c588636 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -2182,7 +2182,7 @@ This is a synonym for @code{comment} and must be closed by an @code{end} tag. @item year @c instance_t::year_directive in textual.cc Denotes the year used for all subsequent transactions that give a date -without a year. The year should appear immediately after the Y, for +without a year. The year should appear immediately after the directive, for example: @code{year 2004}. This is useful at the beginning of a file, to specify the year for that file. If all transactions specify a year, however, this command has no effect. -- cgit v1.2.3 From 269d0fdd5efe2dc9de148f845f97ad95ddc1b8e9 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 3 Jan 2013 10:39:58 -0500 Subject: Created Trial balance report for summary reports. --- .../non-profit-audit-reports/summary-reports.plx | 31 +++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 7d2267d6..ce6d56da 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -3,7 +3,7 @@ # # Script to generate end-of-year summary reports. # -# Copyright (C) 2011, 2012, Bradley M. Kuhn +# Copyright (C) 2011, 2012, 2013, Bradley M. Kuhn # # This program gives you software freedom; you can copy, modify, convey, # and/or redistribute it under the terms of the GNU General Public License @@ -348,6 +348,35 @@ die "calculated total of $overallTotal does equal $firstTotal" print STDERR "\n"; +open(TRIAL, ">", "trial-balance.txt") or die "unable to open accrued.txt for writing: $!"; + +@fullCommand = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', + '-e', $endDate, + '-F', '%-.80A %22.108t\n', '-s', + 'reg'); + +print TRIAL " TRIAL BALANCE \n", + " Ending $formattedEndDate\n\n"; + +open(FILE, "-|", @fullCommand) + or die "unable to run command ledger command: @fullCommand: $!"; + +print STDERR ($VERBOSE ? "Running: @fullCommand\n" : "."); + +my $accruedTotal = $ZERO; + +foreach my $line () { + die "Unable to parse output line from second funds command: $line" + unless $line =~ /^\s*([^\$]+)\s+\$\s*([\-\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $account =~ s/\s+$//; + next if $account =~ /\|^Equity:/ and (abs($amount) <= 0.02); + print TRIAL $line; + + $accruedTotal += $amount; +} + ############################################################################### # # Local variables: -- cgit v1.2.3 From bfdf20b31cbb60b5d92c82ecd3a5192059a0c7b1 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 3 Jan 2013 11:44:55 -0500 Subject: Updated sorting function based on advice of auditing accountants. Our auditing accounts tell us they want accounts sorted by: Assets Liabilities Net Assets Income Expenses in a general ledger report. Generally, I think we should just apply the same sorting. Since Ledger doesn't use account codes by default, this is my hack to solve this problem for now. Maybe there should be an account code tag for sorting purposes at least? --- .../general-ledger-report.plx | 46 ++++++++++++++++------ .../non-profit-audit-reports/summary-reports.plx | 30 ++++++++++++++ 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index d1c92975..66fc0031 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -4,8 +4,8 @@ # Script to generate a General Ledger report that accountants like # using Ledger. # -# Copyright (C) 2011, 2012 Bradley M. Kuhn -# Copyright (C) 2012 Tom Marble +# Copyright (C) 2011, 2012, 2013 Bradley M. Kuhn +# Copyright (C) 2012 Tom Marble # # This program gives you software freedom; you can copy, modify, convey, # and/or redistribute it under the terms of the GNU General Public License @@ -67,18 +67,38 @@ close(CHART_DATA); die "error reading ledger output for chart of accounts: $!" u open(CHART_OUTPUT, ">", "chart-of-accounts.txt") or die "unable to write chart-of-accounts.txt: $!"; print MANIFEST "chart-of-accounts.txt\n"; +sub preferredAccountSorting ($$) { + if ($_[0] =~ /^Assets/) { + return -1; + } elsif ($_[1] =~ /^Assets/) { + return 1; + } elsif ($_[0] =~ /^Liabilities/ and $_[1] !~ /^Assets/) { + return -1; + } elsif ($_[1] =~ /^Liabilities/ and $_[0] !~ /^Assets/) { + return 1; + } elsif ($_[0] =~ /^(Accrued)/ and $_[1] !~ /^(Assets|Liabilities)/) { + return -1; + } elsif ($_[1] =~ /^(Accrued)/ and $_[0] !~ /^(Assets|Liabilities)/) { + return 1; + } elsif ($_[0] =~ /^(Unearned Income)/ and $_[1] !~ /^(Assets|Liabilities|Accrued)/) { + return -1; + } elsif ($_[1] =~ /^(Unearned Income)/ and $_[0] !~ /^(Assets|Liabilities|Accrued)/) { + return 1; + } elsif ($_[0] =~ /^Income/ and $_[1] !~ /^(Assets|Liabilities|Accrued|Unearned Income)/) { + return -1; + } elsif ($_[1] =~ /^Income/ and $_[0] !~ /^(Assets|Liabilities|Accrued|Unearned Income)/) { + return 1; + } elsif ($_[0] =~ /^Expense/ and $_[1] !~ /^(Assets|Liabilities|Accrued|Unearned Income|Expense)/) { + return -1; + } elsif ($_[1] =~ /^Expense/ and $_[0] !~ /^(Assets|Liabilities|Accrued|Unearned Income|Expense)/) { + return 1; + } else { + return $_[0] cmp $_[1]; + } +} + my @sortedAccounts; -foreach my $acct ( - # Proper sorting for a chart of accounts - sort { - if ($a =~ /^Assets/ and $b !~ /^Assets/) { - return -1; - } elsif ($a =~ /^Liabilities/ and $b !~ /^Liabilitie/) { - return -1; - } else { - return $a cmp $b; - } - } @accounts) { +foreach my $acct ( sort preferredAccountSorting @accounts) { print CHART_OUTPUT "$acct\n"; push(@sortedAccounts, $acct); } diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index ce6d56da..30b27505 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -39,6 +39,36 @@ sub Commify ($) { return scalar reverse $text; } +sub preferredAccountSorting ($$) { + if ($_[0] =~ /^Assets/) { + return -1; + } elsif ($_[1] =~ /^Assets/) { + return 1; + } elsif ($_[0] =~ /^Liabilities/ and $_[1] !~ /^Assets/) { + return -1; + } elsif ($_[1] =~ /^Liabilities/ and $_[0] !~ /^Assets/) { + return 1; + } elsif ($_[0] =~ /^(Accrued)/ and $_[1] !~ /^(Assets|Liabilities)/) { + return -1; + } elsif ($_[1] =~ /^(Accrued)/ and $_[0] !~ /^(Assets|Liabilities)/) { + return 1; + } elsif ($_[0] =~ /^(Unearned Income)/ and $_[1] !~ /^(Assets|Liabilities|Accrued)/) { + return -1; + } elsif ($_[1] =~ /^(Unearned Income)/ and $_[0] !~ /^(Assets|Liabilities|Accrued)/) { + return 1; + } elsif ($_[0] =~ /^Income/ and $_[1] !~ /^(Assets|Liabilities|Accrued|Unearned Income)/) { + return -1; + } elsif ($_[1] =~ /^Income/ and $_[0] !~ /^(Assets|Liabilities|Accrued|Unearned Income)/) { + return 1; + } elsif ($_[0] =~ /^Expense/ and $_[1] !~ /^(Assets|Liabilities|Accrued|Unearned Income|Expense)/) { + return -1; + } elsif ($_[1] =~ /^Expense/ and $_[0] !~ /^(Assets|Liabilities|Accrued|Unearned Income|Expense)/) { + return 1; + } else { + return $_[0] cmp $_[1]; + } +} + sub ParseNumber($) { $_[0] =~ s/,//g; return Math::BigFloat->new($_[0]); -- cgit v1.2.3 From f01ddd4766741cd0dc09fd42cb7cc87f4dadbb20 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 3 Jan 2013 12:19:28 -0500 Subject: Change chart of accounts output to be a CSV file instead of TXT file. This includes adding a formatted start date string too. --- .../general-ledger-report.plx | 30 +++++++++++++++------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 66fc0031..3c9ec74d 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -44,10 +44,24 @@ if (@ARGV < 3) { print STDERR "usage: $0 \n"; exit 1; } + + open(MANIFEST, ">", "MANIFEST") or die "Unable to open MANIFEST for writing: $!"; my($beginDate, $endDate, @otherLedgerOpts) = @ARGV; +my $formattedEndDate = new Date::Manip::Date; +die "badly formatted end date, $endDate" if $formattedEndDate->parse($endDate); +my $oneDayLess = new Date::Manip::Delta; +die "bad one day less" if $oneDayLess->parse("- 1 day"); +$formattedEndDate = $formattedEndDate->calc($oneDayLess); +$formattedEndDate = $formattedEndDate->printf("%Y/%m/%d"); + +my $formattedBeginDate = new Date::Manip::Date; +die "badly formatted end date, $endDate" if $formattedBeginDate->parse($endDate); +$formattedBeginDate = $formattedBeginDate->printf("%Y/%m/%d"); + + my(@chartOfAccountsOpts) = ('-V', '-F', "%150A\n", '-w', '-s', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg'); @@ -64,8 +78,12 @@ while (my $line = ) { } close(CHART_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; -open(CHART_OUTPUT, ">", "chart-of-accounts.txt") or die "unable to write chart-of-accounts.txt: $!"; -print MANIFEST "chart-of-accounts.txt\n"; +open(CHART_OUTPUT, ">", "chart-of-accounts.csv") or die "unable to write chart-of-accounts.csv: $!"; +print MANIFEST "chart-of-accounts.csv\n"; + +print CHART_OUTPUT "\"CHART OF ACCOUNTS\","; +print CHART_OUTPUT "\"BEGINNING:\",\"$formattedBeginDate\","; +print CHART_OUTPUT "\"ENDING:\",\"$formattedEndDate\"\n"; sub preferredAccountSorting ($$) { if ($_[0] =~ /^Assets/) { @@ -99,17 +117,11 @@ sub preferredAccountSorting ($$) { my @sortedAccounts; foreach my $acct ( sort preferredAccountSorting @accounts) { - print CHART_OUTPUT "$acct\n"; + print CHART_OUTPUT "\"$acct\"\n"; push(@sortedAccounts, $acct); } close(CHART_OUTPUT); die "error writing to chart-of-accounts.txt: $!" unless $? == 0; -my $formattedEndDate = new Date::Manip::Date; -die "badly formatted end date, $endDate" if $formattedEndDate->parse($endDate); -my $oneDayLess = new Date::Manip::Delta; -die "bad one day less" if $oneDayLess->parse("- 1 day"); -$formattedEndDate = $formattedEndDate->calc($oneDayLess); -$formattedEndDate = $formattedEndDate->printf("%Y/%m/%d"); open(GL_TEXT_OUT, ">", "general-ledger.txt") or die "unable to write general-ledger.txt: $!"; print MANIFEST "general-ledger.txt\n"; -- cgit v1.2.3 From d18e01a00f88ec7d073b88db464679a9aa9910a6 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 3 Jan 2013 12:19:59 -0500 Subject: Changed balance sheet output from a TXT file to a CSV file. --- contrib/non-profit-audit-reports/summary-reports.plx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 30b27505..da2dba9d 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -146,15 +146,15 @@ foreach my $item (keys %reportFields) { print STDERR "$item: $reportFields{$item}{total}\n" if $VERBOSE; } -open(BALANCE_SHEET, ">", "balance-sheet.txt") - or die "unable to open balance-sheet.txt for writing: $!"; +open(BALANCE_SHEET, ">", "balance-sheet.csv") + or die "unable to open balance-sheet.csv for writing: $!"; -print BALANCE_SHEET " BALANCE SHEET\n", - " Ending ", $formattedEndDate, "\n", - "\n\nASSETS\n\n"; +print BALANCE_SHEET "\"BALANCE SHEET\"\n", + "\"Ending\",\"", $formattedEndDate, "\"\n", + "\n\n\"ASSETS\"\n\n"; -my $formatStr = " %-42s \$%13s\n"; -my $formatStrTotal = "%-45s \$%13s\n"; +my $formatStr = "\"\",\"%-42s\",\"\$%13s\"\n"; +my $formatStrTotal = "\"\",\"%-45s\",\"\$%13s\"\n"; my $tot = $ZERO; foreach my $item ('Cash', 'Accounts Receivable', 'Loans Receivable') { next if $reportFields{$item}{total} == $ZERO; @@ -186,7 +186,7 @@ print BALANCE_SHEET "\n", sprintf($formatStr, "TOTAL NET ASSETS", Commify($totNe close BALANCE_SHEET; print STDERR "\n"; -die "unable to write to balance-sheet.txt: $!" unless ($? == 0); +die "unable to write to balance-sheet.csv: $!" unless ($? == 0); die "Cash+accounts receivable total does not equal net assets and liabilities total" if (abs( ($reportFields{'Cash'}{total} + $reportFields{'Accounts Receivable'}{total} -- cgit v1.2.3 From b939bbe8c61a819e413b3e2a24d223f6232bd0d9 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 3 Jan 2013 12:30:43 -0500 Subject: Convert trial-balance report to CSV from TXT file. Also, ignore Ledger's Equity: accounts properly. --- .../non-profit-audit-reports/summary-reports.plx | 23 ++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index da2dba9d..dae8f2ce 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -378,15 +378,15 @@ die "calculated total of $overallTotal does equal $firstTotal" print STDERR "\n"; -open(TRIAL, ">", "trial-balance.txt") or die "unable to open accrued.txt for writing: $!"; +open(TRIAL, ">", "trial-balance.csv") or die "unable to open accrued.txt for writing: $!"; @fullCommand = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', '-e', $endDate, '-F', '%-.80A %22.108t\n', '-s', 'reg'); -print TRIAL " TRIAL BALANCE \n", - " Ending $formattedEndDate\n\n"; +print TRIAL "\"TRIAL BALANCE REPORT\",", + "\"ENDING:\",\"$formattedEndDate\"\n\n\"ACCOUNT NAME\", \"AMOUNT\"\n\n"; open(FILE, "-|", @fullCommand) or die "unable to run command ledger command: @fullCommand: $!"; @@ -395,17 +395,28 @@ print STDERR ($VERBOSE ? "Running: @fullCommand\n" : "."); my $accruedTotal = $ZERO; +my %trialBalances; + foreach my $line () { die "Unable to parse output line from second funds command: $line" unless $line =~ /^\s*([^\$]+)\s+\$\s*([\-\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); $account =~ s/\s+$//; - next if $account =~ /\|^Equity:/ and (abs($amount) <= 0.02); - print TRIAL $line; - + next if $account =~ /\/ and (abs($amount) <= 0.02); + next if $account =~ /^Equity:/; # Stupid auto-account made by ledger. + $trialBalances{$account} = $amount; $accruedTotal += $amount; } +close FILE; +die "unable to run trial balance ledger command: $!" unless ($? == 0); + +foreach my $account (sort preferredAccountSorting keys %trialBalances) { + print TRIAL "\"$account\",\"$trialBalances{$account}\"\n"; +} + +close TRIAL; +die "unable to write trial-balance.csv: $!" unless ($? == 0); ############################################################################### # -- cgit v1.2.3 From fbd6c309031393950ac387b9de5f07214c5fa3cf Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 3 Jan 2013 13:36:38 -0500 Subject: Add option to skip generating the page breaks. --- contrib/non-profit-audit-reports/csv2ods.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/contrib/non-profit-audit-reports/csv2ods.py b/contrib/non-profit-audit-reports/csv2ods.py index 2b3024d4..aded8e65 100755 --- a/contrib/non-profit-audit-reports/csv2ods.py +++ b/contrib/non-profit-audit-reports/csv2ods.py @@ -2,8 +2,8 @@ # csv2ods.py # Convert example csv file to ods # -# Copyright (c) 2012 Tom Marble -# Copyright (c) 2012 Bradley M. Kuhn +# Copyright (c) 2012 Tom Marble +# Copyright (c) 2012, 2013 Bradley M. Kuhn # # This program gives you software freedom; you can copy, modify, convey, # and/or redistribute it under the terms of the GNU General Public License @@ -31,7 +31,7 @@ def err(msg): print 'error: %s' % msg sys.exit(1) -def csv2ods(csvname, odsname, encoding='', verbose = False): +def csv2ods(csvname, odsname, encoding='', verbose = False, skip_page_break = False): if verbose: print 'converting from %s to %s' % (csvname, odsname) doc = ooolib2.Calc() @@ -77,7 +77,8 @@ def csv2ods(csvname, odsname, encoding='', verbose = False): # enter an empty string for blank lines doc.set_cell_value(1, row, 'string', '') # put a pagebreak here - doc.sheets[doc.sheet_index].set_sheet_config(('row', row), style_pagebreak) + if not skip_page_break: + doc.sheets[doc.sheet_index].set_sheet_config(('row', row), style_pagebreak) row += 1 # save the file doc.save(odsname) @@ -96,6 +97,9 @@ def main(): help='ods output filename') parser.add_option('-e', '--encoding', action='store', help='unicode character encoding type') + parser.add_option('-s', '--skip-page-break', action='store_true', + dest='skip_page_break', + help='do not add any page breaks') (options, args) = parser.parse_args() if len(args) != 0: parser.error("not expecting extra args") @@ -109,7 +113,7 @@ def main(): print 'csv:', options.csv print 'ods:', options.ods print 'ods:', options.encoding - csv2ods(options.csv, options.ods, options.verbose, options.encoding) + csv2ods(options.csv, options.ods, options.verbose, options.encoding, options.skip_page_break) if __name__ == '__main__': main() -- cgit v1.2.3 From 750321c0b1e35b0315138b35524f85d3648d8dda Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 3 Jan 2013 13:37:08 -0500 Subject: Change Income and Expenses reports to generate CSV files, rather than TXT files. --- .../non-profit-audit-reports/summary-reports.plx | 35 +++++++++++----------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index dae8f2ce..efad30e7 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -223,7 +223,7 @@ foreach my $type (keys %incomeGroups) { $incomeGroups{"OTHER"}{args} = \@otherArgs; $incomeGroups{"TOTAL"}{args} = ['/^Income/']; -open(INCOME, ">", "income.txt") or die "unable to open income.txt for writing: $!"; +open(INCOME, ">", "income.csv") or die "unable to open income.csv for writing: $!"; foreach my $type (keys %incomeGroups) { my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', @@ -247,32 +247,32 @@ foreach my $type (keys %incomeGroups) { $account =~ s/\s+$//; next if $account =~ /\/ and (abs($amount) <= 0.02); die "Weird account found, $account with amount of $amount in income command\n" - unless $account =~ s/^\s*Income://; + unless $account =~ /^\s*Income:/; $incomeGroups{$type}{total} += $amount; - $incomeGroups{$type}{output} .= " $line"; + $incomeGroups{$type}{output} .= "\"$account\",\"\$$amount\"\n"; } } -print INCOME " INCOME\n", - " Between $formattedStartDate and $formattedEndDate\n\n"; +print INCOME "\"INCOME\",", + "\"STARTING:\",\"$formattedStartDate\",\"ENDING:\",\"$formattedEndDate\"\n\n"; my $overallTotal = $ZERO; -$formatStrTotal = "%-90s \$%14s\n"; +$formatStrTotal = "\"%-90s\",\"\$%14s\"\n"; foreach my $type ('DONATIONS', 'LICENSE ENFORCEMENT', 'CONFERENCES, REGISTRATION', 'CONFERENCES, RELATED BUSINESS INCOME', 'BOOK ROYALTIES & AFFILIATE PROGRAMS', 'ADVERSITING', 'TRADEMARKS', 'INTEREST INCOME', 'OTHER') { next if ($incomeGroups{$type}{output} =~ /^\s*$/ and $incomeGroups{$type}{total} == $ZERO); - print INCOME "\n$type\n", + print INCOME "\n\"$type\"\n", $incomeGroups{$type}{output}, "\n", sprintf($formatStrTotal, "TOTAL $type:", Commify($incomeGroups{$type}{total})); $overallTotal += $incomeGroups{$type}{total}; } print INCOME "\n\n\n", sprintf($formatStrTotal, "OVERALL TOTAL:", Commify($overallTotal)); -close INCOME; die "unable to write to income.txt: $!" unless ($? == 0); +close INCOME; die "unable to write to income.csv: $!" unless ($? == 0); die "calculated total of $overallTotal does equal $incomeGroups{TOTAL}{total}" if (abs($overallTotal) - abs($incomeGroups{TOTAL}{total}) > $ONE_PENNY); @@ -298,7 +298,7 @@ foreach my $type (keys %expenseGroups, 'TRAVEL') { $expenseGroups{$type}{output} = ""; } -open(EXPENSE, ">", "expense.txt") or die "unable to open expense.txt for writing: $!"; +open(EXPENSE, ">", "expense.csv") or die "unable to open expense.csv for writing: $!"; my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', '-b', $startDate, '-e', $endDate, @@ -321,6 +321,7 @@ foreach my $line () { die "Weird account found, $account, with amount of $amount in expenses command\n" unless $account =~ /^\s*Expenses:/; + my $outputLine = "\"$account\",\"\$$amount\"\n"; my $taken = 0; # Note: Prioritize to put things under conference expenses if they were for a conference. foreach my $type ('CONFERENCES', keys %expenseGroups) { @@ -329,23 +330,23 @@ foreach my $line () { next unless $line =~ /$expenseGroups{$type}{regex}/; $taken = 1; $expenseGroups{$type}{total} += $amount; - $expenseGroups{$type}{output} .= " $line"; + $expenseGroups{$type}{output} .= $outputLine; } if (not $taken) { if ($account =~ /Travel/) { $expenseGroups{'TRAVEL'}{total} += $amount; - $expenseGroups{'TRAVEL'}{output} .= " $line"; + $expenseGroups{'TRAVEL'}{output} .= $outputLine; } else { $expenseGroups{'OTHER'}{total} += $amount; - $expenseGroups{'OTHER'}{output} .= " $line"; + $expenseGroups{'OTHER'}{output} .= $outputLine; } } $firstTotal += $amount; } -print EXPENSE " EXPENSES\n", - " Between $formattedStartDate and $formattedEndDate\n\n"; +print EXPENSE "\"EXPENSES\",", + "\"STARTING:\",\"$formattedStartDate\",\"ENDING:\",\"$formattedEndDate\"\n\n"; $overallTotal = $ZERO; -$formatStrTotal = "%-90s \$%14s\n"; +$formatStrTotal = "\"%-90s\",\"\$%14s\"\n"; my %verifyAllGroups; foreach my $key (keys %expenseGroups) { @@ -360,7 +361,7 @@ foreach my $type ('PAYROLL', 'SOFTWARE DEVELOPMENT', 'LICENSE ENFORCEMENT', 'CON die "$type is not defined!" if not defined $expenseGroups{$type}; next if ($expenseGroups{$type}{output} =~ /^\s*$/ and $expenseGroups{$type}{total} == $ZERO); - print EXPENSE "\n$type\n", + print EXPENSE "\n\"$type\"\n", $expenseGroups{$type}{output}, "\n", sprintf($formatStrTotal, "TOTAL $type:", Commify($expenseGroups{$type}{total})); $overallTotal += $expenseGroups{$type}{total}; @@ -368,7 +369,7 @@ foreach my $type ('PAYROLL', 'SOFTWARE DEVELOPMENT', 'LICENSE ENFORCEMENT', 'CON print EXPENSE "\n\n\n", sprintf($formatStrTotal, "OVERALL TOTAL:", Commify($overallTotal)); -close EXPENSE; die "unable to write to expense.txt: $!" unless ($? == 0); +close EXPENSE; die "unable to write to expense.csv: $!" unless ($? == 0); die "GROUPS NOT INCLUDED : ", join(keys(%verifyAllGroups), ", "), "\n" unless (keys %verifyAllGroups == 0); -- cgit v1.2.3 From 2fad8fe238cee8509290562a823fe0c3b312ee94 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 3 Jan 2013 13:37:18 -0500 Subject: Some minor formatting fixes for the trial balance report. --- contrib/non-profit-audit-reports/summary-reports.plx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index efad30e7..8e9339a5 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -387,7 +387,7 @@ open(TRIAL, ">", "trial-balance.csv") or die "unable to open accrued.txt for wri 'reg'); print TRIAL "\"TRIAL BALANCE REPORT\",", - "\"ENDING:\",\"$formattedEndDate\"\n\n\"ACCOUNT NAME\", \"AMOUNT\"\n\n"; + "\"ENDING:\",\"$formattedEndDate\"\n\n\"ACCOUNT NAME\",\"AMOUNT\"\n\n"; open(FILE, "-|", @fullCommand) or die "unable to run command ledger command: @fullCommand: $!"; @@ -413,7 +413,7 @@ close FILE; die "unable to run trial balance ledger command: $!" unless ($? == 0); foreach my $account (sort preferredAccountSorting keys %trialBalances) { - print TRIAL "\"$account\",\"$trialBalances{$account}\"\n"; + print TRIAL "\"$account\",\"\$$trialBalances{$account}\"\n"; } close TRIAL; -- cgit v1.2.3 From e317e1f23e236a2797b13113bc2afae14502fc5c Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 4 Jan 2013 10:18:41 -0500 Subject: Sort of accounts was buggy; it never made the final else due to bad regexes. This fix now has the sort working correctly. --- .../general-ledger-report.plx | 29 +++++++++++++--------- .../non-profit-audit-reports/summary-reports.plx | 28 ++++++++++++--------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 3c9ec74d..a464053b 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -86,35 +86,40 @@ print CHART_OUTPUT "\"BEGINNING:\",\"$formattedBeginDate\","; print CHART_OUTPUT "\"ENDING:\",\"$formattedEndDate\"\n"; sub preferredAccountSorting ($$) { - if ($_[0] =~ /^Assets/) { + if ($_[0] =~ /^Assets/ and $_[1] !~ /^Assets/) { return -1; - } elsif ($_[1] =~ /^Assets/) { + } elsif ($_[1] =~ /^Assets/ and $_[0] !~ /^Assets/) { return 1; - } elsif ($_[0] =~ /^Liabilities/ and $_[1] !~ /^Assets/) { + } elsif ($_[0] =~ /^Liabilities/ and $_[1] !~ /^(Assets|Liabilities)/) { return -1; - } elsif ($_[1] =~ /^Liabilities/ and $_[0] !~ /^Assets/) { + } elsif ($_[1] =~ /^Liabilities/ and $_[0] !~ /^(Assets|Liabilities)/) { return 1; - } elsif ($_[0] =~ /^(Accrued)/ and $_[1] !~ /^(Assets|Liabilities)/) { + } elsif ($_[0] =~ /^(Accrued:[^:]+Receivable)/ and $_[1] !~ /^(Assets|Liabilities|Accrued:[^:]+Receivable)/) { return -1; - } elsif ($_[1] =~ /^(Accrued)/ and $_[0] !~ /^(Assets|Liabilities)/) { + } elsif ($_[1] =~ /^(Accrued:[^:]+Receivable)/ and $_[0] !~ /^(Assets|Liabilities|Accrued:[^:]+Receivable)/) { return 1; - } elsif ($_[0] =~ /^(Unearned Income)/ and $_[1] !~ /^(Assets|Liabilities|Accrued)/) { + } elsif ($_[0] =~ /^(Accrued)/ and $_[1] !~ /^(Assets|Liabilities|Accrued)/) { return -1; - } elsif ($_[1] =~ /^(Unearned Income)/ and $_[0] !~ /^(Assets|Liabilities|Accrued)/) { + } elsif ($_[1] =~ /^(Accrued)/ and $_[0] !~ /^(Assets|Liabilities|Accrued)/) { return 1; - } elsif ($_[0] =~ /^Income/ and $_[1] !~ /^(Assets|Liabilities|Accrued|Unearned Income)/) { + } elsif ($_[0] =~ /^(Unearned Income)/ and $_[1] !~ /^(Assets|Liabilities|Accrued|Unearned Income)/) { return -1; - } elsif ($_[1] =~ /^Income/ and $_[0] !~ /^(Assets|Liabilities|Accrued|Unearned Income)/) { + } elsif ($_[1] =~ /^(Unearned Income)/ and $_[0] !~ /^(Assets|Liabilities|Accrued|Unearned Income)/) { return 1; - } elsif ($_[0] =~ /^Expense/ and $_[1] !~ /^(Assets|Liabilities|Accrued|Unearned Income|Expense)/) { + } elsif ($_[0] =~ /^Income/ and $_[1] !~ /^(Assets|Liabilities|Accrued|Unearned Income|Income)/) { return -1; - } elsif ($_[1] =~ /^Expense/ and $_[0] !~ /^(Assets|Liabilities|Accrued|Unearned Income|Expense)/) { + } elsif ($_[1] =~ /^Income/ and $_[0] !~ /^(Assets|Liabilities|Accrued|Unearned Income|Income)/) { + return 1; + } elsif ($_[0] =~ /^Expense/ and $_[1] !~ /^(Assets|Liabilities|Accrued|Income|Unearned Income|Expense)/) { + return -1; + } elsif ($_[1] =~ /^Expense/ and $_[0] !~ /^(Assets|Liabilities|Accrued|Income|Unearned Income|Expense)/) { return 1; } else { return $_[0] cmp $_[1]; } } + my @sortedAccounts; foreach my $acct ( sort preferredAccountSorting @accounts) { print CHART_OUTPUT "\"$acct\"\n"; diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 8e9339a5..17999c36 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -40,29 +40,33 @@ sub Commify ($) { } sub preferredAccountSorting ($$) { - if ($_[0] =~ /^Assets/) { + if ($_[0] =~ /^Assets/ and $_[1] !~ /^Assets/) { return -1; - } elsif ($_[1] =~ /^Assets/) { + } elsif ($_[1] =~ /^Assets/ and $_[0] !~ /^Assets/) { return 1; - } elsif ($_[0] =~ /^Liabilities/ and $_[1] !~ /^Assets/) { + } elsif ($_[0] =~ /^Liabilities/ and $_[1] !~ /^(Assets|Liabilities)/) { return -1; - } elsif ($_[1] =~ /^Liabilities/ and $_[0] !~ /^Assets/) { + } elsif ($_[1] =~ /^Liabilities/ and $_[0] !~ /^(Assets|Liabilities)/) { return 1; - } elsif ($_[0] =~ /^(Accrued)/ and $_[1] !~ /^(Assets|Liabilities)/) { + } elsif ($_[0] =~ /^(Accrued:[^:]+Receivable)/ and $_[1] !~ /^(Assets|Liabilities|Accrued:[^:]+Receivable)/) { return -1; - } elsif ($_[1] =~ /^(Accrued)/ and $_[0] !~ /^(Assets|Liabilities)/) { + } elsif ($_[1] =~ /^(Accrued:[^:]+Receivable)/ and $_[0] !~ /^(Assets|Liabilities|Accrued:[^:]+Receivable)/) { return 1; - } elsif ($_[0] =~ /^(Unearned Income)/ and $_[1] !~ /^(Assets|Liabilities|Accrued)/) { + } elsif ($_[0] =~ /^(Accrued)/ and $_[1] !~ /^(Assets|Liabilities|Accrued)/) { return -1; - } elsif ($_[1] =~ /^(Unearned Income)/ and $_[0] !~ /^(Assets|Liabilities|Accrued)/) { + } elsif ($_[1] =~ /^(Accrued)/ and $_[0] !~ /^(Assets|Liabilities|Accrued)/) { return 1; - } elsif ($_[0] =~ /^Income/ and $_[1] !~ /^(Assets|Liabilities|Accrued|Unearned Income)/) { + } elsif ($_[0] =~ /^(Unearned Income)/ and $_[1] !~ /^(Assets|Liabilities|Accrued|Unearned Income)/) { return -1; - } elsif ($_[1] =~ /^Income/ and $_[0] !~ /^(Assets|Liabilities|Accrued|Unearned Income)/) { + } elsif ($_[1] =~ /^(Unearned Income)/ and $_[0] !~ /^(Assets|Liabilities|Accrued|Unearned Income)/) { return 1; - } elsif ($_[0] =~ /^Expense/ and $_[1] !~ /^(Assets|Liabilities|Accrued|Unearned Income|Expense)/) { + } elsif ($_[0] =~ /^Income/ and $_[1] !~ /^(Assets|Liabilities|Accrued|Unearned Income|Income)/) { return -1; - } elsif ($_[1] =~ /^Expense/ and $_[0] !~ /^(Assets|Liabilities|Accrued|Unearned Income|Expense)/) { + } elsif ($_[1] =~ /^Income/ and $_[0] !~ /^(Assets|Liabilities|Accrued|Unearned Income|Income)/) { + return 1; + } elsif ($_[0] =~ /^Expense/ and $_[1] !~ /^(Assets|Liabilities|Accrued|Income|Unearned Income|Expense)/) { + return -1; + } elsif ($_[1] =~ /^Expense/ and $_[0] !~ /^(Assets|Liabilities|Accrued|Income|Unearned Income|Expense)/) { return 1; } else { return $_[0] cmp $_[1]; -- cgit v1.2.3 From 986829b1d656611eb243b920703acc198fdf3f37 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 4 Jan 2013 10:19:16 -0500 Subject: Corrected Trial Balance report based on discussion with accountants. I believe this trial balance report will look "more natural" to accountants. --- .../non-profit-audit-reports/summary-reports.plx | 83 +++++++++++++++------- 1 file changed, 57 insertions(+), 26 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 17999c36..bbe83c88 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -385,41 +385,72 @@ print STDERR "\n"; open(TRIAL, ">", "trial-balance.csv") or die "unable to open accrued.txt for writing: $!"; -@fullCommand = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', - '-e', $endDate, - '-F', '%-.80A %22.108t\n', '-s', - 'reg'); +print TRIAL "\"TRIAL BALANCE REPORT\",\"ENDING: $formattedEndDate\"\n\n", + "\"ACCOUNT\",\"BALANCE AT $formattedStartDate\",\"CHANGE DURING FY\",\"BALANCE AT $formattedEndDate\"\n\n"; -print TRIAL "\"TRIAL BALANCE REPORT\",", - "\"ENDING:\",\"$formattedEndDate\"\n\n\"ACCOUNT NAME\",\"AMOUNT\"\n\n"; +my %commands = ( + 'totalEndFY' => [ $LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', + '-e', $endDate, '-F', '%-.80A %22.108t\n', '-s', + 'reg' ], + 'amountInYear' => [ $LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', + '-b', $startDate, '-e', $endDate, '-F', '%-.80A %22.108t\n', + '-s', 'reg' ], + 'totalBeginFY' => [ $LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', + '-e', $startDate, '-F', '%-.80A %22.108t\n', + '-s', 'reg' ]); -open(FILE, "-|", @fullCommand) - or die "unable to run command ledger command: @fullCommand: $!"; +my %trialBalanceData; +my %fullAccountList; -print STDERR ($VERBOSE ? "Running: @fullCommand\n" : "."); +foreach my $id (keys %commands) { + my(@command) = @{$commands{$id}}; -my $accruedTotal = $ZERO; + open(FILE, "-|", @command) + or die "unable to run command ledger command: @command: $!"; -my %trialBalances; + print STDERR ($VERBOSE ? "Running: @command\n" : "."); -foreach my $line () { - die "Unable to parse output line from second funds command: $line" - unless $line =~ /^\s*([^\$]+)\s+\$\s*([\-\d\.\,]+)/; - my($account, $amount) = ($1, $2); - $amount = ParseNumber($amount); - $account =~ s/\s+$//; - next if $account =~ /\/ and (abs($amount) <= 0.02); - next if $account =~ /^Equity:/; # Stupid auto-account made by ledger. - $trialBalances{$account} = $amount; - $accruedTotal += $amount; + foreach my $line () { + die "Unable to parse output line from trial balance $id command: $line" + unless $line =~ /^\s*([^\$]+)\s+\$\s*([\-\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $account =~ s/\s+$//; + next if $account =~ /\/ and (abs($amount) <= 0.02); + next if $account =~ /^Equity:/; # Stupid auto-account made by ledger. + $trialBalanceData{$id}{$account} = $amount; + $fullAccountList{$account} = $id; + } + close FILE; + die "unable to run trial balance ledger command, @command: $!" unless ($? == 0); } -close FILE; -die "unable to run trial balance ledger command: $!" unless ($? == 0); -foreach my $account (sort preferredAccountSorting keys %trialBalances) { - print TRIAL "\"$account\",\"\$$trialBalances{$account}\"\n"; -} +my $curOn = 'Assets'; +foreach my $account (sort preferredAccountSorting keys %fullAccountList) { + # Blank lines right + if ($account !~ /^$curOn/) { + print TRIAL "\n"; + $curOn = $account; + $curOn =~ s/^([^:]+):.*$/$1/; + print "CurOn now: $curOn\n"; + } + if ($account =~ /^Assets|Liabilities|Accrued|Unearned Income/) { + foreach my $id (qw/totalBeginFY totalEndFY amountInYear/) { + $trialBalanceData{$id}{$account} = $ZERO + unless defined $trialBalanceData{$id}{$account}; + } + print TRIAL "\"$account\",\"\$$trialBalanceData{totalBeginFY}{$account}\",", + "\"\$$trialBalanceData{amountInYear}{$account}\",\"\$$trialBalanceData{totalEndFY}{$account}\"\n" + unless $trialBalanceData{totalBeginFY}{$account} == $ZERO and + $trialBalanceData{amountInYear}{$account} == $ZERO and + $trialBalanceData{totalEndFY}{$account} == $ZERO; + } else { + print TRIAL "\"$account\",\"\",\"\$$trialBalanceData{amountInYear}{$account}\",\"\"\n" + if defined $trialBalanceData{amountInYear}{$account} and + $trialBalanceData{amountInYear}{$account} != $ZERO; + } +} close TRIAL; die "unable to write trial-balance.csv: $!" unless ($? == 0); -- cgit v1.2.3 From 87f0c4434d131ba78ba191780dbff2b8c47f3123 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 4 Jan 2013 12:23:37 -0500 Subject: Updated expected test output data for general-ledger report. --- .../tests/non-profit-test-data_chart-of-accounts.csv | 6 ++++++ .../tests/non-profit-test-data_chart-of-accounts.txt | 4 ---- .../tests/non-profit-test-data_general-ledger.ods | Bin 11412 -> 5770 bytes 3 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 contrib/non-profit-audit-reports/tests/non-profit-test-data_chart-of-accounts.csv delete mode 100644 contrib/non-profit-audit-reports/tests/non-profit-test-data_chart-of-accounts.txt diff --git a/contrib/non-profit-audit-reports/tests/non-profit-test-data_chart-of-accounts.csv b/contrib/non-profit-audit-reports/tests/non-profit-test-data_chart-of-accounts.csv new file mode 100644 index 00000000..445bc412 --- /dev/null +++ b/contrib/non-profit-audit-reports/tests/non-profit-test-data_chart-of-accounts.csv @@ -0,0 +1,6 @@ +"CHART OF ACCOUNTS","BEGINNING:","2012/03/01","ENDING:","2012/02/29" +"Assets:Checking" +"Income:Donation" +"Income:Foo:Donation" +"Expenses:Blah:Hosting" +"Expenses:Foo:Hosting" diff --git a/contrib/non-profit-audit-reports/tests/non-profit-test-data_chart-of-accounts.txt b/contrib/non-profit-audit-reports/tests/non-profit-test-data_chart-of-accounts.txt deleted file mode 100644 index 57e636b9..00000000 --- a/contrib/non-profit-audit-reports/tests/non-profit-test-data_chart-of-accounts.txt +++ /dev/null @@ -1,4 +0,0 @@ -Assets:Checking -Expenses:Foo:Hosting -Income:Donation -Income:Foo:Donation diff --git a/contrib/non-profit-audit-reports/tests/non-profit-test-data_general-ledger.ods b/contrib/non-profit-audit-reports/tests/non-profit-test-data_general-ledger.ods index 80771a6d..8eae706f 100644 Binary files a/contrib/non-profit-audit-reports/tests/non-profit-test-data_general-ledger.ods and b/contrib/non-profit-audit-reports/tests/non-profit-test-data_general-ledger.ods differ -- cgit v1.2.3 From 2b237aa3ba15fd0964690eac379f9226990e6f05 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 4 Jan 2013 12:24:30 -0500 Subject: MANIFEST file is now also generated by general-ledger report. We should give the sample MANIFEST for users that want to make sure they got the script working properly, and to show the sample output. --- .gitignore | 1 + .../tests/non-profit-test-data_MANIFEST | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 contrib/non-profit-audit-reports/tests/non-profit-test-data_MANIFEST diff --git a/.gitignore b/.gitignore index 02f6433a..c60fe7d4 100644 --- a/.gitignore +++ b/.gitignore @@ -103,4 +103,5 @@ contrib/non-profit-audit-reports/tests/chart-of-accounts.txt contrib/non-profit-audit-reports/tests/general-ledger.csv contrib/non-profit-audit-reports/tests/general-ledger.ods contrib/non-profit-audit-reports/tests/general-ledger.txt +contrib/non-profit-audit-reports/tests/MANIFEST contrib/non-profit-audit-reports/general-ledger.zip diff --git a/contrib/non-profit-audit-reports/tests/non-profit-test-data_MANIFEST b/contrib/non-profit-audit-reports/tests/non-profit-test-data_MANIFEST new file mode 100644 index 00000000..b8bfc107 --- /dev/null +++ b/contrib/non-profit-audit-reports/tests/non-profit-test-data_MANIFEST @@ -0,0 +1,10 @@ +chart-of-accounts.csv +general-ledger.txt +general-ledger.csv +Financial/BankStuff/bank-statement.pdf +Financial/Invoices/Invoice20110510.pdf +Projects/Foo/Invoices/Invoice20100101.pdf +Projects/Foo/earmark-record.txt +Projects/Blah/Expenses/hosting/AprilHostingReceipt.pdf +Projects/Blah/Expenses/hosting/april-invoice.pdf +Projects/Foo/Expenses/hosting/AprilHostingReceipt.pdf -- cgit v1.2.3 From 4290a4ec52793baeaaa3ae6dbb75cbef993d3ef4 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sat, 5 Jan 2013 13:13:05 -0500 Subject: Add balances for permanent (i.e., asset) accounts. Based on a request from our accountants, I've changed the RUNNING TOTAL field (which is generally useless to accountants anyway) to be a BALANCE amount for starting and ending accounts. --- .../general-ledger-report.plx | 44 ++++++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index a464053b..3b230837 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -127,6 +127,34 @@ foreach my $acct ( sort preferredAccountSorting @accounts) { } close(CHART_OUTPUT); die "error writing to chart-of-accounts.txt: $!" unless $? == 0; +my %commands = ( + 'totalEnd' => [ $LEDGER_CMD, @otherLedgerOpts, '-V', '-X', '$', + '-e', $endDate, '-F', '%-.80A %22.108t\n', '-s', + 'reg' ], + 'totalBegin' => [ $LEDGER_CMD, @otherLedgerOpts, '-V', '-X', '$', + '-e', $beginDate, '-F', '%-.80A %22.108t\n', + '-s', 'reg' ]); + +my %balanceData; + +foreach my $id (keys %commands) { + my(@command) = @{$commands{$id}}; + + open(FILE, "-|", @command) or die "unable to run command ledger command: @command: $!"; + + foreach my $line () { + die "Unable to parse output line from balance data $id command: $line" + unless $line =~ /^\s*([^\$]+)\s+\$\s*([\-\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $account =~ s/\s+$//; + next if $account =~ /\/ and (abs($amount) <= 0.02); + next if $account =~ /^Equity:/; # Stupid auto-account made by ledger. + $balanceData{$id}{$account} = $amount; + } + close FILE; + die "unable to run balance data ledger command, @command: $!" unless ($? == 0); +} open(GL_TEXT_OUT, ">", "general-ledger.txt") or die "unable to write general-ledger.txt: $!"; print MANIFEST "general-ledger.txt\n"; @@ -147,15 +175,20 @@ foreach my $acct (@sortedAccounts) { } close(GL_TEXT_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; - print GL_CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; - print GL_CSV_OUT '"DATE","CHECK NUM","NAME","TRANSACTION AMT","RUNNING TOTAL"'; - my $formatString = '"%(date)","%C","%P","%t","%T"'; + print GL_CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$formattedBeginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; + print GL_CSV_OUT '"DATE","CHECK NUM","NAME","TRANSACTION AMT","BALANCE"'; + + my $formatString = '"%(date)","%C","%P","%t",""'; foreach my $tagField (qw/Receipt Invoice Statement Contract PurchaseOrder Approval Check IncomeDistributionAnalysis CurrencyRate/) { print GL_CSV_OUT ',"', $tagField, '"'; $formatString .= ',"%(tag(\'' . $tagField . '\'))"'; } $formatString .= "\n"; print GL_CSV_OUT "\n"; + if ($acct =~ /^(Assets|Liabilities|Accrued|Unearned Income)/) { + $balanceData{totalBegin}{$acct} = $ZERO unless defined $balanceData{totalBegin}{$acct}; + print GL_CSV_OUT "\"$formattedBeginDate\"", ',"","BALANCE","","$', "$balanceData{totalBegin}{$acct}\"\n"; + } @acctLedgerOpts = ('-V', '-F', $formatString, '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); open(GL_CSV_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) @@ -173,6 +206,11 @@ foreach my $acct (@sortedAccounts) { $manifest{$file} = $line; } } + if ($acct =~ /^(Assets|Liabilities|Accrued|Unearned Income)/) { + $balanceData{totalEnd}{$acct} = $ZERO unless defined $balanceData{totalEnd}{$acct}; + print GL_CSV_OUT "\"$formattedEndDate\"", ',"","BALANCE","","$', "$balanceData{totalEnd}{$acct}\"\n"; + } + close(GL_CSV_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; } close(GL_TEXT_OUT); die "error writing to general-ledger.txt: $!" unless $? == 0; -- cgit v1.2.3 From b04fbb1b7306ce202a015dd7587fe9c396e27103 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sat, 5 Jan 2013 17:39:12 -0500 Subject: First crack at an unpaid accruals report. --- .../unpaid-accruals-report.plx | 84 ++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100755 contrib/non-profit-audit-reports/unpaid-accruals-report.plx diff --git a/contrib/non-profit-audit-reports/unpaid-accruals-report.plx b/contrib/non-profit-audit-reports/unpaid-accruals-report.plx new file mode 100755 index 00000000..3d4c9cb0 --- /dev/null +++ b/contrib/non-profit-audit-reports/unpaid-accruals-report.plx @@ -0,0 +1,84 @@ +#!/usr/bin/perl +# unpaid-acccurals-report.plx -*- Perl -*- + +# This report is designed to create what our accounts call a "Schedule of +# accounts payable". and "Schedule of accounts receivable". + + + +# Copyright (C) 2013 Bradley M. Kuhn +# +# This program gives you software freedom; you can copy, modify, convey, +# and/or redistribute it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program in a file called 'GPLv3'. If not, write to the: +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor +# Boston, MA 02110-1301, USA. + +use strict; +use warnings; + +use Math::BigFloat; +use Date::Manip; + +my $LEDGER_CMD = "/usr/local/bin/ledger"; + +my $ACCT_WIDTH = 70; + +sub ParseNumber($) { + $_[0] =~ s/,//g; + return Math::BigFloat->new($_[0]); +} +Math::BigFloat->precision(-2); +my $ZERO = Math::BigFloat->new("0.00"); +my $TWO_CENTS = Math::BigFloat->new("0.02"); + +if (@ARGV < 2) { + print STDERR "usage: $0 \n"; + exit 1; +} +my($startDate, $endDate, @mainLedgerOptions) = @ARGV; + +my $err; +my $formattedEndDate = UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 day"), \$err), + "%Y/%m/%d"); +die "Date calculation error on $endDate" if ($err); +my $formattedStartDate = UnixDate(ParseDate($startDate), "%Y/%m/%d"); +die "Date calculation error on $startDate" if ($err); + +my(@ledgerOptions) = (@mainLedgerOptions, + '-V', '-X', '$', '-F', + '\"%(tag("Invoice"))\",\"%A\",\"%(date)\",\"%(payee)\",\"%22.108t\"\n', + '--limit', 'tag("Invoice") !~ /^\s*$/', 'reg'); + +my @possibleTypes = ('Accrued:Loans Receivable', 'Accrued:Accounts Payable', + 'Accrued:Accounts Receivable', 'Accrued:Expenses'); + + +foreach my $type (@possibleTypes) { + open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions, "/^$type/") + or die "Unable to run $LEDGER_CMD @ledgerOptions: $!"; + + while (my $line = ) { + next if $line =~ /"\"/; + die "Unable to parse output line $line from @ledgerOptions" + + unless $line =~ /^\s*"([^"]+)","([^"]+)","([^"]+)","([^"]+)","\s*\$\s*([\-\d\.\,]+)"\s*$/; + my($invoice, $account, $date, $payee, $amount) = ($1, $2, $3, $4, $5); + $amount = ParseNumber($amount); + } +} +############################################################################### +# +# Local variables: +# compile-command: "perl -c unpaid-accruals-report.plx" +# End: + -- cgit v1.2.3 From 39db5bbce77c3173b006755fc71ce95ba0e4041a Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 6 Jan 2013 08:21:35 -0500 Subject: Ordering of options had always been incorrect on this call; Fixed. --- contrib/non-profit-audit-reports/csv2ods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/csv2ods.py b/contrib/non-profit-audit-reports/csv2ods.py index aded8e65..e6d33906 100755 --- a/contrib/non-profit-audit-reports/csv2ods.py +++ b/contrib/non-profit-audit-reports/csv2ods.py @@ -113,7 +113,7 @@ def main(): print 'csv:', options.csv print 'ods:', options.ods print 'ods:', options.encoding - csv2ods(options.csv, options.ods, options.verbose, options.encoding, options.skip_page_break) + csv2ods(options.csv, options.ods, options.encoding, options.verbose, options.skip_page_break) if __name__ == '__main__': main() -- cgit v1.2.3 From 2142a36c1c81bae4ea5bdb6fde65141e8dca5227 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 6 Jan 2013 19:28:21 -0500 Subject: Completed report on unpaid accruals. --- .../unpaid-accruals-report.plx | 32 ++++++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/contrib/non-profit-audit-reports/unpaid-accruals-report.plx b/contrib/non-profit-audit-reports/unpaid-accruals-report.plx index 3d4c9cb0..f481e02f 100755 --- a/contrib/non-profit-audit-reports/unpaid-accruals-report.plx +++ b/contrib/non-profit-audit-reports/unpaid-accruals-report.plx @@ -55,14 +55,14 @@ my $formattedStartDate = UnixDate(ParseDate($startDate), "%Y/%m/%d"); die "Date calculation error on $startDate" if ($err); my(@ledgerOptions) = (@mainLedgerOptions, - '-V', '-X', '$', '-F', + '-V', '-X', '$', '-e', $endDate, '-F', '\"%(tag("Invoice"))\",\"%A\",\"%(date)\",\"%(payee)\",\"%22.108t\"\n', '--limit', 'tag("Invoice") !~ /^\s*$/', 'reg'); my @possibleTypes = ('Accrued:Loans Receivable', 'Accrued:Accounts Payable', 'Accrued:Accounts Receivable', 'Accrued:Expenses'); - +my %data; foreach my $type (@possibleTypes) { open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions, "/^$type/") or die "Unable to run $LEDGER_CMD @ledgerOptions: $!"; @@ -73,8 +73,34 @@ foreach my $type (@possibleTypes) { unless $line =~ /^\s*"([^"]+)","([^"]+)","([^"]+)","([^"]+)","\s*\$\s*([\-\d\.\,]+)"\s*$/; my($invoice, $account, $date, $payee, $amount) = ($1, $2, $3, $4, $5); - $amount = ParseNumber($amount); + $amount = ParseNumber($amount); + + push(@{$data{$type}{$invoice}{entries}}, { account => $account, date => $date, payee => $payee, amount => $amount}); + $data{$type}{$invoice}{total} = $ZERO unless defined $data{$type}{$invoice}{total}; + $data{$type}{$invoice}{total} += $amount; + } + close LEDGER_FUNDS; + die "Failure on ledger command for $type: $!" unless ($? == 0); + +} +foreach my $type (keys %data) { + foreach my $invoice (keys %{$data{$type}}) { + delete $data{$type}{$invoice} if abs($data{$type}{$invoice}{total}) <= $TWO_CENTS; + } +} +foreach my $type (keys %data) { + delete $data{$type} if scalar(keys %{$data{$type}}) == 0; +} +foreach my $type (keys %data) { + print "\"SCHEDULE OF $type\"\n\"ENDING:\",\"$formattedEndDate\"\n\n", + '"DATE","PAYEE","ACCOUNT","AMOUNT","INVOICE"', "\n"; + foreach my $invoice (keys %{$data{$type}}) { + my $vals; + foreach my $vals (@{$data{$type}{$invoice}{entries}}) { + print "\"$vals->{date}\",\"$vals->{payee}\",\"$vals->{account}\",\"\$$vals->{amount}\",\"link:$invoice\"\n"; + } } + print "pagebreak\n"; } ############################################################################### # -- cgit v1.2.3 From 6d98bc58ae555d5d4487e7ee90c6ce8b2a49cbe6 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 6 Jan 2013 19:28:46 -0500 Subject: Correct sorting of output in trial balance report. --- contrib/non-profit-audit-reports/summary-reports.plx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index bbe83c88..e9e1a3b8 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -430,10 +430,13 @@ my $curOn = 'Assets'; foreach my $account (sort preferredAccountSorting keys %fullAccountList) { # Blank lines right if ($account !~ /^$curOn/) { - print TRIAL "\n"; + print TRIAL "pagebreak\n"; $curOn = $account; - $curOn =~ s/^([^:]+):.*$/$1/; - print "CurOn now: $curOn\n"; + if ($curOn =~ /(Accrued:[^:]+):.*$/) { + $curOn = $1; + } else { + $curOn =~ s/^([^:]+):.*$/$1/; + } } if ($account =~ /^Assets|Liabilities|Accrued|Unearned Income/) { foreach my $id (qw/totalBeginFY totalEndFY amountInYear/) { -- cgit v1.2.3 From 8cddda4c3eb67234c12285fe52bd2bc328f6678b Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 6 Jan 2013 19:43:54 -0500 Subject: More flexible CSV -> ODS hyperlinks and pagebreaks; csv2ods.py produces MANIFEST. Previous version of csv2ods.py simply assumed that fields beyond five would have links to files. This obviously lacked flexibility and was a silly hard-code. Now, those CSV fields that have link:SOMETHING will cause a hyperlink to be created to SOMETHING. Meanwhile, the pagebreak support was similarly hard-coded. Now, any CSV field that has the word "pagebreak" in it will generate a pagebreak. The general ledger and cash receipts/disbursement journals have been modified to make use of these new features in csv2ods.py. Finally, the --skip-page-break option is now moot in csv2ods.py, so that is herein removed. --- .../cash-receipts-and-disbursments-journals.plx | 4 +- contrib/non-profit-audit-reports/csv2ods.py | 43 +++++++++++++--------- .../general-ledger-report.plx | 6 ++- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx index 346e4064..2ad18a44 100755 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -113,7 +113,7 @@ foreach my $acct (@accounts) { my $formatString = '\n"%(date)","%C","%P","%A","%t"\n%/"","","","%A","%t"'; foreach my $tagField (qw/Receipt Invoice Statement Contract PurchaseOrder Approval Check IncomeDistributionAnalysis CurrencyRate/) { print CSV_OUT ',"', $tagField, '"'; - $formatString .= ',"%(tag(\'' . $tagField . '\'))"'; + $formatString .= ',"link:%(tag(\'' . $tagField . '\'))"'; } $formatString .= "\n"; print CSV_OUT "\n"; @@ -130,7 +130,7 @@ foreach my $acct (@accounts) { open(CSV_DATA, "-|", $LEDGER_CMD, @csvRegLedgerOpts) or die "unable to run ledger command for $fileNameBase.csv: $!"; - while (my $line = ) { print CSV_OUT $line; } + while (my $line = ) { $line =~ s/"link:"/""/g; print CSV_OUT $line; } close(CSV_DATA); die "Error read from csv ledger command $!" unless $? == 0; SKIP_REGISTER_COMMANDS: diff --git a/contrib/non-profit-audit-reports/csv2ods.py b/contrib/non-profit-audit-reports/csv2ods.py index e6d33906..8b880648 100755 --- a/contrib/non-profit-audit-reports/csv2ods.py +++ b/contrib/non-profit-audit-reports/csv2ods.py @@ -24,14 +24,13 @@ import sys, os, os.path, optparse import csv import ooolib2 -file_fields = [ 'Receipt', 'Invoice', 'Statement', 'Contract', 'PurchaseOrder', - 'Approval', 'Check', 'IncomeDistributionAnalysis', 'CurrencyRate' ] - def err(msg): print 'error: %s' % msg sys.exit(1) -def csv2ods(csvname, odsname, encoding='', verbose = False, skip_page_break = False): +def csv2ods(csvname, odsname, encoding='', verbose = False): + filesSavedinManifest = {} + if verbose: print 'converting from %s to %s' % (csvname, odsname) doc = ooolib2.Calc() @@ -45,7 +44,7 @@ def csv2ods(csvname, odsname, encoding='', verbose = False, skip_page_break = Fa style_currency = doc.styles.get_next_style('cell') style_data = tuple([style]) doc.styles.style_config[style_data] = style_currency - + row = 1 csvdir = os.path.dirname(csvname) if len(csvdir) == 0: @@ -61,26 +60,39 @@ def csv2ods(csvname, odsname, encoding='', verbose = False, skip_page_break = Fa if len(val) > 0 and val[0] == '$': doc.set_cell_value(col + 1, row, 'currency', val[1:]) else: - if ((col >= 5) and (not val in file_fields) and len(val) > 0): + if (len(val) > 0 and val[0:5] == "link:"): + val = val[5:] linkrel = '../' + val # ../ means remove the name of the *.ods linkname = os.path.basename(val) # name is just the last component doc.set_cell_value(col + 1, row, 'link', (linkrel, linkname)) linkpath = csvdir + '/' + val + + if not val in filesSavedinManifest: + filesSavedinManifest[val] = col + + if not os.path.exists(linkpath): + print "WARNING: link %s DOES NOT EXIST at %s" % (val, linkpath) if verbose: if os.path.exists(linkpath): print 'relative link %s EXISTS at %s' % (val, linkpath) - else: - print 'relative link %s DOES NOT EXIST at %s' % (val, linkpath) else: - doc.set_cell_value(col + 1, row, 'string', val) + if val == "pagebreak": + doc.sheets[doc.sheet_index].set_sheet_config(('row', row), style_pagebreak) + else: + doc.set_cell_value(col + 1, row, 'string', val) else: # enter an empty string for blank lines doc.set_cell_value(1, row, 'string', '') - # put a pagebreak here - if not skip_page_break: - doc.sheets[doc.sheet_index].set_sheet_config(('row', row), style_pagebreak) row += 1 - # save the file + # save manifest file + if filesSavedinManifest.keys() != []: + manifestFH = open("MANIFEST", "a") + manifestFH.write("# Files from %s\n" % odsname) + for file in filesSavedinManifest.keys(): + manifestFH.write("%s\n" % file) + + manifestFH.close() + # Save spreadsheet file. doc.save(odsname) def main(): @@ -97,9 +109,6 @@ def main(): help='ods output filename') parser.add_option('-e', '--encoding', action='store', help='unicode character encoding type') - parser.add_option('-s', '--skip-page-break', action='store_true', - dest='skip_page_break', - help='do not add any page breaks') (options, args) = parser.parse_args() if len(args) != 0: parser.error("not expecting extra args") @@ -113,7 +122,7 @@ def main(): print 'csv:', options.csv print 'ods:', options.ods print 'ods:', options.encoding - csv2ods(options.csv, options.ods, options.encoding, options.verbose, options.skip_page_break) + csv2ods(options.csv, options.ods, options.encoding, options.verbose) if __name__ == '__main__': main() diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 3b230837..1fd0e7ce 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -181,7 +181,7 @@ foreach my $acct (@sortedAccounts) { my $formatString = '"%(date)","%C","%P","%t",""'; foreach my $tagField (qw/Receipt Invoice Statement Contract PurchaseOrder Approval Check IncomeDistributionAnalysis CurrencyRate/) { print GL_CSV_OUT ',"', $tagField, '"'; - $formatString .= ',"%(tag(\'' . $tagField . '\'))"'; + $formatString .= ',"link:%(tag(\'' . $tagField . '\'))"'; } $formatString .= "\n"; print GL_CSV_OUT "\n"; @@ -195,12 +195,14 @@ foreach my $acct (@sortedAccounts) { or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!"; foreach my $line () { + $line =~ s/"link:"/""/g; print GL_CSV_OUT $line; next if $line =~ /ACCOUNT:.*PERIOD/; # Skip column header lines $line =~ s/^"[^"]*","[^"]*","[^"]*","[^"]*","[^"]*",//; while ($line =~ s/^"([^"]*)"(,|$)//) { my $file = $1; next if $file =~ /^\s*$/; + $file =~ s/^link:(.*)$/$1/; warn "$file does not exist and/or is not readable" unless -r $file; print MANIFEST "$file\n" if not defined $manifest{$file}; $manifest{$file} = $line; @@ -210,7 +212,7 @@ foreach my $acct (@sortedAccounts) { $balanceData{totalEnd}{$acct} = $ZERO unless defined $balanceData{totalEnd}{$acct}; print GL_CSV_OUT "\"$formattedEndDate\"", ',"","BALANCE","","$', "$balanceData{totalEnd}{$acct}\"\n"; } - + print GL_CSV_OUT "pagebreak\n"; close(GL_CSV_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; } close(GL_TEXT_OUT); die "error writing to general-ledger.txt: $!" unless $? == 0; -- cgit v1.2.3 From 9d78dc639593e5ae6f4ccbf7867131763df33dcd Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 6 Jan 2013 19:48:22 -0500 Subject: The restricted fund report has been almost entirely rewritten. The previous version was somewhat confusing anyway. Now it builds a relatively clear spreadsheet of all categories. It also now outputs CSV. --- contrib/non-profit-audit-reports/fund-report.plx | 221 ++++++++++++++++------- 1 file changed, 151 insertions(+), 70 deletions(-) diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index 0c03d009..ce59da96 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -1,9 +1,19 @@ #!/usr/bin/perl # fund-report.plx -*- Perl -*- # -# Script to generate a Trial Balance report for a ledger. +# Script to generate a Restricted Fund Report. Usefulness of this +# script may be confined to those who track separate funds in their +# accounts by having accounts that match this format: +# /^(Income|Expenses|Unearned Income|(Accrued:[^:]+:):PROJECTNAME/ + +# Conservancy does this because we carefully track fund balances for our +# fiscal sponsored projects. Those who aren't fiscal sponsors won't find +# this report all that useful, I suspect. Note that the name +# "Conservancy" is special-cased in a few places, mainly because our +# "General" fund is called "Conservancy". + # -# Copyright (C) 2011, 2012, Bradley M. Kuhn +# Copyright (C) 2011, 2012, 2013 Bradley M. Kuhn # # This program gives you software freedom; you can copy, modify, convey, # and/or redistribute it under the terms of the GNU General Public License @@ -36,6 +46,7 @@ sub ParseNumber($) { } Math::BigFloat->precision(-2); my $ZERO = Math::BigFloat->new("0.00"); +my $TWO_CENTS = Math::BigFloat->new("0.02"); if (@ARGV < 2) { print STDERR "usage: $0 \n"; @@ -45,71 +56,65 @@ my($startDate, $endDate, @mainLedgerOptions) = @ARGV; my $err; my $formattedEndDate = UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 day"), \$err), - "%B %e, %Y"); + "%Y/%m/%d"); die "Date calculation error on $endDate" if ($err); -my $formattedStartDate = UnixDate(ParseDate($startDate), "%B %e, %Y"); +my $formattedStartDate = UnixDate(ParseDate($startDate), "%Y/%m/%d"); die "Date calculation error on $startDate" if ($err); -# First, get fund list from ending balance -my(@ledgerOptions) = (@mainLedgerOptions, - '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-s', - '-e', $endDate, 'reg', '/^Funds:Restricted:/'); +# First, get balances for starting and ending for each fund + my %funds; -open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) - or die "Unable to run $LEDGER_CMD for funds: $!"; - -while (my $fundLine = ) { - die "Unable to parse output line from first funds command: \"$fundLine\"" - unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\-\d\.\,]+)/; - my($account, $amount) = ($1, $2); - $amount = ParseNumber($amount); - $account =~ s/\s+$//; - next if $account =~ /\/ and (abs($amount) <= 0.02); - die "Weird account found, $account with amount of $amount in first funds command\n" - unless $account =~ s/^\s*Funds:Restricted://; - $funds{$account}{ending} = $amount; -} -close LEDGER_FUNDS; +foreach my $type ('starting', 'ending') { + my(@ledgerOptions) = (@mainLedgerOptions, + '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-s'); -# First, get fund list from starting balance -@ledgerOptions = (@mainLedgerOptions, - '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-w', '-s', - '-e', $startDate, 'reg', '^Funds:Restricted:'); - -open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) - or die "Unable to run $LEDGER_CMD for funds: $!"; - -while (my $fundLine = ) { - die "Unable to parse output line from second funds command: $fundLine" - unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*([\-\d\.\,]+)/; - my($account, $amount) = ($1, $2); - $amount = ParseNumber($amount); - $account =~ s/\s+$//; - next if $account =~ /\/ and (abs($amount) <= 0.02); - die "Weird account found, $account with amount of $amount in first second command\n" - unless $account =~ s/^\s*Funds:Restricted://; - $funds{$account}{starting} = $amount; + if ($type eq 'starting') { + push(@ledgerOptions, '-e', $startDate); + } else { + push(@ledgerOptions,'-e', $endDate); + } + push(@ledgerOptions, 'reg', '/^(Income|Expenses):([^:]+):/'); + + open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) + or die "Unable to run $LEDGER_CMD @ledgerOptions: $!"; + + while (my $fundLine = ) { + die "Unable to parse output line from first funds command: \"$fundLine\"" + unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\-\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $account =~ s/\s+$//; + next if $account =~ /\/ and (abs($amount) <= $TWO_CENTS); + die "Weird account found, $account with amount of $amount in command: @ledgerOptions\n" + unless $account =~ s/^\s*(?:Income|Expenses):([^:]+)://; + $account = $1; + $account = 'General' if $account eq 'Conservancy'; # FIXME: this is a special case for Consrevancy + $funds{$account}{$type} += $amount; + } + close LEDGER_FUNDS; + die "Failure on ledger command @ledgerOptions: $!" unless ($? == 0); } -close LEDGER_FUNDS; - - foreach my $fund (keys %funds) { - $funds{$fund}{starting} = $ZERO if not defined $funds{$fund}{starting}; + foreach my $type (keys %{$funds{$fund}}) { + $funds{$fund}{$type} = $ZERO - $funds{$fund}{$type}; + } } - -@ledgerOptions = (@mainLedgerOptions, +my(@ledgerOptions) = (@mainLedgerOptions, '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-w', '-s', '-b', $startDate, '-e', $endDate, 'reg'); -my @possibleTypes = ('Unearned Income', 'Retained Earnings', 'Retained Costs', - 'Accrued:Accounts Payable', 'Accrued:Accounts Receivable'); +my @possibleTypes = ('Income', 'Expenses', 'Unearned Income', 'Retained Earnings', 'Retained Costs', + 'Accrued:Loans Receivable', 'Accrued:Accounts Payable', + 'Accrued:Accounts Receivable', 'Accrued:Expenses'); -foreach my $type ('Income', 'Expenses', @possibleTypes) { +foreach my $type (@possibleTypes) { foreach my $fund (keys %funds) { - open(LEDGER_INCOME, "-|", $LEDGER_CMD, @ledgerOptions, "^${type}:$fund") + my $query; + $query = ($fund eq 'General') ? "/^${type}:Conservancy/": "/^${type}:$fund/"; + open(LEDGER_INCOME, "-|", $LEDGER_CMD, @ledgerOptions, $query) or die "Unable to run $LEDGER_CMD for funds: $!"; - $funds{$fund}{$type} = $ZERO; + $funds{$fund}{$type} = $ZERO; while (my $line = ) { die "Unable to parse output line from $type line command: $line" unless $line =~ /^\s*([^\$]+)\s+\$\s*\s*([\-\d\.\,]+)/; @@ -118,34 +123,110 @@ foreach my $type ('Income', 'Expenses', @possibleTypes) { $funds{$fund}{$type} += $amount; } close LEDGER_INCOME; + die "Failure on ledger command for ${type}:$fund: $!" unless ($? == 0); + } +} + +my %tot; +($tot{Start}, $tot{End}) = ($ZERO, $ZERO); + +my %beforeEndings = ('Income' => 1, 'Expenses' => 1); +my %afterEndings; + +# For other @possibleTypes, build up @fieldsList to just thoes that are present. + +foreach my $fund (keys %funds) { + foreach my $type (@possibleTypes) { + if ($funds{$fund}{$type} != $ZERO) { + if ($type =~ /^(Unearned Income|Accrued)/) { + $afterEndings{$type} = 1; + } else { + $beforeEndings{$type} = 1; + } + } } } +my(@beforeEndingFields, @afterEndingFields); + +foreach my $ii (@possibleTypes) { + push(@beforeEndingFields, $ii) if defined $beforeEndings{$ii}; + push(@afterEndingFields, $ii) if defined $afterEndings{$ii}; +} +# Make sure fieldLists present items are zero for those that should be zero. +foreach my $fund (keys %funds) { + foreach my $type ('starting', @beforeEndingFields, 'ending', @afterEndingFields) { + $funds{$fund}{$type} = $ZERO unless defined $funds{$fund}{$type}; + } +} + +print '"RESTRICTED AND GENERAL FUND REPORT",', "\"BEGINNING:\",\"$formattedStartDate\",\"ENDING:\",\"$formattedEndDate\"\n\n"; +print '"FUND","STARTING BALANCE",'; +my @finalPrints; +foreach my $type (@beforeEndingFields) { + $tot{$type} = $ZERO; + my $formattedType = $type; + print "\"$formattedType\","; +} +print '"ENDING BALANCE",""'; +foreach my $type (@afterEndingFields) { + $tot{$type} = $ZERO; + my $formattedType = $type; + $formattedType = "Prepaid Expenses" if $formattedType eq 'Accrued:Expenses'; + $formattedType =~ s/^Accrued://; + print ",\"$formattedType\""; +} +print "\n\n"; -my($totStart, $totEnd) = ($ZERO, $ZERO); +sub printTotal ($$) { + my($label, $tot) = @_; + print "\"$label\",\"\$$tot->{Start}\","; + foreach my $type (@beforeEndingFields) { + print "\"\$$tot->{$type}\","; + } + print "\"\$$tot->{End}\",\"\""; + foreach my $type (@afterEndingFields) { + print ",\"\$$tot->{$type}\""; + } + print "\n"; +} -foreach my $fund (sort keys %funds) { +foreach my $fund (sort { + if ($a eq "General") { return 1 } + elsif ($b eq "General") { return -1 } + else { return $a cmp $b } } + keys %funds) { my $sanityTotal = $funds{$fund}{starting}; - print "Fund: $fund\n", sprintf("%-35s\$%26.2f\n\n", "Balance as of $formattedStartDate:", - $funds{$fund}{starting}); - foreach my $type ('Income', 'Expenses', @possibleTypes) { - my $formattedType = $type; $formattedType =~ s/^Accrued://; - next if $type ne 'Income' and $type ne 'Expenses' and $funds{$fund}{$type} == $ZERO; - print sprintf("%19s during period: \$%26.2f\n", $formattedType, $funds{$fund}{$type}); + + if ($fund eq 'General') { + print "\n"; + printTotal("Restricted Subtotal", \%tot); + print "\n"; + } + $tot{Start} += $funds{$fund}{starting}; + $tot{End} += $funds{$fund}{ending}; + + print "\"$fund\",\"\$$funds{$fund}{starting}\","; + foreach my $type (@beforeEndingFields) { + print "\"\$$funds{$fund}{$type}\","; + $tot{$type} += $funds{$fund}{$type}; + } + print "\"\$$funds{$fund}{ending}\",\"\""; + foreach my $type (@afterEndingFields) { + print ",\"\$$funds{$fund}{$type}\""; + $tot{$type} += $funds{$fund}{$type}; } - print sprintf("\n%-35s\$%26.2f\n", "Balance as of $formattedEndDate:", - $funds{$fund}{ending}), "\n\n"; + print "\n"; # Santity check: - if ($funds{$fund}{ending} != + if (abs($funds{$fund}{ending} - ($funds{$fund}{starting} - - $funds{$fund}{Income} - $funds{$fund}{'Unearned Income'} - $funds{$fund}{Expenses})) { - print "$fund FAILED SANITY CHECK\n\n\n"; - die "$fund FAILED SANITY CHECK"; + - $funds{$fund}{Income} - $funds{$fund}{Expenses})) + > $TWO_CENTS) { + print "$fund FAILED SANITY CHECK: Ending: $funds{$fund}{ending} \n\n\n"; + warn "$fund FAILED SANITY CHECK"; } - $totStart += $funds{$fund}{starting}; - $totEnd += $funds{$fund}{ending}; } -print "\n\n\nTotal Restricted Funds as of $formattedStartDate: ", sprintf("\$%15.2f\n", $totStart); -print "\nTotal Restricted Funds as of $formattedStartDate: ", sprintf("\$%15.2f\n", $totEnd); +print "\n"; +printTotal("OVERALL TOTAL", \%tot); ############################################################################### # # Local variables: -- cgit v1.2.3 From 67a598f6ff3b9b19b08af108c8bfe26064728457 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Mon, 7 Jan 2013 20:15:49 -0700 Subject: Bug551 fixed, commodities and accounts now sort Added two compare structs for std::map to use. I tried to override the < operator got a clean compile but map wasn't picking it up, I couldn't figure out why so I took the less elegant route. --- src/account.h | 7 +++++++ src/commodity.h | 7 +++++++ src/output.h | 4 ++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/account.h b/src/account.h index a2fcb8de..3642ada0 100644 --- a/src/account.h +++ b/src/account.h @@ -308,6 +308,13 @@ std::ostream& operator<<(std::ostream& out, const account_t& account); void put_account(property_tree::ptree& pt, const account_t& acct, function pred); +//simple struct added to allow std::map to compare accounts in the accounts report +struct account_compare { + bool operator() (const account_t& lhs, const account_t& rhs){ + return (lhs.fullname().compare(rhs.fullname()) < 0); + } +}; + } // namespace ledger #endif // _ACCOUNT_H diff --git a/src/commodity.h b/src/commodity.h index ab496850..37b02e74 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -349,6 +349,13 @@ inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) { void put_commodity(property_tree::ptree& pt, const commodity_t& comm, bool commodity_details = false); +//simple struct to allow std::map to compare commodities names +struct commodity_compare { + bool operator() (const commodity_t* lhs, const commodity_t* rhs){ + return (lhs->symbol().compare(rhs->symbol()) < 0); + } +}; + } // namespace ledger #endif // _COMMODITY_H diff --git a/src/output.h b/src/output.h index 281f69b6..5ce9dc58 100644 --- a/src/output.h +++ b/src/output.h @@ -142,7 +142,7 @@ class report_accounts : public item_handler protected: report_t& report; - std::map accounts; + std::map accounts; typedef std::map::value_type accounts_pair; @@ -194,7 +194,7 @@ class report_commodities : public item_handler protected: report_t& report; - std::map commodities; + std::map commodities; typedef std::map::value_type commodities_pair; -- cgit v1.2.3 From 82ac7ef313ae8a8d9251706d66345efed6bf90ab Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 11 Jan 2013 00:10:30 -0600 Subject: Guard against a possible NULL --- src/filters.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/filters.cc b/src/filters.cc index 5e2bf983..7570809a 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -983,7 +983,8 @@ void interval_posts::flush() sort_posts_by_date()); // Determine the beginning interval by using the earliest post - if (! interval.find_period(all_posts.front()->date())) + if (all_posts.front() && + ! interval.find_period(all_posts.front()->date())) throw_(std::logic_error, _("Failed to find period for interval report")); // Walk the interval forward reporting all posts within each one -- cgit v1.2.3 From aba0a5ed2dc2dc91f61be32f4c12a5cf6bffd754 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 11 Jan 2013 07:08:51 -0600 Subject: Improvement to account alias expansion Aliases are now expanded not only if they occur by themselves, but also if they occur as the beginning of a multi-part account. Given the account should now be expanded to . --- src/journal.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/journal.cc b/src/journal.cc index e6c09125..f45b7527 100644 --- a/src/journal.cc +++ b/src/journal.cc @@ -127,8 +127,19 @@ account_t * journal_t::register_account(const string& name, post_t * post, // object. if (account_aliases.size() > 0) { accounts_map::const_iterator i = account_aliases.find(name); - if (i != account_aliases.end()) + if (i != account_aliases.end()) { result = (*i).second; + } else { + // only check the very first account for alias expansion, in case + // that can be expanded successfully + size_t colon = name.find(':'); + if(colon != string::npos) { + accounts_map::const_iterator i = account_aliases.find(name.substr(0, colon)); + if (i != account_aliases.end()) { + result = find_account((*i).second->fullname() + name.substr(colon)); + } + } + } } // Create the account object and associate it with the journal; this -- cgit v1.2.3 From ea09a8d50720f0ca42cee46d017e111a4349fa97 Mon Sep 17 00:00:00 2001 From: Simon Michael Date: Fri, 11 Jan 2013 10:07:58 -0800 Subject: escape @ characters properly so they show up --- doc/ledger3.texi | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index f99504f0..caec7667 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -1312,9 +1312,9 @@ your opening balance entry could look like this: Assets:Joint Checking $800.14 Assets:Other Checking $63.44 Assets:Savings $2805.54 - Assets:Investments:401K:Deferred 100.0000 VIFSX @ $80.5227 - Assets:Investments:401K:Matching 50.0000 VIFSX @ $83.7015 - Assets:Investments:IRA 250.0000 VTHRX @ $20.5324 + Assets:Investments:401K:Deferred 100.0000 VIFSX @@ $80.5227 + Assets:Investments:401K:Matching 50.0000 VIFSX @@ $83.7015 + Assets:Investments:IRA 250.0000 VTHRX @@ $20.5324 Liabilities:Mortgage $-175634.88 Liabilities:Car Loan $-3494.26 Liabilities:Visa -$1762.44 @@ -2970,12 +2970,12 @@ resulting posting cost is $50.00 per share. @node Explicit posting costs, Posting cost expressions, Posting cost, Transactions @section Explicit posting costs -You can make any posting's cost explicit using the @ symbol after the amount +You can make any posting's cost explicit using the @@ symbol after the amount or amount expression: @smallexample 2012-03-10 My Broker - Assets:Brokerage 10 AAPL @ $50.00 + Assets:Brokerage 10 AAPL @@ $50.00 Assets:Brokerage:Cash $-500.00 @end smallexample @@ -2984,7 +2984,7 @@ the first posting's cost, you can elide the other amount: @smallexample 2012-03-10 My Broker - Assets:Brokerage 10 AAPL @ $50.00 + Assets:Brokerage 10 AAPL @@ $50.00 Assets:Brokerage:Cash @end smallexample @@ -3029,7 +3029,7 @@ You can even have both: @node Total posting costs, Virtual posting costs, Posting cost expressions, Transactions @section Total posting costs -The cost figure following the @ character specifies the @emph{per-unit} price for +The cost figure following the @@ character specifies the @emph{per-unit} price for the commodity being transferred. If you'd like to specify the total cost instead, use @@@@: @@ -3149,7 +3149,7 @@ Plus, it comes with dangers. This works fine: @smallexample 2012-04-10 My Broker - Assets:Brokerage 10 AAPL @ $50.00 + Assets:Brokerage 10 AAPL @@ $50.00 Assets:Brokerage:Cash $750.00 2012-04-10 My Broker @@ -3167,7 +3167,7 @@ Plus, it comes with dangers. This works fine: @smallexample 2012-04-10 My Broker - Assets:Brokerage 10 AAPL @ $50.00 + Assets:Brokerage 10 AAPL @@ $50.00 Assets:Brokerage:Cash $750.00 2012-04-10 My Broker @@ -3192,7 +3192,7 @@ following two transactions are equivalent: @smallexample 2012-04-10 My Broker - Assets:Brokerage 10 AAPL @ $50.00 + Assets:Brokerage 10 AAPL @@ $50.00 Assets:Brokerage:Cash $750.00 2012-04-10 My Broker @@ -3257,7 +3257,7 @@ that dates are parsed in value expressions): You can also associate arbitrary notes for your own record keeping in parentheses, and reveal them with --lot-notes. One caveat is that the note -cannot begin with an @ character, as that would indicate a virtual cost: +cannot begin with an @@ character, as that would indicate a virtual cost: @smallexample 2012-04-10 My Broker @@ -4914,7 +4914,7 @@ model transaction: --- Context is first posting of the following transaction --- 2004/05/27 Book Store ; This note applies to all postings. :SecondTag: - Expenses:Books 20 BOOK @ $10 + Expenses:Books 20 BOOK @@ $10 ; Metadata: Some Value ; Typed:: $100 + $200 ; :ExampleTag: -- cgit v1.2.3 From c88862fd66489fa8c06d06d3876b2c0f59dff3a5 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Mon, 14 Jan 2013 16:23:16 +0100 Subject: convert doc/Makefile to CMake CMake will build the pdf version of the manual if texi2pdf is installed. It will be installed to DOCDIR/ledger{,3}.pdf, for example /usr/local/share/ledger/ledger3.pdf. Also, the man page will be installed to MANDIR/man1/ledger.1 The option BUILD_DOCS is now on by default. A new option BUILD_WEB_DOCS is used to toggle the generation of the html version of the manual and the man page (off by default). All this is added to the 'doc' make target. --- CMakeLists.txt | 5 ++-- doc/CMakeLists.txt | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ doc/Makefile | 17 ------------- 3 files changed, 76 insertions(+), 19 deletions(-) delete mode 100644 doc/Makefile diff --git a/CMakeLists.txt b/CMakeLists.txt index a4109a17..132d7c47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8.5) -project(Ledger) +PROJECT(ledger) set(Ledger_VERSION_MAJOR 3) set(Ledger_VERSION_MINOR 0) @@ -18,7 +18,8 @@ option(DISABLE_ASSERTS "Build without any internal consistency checks" OFF) option(BUILD_DEBUG "Build support for runtime debugging" OFF) option(BUILD_LIBRARY "Build and install Ledger as a library" ON) -option(BUILD_DOCS "Build and install documentation" OFF) +option(BUILD_DOCS "Build and install documentation" ON) +option(BUILD_WEB_DOCS "Build version of documentation suitable for viewing online" OFF) option(BUILD_EMACSLISP "Build and install ledger-mode for Emacs" OFF) if(BUILD_DEBUG) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index e69de29b..b50c8696 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -0,0 +1,73 @@ +set(info_files ledger.texi ledger3.texi) + +find_program(MAKEINFO makeinfo) +find_program(TEXI2PDF texi2pdf) +find_program(MAN2HTML man2html) + +######################################################################## + +foreach(file ${info_files}) + get_filename_component(file_base ${file} NAME_WE) + if(BUILD_WEB_DOCS) + if(NOT MAKEINFO) + message(FATAL_ERROR "Could not find makeinfo. HTML version of documentation cannot be built.") + endif() + + add_custom_command(OUTPUT ${file_base}.html + COMMAND makeinfo --force --html --no-split -o ${file_base}.html ${file} + DEPENDS ${file} + VERBATIM) + list(APPEND ledger_doc_files ${file_base}.html) + endif(BUILD_WEB_DOCS) + + if(NOT TEXI2PDF) + mesage(WARNING "Could not find texi2pdf. PDF version of documentation will not be built.") + else() + get_filename_component(file_base ${file} NAME_WE) + add_custom_command(OUTPUT ${file_base}.pdf + COMMAND texi2pdf -b -q ${file} + COMMAND rm -f ${file_base}.aux ${file_base}.cp ${file_base}.fn ${file_base}.ky ${file_base}.log ${file_base}.pg ${file_base}.toc ${file_base}.tp ${file_base}.vr + DEPENDS ${file} + VERBATIM) + list(APPEND ledger_doc_files ${file_base}.pdf) + endif() +endforeach() + +######################################################################## + +if(BUILD_WEB_DOCS) + include(FindUnixCommands) + if(NOT BASH) + message(FATAL_ERROR "Could not find bash. Unable to build documentation.") + endif() + if(NOT MAN2HTML) + message(FATAL_ERROR "Could not find man2html. HTML version of man page cannot be built.") + endif() + + add_custom_command(OUTPUT ledger.1.html + COMMAND ${BASH} -c "man2html ledger.1 | tail -n+3 > ledger.1.html" + DEPENDS ledger.1 + VERBATIM) + list(APPEND ledger_doc_files ledger.1.html) +endif(BUILD_WEB_DOCS) + +######################################################################## + +add_custom_target(doc ALL DEPENDS ${ledger_doc_files}) + +######################################################################## + +include(GNUInstallDirs) + +if(CMAKE_INSTALL_MANDIR) + install(FILES ledger.1 + DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT doc) +endif(CMAKE_INSTALL_MANDIR) + +if(CMAKE_INSTALL_DOCDIR) + foreach(file ${info_files}) + get_filename_component(file_base ${file} NAME_WE) + install(FILES ${file_base}.pdf + DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT doc OPTIONAL) + endforeach() +endif(CMAKE_INSTALL_DOCDIR) diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 64a271fa..00000000 --- a/doc/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# quick doc-building makefile used by website -# requires: man2html, texinfo - -docs: ledger.1.html ledger.html ledger.pdf ledger3.html ledger3.pdf - -%.1.html: %.1 - -man2html $< | tail -n+3 >$@ - -%.html: %.texi - -makeinfo --force --html --no-split -o $@ $< - -%.pdf: %.texi - -texi2pdf -b -q $< - rm -f $*.aux $*.cp $*.fn $*.ky $*.log $*.pg $*.toc $*.tp $*.vr - -clean: - rm -rf ledger.1.html ledger.html ledger3.html ledger.pdf ledger3.pdf -- cgit v1.2.3 From dd105fecd79d1c7e6fb3e22ace19b1359dd7de3b Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Mon, 14 Jan 2013 22:38:30 +0100 Subject: fix issue for separate build dir --- doc/CMakeLists.txt | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index b50c8696..a817c151 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -14,8 +14,8 @@ foreach(file ${info_files}) endif() add_custom_command(OUTPUT ${file_base}.html - COMMAND makeinfo --force --html --no-split -o ${file_base}.html ${file} - DEPENDS ${file} + COMMAND makeinfo --force --html --no-split -o ${file_base}.html ${CMAKE_CURRENT_SOURCE_DIR}/${file} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file} VERBATIM) list(APPEND ledger_doc_files ${file_base}.html) endif(BUILD_WEB_DOCS) @@ -23,11 +23,9 @@ foreach(file ${info_files}) if(NOT TEXI2PDF) mesage(WARNING "Could not find texi2pdf. PDF version of documentation will not be built.") else() - get_filename_component(file_base ${file} NAME_WE) add_custom_command(OUTPUT ${file_base}.pdf - COMMAND texi2pdf -b -q ${file} - COMMAND rm -f ${file_base}.aux ${file_base}.cp ${file_base}.fn ${file_base}.ky ${file_base}.log ${file_base}.pg ${file_base}.toc ${file_base}.tp ${file_base}.vr - DEPENDS ${file} + COMMAND texi2pdf -b -q --tidy -o ${file_base}.pdf ${CMAKE_CURRENT_SOURCE_DIR}/${file} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file} VERBATIM) list(APPEND ledger_doc_files ${file_base}.pdf) endif() @@ -45,8 +43,8 @@ if(BUILD_WEB_DOCS) endif() add_custom_command(OUTPUT ledger.1.html - COMMAND ${BASH} -c "man2html ledger.1 | tail -n+3 > ledger.1.html" - DEPENDS ledger.1 + COMMAND ${BASH} -c "man2html $<1:CMAKE_CURRENT_SOURCE_DIR>/ledger.1 | tail -n+3 > ledger.1.html" + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ledger.1 VERBATIM) list(APPEND ledger_doc_files ledger.1.html) endif(BUILD_WEB_DOCS) @@ -60,14 +58,14 @@ add_custom_target(doc ALL DEPENDS ${ledger_doc_files}) include(GNUInstallDirs) if(CMAKE_INSTALL_MANDIR) - install(FILES ledger.1 + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/ledger.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT doc) endif(CMAKE_INSTALL_MANDIR) if(CMAKE_INSTALL_DOCDIR) foreach(file ${info_files}) get_filename_component(file_base ${file} NAME_WE) - install(FILES ${file_base}.pdf + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${file_base}.pdf DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT doc OPTIONAL) endforeach() endif(CMAKE_INSTALL_DOCDIR) -- cgit v1.2.3 From b13f0c33c3c9633ef370633817e35bb35c399b42 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Mon, 14 Jan 2013 22:24:56 +0100 Subject: repair doxygen support --- CMakeLists.txt | 4 +- doc/CMakeLists.txt | 18 + doc/Doxyfile | 1485 ---------------------------------------------------- doc/Doxyfile.in | 1485 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1504 insertions(+), 1488 deletions(-) delete mode 100644 doc/Doxyfile create mode 100644 doc/Doxyfile.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 132d7c47..f18df69a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -276,9 +276,7 @@ elseif(CMAKE_CXX_COMPILER MATCHES "g\\+\\+") endif() add_subdirectory(src) -if(BUILD_DOCS) - add_subdirectory(doc) -endif() +add_subdirectory(doc) if(BUILD_EMACSLISP) add_subdirectory(lisp) endif() diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index a817c151..54c58737 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,3 +1,21 @@ +if (USE_DOXYGEN) + find_package(Doxygen) + if(NOT DOXYGEN_FOUND) + message(FATAL_ERROR "Could not find doxygen. Reference documentation cannot be built.") + endif() + + configure_file(Doxyfile.in Doxyfile @ONLY) + add_custom_target(doxygen ALL + COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile + SOURCES Doxyfile) +endif(USE_DOXYGEN) + +######################################################################## + +if(NOT BUILD_DOCS) + return() +endif() + set(info_files ledger.texi ledger3.texi) find_program(MAKEINFO makeinfo) diff --git a/doc/Doxyfile b/doc/Doxyfile deleted file mode 100644 index d59d3f82..00000000 --- a/doc/Doxyfile +++ /dev/null @@ -1,1485 +0,0 @@ -# Doxyfile 1.5.7.1 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = Ledger - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = 3.0 - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = %builddir%/doc - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, -# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, -# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, -# Spanish, Swedish, and Ukrainian. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = YES - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = YES - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = NO - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = %srcdir%/src/ - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = YES - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = YES - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen to replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penality. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will rougly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols - -SYMBOL_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = NO - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = YES - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = YES - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = NO - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = YES - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = NO - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by -# doxygen. The layout file controls the global structure of the generated output files -# in an output format independent way. The create the layout file that represents -# doxygen's defaults, run doxygen with the -l option. You can optionally specify a -# file name after the option, if omitted DoxygenLayout.xml will be used as the name -# of the layout file. - -LAYOUT_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -# jww (2009-01-31): Enable this toward the end -#WARN_IF_UNDOCUMENTED = YES -WARN_IF_UNDOCUMENTED = NO - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = YES - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = src - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 - -FILE_PATTERNS = *.h - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = * - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = YES - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = YES - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER -# are set, an additional index file will be generated that can be used as input for -# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated -# HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# Qt Help Project / Namespace. - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# Qt Help Project / Virtual Folders. - -QHP_VIRTUAL_FOLDER = doc - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file . - -QHG_LOCATION = - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to FRAME, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. Other possible values -# for this tag are: HIERARCHIES, which will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list; -# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which -# disables this behavior completely. For backwards compatibility with previous -# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE -# respectively. - -GENERATE_TREEVIEW = YES - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = YES - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = letter - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = YES - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = YES - -# By default doxygen will write a font called FreeSans.ttf to the output -# directory and reference it in all dot files that doxygen generates. This -# font does not include all possible unicode characters however, so when you need -# these (or just want a differently looking font) you can specify the font name -# using DOT_FONTNAME. You need need to make sure dot is able to find the font, -# which can be done by putting it in a standard location or by setting the -# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -# containing the font. - -DOT_FONTNAME = FreeSans - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 11 - -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = YES - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = YES - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = jpg - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 1000 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in new file mode 100644 index 00000000..734eb8df --- /dev/null +++ b/doc/Doxyfile.in @@ -0,0 +1,1485 @@ +# Doxyfile 1.5.7.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = Ledger + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 3.0 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@ + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = YES + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@/src/ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = YES + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +# jww (2009-01-31): Enable this toward the end +#WARN_IF_UNDOCUMENTED = YES +WARN_IF_UNDOCUMENTED = NO + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @PROJECT_SOURCE_DIR@/src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# Qt Help Project / Namespace. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# Qt Help Project / Virtual Folders. + +QHP_VIRTUAL_FOLDER = doc + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file . + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = letter + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 11 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = YES + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = jpg + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 1000 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO -- cgit v1.2.3 From 428490e917f1858acdcc3f70441353da2cb382c5 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Tue, 15 Jan 2013 00:23:25 +0100 Subject: fix for 'store absolute paths internally' `parent_path` was called on unprocessed path so neither `resolve_path` nor `filesystem::absolute` had any effect. --- src/context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context.h b/src/context.h index 7373be39..9fe0613b 100644 --- a/src/context.h +++ b/src/context.h @@ -121,7 +121,7 @@ inline parse_context_t open_for_reading(const path& pathname, throw_(std::runtime_error, _f("Cannot read journal file %1%") % filename); - path parent(pathname.parent_path()); + path parent(filename.parent_path()); shared_ptr stream(new ifstream(filename)); parse_context_t context(stream, parent); context.pathname = filename; -- cgit v1.2.3 From 2b1cfd670681fe732daf81b4d0bb6eb4749eb240 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Tue, 15 Jan 2013 00:33:14 +0100 Subject: remove superfluous 'break' --- src/item.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/item.cc b/src/item.cc index 24d03ba1..362fac7f 100644 --- a/src/item.cc +++ b/src/item.cc @@ -476,7 +476,6 @@ expr_t::ptr_op_t item_t::lookup(const symbol_t::kind_t kind, else if (name == "filepath") return WRAP_FUNCTOR(get_wrapper<&get_filepath>); break; - break; case 'h': if (name == "has_tag") -- cgit v1.2.3 From a633bc7fcedfecb0da557a19866e6e9bca131e6a Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Tue, 15 Jan 2013 10:07:50 +0100 Subject: add unit tests for amount_t→floor/ceil MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/unit/t_amount.cc | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/test/unit/t_amount.cc b/test/unit/t_amount.cc index 07cde8f3..b82de510 100644 --- a/test/unit/t_amount.cc +++ b/test/unit/t_amount.cc @@ -1109,6 +1109,60 @@ BOOST_AUTO_TEST_CASE(testCommodityAbs) BOOST_CHECK(x2.valid()); } +BOOST_AUTO_TEST_CASE(testFloor) +{ + amount_t x0; + amount_t x1("123.123"); + amount_t x2("-123.123"); + + BOOST_CHECK_THROW(x0.floored(), amount_error); + BOOST_CHECK_EQUAL(amount_t(123L), x1.floored()); + BOOST_CHECK_EQUAL(amount_t(-124L), x2.floored()); + + BOOST_CHECK(x0.valid()); + BOOST_CHECK(x1.valid()); + BOOST_CHECK(x2.valid()); +} + +BOOST_AUTO_TEST_CASE(testCommodityFloor) +{ + amount_t x1("$1234.56"); + amount_t x2("$-1234.56"); + + BOOST_CHECK_EQUAL(amount_t("$1234"), x1.floored()); + BOOST_CHECK_EQUAL(amount_t("$-1235"), x2.floored()); + + BOOST_CHECK(x1.valid()); + BOOST_CHECK(x2.valid()); +} + +BOOST_AUTO_TEST_CASE(testCeiling) +{ + amount_t x0; + amount_t x1("123.123"); + amount_t x2("-123.123"); + + BOOST_CHECK_THROW(x0.ceilinged(), amount_error); + BOOST_CHECK_EQUAL(amount_t(124L), x1.ceilinged()); + BOOST_CHECK_EQUAL(amount_t(-123L), x2.ceilinged()); + + BOOST_CHECK(x0.valid()); + BOOST_CHECK(x1.valid()); + BOOST_CHECK(x2.valid()); +} + +BOOST_AUTO_TEST_CASE(testCommodityCeiling) +{ + amount_t x1("$1234.56"); + amount_t x2("$-1234.56"); + + BOOST_CHECK_EQUAL(amount_t("$1235"), x1.ceilinged()); + BOOST_CHECK_EQUAL(amount_t("$-1234"), x2.ceilinged()); + + BOOST_CHECK(x1.valid()); + BOOST_CHECK(x2.valid()); +} + #ifndef NOT_FOR_PYTHON #if 0 BOOST_AUTO_TEST_CASE(testReduction) -- cgit v1.2.3 From 0a1ff035421d5f97675ad769a7fcdbc68399f3dc Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Tue, 8 Jan 2013 23:20:08 +0100 Subject: fix bug 788: behaviour of source_context for '-f -' `session_t::read_data` did not set context.pathname to `/dev/stdin` for the special case `-f -`. I chose to adjust `source_context` too as there is no sensible context if no file name is provided. --- src/error.cc | 2 +- src/session.cc | 1 + test/regress/BF3C1F82.test | 12 ++++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 test/regress/BF3C1F82.test diff --git a/src/error.cc b/src/error.cc index 58339db7..d7e92daa 100644 --- a/src/error.cc +++ b/src/error.cc @@ -84,7 +84,7 @@ string source_context(const path& file, const string& prefix) { const std::streamoff len = end_pos - pos; - if (! len || file == path("/dev/stdin")) + if (! len || file == path("/dev/stdin") || file.empty()) return _(""); assert(len > 0); diff --git a/src/session.cc b/src/session.cc index b6153203..a8bb628a 100644 --- a/src/session.cc +++ b/src/session.cc @@ -159,6 +159,7 @@ std::size_t session_t::read_data(const string& master_account) shared_ptr stream(new std::istringstream(buffer.str())); parsing_context.push(stream); + parsing_context.get_current().pathname = "/dev/stdin"; } else { parsing_context.push(pathname); } diff --git a/test/regress/BF3C1F82.test b/test/regress/BF3C1F82.test new file mode 100644 index 00000000..8d465f4d --- /dev/null +++ b/test/regress/BF3C1F82.test @@ -0,0 +1,12 @@ +; Check that error reporting works for "-f -" + +2012/02/30 * Test + a 1 + b +test -f - reg -> 1 +__ERROR__ +While parsing file "/dev/stdin", line 3: +While parsing transaction: + +Error: Day of month is not valid for year +end test -- cgit v1.2.3 From d922f4659570c87a06352b0da9d877f047ec442c Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Tue, 15 Jan 2013 23:30:17 +0100 Subject: fix bug 748: option aliases not recognized --- src/report.cc | 15 +++++++++++---- test/baseline/opt-aux-date.test | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/report.cc b/src/report.cc index 08365a6b..d4beaf2a 100644 --- a/src/report.cc +++ b/src/report.cc @@ -1089,6 +1089,7 @@ option_t * report_t::lookup_option(const char * p) else OPT(anon); else OPT_ALT(color, ansi); else OPT(auto_match); + else OPT(aux_date); else OPT(average); else OPT(account_width_); else OPT(amount_width_); @@ -1096,7 +1097,7 @@ option_t * report_t::lookup_option(const char * p) case 'b': OPT(balance_format_); else OPT(base); - else OPT_ALT(basis, cost); + else OPT(basis); else OPT_(begin_); else OPT(bold_if_); else OPT(budget); @@ -1105,6 +1106,7 @@ option_t * report_t::lookup_option(const char * p) break; case 'c': OPT(csv_format_); + else OPT_ALT(gain, change); else OPT(cleared); else OPT(collapse); else OPT(collapse_if_zero); @@ -1122,6 +1124,7 @@ option_t * report_t::lookup_option(const char * p) else OPT(dc); else OPT(depth_); else OPT(deviation); + else OPT_ALT(rich_data, detail); else OPT_(display_); else OPT(display_amount_); else OPT(display_total_); @@ -1146,7 +1149,7 @@ option_t * report_t::lookup_option(const char * p) else OPT_ALT(head_, first_); break; case 'g': - OPT_ALT(gain, change); + OPT(gain); else OPT(group_by_); else OPT(group_title_format_); else OPT(generated); @@ -1173,7 +1176,7 @@ option_t * report_t::lookup_option(const char * p) else OPT_ALT(tail_, last_); break; case 'm': - OPT_ALT(market, value); + OPT(market); else OPT(monthly); else OPT(meta_); else OPT(meta_width_); @@ -1203,6 +1206,7 @@ option_t * report_t::lookup_option(const char * p) else OPT(price); else OPT(prices_format_); else OPT(pricedb_format_); + else OPT(primary_date); else OPT(payee_width_); else OPT(prepend_format_); else OPT(prepend_width_); @@ -1220,7 +1224,7 @@ option_t * report_t::lookup_option(const char * p) else OPT(revalued); else OPT(revalued_only); else OPT(revalued_total_); - else OPT_ALT(rich_data, detail); + else OPT(rich_data); break; case 's': OPT(sort_); @@ -1247,6 +1251,9 @@ option_t * report_t::lookup_option(const char * p) else OPT(unrealized_losses_); else OPT(unround); break; + case 'v': + OPT_ALT(market, value); + break; case 'w': OPT(weekly); else OPT_(wide); diff --git a/test/baseline/opt-aux-date.test b/test/baseline/opt-aux-date.test index 9d1e73d0..495bb7e6 100644 --- a/test/baseline/opt-aux-date.test +++ b/test/baseline/opt-aux-date.test @@ -10,7 +10,7 @@ Expenses:Books $20.00 Assets:Cash -test reg --effective +test reg --aux-date 08-Jan-01 January Expenses:Books $10.00 $10.00 Assets:Cash $-10.00 0 08-Feb-01 End of January Expenses:Books $10.00 $10.00 -- cgit v1.2.3 From 855432c4cd32b03b0751cffb0e215f2ceefdc6e5 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Wed, 16 Jan 2013 11:44:13 -0800 Subject: Fixed ledger-add-entry copied ledger-iterate-entries, ledger-set-year and ledger-set-month from the old ledger.el. Changed ledger-add-entry to use ledger-exec-ledger vice the old ledger-run-ledger. --- lisp/ldg-mode.el | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 6090a312..04c6ee1b 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -76,6 +76,47 @@ Return the difference in the format of a time value." (if (ledger-time-less-p moment date) (throw 'found t))))))) +(defun ledger-iterate-entries (callback) + (goto-char (point-min)) + (let* ((now (current-time)) + (current-year (nth 5 (decode-time now)))) + (while (not (eobp)) + (when (looking-at + (concat "\\(Y\\s-+\\([0-9]+\\)\\|" + "\\([0-9]\\{4\\}+\\)?[./]?" + "\\([0-9]+\\)[./]\\([0-9]+\\)\\s-+" + "\\(\\*\\s-+\\)?\\(.+\\)\\)")) + (let ((found (match-string 2))) + (if found + (setq current-year (string-to-number found)) + (let ((start (match-beginning 0)) + (year (match-string 3)) + (month (string-to-number (match-string 4))) + (day (string-to-number (match-string 5))) + (mark (match-string 6)) + (desc (match-string 7))) + (if (and year (> (length year) 0)) + (setq year (string-to-number year))) + (funcall callback start + (encode-time 0 0 0 day month + (or year current-year)) + mark desc))))) + (forward-line)))) + +(defun ledger-set-year (newyear) + "Set ledger's idea of the current year to the prefix argument." + (interactive "p") + (if (= newyear 1) + (setq ledger-year (read-string "Year: " (ledger-current-year))) + (setq ledger-year (number-to-string newyear)))) + +(defun ledger-set-month (newmonth) + "Set ledger's idea of the current month to the prefix argument." + (interactive "p") + (if (= newmonth 1) + (setq ledger-month (read-string "Month: " (ledger-current-month))) + (setq ledger-month (format "%02d" newmonth)))) + (defun ledger-add-entry (entry-text &optional insert-at-point) (interactive "sEntry: ") (let* ((args (with-temp-buffer @@ -95,7 +136,7 @@ Return the difference in the format of a time value." (insert (with-temp-buffer (setq exit-code - (apply #'ledger-run-ledger ledger-buf "entry" + (apply #'ledger-exec-ledger ledger-buf ledger-buf "entry" (mapcar 'eval args))) (goto-char (point-min)) (if (looking-at "Error: ") -- cgit v1.2.3 From 3ed53b7b3c6fb3a82f863e07414372681aa92768 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Tue, 15 Jan 2013 00:31:12 +0100 Subject: whitespace cleanup --- src/amount.cc | 2 +- src/global.cc | 4 ++-- src/global.h | 6 +++--- src/journal.cc | 8 ++++---- src/xact.cc | 10 +++++----- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/amount.cc b/src/amount.cc index 4e658212..cba9a282 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -684,7 +684,7 @@ void amount_t::in_place_ceiling() throw_(amount_error, _("Cannot ceiling an uninitialized amount")); _dup(); - + mpz_t quot; mpz_init(quot); mpz_cdiv_q(quot, mpq_numref(MP(quantity)), mpq_denref(MP(quantity))); diff --git a/src/global.cc b/src/global.cc index 3e83ba04..bc172075 100644 --- a/src/global.cc +++ b/src/global.cc @@ -477,8 +477,8 @@ void handle_debug_options(int argc, char * argv[]) #endif } else if (i + 1 < argc && std::strcmp(argv[i], "--init-file") == 0) { - _init_file = argv[i + 1]; - i++; + _init_file = argv[i + 1]; + i++; } else if (i + 1 < argc && std::strcmp(argv[i], "--debug") == 0) { #if DEBUG_ON diff --git a/src/global.h b/src/global.h index d37043fc..dc6abd78 100644 --- a/src/global.h +++ b/src/global.h @@ -153,14 +153,14 @@ See LICENSE file included with the distribution for details and disclaimer."); OPTION__ (global_scope_t, init_file_, // -i CTOR(global_scope_t, init_file_) { - if(!_init_file.empty()) + if (!_init_file.empty()) // _init_file is filled during handle_debug_options on(none, _init_file); else if (const char * home_var = std::getenv("HOME")) - on(none, (path(home_var) / ".ledgerrc").string()); + on(none, (path(home_var) / ".ledgerrc").string()); else - on(none, path("./.ledgerrc").string()); + on(none, path("./.ledgerrc").string()); }); OPTION(global_scope_t, options); diff --git a/src/journal.cc b/src/journal.cc index f45b7527..68939be6 100644 --- a/src/journal.cc +++ b/src/journal.cc @@ -134,10 +134,10 @@ account_t * journal_t::register_account(const string& name, post_t * post, // that can be expanded successfully size_t colon = name.find(':'); if(colon != string::npos) { - accounts_map::const_iterator i = account_aliases.find(name.substr(0, colon)); - if (i != account_aliases.end()) { - result = find_account((*i).second->fullname() + name.substr(colon)); - } + accounts_map::const_iterator i = account_aliases.find(name.substr(0, colon)); + if (i != account_aliases.end()) { + result = find_account((*i).second->fullname() + name.substr(colon)); + } } } } diff --git a/src/xact.cc b/src/xact.cc index 7888dadf..7ac7a9e9 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -803,12 +803,12 @@ void auto_xact_t::extend_xact(xact_base_t& xact, parse_context_t& context) post_t * new_post = new post_t(account, amt); new_post->copy_details(*post); - // A Cleared transaction implies all of its automatic posting are cleared + // A Cleared transaction implies all of its automatic posting are cleared // CPR 2012/10/23 - if(xact.state() == item_t::CLEARED){ - DEBUG("xact.extend.cleared", "CLEARED"); - new_post->set_state(item_t::CLEARED); - } + if (xact.state() == item_t::CLEARED) { + DEBUG("xact.extend.cleared", "CLEARED"); + new_post->set_state(item_t::CLEARED); + } new_post->add_flags(ITEM_GENERATED); new_post->account = -- cgit v1.2.3 From 23483b7973f3db45cace4ff9529daed54a0059c6 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 16 Jan 2013 17:40:39 -0600 Subject: On the Mac, texi2pdf doesn't have a --tidy option --- doc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 54c58737..a812d9fe 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -42,7 +42,7 @@ foreach(file ${info_files}) mesage(WARNING "Could not find texi2pdf. PDF version of documentation will not be built.") else() add_custom_command(OUTPUT ${file_base}.pdf - COMMAND texi2pdf -b -q --tidy -o ${file_base}.pdf ${CMAKE_CURRENT_SOURCE_DIR}/${file} + COMMAND texi2pdf -b -q -o ${file_base}.pdf ${CMAKE_CURRENT_SOURCE_DIR}/${file} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file} VERBATIM) list(APPEND ledger_doc_files ${file_base}.pdf) -- cgit v1.2.3 From 24b791ad078e36cfd8f895544636320467aa70ce Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 16 Jan 2013 17:50:31 -0600 Subject: Apply patch to update ldg-reconcile.el --- lisp/ldg-reconcile.el | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index baeadc33..d3dda60f 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -105,7 +105,45 @@ (ledger-reconcile-save)) (defun ledger-do-reconcile () - ) + (let* ((buf ledger-buf) + (account ledger-acct) + (items + (with-current-buffer + (apply #'ledger-exec-ledger + buf nil "emacs" account "--uncleared" '("--real")) + (goto-char (point-min)) + (unless (eobp) + (unless (looking-at "(") + (error (buffer-string))) + (read (current-buffer)))))) + (dolist (item items) + (let ((index 1)) + (dolist (xact (nthcdr 5 item)) + (let ((beg (point)) + (where + (with-current-buffer buf + (cons + (nth 0 item) + (if ledger-clear-whole-entries + (save-excursion + (goto-line (nth 1 item)) + (point-marker)) + (save-excursion + (goto-line (nth 0 xact)) + (point-marker))))))) + (insert (format "%s %-30s %-25s %15s\n" + (format-time-string "%m/%d" (nth 2 item)) + (nth 4 item) (nth 1 xact) (nth 2 xact))) + (if (nth 3 xact) + (set-text-properties beg (1- (point)) + (list 'face 'bold + 'where where)) + (set-text-properties beg (1- (point)) + (list 'where where)))) + (setq index (1+ index))))) + (goto-char (point-min)) + (set-buffer-modified-p nil) + (toggle-read-only t))) (defun ledger-reconcile (account) (interactive "sAccount to reconcile: ") -- cgit v1.2.3 From d1c96190e9549267782704eab991bf304d3f86e2 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 16 Jan 2013 18:10:30 -0600 Subject: Revert "fix bug 788: behaviour of source_context for '-f -'" This reverts commit 0a1ff035421d5f97675ad769a7fcdbc68399f3dc. --- src/error.cc | 2 +- src/session.cc | 1 - test/regress/BF3C1F82.test | 12 ------------ 3 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 test/regress/BF3C1F82.test diff --git a/src/error.cc b/src/error.cc index d7e92daa..58339db7 100644 --- a/src/error.cc +++ b/src/error.cc @@ -84,7 +84,7 @@ string source_context(const path& file, const string& prefix) { const std::streamoff len = end_pos - pos; - if (! len || file == path("/dev/stdin") || file.empty()) + if (! len || file == path("/dev/stdin")) return _(""); assert(len > 0); diff --git a/src/session.cc b/src/session.cc index a8bb628a..b6153203 100644 --- a/src/session.cc +++ b/src/session.cc @@ -159,7 +159,6 @@ std::size_t session_t::read_data(const string& master_account) shared_ptr stream(new std::istringstream(buffer.str())); parsing_context.push(stream); - parsing_context.get_current().pathname = "/dev/stdin"; } else { parsing_context.push(pathname); } diff --git a/test/regress/BF3C1F82.test b/test/regress/BF3C1F82.test deleted file mode 100644 index 8d465f4d..00000000 --- a/test/regress/BF3C1F82.test +++ /dev/null @@ -1,12 +0,0 @@ -; Check that error reporting works for "-f -" - -2012/02/30 * Test - a 1 - b -test -f - reg -> 1 -__ERROR__ -While parsing file "/dev/stdin", line 3: -While parsing transaction: - -Error: Day of month is not valid for year -end test -- cgit v1.2.3 From 9252c5f1f3d3e34998129be3f7e9f8521ae591f8 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 16 Jan 2013 18:14:34 -0600 Subject: Revert "Bug551 fixed, commodities and accounts now sort" This reverts commit 67a598f6ff3b9b19b08af108c8bfe26064728457. --- src/account.h | 7 ------- src/commodity.h | 7 ------- src/output.h | 4 ++-- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/account.h b/src/account.h index 3642ada0..a2fcb8de 100644 --- a/src/account.h +++ b/src/account.h @@ -308,13 +308,6 @@ std::ostream& operator<<(std::ostream& out, const account_t& account); void put_account(property_tree::ptree& pt, const account_t& acct, function pred); -//simple struct added to allow std::map to compare accounts in the accounts report -struct account_compare { - bool operator() (const account_t& lhs, const account_t& rhs){ - return (lhs.fullname().compare(rhs.fullname()) < 0); - } -}; - } // namespace ledger #endif // _ACCOUNT_H diff --git a/src/commodity.h b/src/commodity.h index 37b02e74..ab496850 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -349,13 +349,6 @@ inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) { void put_commodity(property_tree::ptree& pt, const commodity_t& comm, bool commodity_details = false); -//simple struct to allow std::map to compare commodities names -struct commodity_compare { - bool operator() (const commodity_t* lhs, const commodity_t* rhs){ - return (lhs->symbol().compare(rhs->symbol()) < 0); - } -}; - } // namespace ledger #endif // _COMMODITY_H diff --git a/src/output.h b/src/output.h index 5ce9dc58..281f69b6 100644 --- a/src/output.h +++ b/src/output.h @@ -142,7 +142,7 @@ class report_accounts : public item_handler protected: report_t& report; - std::map accounts; + std::map accounts; typedef std::map::value_type accounts_pair; @@ -194,7 +194,7 @@ class report_commodities : public item_handler protected: report_t& report; - std::map commodities; + std::map commodities; typedef std::map::value_type commodities_pair; -- cgit v1.2.3 From 74a1f63efbb5703e417e05466aca2ae51268862e Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Thu, 17 Jan 2013 09:30:36 +0100 Subject: fix ctest rules --- test/CMakeLists.txt | 2 +- test/regress/CMakeLists.txt | 20 +------------------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b5d8cf09..94ce0a0a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -22,7 +22,7 @@ macro(add_ledger_harness_tests _class) foreach(TestFile ${${_class}_TESTS}) get_filename_component(TestFile_Name ${TestFile} NAME_WE) string(FIND ${TestFile_Name} "_py" TestFile_IsPythonTest) - if((NOT TestFile_IsPythonTest) OR HAVE_BOOST_PYTHON) + if((TestFile_IsPythonTest EQUAL -1) OR HAVE_BOOST_PYTHON) add_test(${_class}Test_${TestFile_Name} ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/test/RegressTests.py ${LEDGER_LOCATION} ${PROJECT_SOURCE_DIR} diff --git a/test/regress/CMakeLists.txt b/test/regress/CMakeLists.txt index 4b6232dd..26f55e84 100644 --- a/test/regress/CMakeLists.txt +++ b/test/regress/CMakeLists.txt @@ -1,19 +1 @@ -if(HAVE_BOOST_PYTHON) - set(TEST_PYTHON_FLAGS "--python") -endif() - -if(PYTHONINTERP_FOUND) - file(GLOB REGRESSION_TESTS *.test) - foreach(TestFile ${REGRESSION_TESTS}) - get_filename_component(TestFile_Name ${TestFile} NAME_WE) - string(FIND ${TestFile_Name} "_py" TestFile_IsPythonTest) - if((NOT TestFile_IsPythonTest) OR HAVE_BOOST_PYTHON) - add_test(RegressionTest_${TestFile_Name} - ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/test/RegressTests.py - ${LEDGER_LOCATION} ${PROJECT_SOURCE_DIR} - ${TestFile} ${TEST_PYTHON_FLAGS}) - set_target_properties(check - PROPERTIES DEPENDS RegressionTest_${TestFile_Name}) - endif() - endforeach() -endif() +add_ledger_harness_tests(Regress) -- cgit v1.2.3 From ea249423d4ba00236c456080fade92f49d0622af Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Thu, 17 Jan 2013 12:07:21 +0100 Subject: allow -f /dev/stdin in test runner --- test/RegressTests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/RegressTests.py b/test/RegressTests.py index 1094d0d5..01e14191 100755 --- a/test/RegressTests.py +++ b/test/RegressTests.py @@ -100,7 +100,7 @@ class RegressFile(object): use_stdin = False if test['command'].find("-f ") != -1: test['command'] = '$ledger ' + test['command'] - if test['command'].find("-f - ") != -1: + if re.search("-f (-|/dev/stdin)(\s|$)", test['command']): use_stdin = True else: test['command'] = (('$ledger -f "%s" ' % -- cgit v1.2.3 From 3fe2ef59566ef679d9de58e5f9454b7443d9153a Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Thu, 17 Jan 2013 12:18:58 +0100 Subject: change handling of standard input For `-f /dev/stdin`, the `pathname` of the parsing context will be empty as for any other streamed input. `instance_t::include_directive` did not work as expected for `-f /dev/stdin` and relative file names. One would expect them to be relative to the current directory rather than `/dev`. This will lead to `While parsing file ""` messages. This could be adjusted to read `While parsing standard input`, but maybe it's not worth the special cases. This commit also fixes bug 788: behaviour of source_context for '-f -' --- src/error.cc | 2 +- src/item.cc | 4 ++-- src/session.cc | 2 +- test/regress/BF3C1F82-2.test | 12 ++++++++++++ test/regress/BF3C1F82.test | 19 +++++++++++++++++++ 5 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 test/regress/BF3C1F82-2.test create mode 100644 test/regress/BF3C1F82.test diff --git a/src/error.cc b/src/error.cc index 58339db7..8aa1d3d6 100644 --- a/src/error.cc +++ b/src/error.cc @@ -84,7 +84,7 @@ string source_context(const path& file, const string& prefix) { const std::streamoff len = end_pos - pos; - if (! len || file == path("/dev/stdin")) + if (! len || file.empty()) return _(""); assert(len > 0); diff --git a/src/item.cc b/src/item.cc index 362fac7f..4e2a487c 100644 --- a/src/item.cc +++ b/src/item.cc @@ -582,8 +582,8 @@ string item_context(const item_t& item, const string& desc) std::ostringstream out; - if (item.pos->pathname == path("/dev/stdin")) { - out << desc << _(" from standard input:"); + if (item.pos->pathname.empty()) { + out << desc << _(" from streamed input:"); return out.str(); } diff --git a/src/session.cc b/src/session.cc index b6153203..f047a540 100644 --- a/src/session.cc +++ b/src/session.cc @@ -143,7 +143,7 @@ std::size_t session_t::read_data(const string& master_account) } foreach (const path& pathname, HANDLER(file_).data_files) { - if (pathname == "-") { + if (pathname == "-" || pathname == "/dev/stdin") { // To avoid problems with stdin and pipes, etc., we read the entire // file in beforehand into a memory buffer, and then parcel it out // from there. diff --git a/test/regress/BF3C1F82-2.test b/test/regress/BF3C1F82-2.test new file mode 100644 index 00000000..453151ce --- /dev/null +++ b/test/regress/BF3C1F82-2.test @@ -0,0 +1,12 @@ +; Check that include directives are relative for "-f /dev/stdin" +include non-existent-ledger-file-BF3C1F82 +test -f - reg -> 1 +__ERROR__ +While parsing file "", line 2: +Error: File to include was not found: "./non-existent-ledger-file-BF3C1F82" +end test +test -f /dev/stdin reg -> 1 +__ERROR__ +While parsing file "", line 2: +Error: File to include was not found: "./non-existent-ledger-file-BF3C1F82" +end test diff --git a/test/regress/BF3C1F82.test b/test/regress/BF3C1F82.test new file mode 100644 index 00000000..50f4106f --- /dev/null +++ b/test/regress/BF3C1F82.test @@ -0,0 +1,19 @@ +; Check that error reporting works for "-f -" + +2012/02/30 * Test + a 1 + b +test -f - reg -> 1 +__ERROR__ +While parsing file "", line 3: +While parsing transaction: + +Error: Day of month is not valid for year +end test +test -f /dev/stdin reg -> 1 +__ERROR__ +While parsing file "", line 3: +While parsing transaction: + +Error: Day of month is not valid for year +end test -- cgit v1.2.3 From 252bc9bcf5bc64f31940302fba386cacadbeb949 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Sat, 19 Jan 2013 13:22:59 +0100 Subject: only run doxygen once To update the documentation run `ninja doxygen` or `make doxygen`. --- doc/CMakeLists.txt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index a812d9fe..7154be70 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -5,14 +5,22 @@ if (USE_DOXYGEN) endif() configure_file(Doxyfile.in Doxyfile @ONLY) - add_custom_target(doxygen ALL + add_custom_command(OUTPUT html/index.html COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile - SOURCES Doxyfile) + DEPENDS Doxyfile + COMMENT "Building doxygen documentation") + add_custom_target(doxygen + COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile + DEPENDS Doxyfile + COMMENT "Building doxygen documentation") + message("NOTE: Doxygen documentation will be built once. Use target doxygen to update.") + list(APPEND ledger_doc_files html/index.html) endif(USE_DOXYGEN) ######################################################################## if(NOT BUILD_DOCS) + add_custom_target(doc ALL DEPENDS ${ledger_doc_files}) return() endif() -- cgit v1.2.3 From d5323000ca61bc6a247694375d87c18fcfc7eee3 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Sat, 19 Jan 2013 13:24:29 +0100 Subject: update Doxyfile.in (using doxygen -u) --- .gitignore | 2 +- doc/Doxyfile.in | 1748 ++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 1070 insertions(+), 680 deletions(-) diff --git a/.gitignore b/.gitignore index 02f6433a..e4d6e4f0 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ .libs/ ABOUT-NLS BaselineTests -Doxyfile.gen Makefile Makefile.am Makefile.in @@ -34,6 +33,7 @@ configure configure.ac data_tests depcomp +doc/Doxyfile doc/*.aux doc/*.cp doc/*.fn diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 734eb8df..7cee2256 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -1,89 +1,103 @@ -# Doxyfile 1.5.7.1 +# Doxyfile 1.8.3 # This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project +# doxygen (www.doxygen.org) for a project. # -# All text after a hash (#) is considered a comment and will be ignored +# All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") +# Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. PROJECT_NAME = Ledger -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = 3.0 -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@ -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, -# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, -# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, -# Spanish, Swedish, and Ukrainian. +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class" \ @@ -98,130 +112,168 @@ ABBREVIATE_BRIEF = "The $name class" \ an \ the -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = YES -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = YES -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@/src/ -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = YES -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO -# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. -ALIASES = +ALIASES = -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES @@ -231,473 +283,557 @@ BUILTIN_STL_SUPPORT = YES CPP_CLI_SUPPORT = NO -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen to replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penality. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will rougly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. SYMBOL_CACHE_SIZE = 0 +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO -# If the EXTRACT_STATIC tag is set to YES all static members of a file +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = NO -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = YES -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = YES -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = NO -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = YES -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the +# Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if section-label ... \endif +# and \cond section-label ... \endcond blocks. -ENABLED_SECTIONS = +ENABLED_SECTIONS = -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = NO - # Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the +# This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. This will remove the Namespaces entry from the Quick Index +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by -# doxygen. The layout file controls the global structure of the generated output files -# in an output format independent way. The create the layout file that represents -# doxygen's defaults, run doxygen with the -l option. You can optionally specify a -# file name after the option, if omitted DoxygenLayout.xml will be used as the name -# of the layout file. +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. Do not use +# file names with spaces, bibtex cannot handle them. -LAYOUT_FILE = +CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- -# The QUIET tag can be used to turn on/off the messages that are generated +# The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. # jww (2009-01-31): Enable this toward the end -#WARN_IF_UNDOCUMENTED = YES WARN_IF_UNDOCUMENTED = NO -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = YES -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written # to stderr. -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = @PROJECT_SOURCE_DIR@/src -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.h -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. -EXCLUDE = +EXCLUDE = -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see # the \include command). -EXAMPLE_PATH = +EXAMPLE_PATH = -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = * -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see # the \image command). -IMAGE_PATH = +IMAGE_PATH = -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be # ignored. -INPUT_FILTER = +INPUT_FILTER = -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. -FILTER_PATTERNS = +FILTER_PATTERNS = -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page (index.html). +# This can be useful if you have a project on for instance GitHub and want reuse +# the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES -# Setting the INLINE_SOURCES tag to YES will include the body +# Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. STRIP_CODE_COMMENTS = YES -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES @@ -705,20 +841,21 @@ REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. +# link to the source code. +# Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES @@ -727,130 +864,201 @@ VERBATIM_HEADERS = YES # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. -IGNORE_PREFIX = +IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = -HTML_HEADER = +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. -HTML_FOOTER = +HTML_EXTRA_FILES = -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. -HTML_STYLESHEET = +HTML_COLORSTYLE_HUE = 220 -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. -HTML_ALIGN_MEMBERS = YES +HTML_COLORSTYLE_SAT = 100 -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. HTML_DYNAMIC_SECTIONS = NO -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. GENERATE_DOCSET = NO -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be # written to the html output directory. -CHM_FILE = +CHM_FILE = -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. -HHC_LOCATION = +HHC_LOCATION = -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO @@ -859,235 +1067,396 @@ GENERATE_CHI = NO # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. -CHM_INDEX_ENCODING = +CHM_INDEX_ENCODING = -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO -# The TOC_EXPAND flag can be set to YES to add extra items for group members +# The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER -# are set, an additional index file will be generated that can be used as input for -# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated -# HTML documentation. +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. -QCH_FILE = +QCH_FILE = -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# Qt Help Project / Namespace. +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# Qt Help Project / Virtual Folders. +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file . +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters -QHG_LOCATION = +QHP_CUST_FILTER_NAME = -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. -DISABLE_INDEX = NO +QHP_CUST_FILTER_ATTRS = -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. -ENUM_VALUES_PER_LINE = 4 +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. -# If the tag value is set to FRAME, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. Other possible values -# for this tag are: HIERARCHIES, which will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list; -# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which -# disables this behavior completely. For backwards compatibility with previous -# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE -# respectively. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = YES -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and +# SVG. The default value is HTML-CSS, which is slower, but has the best +# compatibility. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. +# There are two flavours of web server based search depending on the +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for +# searching and an index file used by the script. When EXTERNAL_SEARCH is +# enabled the indexing and searching needs to be provided by external tools. +# See the manual for details. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain +# the search results. Doxygen ships with an example indexer (doxyindexer) and +# search engine (doxysearch.cgi) which are based on the open source search engine +# library Xapian. See the manual for configuration details. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will returned the search results when EXTERNAL_SEARCH is enabled. +# Doxygen ships with an example search engine (doxysearch) which is based on +# the open source search engine library Xapian. See the manual for configuration +# details. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. + +SEARCHDATA_FILE = searchdata.xml + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through other +# doxygen projects that are not otherwise connected via tags files, but are +# all added to the same search index. Each project needs to have a tag file set +# via GENERATE_TAGFILE. The search mapping then maps the name of the tag file +# to a relative location where the documentation can be found, +# similar to the +# TAGFILES option but without actually processing the tag file. +# The format is: EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... + +EXTRA_SEARCH_MAPPINGS = + #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. LATEX_CMD_NAME = latex -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = letter -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. -EXTRA_PACKAGES = +EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! -LATEX_HEADER = +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = -# Set optional variables used in the generation of an rtf document. +# Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. -RTF_EXTENSIONS_FILE = +RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man -# The MAN_EXTENSION tag determines the extension that is added to +# The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO @@ -1096,33 +1465,33 @@ MAN_LINKS = NO # configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the # syntax of the XML files. -XML_SCHEMA = +XML_SCHEMA = -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the # syntax of the XML files. -XML_DTD = +XML_DTD = -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES @@ -1131,10 +1500,10 @@ XML_PROGRAMLISTING = YES # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO @@ -1143,343 +1512,364 @@ GENERATE_AUTOGEN_DEF = NO # configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. -PERLMOD_MAKEVAR_PREFIX = +PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- -# Configuration options related to the preprocessor +# Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = YES -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by # the preprocessor. -INCLUDE_PATH = +INCLUDE_PATH = -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = +PREDEFINED = -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- -# Configuration::additions related to external references +# Configuration::additions related to external references #--------------------------------------------------------------------------- -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. -GENERATE_TAGFILE = +GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES -# The PERL_PATH should be the absolute path and name of the perl script +# The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. -MSCGEN_PATH = +MSCGEN_PATH = -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES -# By default doxygen will write a font called FreeSans.ttf to the output -# directory and reference it in all dot files that doxygen generates. This -# font does not include all possible unicode characters however, so when you need -# these (or just want a differently looking font) you can specify the font name -# using DOT_FONTNAME. You need need to make sure dot is able to find the font, -# which can be done by putting it in a standard location or by setting the -# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -# containing the font. +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. DOT_FONTNAME = FreeSans -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 11 -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. -DOT_FONTPATH = +DOT_FONTPATH = -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO -# If set to YES, the inheritance and collaboration graphs will show the +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = YES -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = YES -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = jpg -# The tag DOT_PATH can be used to specify the path where the dot tool can be +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. -DOT_PATH = +DOT_PATH = -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the # \dotfile command). -DOTFILE_DIRS = +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 1000 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO -- cgit v1.2.3 From b66c19b1f8a6449af89154e75b2348ad41080c00 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Sat, 19 Jan 2013 13:27:15 +0100 Subject: doxygen: enable search and folding --- doc/Doxyfile.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 7cee2256..ff08c0f1 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -986,7 +986,7 @@ HTML_TIMESTAMP = YES # documentation will contain sections that can be hidden and shown after the # page has loaded. -HTML_DYNAMIC_SECTIONS = NO +HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of # entries shown in the various tree structured indices initially; the user @@ -1245,7 +1245,7 @@ MATHJAX_EXTENSIONS = # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. -SEARCHENGINE = NO +SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. -- cgit v1.2.3 From 54c14f9770e86eca0312d3e5ec3bb201c484358f Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Sat, 19 Jan 2013 22:56:12 +0100 Subject: improve doxygen build logic Doxygen will only be called when the 'doc' target is built and one of its input files has changed. --- doc/CMakeLists.txt | 32 ++++++++++++++++++++++---------- doc/Doxyfile.in | 2 ++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 7154be70..6753b3a8 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,3 +1,13 @@ +# The following will be generated or updated… +# …for every build (target 'doc.auto'): +# • user guide and man pages: if BUILD_DOCS is set +# • HTML versions of the above: if BUILD_DOCS and BUILD_WEB_DOCS are set +# +# …only when the 'doc' target is built explicitly: +# • Doxygen / reference documentation: if USE_DOXYGEN is set + +######################################################################## + if (USE_DOXYGEN) find_package(Doxygen) if(NOT DOXYGEN_FOUND) @@ -5,22 +15,23 @@ if (USE_DOXYGEN) endif() configure_file(Doxyfile.in Doxyfile @ONLY) + + # see INPUT/FILE_PATTERNS in Doxyfile.in + file(GLOB doxygen_input_files ${CMAKE_SOURCE_DIR}/src/*.h) + add_custom_command(OUTPUT html/index.html COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile - DEPENDS Doxyfile - COMMENT "Building doxygen documentation") - add_custom_target(doxygen - COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile - DEPENDS Doxyfile + DEPENDS Doxyfile ${doxygen_input_files} COMMENT "Building doxygen documentation") - message("NOTE: Doxygen documentation will be built once. Use target doxygen to update.") - list(APPEND ledger_doc_files html/index.html) -endif(USE_DOXYGEN) + add_custom_target(doc.doxygen DEPENDS html/index.html) +else() + add_custom_target(doc.doxygen) +endif() ######################################################################## if(NOT BUILD_DOCS) - add_custom_target(doc ALL DEPENDS ${ledger_doc_files}) + add_custom_target(doc DEPENDS doc.doxygen) return() endif() @@ -77,7 +88,8 @@ endif(BUILD_WEB_DOCS) ######################################################################## -add_custom_target(doc ALL DEPENDS ${ledger_doc_files}) +add_custom_target(doc.auto ALL DEPENDS ${ledger_doc_files}) +add_custom_target(doc DEPENDS doc.auto doc.doxygen) ######################################################################## diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index ff08c0f1..e340d84a 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -679,6 +679,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. +# please update dependencies in CMakeList.txt if you change this INPUT = @PROJECT_SOURCE_DIR@/src # This tag can be used to specify the character encoding of the source files @@ -697,6 +698,7 @@ INPUT_ENCODING = UTF-8 # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl +# please update dependencies in CMakeList.txt if you change this FILE_PATTERNS = *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories -- cgit v1.2.3 From de128c948149dd6ae47896506c7659ad4c33a5cb Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Sat, 19 Jan 2013 23:27:08 +0100 Subject: do not auto-build documentation Use 'ninja doc' or 'make doc' instead. --- doc/CMakeLists.txt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 6753b3a8..72a6da84 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,9 +1,6 @@ -# The following will be generated or updated… -# …for every build (target 'doc.auto'): +# The following will be generated or updated when the 'doc' target is built: # • user guide and man pages: if BUILD_DOCS is set # • HTML versions of the above: if BUILD_DOCS and BUILD_WEB_DOCS are set -# -# …only when the 'doc' target is built explicitly: # • Doxygen / reference documentation: if USE_DOXYGEN is set ######################################################################## @@ -88,8 +85,7 @@ endif(BUILD_WEB_DOCS) ######################################################################## -add_custom_target(doc.auto ALL DEPENDS ${ledger_doc_files}) -add_custom_target(doc DEPENDS doc.auto doc.doxygen) +add_custom_target(doc DEPENDS ${ledger_doc_files} doc.doxygen) ######################################################################## -- cgit v1.2.3 From 5d1971ee51a18f927185d20fb0a4426d8f08aa86 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 25 Jan 2013 07:26:55 -0700 Subject: Added Huququ'llah calculation back in. Example was inadvertantly removed while writing the Automated Transaction section. --- doc/ledger3.texi | 104 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 91 insertions(+), 13 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index b8aaa49b..f60bb26e 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -1814,7 +1814,7 @@ sign. After this initial line there should be a set of one or more postings, just as if it were normal transaction. If the amounts of the postings have no commodity, they will be applied as modifiers to -whichever real posting is matched by the value expression(See @pxref{Automated transactions}). +whichever real posting is matched by the value expression(See @pxref{Automated Transactions}). @item ~ A period transaction. A period expression must appear after the tilde. @@ -2542,7 +2542,7 @@ kill the report buffer * Lot dates:: * Lot notes:: * Lot value expressions:: -* Automated transactions:: +* Automated Transactions:: @end menu @node Basic format, Eliding amounts, Transactions , Transactions @@ -3271,7 +3271,7 @@ all optional. To show all lot information in a report, use @code{--lots}. -@node Lot value expressions, Automated transactions, Lot notes, Transactions +@node Lot value expressions, Automated Transactions, Lot notes, Transactions @section Lot value expressions Normally when you ask Ledger to display the values of commodities held, it @@ -3338,8 +3338,8 @@ In most cases, it is simplest to either use explicit amounts in your valuation expressions, or just pass the arguments down to market after modifying them to suit your needs. -@node Automated transactions, , Lot value expressions, Transactions -@section Automated transactions +@node Automated Transactions, , Lot value expressions, Transactions +@section Automated Transactions An automated transaction is a special kind of transaction which adds its postings to other transactions any time one of that other transactions' @@ -3391,9 +3391,10 @@ transaction. * State flags:: * Effective Dates:: * Periodic Transactions:: +* Concrete Example of Automated Transactions:: @end menu -@node Amount multipliers, Accessing the matching posting's amount, Automated transactions, Automated transactions +@node Amount multipliers, Accessing the matching posting's amount, Automated Transactions, Automated Transactions @subsection Amount multipliers As a special case, if an automated transaction's posting's amount (phew) has @@ -3422,7 +3423,7 @@ Then the latter transaction turns into this during parsing: Bar $-1000.00 @end smallexample -@node Accessing the matching posting's amount, Referring to the matching posting's account, Amount multipliers, Automated transactions +@node Accessing the matching posting's amount, Referring to the matching posting's account, Amount multipliers, Automated Transactions @subsection Accessing the matching posting's amount If you use an amount expression for an automated transaction's posting, that @@ -3449,7 +3450,7 @@ This becomes: (Foo) $-40.00 @end smallexample -@node Referring to the matching posting's account, Applying metadata to every matched posting, Accessing the matching posting's amount, Automated transactions +@node Referring to the matching posting's account, Applying metadata to every matched posting, Accessing the matching posting's amount, Automated Transactions @subsection Referring to the matching posting's account Sometimes want to refer to the account that matched in some way within the @@ -3474,7 +3475,7 @@ Becomes: Assets:Cash $-20.00 @end smallexample -@node Applying metadata to every matched posting, Applying metadata to the generated posting, Referring to the matching posting's account, Automated transactions +@node Applying metadata to every matched posting, Applying metadata to the generated posting, Referring to the matching posting's account, Automated Transactions @subsection Applying metadata to every matched posting If the automated transaction has a transaction note, that note is copied @@ -3500,7 +3501,7 @@ Becomes: Assets:Cash $-20.00 @end smallexample -@node Applying metadata to the generated posting, State flags, Applying metadata to every matched posting, Automated transactions +@node Applying metadata to the generated posting, State flags, Applying metadata to every matched posting, Automated Transactions @subsection Applying metadata to the generated posting If the automated transaction's posting has a note, that note is carried to the @@ -3530,14 +3531,14 @@ This is slightly different from the rules for regular transaction notes, in that an automated transaction's note does not apply to every posting within the automated transaction itself, but rather to every posting it matches. -@node State flags, Effective Dates, Applying metadata to the generated posting, Automated transactions +@node State flags, Effective Dates, Applying metadata to the generated posting, Automated Transactions @subsection State flags Although you cannot mark an automated transaction as a whole as cleared or pending, you can mark its postings with a * or ! before the account name, and that state flag gets carried to the generated posting. -@node Effective Dates, Periodic Transactions, State flags, Automated transactions +@node Effective Dates, Periodic Transactions, State flags, Automated Transactions @subsection Effective Dates @cindex effective dates @@ -3604,7 +3605,7 @@ automatic $37.50 deficit like you should, while your checking account really knows that it debited $225 this month. -@node Periodic Transactions, , Effective Dates, Automated transactions +@node Periodic Transactions, Concrete Example of Automated Transactions, Effective Dates, Automated Transactions @subsection Periodic Transactions A periodic transaction starts with a ~ followed by a period expression. @@ -3614,6 +3615,83 @@ have no effect without the @code{--budget} option specified. See @ref{Budgeting and Forecasting} for examples and details. +@node Concrete Example of Automated Transactions, , Periodic Transactions, Automated Transactions +@subsection Concrete Example of Automated Transactions + + +As a Bahá'í, I need to compute Huqúqu'lláh whenever I acquire assets. +It is similar to tithing for Jews and Christians, or to Zakát for +Muslims. The exact details of computing Huqúqu'lláh are somewhat +complex, but if you have further interest, please consult the Web. + +Ledger makes this otherwise difficult law very easy. Just set up an +automated posting at the top of your ledger file: + +@smallexample +; This automated transaction will compute Huqúqu'lláh based on this +; journal's postings. Any that match will affect the +; Liabilities:Huququ'llah account by 19% of the value of that posting. + += /^(?:Income:|Expenses:(?:Business|Rent$|Furnishings|Taxes|Insurance))/ + (Liabilities:Huququ'llah) 0.19 +@end smallexample + +This automated posting works by looking at each posting in the +ledger file. If any match the given value expression, 19% of the +posting's value is applied to the @samp{Liabilities:Huququ'llah} +account. So, if $1000 is earned from @samp{Income:Salary}, $190 is +added to @samp{Liabilities:Huqúqu'lláh}; if $1000 is spent on Rent, +$190 is subtracted. The ultimate balance of Huqúqu'lláh reflects how +much is owed in order to fulfill one's obligation to Huqúqu'lláh. +When ready to pay, just write a check to cover the amount shown in +@samp{Liabilities:Huququ'llah}. That transaction would look like: + +@smallexample +2003/01/01 (101) Baha'i Huqúqu'lláh Trust + Liabilities:Huququ'llah $1,000.00 + Assets:Checking +@end smallexample + +That's it. To see how much Huqúq is currently owed based on your +ledger transactions, use: + +@smallexample +ledger balance Liabilities:Huquq +@end smallexample + +This works fine, but omits one aspect of the law: that Huquq is only +due once the liability exceeds the value of 19 mithqáls of gold (which +is roughly 2.22 ounces). So what we want is for the liability to +appear in the balance report only when it exceeds the present day +value of 2.22 ounces of gold. This can be accomplished using the +command: + +@smallexample +ledger -Q -t "/Liab.*Huquq/?(a/P@{2.22 AU@}<=@{-1.0@}&a):a" -s bal liab +@end smallexample + +With this command, the current price for gold is downloaded, and the +Huqúqu'lláh is reported only if its value exceeds that of 2.22 ounces +of gold. If you wish the liability to be reflected in the parent +subtotal either way, use this instead: + +@smallexample +ledger -Q -T "/Liab.*Huquq/?(O/P@{2.22 AU@}<=@{-1.0@}&O):O" -s bal liab +@end smallexample + +In some cases, you may wish to refer to the account of whichever +posting matched your automated transaction's value expression. To do +this, use the special account name @samp{$account}: + +@smallexample += /^Some:Long:Account:Name/ + [$account] -0.10 + [Savings] 0.10 +@end smallexample + +This example causes 10% of the matching account's total to be deferred +to the @samp{Savings} account---as a balanced virtual posting, +which may be excluded from reports by using @option{--real}. -- cgit v1.2.3 From 0bbff75f43a096823c2838ae3b7330cf86a54b78 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 29 Jan 2013 08:50:50 -0700 Subject: fixes the reconcile mode, adds menus for all modes thanks to dk for the is-std defun. --- lisp/ldg-mode.el | 38 +++++++++++++- lisp/ldg-reconcile.el | 136 ++++++++++++++++++++++++++++++-------------------- lisp/ldg-report.el | 15 ++++++ 3 files changed, 132 insertions(+), 57 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 04c6ee1b..caa57e8e 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -19,6 +19,7 @@ (defvar ledger-mode-abbrev-table) + ;;;###autoload (define-derived-mode ledger-mode text-mode "Ledger" "A mode for editing ledger data files." @@ -51,8 +52,41 @@ (define-key map [tab] 'pcomplete) (define-key map [(control ?i)] 'pcomplete) (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) - (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry)) - + (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry) + (define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report) + (define-key map [(control ?c) (control ?o) (control ?g)] 'ledger-report-goto) + (define-key map [(control ?c) (control ?o) (control ?a)] 'ledger-report-redo) + (define-key map [(control ?c) (control ?o) (control ?s)] 'ledger-report-save) + (define-key map [(control ?c) (control ?o) (control ?e)] 'ledger-report-edit) + (define-key map [(control ?c) (control ?o) (control ?k)] 'ledger-report-kill) + + + (define-key map [menu-bar] (make-sparse-keymap "ldg-menu")) + (define-key map [menu-bar ldg-menu] (cons "Ledger" map)) + + (define-key map [menu-bar ldg-menu lrk] '("Kill Report" . ledger-report-kill)) + (define-key map [menu-bar ldg-menu lre] '("Edit Report" . ledger-report-edit)) + (define-key map [menu-bar ldg-menu lrs] '("Save Report" . ledger-report-save)) + (define-key map [menu-bar ldg-menu lrr] '("Re-run Report" . ledger-report-redo)) + (define-key map [menu-bar ldg-menu lrg] '("Goto Report" . ledger-report-goto)) + (define-key map [menu-bar ldg-menu lr] '("Run Report" . ledger-report)) + (define-key map [menu-bar ldg-menu s5] '("--")) + (define-key map [menu-bar ldg-menu sm] '("Set Month" . ledger-set-month)) + (define-key map [menu-bar ldg-menu sy] '("Set Year" . ledger-set-year)) + (define-key map [menu-bar ldg-menu s1] '("--")) + (define-key map [menu-bar ldg-menu so] '("Sort Buffer" . ledger-sort)) + (define-key map [menu-bar ldg-menu s2] '("--")) + (define-key map [menu-bar ldg-menu te] '("Toggle Current Posting" . ledger-toggle-current)) + (define-key map [menu-bar ldg-menu tt] '("Toggle Current Transaction" . ledger-toggle-current-entry)) + (define-key map [menu-bar ldg-menu s4] '("--")) + (define-key map [menu-bar ldg-menu de] '("Delete Entry" . ledger-delete-current-entry)) + (define-key map [menu-bar ldg-menu ae] '("Add Entry" . ledger-add-entry)) + (define-key map [menu-bar ldg-menu s3] '("--")) + (define-key map [menu-bar ldg-menu re] '("Reconcile Account" . ledger-reconcile))) + + + + (ledger-report-patch-reports (current-buffer))) (defun ledger-time-less-p (t1 t2) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index d3dda60f..73409e66 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -4,18 +4,24 @@ (defvar ledger-acct nil) (defun ledger-display-balance () + "Calculate the cleared balance of the account being reconciled" (let ((buffer ledger-buf) (account ledger-acct)) (with-temp-buffer - (let ((exit-code (ledger-run-ledger buffer "-C" "balance" account))) - (if (/= 0 exit-code) - (message "Error determining cleared balance") - (goto-char (1- (point-max))) - (goto-char (line-beginning-position)) - (delete-horizontal-space) - (message "Cleared balance = %s" - (buffer-substring-no-properties (point) - (line-end-position)))))))) + (ledger-exec-ledger buffer (current-buffer) "-C" "balance" account) + (goto-char (1- (point-max))) + (goto-char (line-beginning-position)) + (delete-horizontal-space) + (message "Cleared balance = %s" + (buffer-substring-no-properties (point) + (line-end-position)))))) + +(defun is-stdin (file) + "True if ledger file is standard input" + (or + (equal file "") + (equal file "") + (equal file "/dev/stdin"))) (defun ledger-reconcile-toggle () (interactive) @@ -23,18 +29,19 @@ (account ledger-acct) (inhibit-read-only t) cleared) - (when (or (equal (car where) "") (equal (car where) "/dev/stdin")) + (when (is-stdin (car where)) (with-current-buffer ledger-buf - (goto-char (cdr where)) - (setq cleared (ledger-toggle-current 'pending))) + (goto-char (cdr where)) + (setq cleared (ledger-toggle-current-entry))) (if cleared - (add-text-properties (line-beginning-position) - (line-end-position) - (list 'face 'bold)) - (remove-text-properties (line-beginning-position) - (line-end-position) - (list 'face)))) - (forward-line))) + (add-text-properties (line-beginning-position) + (line-end-position) + (list 'face 'bold)) + (remove-text-properties (line-beginning-position) + (line-end-position) + (list 'face)))) + (forward-line) + (ledger-display-balance))) (defun ledger-reconcile-refresh () (interactive) @@ -62,7 +69,7 @@ (defun ledger-reconcile-delete () (interactive) (let ((where (get-text-property (point) 'where))) - (when (or (equal (car where) "") (equal (car where) "/dev/stdin")) + (when (is-stdin (car where)) (with-current-buffer ledger-buf (goto-char (cdr where)) (ledger-delete-current-entry)) @@ -74,7 +81,7 @@ (defun ledger-reconcile-visit () (interactive) (let ((where (get-text-property (point) 'where))) - (when (or (equal (car where) "") (equal (car where) "/dev/stdin")) + (when (is-stdin (car where)) (switch-to-buffer-other-window ledger-buf) (goto-char (cdr where))))) @@ -97,7 +104,7 @@ (let ((where (get-text-property (point) 'where)) (face (get-text-property (point) 'face))) (if (and (eq face 'bold) - (or (equal (car where) "") (equal (car where) "/dev/stdin"))) + (when (is-stdin (car where)))) (with-current-buffer ledger-buf (goto-char (cdr where)) (ledger-toggle-current 'cleared)))) @@ -105,45 +112,48 @@ (ledger-reconcile-save)) (defun ledger-do-reconcile () - (let* ((buf ledger-buf) + "get the uncleared transactions in the account and display them in the *Reconcile* buffer" + (let* ((buf ledger-buf) (account ledger-acct) (items - (with-current-buffer - (apply #'ledger-exec-ledger - buf nil "emacs" account "--uncleared" '("--real")) + (with-temp-buffer + (ledger-exec-ledger buf (current-buffer) "--uncleared" "--real" + "emacs" account) (goto-char (point-min)) (unless (eobp) (unless (looking-at "(") (error (buffer-string))) - (read (current-buffer)))))) - (dolist (item items) - (let ((index 1)) - (dolist (xact (nthcdr 5 item)) - (let ((beg (point)) - (where - (with-current-buffer buf - (cons - (nth 0 item) - (if ledger-clear-whole-entries - (save-excursion - (goto-line (nth 1 item)) - (point-marker)) - (save-excursion - (goto-line (nth 0 xact)) - (point-marker))))))) - (insert (format "%s %-30s %-25s %15s\n" - (format-time-string "%m/%d" (nth 2 item)) - (nth 4 item) (nth 1 xact) (nth 2 xact))) - (if (nth 3 xact) - (set-text-properties beg (1- (point)) - (list 'face 'bold - 'where where)) - (set-text-properties beg (1- (point)) - (list 'where where)))) - (setq index (1+ index))))) - (goto-char (point-min)) - (set-buffer-modified-p nil) - (toggle-read-only t))) + (read (current-buffer)))))) + (dolist (item items) + (let ((index 1)) + (dolist (xact (nthcdr 5 item)) + (let ((beg (point)) + (where + (with-current-buffer buf + (cons + (nth 0 item) + (if ledger-clear-whole-entries + (save-excursion + (goto-line (nth 1 item)) + (point-marker)) + (save-excursion + (goto-line (nth 0 xact)) + (point-marker))))))) + (insert (format "%s %-4s %-30s %-30s %15s\n" + (format-time-string "%Y/%m/%d" (nth 2 item)) + (nth 3 item) + (nth 4 item) (nth 1 xact) (nth 2 xact))) + (if (nth 3 xact) + (set-text-properties beg (1- (point)) + (list 'face 'bold + 'where where)) + (set-text-properties beg (1- (point)) + (list 'where where)))) + (setq index (1+ index))))) + (goto-char (point-min)) + (set-buffer-modified-p nil) + (toggle-read-only t))) + (defun ledger-reconcile (account) (interactive "sAccount to reconcile: ") @@ -176,4 +186,20 @@ (define-key map [?p] 'previous-line) (define-key map [?s] 'ledger-reconcile-save) (define-key map [?q] 'ledger-reconcile-quit) + + (define-key map [menu-bar] (make-sparse-keymap "ldg-recon-menu")) + (define-key map [menu-bar ldg-recon-menu] (cons "Reconcile" map)) + (define-key map [menu-bar ldg-recon-menu qui] '("Quit" . ledger-reconcile-quit)) + (define-key map [menu-bar ldg-recon-menu sep1] '("--")) + (define-key map [menu-bar ldg-recon-menu pre] '("Previous Entry" . previous-line)) + (define-key map [menu-bar ldg-recon-menu vis] '("Visit Entry" . ledger-reconcile-visit)) + (define-key map [menu-bar ldg-recon-menu nex] '("Next Entry" . next-line)) + (define-key map [menu-bar ldg-recon-menu sep2] '("--")) + (define-key map [menu-bar ldg-recon-menu del] '("Delete Entry" . ledger-reconcile-delete)) + (define-key map [menu-bar ldg-recon-menu add] '("Add Entry" . ledger-reconcile-add)) + (define-key map [menu-bar ldg-recon-menu tog] '("Toggle Entry" . ledger-reconcile-toggle)) + (define-key map [menu-bar ldg-recon-menu sep3] '("--")) + (define-key map [menu-bar ldg-recon-menu ref] '("Refresh" . ledger-reconcile-refresh)) + (define-key map [menu-bar ldg-recon-menu sav] '("Save" . ledger-reconcile-save)) + (use-local-map map))) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index f9c6afca..efd9bdb4 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -70,6 +70,21 @@ text that should replace the format specifier." (define-key map [(control ?c) (control ?l) (control ?e)] 'ledger-report-edit) (define-key map [(control ?c) (control ?c)] 'ledger-report-visit-source) + + + (define-key map [menu-bar] (make-sparse-keymap "ldg-rep")) + (define-key map [menu-bar ldg-rep] (cons "Reports" map)) + + (define-key map [menu-bar ldg-rep lrq] '("Quit" . ledger-report-quit)) + (define-key map [menu-bar ldg-rep s2] '("--")) + (define-key map [menu-bar ldg-rep lrd] '("Scroll Down" . scroll-down)) + (define-key map [menu-bar ldg-rep lru] '("Scroll Up" . scroll-up)) + (define-key map [menu-bar ldg-rep s1] '("--")) + (define-key map [menu-bar ldg-rep lrk] '("Kill Report" . ledger-report-kill)) + (define-key map [menu-bar ldg-rep lrr] '("Re-run Report" . ledger-report-redo)) + (define-key map [menu-bar ldg-rep lre] '("Edit Report" . ledger-report-edit)) + (define-key map [menu-bar ldg-rep lrs] '("Save Report" . ledger-report-save)) + (use-local-map map))) (defun ledger-report-read-name () -- cgit v1.2.3 From 3e72a51dc3d296c9f647efaf4cbfbbdcf4bf6df1 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 29 Jan 2013 09:42:10 -0700 Subject: Addes tags command and --values option Tags command reports all metadat tags in use. With the values option it reports tags and their values. --- src/output.cc | 28 ++++++++++++++++++++++++++++ src/output.h | 27 +++++++++++++++++++++++++++ src/report.cc | 20 ++++++++++---------- src/report.h | 2 ++ 4 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/output.cc b/src/output.cc index f433f8d1..6ed7f861 100644 --- a/src/output.cc +++ b/src/output.cc @@ -318,6 +318,34 @@ void report_payees::operator()(post_t& post) (*i).second++; } +void report_tags::flush() +{ + std::ostream& out(report.output_stream); + + foreach (tags_pair& entry, tags) { + if (report.HANDLED(count)) + out << entry.second << ' '; + out << entry.first << '\n'; + } +} + +void report_tags::operator()(post_t& post) +{ + if(post.metadata){ + foreach (const item_t::string_map::value_type& data, *post.metadata){ + string tag=data.first; + if(report.HANDLED(values) && (data.second).first){ + tag+=": "+ (data.second).first.get().to_string(); + } + std::map::iterator i = tags.find(tag); + if (i == tags.end()) + tags.insert(tags_pair(tag, 1)); + else + (*i).second++; + } + } +} + void report_commodities::flush() { std::ostream& out(report.output_stream); diff --git a/src/output.h b/src/output.h index 281f69b6..9895cb44 100644 --- a/src/output.h +++ b/src/output.h @@ -189,6 +189,33 @@ public: } }; +class report_tags : public item_handler +{ +protected: + report_t& report; + + std::map tags; + + typedef std::map::value_type tags_pair; + +public: + report_tags(report_t& _report) : report(_report) { + TRACE_CTOR(report_tags, "report&"); + } + virtual ~report_tags() { + TRACE_DTOR(report_tags); + } + + virtual void flush(); + virtual void operator()(post_t& post); + + virtual void clear() { + tags.clear(); + item_handler::clear(); + } +}; + + class report_commodities : public item_handler { protected: diff --git a/src/report.cc b/src/report.cc index d4beaf2a..f7b71b94 100644 --- a/src/report.cc +++ b/src/report.cc @@ -1089,7 +1089,6 @@ option_t * report_t::lookup_option(const char * p) else OPT(anon); else OPT_ALT(color, ansi); else OPT(auto_match); - else OPT(aux_date); else OPT(average); else OPT(account_width_); else OPT(amount_width_); @@ -1097,7 +1096,7 @@ option_t * report_t::lookup_option(const char * p) case 'b': OPT(balance_format_); else OPT(base); - else OPT(basis); + else OPT_ALT(basis, cost); else OPT_(begin_); else OPT(bold_if_); else OPT(budget); @@ -1106,7 +1105,6 @@ option_t * report_t::lookup_option(const char * p) break; case 'c': OPT(csv_format_); - else OPT_ALT(gain, change); else OPT(cleared); else OPT(collapse); else OPT(collapse_if_zero); @@ -1124,7 +1122,6 @@ option_t * report_t::lookup_option(const char * p) else OPT(dc); else OPT(depth_); else OPT(deviation); - else OPT_ALT(rich_data, detail); else OPT_(display_); else OPT(display_amount_); else OPT(display_total_); @@ -1149,7 +1146,7 @@ option_t * report_t::lookup_option(const char * p) else OPT_ALT(head_, first_); break; case 'g': - OPT(gain); + OPT_ALT(gain, change); else OPT(group_by_); else OPT(group_title_format_); else OPT(generated); @@ -1176,7 +1173,7 @@ option_t * report_t::lookup_option(const char * p) else OPT_ALT(tail_, last_); break; case 'm': - OPT(market); + OPT_ALT(market, value); else OPT(monthly); else OPT(meta_); else OPT(meta_width_); @@ -1206,7 +1203,6 @@ option_t * report_t::lookup_option(const char * p) else OPT(price); else OPT(prices_format_); else OPT(pricedb_format_); - else OPT(primary_date); else OPT(payee_width_); else OPT(prepend_format_); else OPT(prepend_width_); @@ -1224,7 +1220,7 @@ option_t * report_t::lookup_option(const char * p) else OPT(revalued); else OPT(revalued_only); else OPT(revalued_total_); - else OPT(rich_data); + else OPT_ALT(rich_data, detail); break; case 's': OPT(sort_); @@ -1252,7 +1248,7 @@ option_t * report_t::lookup_option(const char * p) else OPT(unround); break; case 'v': - OPT_ALT(market, value); + OPT(values); break; case 'w': OPT(weekly); @@ -1670,7 +1666,11 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, else if (is_eq(p, "select")) return WRAP_FUNCTOR(select_command); break; - + case 't': + if (is_eq(p, "tags")) { + return POSTS_REPORTER(new report_tags(*this)); + } + break; case 'x': if (is_eq(p, "xact")) return WRAP_FUNCTOR(xact_command); diff --git a/src/report.h b/src/report.h index 2eac61fe..b0044f60 100644 --- a/src/report.h +++ b/src/report.h @@ -358,6 +358,7 @@ public: HANDLER(account_width_).report(out); HANDLER(amount_width_).report(out); HANDLER(total_width_).report(out); + HANDLER(values).report(out); } option_t * lookup_option(const char * p); @@ -1043,6 +1044,7 @@ public: OPTION(report_t, account_width_); OPTION(report_t, amount_width_); OPTION(report_t, total_width_); + OPTION(report_t, values); }; template Date: Tue, 29 Jan 2013 10:03:47 -0700 Subject: Fixes bug 514. accounts and commodities output now sorts updated tests included. --- src/account.h | 7 +++++++ src/commodity.h | 7 +++++++ src/output.h | 4 ++-- test/baseline/cmd-accounts.test | 6 +++--- test/baseline/cmd-commodities.test | 4 ++-- test/baseline/opt-count.test | 6 +++--- 6 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/account.h b/src/account.h index a2fcb8de..3642ada0 100644 --- a/src/account.h +++ b/src/account.h @@ -308,6 +308,13 @@ std::ostream& operator<<(std::ostream& out, const account_t& account); void put_account(property_tree::ptree& pt, const account_t& acct, function pred); +//simple struct added to allow std::map to compare accounts in the accounts report +struct account_compare { + bool operator() (const account_t& lhs, const account_t& rhs){ + return (lhs.fullname().compare(rhs.fullname()) < 0); + } +}; + } // namespace ledger #endif // _ACCOUNT_H diff --git a/src/commodity.h b/src/commodity.h index ab496850..37b02e74 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -349,6 +349,13 @@ inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) { void put_commodity(property_tree::ptree& pt, const commodity_t& comm, bool commodity_details = false); +//simple struct to allow std::map to compare commodities names +struct commodity_compare { + bool operator() (const commodity_t* lhs, const commodity_t* rhs){ + return (lhs->symbol().compare(rhs->symbol()) < 0); + } +}; + } // namespace ledger #endif // _COMMODITY_H diff --git a/src/output.h b/src/output.h index 281f69b6..5ce9dc58 100644 --- a/src/output.h +++ b/src/output.h @@ -142,7 +142,7 @@ class report_accounts : public item_handler protected: report_t& report; - std::map accounts; + std::map accounts; typedef std::map::value_type accounts_pair; @@ -194,7 +194,7 @@ class report_commodities : public item_handler protected: report_t& report; - std::map commodities; + std::map commodities; typedef std::map::value_type commodities_pair; diff --git a/test/baseline/cmd-accounts.test b/test/baseline/cmd-accounts.test index be6365fd..2f0310da 100644 --- a/test/baseline/cmd-accounts.test +++ b/test/baseline/cmd-accounts.test @@ -15,12 +15,12 @@ Assets:Testing123ÕßDone test accounts +Assets:AAA Assets:Bank -Equity:Opening balance +Assets:Testing123ÕßDone Assets:XXX -Assets:AAA Assets:♚ -Assets:Testing123ÕßDone +Equity:Opening balance end test test accounts assets:a diff --git a/test/baseline/cmd-commodities.test b/test/baseline/cmd-commodities.test index 0ce6f7a0..719b6798 100644 --- a/test/baseline/cmd-commodities.test +++ b/test/baseline/cmd-commodities.test @@ -15,10 +15,10 @@ Income:Rewards test commodities -GBP -AAA "AA2" "M&M" +AAA +GBP end test test commodities Assets:Rewards diff --git a/test/baseline/opt-count.test b/test/baseline/opt-count.test index 9c5495c8..7c935c7a 100644 --- a/test/baseline/opt-count.test +++ b/test/baseline/opt-count.test @@ -17,14 +17,14 @@ Assets:Cash -30.00 EUR test accounts --count -2 Expenses:Phone 4 Assets:Cash +2 Expenses:Phone 2 Expenses:Rent end test test commodities --count -4 GBP 4 EUR +4 GBP end test test payees --count @@ -33,8 +33,8 @@ test payees --count end test test commodities :rent --count -1 GBP 1 EUR +1 GBP end test test payees tag bnb --count -- cgit v1.2.3 From aba5c1aa465c6ad92839fc9259a6a21d2292192e Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 29 Jan 2013 10:30:18 -0700 Subject: Fixes bugs 705 and 862. Ledger now fails if init or pricedb files are specified on the command line but not found. --- src/global.cc | 53 +++++++++++++++++++++++++++++++++++++---------------- src/global.h | 6 +----- src/session.cc | 6 +++++- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/global.cc b/src/global.cc index bc172075..5fc10f02 100644 --- a/src/global.cc +++ b/src/global.cc @@ -107,32 +107,53 @@ global_scope_t::~global_scope_t() #endif } +void global_scope_t::parse_init(path init_file) +{ + TRACE_START(init, 1, "Read initialization file"); + + parse_context_stack_t parsing_context; + parsing_context.push(init_file); + parsing_context.get_current().journal = session().journal.get(); + parsing_context.get_current().scope = &report(); + + if (session().journal->read(parsing_context) > 0 || + session().journal->auto_xacts.size() > 0 || + session().journal->period_xacts.size() > 0) { + throw_(parse_error, _f("Transactions found in initialization file '%1%'") + % init_file); + } + + TRACE_FINISH(init, 1); +} + void global_scope_t::read_init() { + // if specified on the command line init_file_ is filled in + // global_scope_t::handle_debug_options. If it was specified on the command line + // fail is the file doesn't exist. If no init file was specified + // on the command-line then try the default values, but don't fail if there + // isn't one. + path init_file; if (HANDLED(init_file_)) { - path init_file(HANDLER(init_file_).str()); + init_file=HANDLER(init_file_).str(); if (exists(init_file)) { - TRACE_START(init, 1, "Read initialization file"); - - parse_context_stack_t parsing_context; - parsing_context.push(init_file); - parsing_context.get_current().journal = session().journal.get(); - parsing_context.get_current().scope = &report(); - - if (session().journal->read(parsing_context) > 0 || - session().journal->auto_xacts.size() > 0 || - session().journal->period_xacts.size() > 0) { - throw_(parse_error, _f("Transactions found in initialization file '%1%'") - % init_file); - } - - TRACE_FINISH(init, 1); + parse_init(init_file); } else { throw_(parse_error, _f("Could not find specified init file %1%") % init_file); } + } else { + if (const char * home_var = std::getenv("HOME")){ + init_file = (path(home_var) / ".ledgerrc"); + } else { + init_file = ("./.ledgerrc"); + } + } + if(exists(init_file)){ + parse_init(init_file); } } + char * global_scope_t::prompt_string() { static char prompt[32]; diff --git a/src/global.h b/src/global.h index dc6abd78..11459529 100644 --- a/src/global.h +++ b/src/global.h @@ -67,6 +67,7 @@ public: return _("global scope"); } + void parse_init(path init_file); void read_init(); void read_environment_settings(char * envp[]); strings_list read_command_arguments(scope_t& scope, strings_list args); @@ -156,11 +157,6 @@ See LICENSE file included with the distribution for details and disclaimer."); if (!_init_file.empty()) // _init_file is filled during handle_debug_options on(none, _init_file); - else - if (const char * home_var = std::getenv("HOME")) - on(none, (path(home_var) / ".ledgerrc").string()); - else - on(none, path("./.ledgerrc").string()); }); OPTION(global_scope_t, options); diff --git a/src/session.cc b/src/session.cc index f047a540..f9815c3f 100644 --- a/src/session.cc +++ b/src/session.cc @@ -98,8 +98,12 @@ std::size_t session_t::read_data(const string& master_account) acct = journal->find_account(master_account); optional price_db_path; - if (HANDLED(price_db_)) + if (HANDLED(price_db_)){ price_db_path = resolve_path(HANDLER(price_db_).str()); + if (!exists(price_db_path.get())){ + throw_(parse_error, _f("Could not find specified price file %1%") % price_db_path); + } + } if (HANDLED(explicit)) journal->force_checking = true; -- cgit v1.2.3 From 1b3dfa1297101fbdd0cbdab57377c40b3a1c3234 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 29 Jan 2013 11:26:43 -0700 Subject: Fixes regression error introduced by tags command patch Not sure how the changes to the options got into the repot.cc file, but this takes the changes out. --- src/report.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/report.cc b/src/report.cc index f7b71b94..80993515 100644 --- a/src/report.cc +++ b/src/report.cc @@ -1089,6 +1089,7 @@ option_t * report_t::lookup_option(const char * p) else OPT(anon); else OPT_ALT(color, ansi); else OPT(auto_match); + else OPT(aux_date); else OPT(average); else OPT(account_width_); else OPT(amount_width_); @@ -1096,7 +1097,7 @@ option_t * report_t::lookup_option(const char * p) case 'b': OPT(balance_format_); else OPT(base); - else OPT_ALT(basis, cost); + else OPT(basis); else OPT_(begin_); else OPT(bold_if_); else OPT(budget); @@ -1105,6 +1106,7 @@ option_t * report_t::lookup_option(const char * p) break; case 'c': OPT(csv_format_); + else OPT_ALT(gain, change); else OPT(cleared); else OPT(collapse); else OPT(collapse_if_zero); @@ -1122,6 +1124,7 @@ option_t * report_t::lookup_option(const char * p) else OPT(dc); else OPT(depth_); else OPT(deviation); + else OPT_ALT(rich_data, detail); else OPT_(display_); else OPT(display_amount_); else OPT(display_total_); @@ -1146,7 +1149,7 @@ option_t * report_t::lookup_option(const char * p) else OPT_ALT(head_, first_); break; case 'g': - OPT_ALT(gain, change); + OPT(gain); else OPT(group_by_); else OPT(group_title_format_); else OPT(generated); @@ -1173,7 +1176,7 @@ option_t * report_t::lookup_option(const char * p) else OPT_ALT(tail_, last_); break; case 'm': - OPT_ALT(market, value); + OPT(market); else OPT(monthly); else OPT(meta_); else OPT(meta_width_); @@ -1203,6 +1206,7 @@ option_t * report_t::lookup_option(const char * p) else OPT(price); else OPT(prices_format_); else OPT(pricedb_format_); + else OPT(primary_date); else OPT(payee_width_); else OPT(prepend_format_); else OPT(prepend_width_); @@ -1220,7 +1224,7 @@ option_t * report_t::lookup_option(const char * p) else OPT(revalued); else OPT(revalued_only); else OPT(revalued_total_); - else OPT_ALT(rich_data, detail); + else OPT(rich_data); break; case 's': OPT(sort_); @@ -1248,7 +1252,8 @@ option_t * report_t::lookup_option(const char * p) else OPT(unround); break; case 'v': - OPT(values); + OPT_ALT(market, value); + else OPT(values); break; case 'w': OPT(weekly); -- cgit v1.2.3 From 426e1056518301456959e27fd0bbb16829274a1b Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 29 Jan 2013 12:16:47 -0700 Subject: Fixed the new ledger mod so that loading leg-new.el is sufficient The reconcile package and the xact package didn't provide themselves, and the leg-new module didn't load up everything it needed. --- lisp/ldg-new.el | 13 +++++++++---- lisp/ldg-reconcile.el | 2 ++ lisp/ldg-xact.el | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index 8505fe4a..d9e0fc60 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -32,12 +32,17 @@ ;;; Commentary: -(require 'ldg-post) -(require 'ldg-mode) (require 'ldg-complete) -(require 'ldg-state) +(require 'ldg-exec) +(require 'ldg-mode) +(require 'ldg-post) +(require 'ldg-reconcile) +(require 'ldg-register) (require 'ldg-report) - +(require 'ldg-state) +(require 'ldg-test) +(require 'ldg-texi) +(require 'ldg-xact) ;(autoload #'ledger-mode "ldg-mode" nil t) ;(autoload #'ledger-fully-complete-entry "ldg-complete" nil t) ;(autoload #'ledger-toggle-current "ldg-state" nil t) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 73409e66..08dbc587 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -203,3 +203,5 @@ (define-key map [menu-bar ldg-recon-menu sav] '("Save" . ledger-reconcile-save)) (use-local-map map))) + +(provide 'ldg-reconcile) \ No newline at end of file diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index e1f165a7..6e14a14c 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -18,3 +18,4 @@ (lambda () (forward-paragraph)))))) +(provide 'ldg-xact) \ No newline at end of file -- cgit v1.2.3 From 619b6abd5ca3713a01c1fcb38a055f037cbc30af Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 29 Jan 2013 12:47:27 -0700 Subject: Fixes the set-year and set-month functions Also adds current year and month to the entry prompt. --- lisp/ldg-mode.el | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index caa57e8e..e36dc969 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -1,3 +1,16 @@ +(defsubst ledger-current-year () + (format-time-string "%Y")) +(defsubst ledger-current-month () + (format-time-string "%m")) + +(defvar ledger-year (ledger-current-year) + "Start a ledger session with the current year, but make it +customizable to ease retro-entry.") +(defvar ledger-month (ledger-current-month) + "Start a ledger session with the current month, but make it +customizable to ease retro-entry.") + + (defcustom ledger-default-acct-transaction-indent " " "Default indentation for account transactions in an entry." :type 'string @@ -152,7 +165,8 @@ Return the difference in the format of a time value." (setq ledger-month (format "%02d" newmonth)))) (defun ledger-add-entry (entry-text &optional insert-at-point) - (interactive "sEntry: ") + (interactive (list + (read-string "Entry: " (concat ledger-year "/" ledger-month "/")))) (let* ((args (with-temp-buffer (insert entry-text) (eshell-parse-arguments (point-min) (point-max)))) -- cgit v1.2.3 From b9dbf54d9a5d0002e379263b4407450074e45211 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 29 Jan 2013 13:13:30 -0700 Subject: Improved emacs section. Now documents all behavior. --- doc/ledger3.texi | 66 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index f60bb26e..2e0f9ed5 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -2325,7 +2325,9 @@ doing it. Journal files are simple free text files easily modified by any text editor. A special mode for EMACS is included with the source -distribution. +distribution. This mode provides syntax highlighting, a reconcile mode +and a report mode. This makes it quote possible to use ledger without +ever leaving EMACS. @cindex EMACS .emacs file @@ -2335,7 +2337,7 @@ Add the following line to your @file{.emacs} (or equivalent, (load "ldg-new") @end smallexample -Copy the several lisp files from the source lisp directory your your +Copy the several lisp files (@file{ldg-*.el}) from the source lisp directory your your @file{site-lisp} directory, or add the ledger lisp source directory to your EMACS load path by adding: @smallexample @@ -2352,7 +2354,8 @@ To enter ledger-mode on a new file, type @command{M-x ledger-mode}. Once you have loaded a Journal file into EMACS, you have several commands available to make entering, clearing and reconciling -transactions and producing reports: +transactions and producing reports (these are also available from the +menu if you can't remember the key combinations): @cindex EMACS commands @table @code @@ -2431,10 +2434,11 @@ will be interpreted as a new account by ledger. @code{C-c C-a} will run the @code{ledger entry} command (@pxref{entry and xact}) from within EMACS. When typed, the mini-buffer will appear with the current year and month, waiting for you to enter the day and -the payee. Ledger will generate a new entry based on the most recent -entry for that payee, using the amount and accounts from that -transaction. If you have a new amount simply type the amount after the -payee. For example, if your journal contains an entry +the payee, and optionally, a commoditized amount. Ledger will generate +a new entry based on the most recent entry for that payee, using the +amount and accounts from that transaction. If you have a new amount +simply type the amount after the payee. For example, if your journal +contains an entry @smallexample 2011/11/25 Viva Italiano Expenses:Food $12.45 @@ -2454,7 +2458,10 @@ Entry: 2011/11/28 viva food 34 tip 7 Liabilities:MasterCard @end smallexample @noindent Notice that the entry will appear at the correct place in the journal -ordered by date, not necessarily at the bottom of the file. +ordered by date, not at the bottom of the file. If you need to include +spaces in the payee name, then surrond the name of the payee with double +quotes, otherwise ledger will interpret the second part of the name as +an account. @node Clearing Transactions, , Automagically Adding new entries, Working with entries @subsubsection Clearing Transactions and Postings @cindex clearing transactions in EMACS @@ -2483,21 +2490,46 @@ toggled. @node Reconciling accounts, Generating Reports, Working with entries, Using EMACS @subsection Reconciling accounts -In the reconcile buffer, use SPACE to toggle the cleared status of a -transaction, C-x C-s to save changes (to the ledger file as well). +Enter the reconcile mode using the menu entry, or @code{C-c C-r}. Emacs +will prompt you for an account name, then display a second buffer with +all of the uncleared transactions. The reconcile buffer has several functions: +@table @code + @item SPACE + toggles the cleared status of a transaction, and show cleared balance inthe minibuffer + @item RETURN + moves the cursor to that transaction in the ledger. + @item C-x C-s + to save changes (to the ledger file as well). + @item q + quite the reconcile mode + @item n p + next line or previous line + @item A + add entry + @item D + delete entry + @item C-l + refresh display +@end table @node Generating Reports, , Reconciling accounts, Using EMACS @subsection Generating Reports The ledger reports command asks the user to select a report to run then creates a report buffer containing the results of running the associated -command line. Its' behavior is modified by a prefix argument which, -when given, causes the generated command line that will be used to -create the report to be presented for editing before the report is -actually run. Arbitrary unnamed command lines can be run by specifying -an empty name for the report. The command line used can later be named -and saved for future use as a named report from the generated reports -buffer. +command line. This allows you to run frequently used reports without +retyping the command line, or writing shell scripts for simple one line +commands. + +To generate a report, select the @code{Run Reports} menu, or type +@code{C-c C-o C-r}. Emacs will prompt for a report name. If it +recognizes the name it will run the report again. If it is a new name, +or blank it will respond by giving you an example command line to edit. +Hitting return willrun the report and present it in a new buffer. + +If you have given it a new name, then @code{s} will save the report for +future use. + In a report buffer, the following keys are available: @table @code -- cgit v1.2.3 From 2ecb03878fe948167b1e3049f35e77c750714852 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 29 Jan 2013 13:26:31 -0700 Subject: Documented the tags command. Documented that the account and commodities command now sort. --- doc/ledger3.texi | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 2e0f9ed5..377d740c 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -2574,7 +2574,7 @@ kill the report buffer * Lot dates:: * Lot notes:: * Lot value expressions:: -* Automated Transactions:: +* Automated Transactions:: @end menu @node Basic format, Eliding amounts, Transactions , Transactions @@ -4776,6 +4776,7 @@ database files. @menu * accounts:: * commodities:: +* tags:: * entry and xact:: * payees:: @end menu @@ -4785,15 +4786,27 @@ database files. The @command{accounts} reports all of the accounts in the journal. Following the command with a regular expression will limit the output to -accounts matching the regex. +accounts matching the regex. The output is sorted by name. Using the +@code{--count} option will tell you haw many entries use each account. -@node commodities, entry and xact, accounts, Reports about your Journals +@node commodities, tags, accounts, Reports about your Journals @subsection @command{commodities} -Report all commodities present in the journals under consideration. +Report all commodities present in the journals under consideration. The + output is sorted by name. Using the @code{--count} option will tell + you haw many entries use each commodity. +@node tags, entry and xact, commodities, Reports about your Journals +@subsection @command{tags} -@node entry and xact, payees, commodities, Reports about your Journals +The @command{tags} reports all of the tags in the journal. The output +is sorted by name. Using the @code{--count} option will tell you haw +many entries use each tag. Using the @code{--values} option will report +the values used by each tag. + + + +@node entry and xact, payees, tags, Reports about your Journals @subsection @command{draft}, @command{entry} and @command{xact} The @code{draft}, @code{entry} and @command{xact} commands simplify the -- cgit v1.2.3 From eff14723378133469238a9e302677b84c3f7b63e Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 29 Jan 2013 13:57:22 -0700 Subject: Added GPL licensing information to lisp files --- lisp/ldg-complete.el | 21 +++++++++++++++++++++ lisp/ldg-exec.el | 21 +++++++++++++++++++++ lisp/ldg-mode.el | 22 ++++++++++++++++++++++ lisp/ldg-post.el | 21 +++++++++++++++++++++ lisp/ldg-reconcile.el | 21 +++++++++++++++++++++ lisp/ldg-regex.el | 21 +++++++++++++++++++++ lisp/ldg-register.el | 21 +++++++++++++++++++++ lisp/ldg-report.el | 21 +++++++++++++++++++++ lisp/ldg-state.el | 21 +++++++++++++++++++++ lisp/ldg-test.el | 21 +++++++++++++++++++++ lisp/ldg-texi.el | 21 +++++++++++++++++++++ lisp/ldg-xact.el | 21 +++++++++++++++++++++ 12 files changed, 253 insertions(+) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index 7b4b0471..85546156 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -1,3 +1,24 @@ +;;; ldg-complete.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + ;;(require 'esh-util) ;;(require 'esh-arg) (require 'pcomplete) diff --git a/lisp/ldg-exec.el b/lisp/ldg-exec.el index bf3565b4..ab041fec 100644 --- a/lisp/ldg-exec.el +++ b/lisp/ldg-exec.el @@ -1,3 +1,24 @@ +;;; ldg-exec.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + (defgroup ledger-exec nil "Interface to the Ledger command-line accounting program." :group 'ledger) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index e36dc969..842cd582 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -1,3 +1,25 @@ +;;; ldg-mode.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + + (defsubst ledger-current-year () (format-time-string "%Y")) (defsubst ledger-current-month () diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 05b9d352..7cb525a7 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -1,3 +1,24 @@ +;;; ldg-post.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + (require 'ldg-regex) (defgroup ledger-post nil diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 08dbc587..011bf400 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -1,3 +1,24 @@ +;;; ldg-reconcile.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + ;; Reconcile mode (defvar ledger-buf nil) diff --git a/lisp/ldg-regex.el b/lisp/ldg-regex.el index 1c6b8f06..f2f83937 100644 --- a/lisp/ldg-regex.el +++ b/lisp/ldg-regex.el @@ -1,3 +1,24 @@ +;;; ldg-regex.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + (require 'rx) (eval-when-compile diff --git a/lisp/ldg-register.el b/lisp/ldg-register.el index 7b5c0d0a..4c397049 100644 --- a/lisp/ldg-register.el +++ b/lisp/ldg-register.el @@ -1,3 +1,24 @@ +;;; ldg-register.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + (require 'ldg-post) (require 'ldg-state) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index a1ffe3b0..394c12e7 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -1,3 +1,24 @@ +;;; ldg-report.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + (eval-when-compile (require 'cl)) diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index 6a841621..03017b25 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -1,3 +1,24 @@ +;;; ldg-state.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + (defcustom ledger-clear-whole-entries nil "If non-nil, clear whole entries, not individual transactions." :type 'boolean diff --git a/lisp/ldg-test.el b/lisp/ldg-test.el index 478c62d8..2036ea7b 100644 --- a/lisp/ldg-test.el +++ b/lisp/ldg-test.el @@ -1,3 +1,24 @@ +;;; ldg-test.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + (defcustom ledger-source-directory "~/src/ledger" "Directory where the Ledger sources are located." :type 'directory diff --git a/lisp/ldg-texi.el b/lisp/ldg-texi.el index b0334099..fefa7d2b 100644 --- a/lisp/ldg-texi.el +++ b/lisp/ldg-texi.el @@ -1,3 +1,24 @@ +;;; ldg-texi.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + (defvar ledger-path "/Users/johnw/bin/ledger") (defvar ledger-sample-doc-path "/Users/johnw/src/ledger/doc/sample.dat") (defvar ledger-normalization-args "--args-only --columns 80") diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index 6e14a14c..11e6fbaf 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -1,3 +1,24 @@ +;;; ldg-xact.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + ;; A sample entry sorting function, which works if entry dates are of ;; the form YYYY/mm/dd. -- cgit v1.2.3 From 1903ff7c2ebdc2cccd4898fd98c28a0c4a74d5af Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 29 Jan 2013 14:10:08 -0700 Subject: Fixed problem finding the default priced file. Bug fix to detect badly specified priced files on the command line didn't handle the default correctly. --- src/session.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/session.cc b/src/session.cc index 632002d4..0f9cca22 100644 --- a/src/session.cc +++ b/src/session.cc @@ -62,12 +62,7 @@ void set_session_context(session_t * session) session_t::session_t() : flush_on_next_data_file(false), journal(new journal_t) { - if (const char * home_var = std::getenv("HOME")) - HANDLER(price_db_).on(none, (path(home_var) / ".pricedb").string()); - else - HANDLER(price_db_).on(none, path("./.pricedb").string()); - - parsing_context.push(); + parsing_context.push(); TRACE_CTOR(session_t, ""); } @@ -101,7 +96,13 @@ std::size_t session_t::read_data(const string& master_account) if (HANDLED(price_db_)){ price_db_path = resolve_path(HANDLER(price_db_).str()); if (!exists(price_db_path.get())){ - throw_(parse_error, _f("Could not find specified price file %1%") % price_db_path); + throw_(parse_error, _f("Could not find specified price-db file %1%") % price_db_path); + } + } else { + if (const char * home_var = std::getenv("HOME")){ + price_db_path = (path(home_var) / ".pricedb"); + } else { + price_db_path = ("./.ledgerrc"); } } -- cgit v1.2.3 From 383c341d885e1a69fc63aca2ae7db4a2ff5ff1a8 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Tue, 29 Jan 2013 23:29:46 +0100 Subject: fix CMake variable expansion for man2html --- doc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 72a6da84..8ca83783 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -77,7 +77,7 @@ if(BUILD_WEB_DOCS) endif() add_custom_command(OUTPUT ledger.1.html - COMMAND ${BASH} -c "man2html $<1:CMAKE_CURRENT_SOURCE_DIR>/ledger.1 | tail -n+3 > ledger.1.html" + COMMAND ${BASH} -c "man2html ${CMAKE_CURRENT_SOURCE_DIR}/ledger.1 | tail -n+3 > ledger.1.html" DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ledger.1 VERBATIM) list(APPEND ledger_doc_files ledger.1.html) -- cgit v1.2.3 From 97550db9bd08671d6b5c84a6a99a61c4779c0cee Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Wed, 30 Jan 2013 13:27:51 -0700 Subject: Removed call to ledger-reports-patch-reports This function was never defined and appeared to nothing. I caused errors on some system by not existing. --- lisp/ldg-mode.el | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 842cd582..128dfeac 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -117,12 +117,7 @@ customizable to ease retro-entry.") (define-key map [menu-bar ldg-menu de] '("Delete Entry" . ledger-delete-current-entry)) (define-key map [menu-bar ldg-menu ae] '("Add Entry" . ledger-add-entry)) (define-key map [menu-bar ldg-menu s3] '("--")) - (define-key map [menu-bar ldg-menu re] '("Reconcile Account" . ledger-reconcile))) - - - - - (ledger-report-patch-reports (current-buffer))) + (define-key map [menu-bar ldg-menu re] '("Reconcile Account" . ledger-reconcile)))) (defun ledger-time-less-p (t1 t2) "Say whether time value T1 is less than time value T2." -- cgit v1.2.3 From 5ee03de0ad8c2df38bc10acf67f02cf862c6c83c Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 30 Jan 2013 01:04:29 +0100 Subject: fix option handling in acprep Both the `--local` option and the default to build local if no build directory exists did not work, because `build_directory()` uses `self.options.build_dir`, but the default and the `--local` option used `self.build_dir`. I changed the code to always use `self.options` for options/flags. Now `self.options` is set to the default values of OptParser and is updated when `parse_args` is called in `run`. After this commit ledger will be built in: * The directory specified using `--output=` * Else in a subdirectory of `./build` or `~/Products` if one of those directories exist and `--local` is not used. * Else inside the source tree (default). --- acprep | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/acprep b/acprep index 26f8d8b2..6330a7f8 100755 --- a/acprep +++ b/acprep @@ -101,13 +101,6 @@ class CommandLineApp(object): log_handler = None boost_major = "1_50" - options = { - 'debug': False, - 'verbose': False, - 'logfile': False, - 'loglevel': False - } - def __init__(self): "Initialize CommandLineApp." # Create the logger @@ -137,7 +130,8 @@ class CommandLineApp(object): op.add_option('', '--loglevel', metavar='LEVEL', type='string', action='store', dest='loglevel', default=False, help='set log level: DEBUG, INFO, WARNING, ERROR, CRITICAL') - return + + self.options = op.get_default_values() def main(self, *args): """Main body of your application. @@ -167,7 +161,7 @@ class CommandLineApp(object): Process options and execute callback functions as needed. This method should not need to be overridden, if the main() method is defined.""" # Process the options supported and given - self.options, main_args = self.option_parser.parse_args() + self.options, main_args = self.option_parser.parse_args(values=self.options) if self.options.logfile: fh = logging.handlers.RotatingFileHandler(self.options.logfile, @@ -238,9 +232,7 @@ class PrepareBuild(CommandLineApp): self.current_ver = None #self.current_flavor = 'default' self.current_flavor = 'debug' - self.prefix_dir = None self.products_dir = None - self.build_dir = self.source_dir self.configure_args = [] self.CXXFLAGS = [] self.LDFLAGS = [] @@ -264,7 +256,7 @@ class PrepareBuild(CommandLineApp): products = self.default_products_directory() if (exists(products) and isdir(products)) or \ (exists('build') and isdir('build')): - self.build_dir = None + self.options.build_dir = None def __init__(self): CommandLineApp.__init__(self) @@ -272,8 +264,6 @@ class PrepareBuild(CommandLineApp): self.source_dir = os.getcwd() - self.initialize() - op = self.option_parser op.add_option('', '--help', action="callback", @@ -321,11 +311,16 @@ class PrepareBuild(CommandLineApp): dest="option_products", help='Collect all build products in this directory') op.add_option('', '--output', metavar='DIR', action="store", + default=self.source_dir, dest="build_dir", help='Build in the specified directory') op.add_option('', '--local', action="callback", callback=self.option_local, help='Build directly within the source tree (default)') + self.options = op.get_default_values() + + self.initialize() + def main(self, *args): if args and args[0] in ['default', 'debug', 'opt', 'gcov', 'gprof']: self.current_flavor = args[0] @@ -740,7 +735,7 @@ class PrepareBuild(CommandLineApp): def option_local(self, option=None, opt_str=None, value=None, parser=None): self.log.debug('Saw option --local') - self.build_dir = self.source_dir + self.options.build_dir = self.source_dir def option_help(self, option=None, opt_str=None, value=None, parser=None): self.phase_help() @@ -841,7 +836,7 @@ class PrepareBuild(CommandLineApp): try: os.chdir(build_dir) - need_to_config = not isfile('Makefile') + need_to_config = not isfile('rules.ninja' if self.options.use_ninja else 'Makefile') if need_to_config: self.log.debug('Source => ' + self.source_dir) self.log.debug('Build => ' + build_dir) @@ -945,10 +940,10 @@ class PrepareBuild(CommandLineApp): ######################################################################### def configure_flavor(self, flavor, reset=True): - self.initialize() # reset everything - self.build_dir = None # use the build/ tree + self.initialize() # reset everything self.current_flavor = flavor - self.prefix_dir = None + self.options.build_dir = None # use the build/ tree + self.options.prefix_dir = None if reset and exists(self.build_directory()) and \ isdir(self.build_directory()): -- cgit v1.2.3 From 0df13661686dfec66aa0d5a8dd88920e1e104fbc Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Wed, 30 Jan 2013 15:35:31 -0700 Subject: Bug 634 Added roundto function, optimized floor and ceiling Fixes Bug634 by adding roundto(amount, places). --- doc/ledger3.texi | 4 +++- src/amount.cc | 29 +++++++++++++++-------------- src/amount.h | 7 +++++++ src/balance.h | 11 +++++++++++ src/report.cc | 8 ++++++++ src/report.h | 1 + src/value.cc | 21 +++++++++++++++++++++ src/value.h | 7 +++++++ test/regress/25A099C9.test | 20 ++++++++++---------- 9 files changed, 83 insertions(+), 25 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 377d740c..ee4c990b 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -7192,6 +7192,7 @@ Useful specifying a date in plain terms. For example, you could say @item @strong{Function} @tab @strong{Abbrev.} @tab @strong{Description} @item @code{amount_expr } @tab @code{} @tab @item @code{abs } @tab @code{} @tab --> U +@item @code{ceiling } @tab @code{} @tab Returns the next integer toward +infty @item @code{code} @tab @code{} @tab returns the transaction code, the string between the parenthesis after the date. @item @code{commodity } @tab @code{} @tab @item @code{display_amount } @tab @code{} @tab --> t @@ -7199,7 +7200,7 @@ Useful specifying a date in plain terms. For example, you could say @item @code{date } @tab @code{} @tab @item @code{format_date } @tab @code{} @tab @item @code{format } @tab @code{} @tab -@item @code{floor } @tab @code{} @tab +@item @code{floor } @tab @code{} @tab Returns the next integer toward -infty @item @code{get_at } @tab @code{} @tab @item @code{is_seq } @tab @code{} @tab @item @code{justify } @tab @code{} @tab @@ -7215,6 +7216,7 @@ Useful specifying a date in plain terms. For example, you could say @item @code{quoted } @tab @code{} @tab @item @code{quantity } @tab @code{} @tab @item @code{rounded } @tab @code{} @tab +@item @code{roundto } @tab @code{} @tab Returns value rounded to n digits. Does not affect formatting. @item @code{scrub } @tab @code{} @tab @item @code{strip --> S } @tab @code{} @tab @item @code{should_bold } @tab @code{} @tab diff --git a/src/amount.cc b/src/amount.cc index ee03827e..51e69290 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -30,6 +30,7 @@ */ #include +#include #include "amount.h" #include "commodity.h" @@ -672,31 +673,31 @@ void amount_t::in_place_truncate() void amount_t::in_place_floor() { if (! quantity) - throw_(amount_error, _("Cannot floor an uninitialized amount")); + throw_(amount_error, _("Cannot compute floor on an uninitialized amount")); _dup(); - mpz_t quot; - mpz_init(quot); - mpz_fdiv_q(quot, mpq_numref(MP(quantity)), mpq_denref(MP(quantity))); - mpq_clear(MP(quantity)); - mpq_init(MP(quantity)); - mpq_set_num(MP(quantity), quot); + mpz_fdiv_q(temp, mpq_numref(MP(quantity)), mpq_denref(MP(quantity))); + mpq_set_z(MP(quantity), temp); } void amount_t::in_place_ceiling() { if (! quantity) - throw_(amount_error, _("Cannot ceiling an uninitialized amount")); + throw_(amount_error, _("Cannot compute ceiling on an uninitialized amount")); _dup(); - mpz_t quot; - mpz_init(quot); - mpz_cdiv_q(quot, mpq_numref(MP(quantity)), mpq_denref(MP(quantity))); - mpq_clear(MP(quantity)); - mpq_init(MP(quantity)); - mpq_set_num(MP(quantity), quot); + mpz_cdiv_q(temp, mpq_numref(MP(quantity)), mpq_denref(MP(quantity))); + mpq_set_z(MP(quantity), temp); +} + +void amount_t::in_place_roundto(int places) +{ + if (! quantity) + throw_(amount_error, _("Cannot round an uninitialized amount")); + double x=ceil(mpq_get_d(MP(quantity))*pow(10, places) - 0.49999999) / pow(10, places); + mpq_set_d(MP(quantity), x); } void amount_t::in_place_unround() diff --git a/src/amount.h b/src/amount.h index 1b7d2101..5fc2ad2e 100644 --- a/src/amount.h +++ b/src/amount.h @@ -346,6 +346,13 @@ public: } void in_place_round(); + amount_t roundto(int places) const { + amount_t temp(*this); + temp.in_place_round(); + return temp; + } + void in_place_roundto(int places); + /** Yields an amount which has lost all of its extra precision, beyond what the display precision of the commodity would have printed. */ amount_t truncated() const { diff --git a/src/balance.h b/src/balance.h index 9635742d..f822e353 100644 --- a/src/balance.h +++ b/src/balance.h @@ -325,6 +325,17 @@ public: pair.second.in_place_round(); } + balance_t roundto(int places) const { + balance_t temp(*this); + temp.in_place_roundto(places); + return temp; + } + + void in_place_roundto(int places) { + foreach (amounts_map::value_type& pair, amounts) + pair.second.in_place_roundto(places); + } + balance_t truncated() const { balance_t temp(*this); temp.in_place_truncate(); diff --git a/src/report.cc b/src/report.cc index 80993515..d90d22e4 100644 --- a/src/report.cc +++ b/src/report.cc @@ -691,6 +691,12 @@ value_t report_t::fn_round(call_scope_t& args) return args[0].rounded(); } +value_t report_t::fn_roundto(call_scope_t& args) +{ + if(args.has(1)) + return args[0].roundto(args.get(1)); +} + value_t report_t::fn_unround(call_scope_t& args) { return args[0].unrounded(); @@ -1435,6 +1441,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, return WRAP_FUNCTOR(fn_red); else if (is_eq(p, "round")) return MAKE_FUNCTOR(report_t::fn_round); + else if (is_eq(p, "roundto")) + return MAKE_FUNCTOR(report_t::fn_roundto); break; case 's': diff --git a/src/report.h b/src/report.h index b0044f60..6533d2f1 100644 --- a/src/report.h +++ b/src/report.h @@ -176,6 +176,7 @@ public: value_t fn_floor(call_scope_t& scope); value_t fn_ceiling(call_scope_t& scope); value_t fn_round(call_scope_t& scope); + value_t fn_roundto(call_scope_t& scope); value_t fn_unround(call_scope_t& scope); value_t fn_abs(call_scope_t& scope); value_t fn_justify(call_scope_t& scope); diff --git a/src/value.cc b/src/value.cc index c57cff78..3df8f3c7 100644 --- a/src/value.cc +++ b/src/value.cc @@ -1612,6 +1612,27 @@ void value_t::in_place_round() throw_(value_error, _f("Cannot set rounding for %1%") % label()); } +void value_t::in_place_roundto(int places) +{ + DEBUG("amount.roundto", "=====> roundto places " << places); + switch (type()) { + case INTEGER: + return; + case AMOUNT: + as_amount_lval().in_place_roundto(places); + return; + case BALANCE: + as_balance_lval().in_place_roundto(places); + return; + case SEQUENCE: + foreach (value_t& value, as_sequence_lval()) + value.in_place_roundto(places); + return; + default: + break; + } +} + void value_t::in_place_truncate() { switch (type()) { diff --git a/src/value.h b/src/value.h index 249f3d7f..49d64ab6 100644 --- a/src/value.h +++ b/src/value.h @@ -443,6 +443,13 @@ public: } void in_place_round(); + value_t roundto(int places) const { + value_t temp(*this); + temp.in_place_roundto(places); + return temp; + } + void in_place_roundto(int places); + value_t truncated() const { value_t temp(*this); temp.in_place_truncate(); diff --git a/test/regress/25A099C9.test b/test/regress/25A099C9.test index fb362a4b..34c92c40 100644 --- a/test/regress/25A099C9.test +++ b/test/regress/25A099C9.test @@ -20,24 +20,24 @@ While parsing file "$sourcepath/src/amount.h", line 121: Error: Unexpected whitespace at beginning of line While parsing file "$sourcepath/src/amount.h", line 132: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 711: +While parsing file "$sourcepath/src/amount.h", line 718: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 741: +While parsing file "$sourcepath/src/amount.h", line 748: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 749: +While parsing file "$sourcepath/src/amount.h", line 756: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 752: +While parsing file "$sourcepath/src/amount.h", line 759: Error: Invalid date/time: line amount_t amoun -While parsing file "$sourcepath/src/amount.h", line 758: +While parsing file "$sourcepath/src/amount.h", line 765: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 764: +While parsing file "$sourcepath/src/amount.h", line 771: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 770: +While parsing file "$sourcepath/src/amount.h", line 777: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 776: -Error: Invalid date/time: line std::ostream& While parsing file "$sourcepath/src/amount.h", line 783: +Error: Invalid date/time: line std::ostream& +While parsing file "$sourcepath/src/amount.h", line 790: Error: Invalid date/time: line std::istream& -While parsing file "$sourcepath/src/amount.h", line 789: +While parsing file "$sourcepath/src/amount.h", line 796: Error: Unexpected whitespace at beginning of line end test -- cgit v1.2.3 From 9e3652dd4fc4bea3453b5b79f9a687501a63cb90 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 30 Jan 2013 23:31:39 +0100 Subject: acprep: pass options starting with -D to CMake --- acprep | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/acprep b/acprep index 6330a7f8..fe49be47 100755 --- a/acprep +++ b/acprep @@ -875,7 +875,7 @@ class PrepareBuild(CommandLineApp): make_args = [] for arg in args: - if arg.startswith('--'): + if arg.startswith('--') or arg.startswith('-D'): config_args.append(arg) else: make_args.append(arg) @@ -1068,12 +1068,17 @@ typical user: submodule Updates Git submodules (better to use 'pull') version Output current HEAD version to version.m4 -NOTE: If you wish to pass options to configure or make, add "--" followed by -your options. Here are some real-world examples: +NOTE: If you wish to pass options to CMake or make, add "--" followed by +your options. Those starting with "-D" or "--" will be passed on to CMake, +positional arguments and other options will be passed to make. +For the 'config' and 'configure' phase everything will be passed to CMake. + +Here are some real-world examples: ./acprep - ./acprep opt -- make -j3 - ./acprep --enable-doxygen""" + ./acprep --python + ./acprep opt make + ./acprep make doc -- -DBUILD_WEB_DOCS=1""" sys.exit(0) PrepareBuild().run() -- cgit v1.2.3 From 20217e7c9c990039a264b94637bba6b2caffe885 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 30 Jan 2013 23:37:37 +0100 Subject: fix --no-python option This would fail with `ValueError: list.remove(x): x not in list`. --- acprep | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/acprep b/acprep index fe49be47..ca718136 100755 --- a/acprep +++ b/acprep @@ -301,10 +301,9 @@ class PrepareBuild(CommandLineApp): help='Enable use of Doxygen to build ref manual ("make docs")') op.add_option('', '--python', action='store_true', dest='python', default=False, - help='Enable Python support (if disabled in acprep)') - op.add_option('', '--no-python', action='store_true', dest='no_python', - default=False, - help='Do not enable Python support by default') + help='Enable Python support') + op.add_option('', '--no-python', action='store_false', dest='python', + help='Disable python support (default)') op.add_option('', '--prefix', metavar='DIR', action="store", dest="prefix_dir", help='Use custom installation prefix') op.add_option('', '--products', metavar='DIR', action="store", @@ -684,8 +683,6 @@ class PrepareBuild(CommandLineApp): self.configure_args.append('-DUSE_DOXYGEN=1') if self.options.python: self.configure_args.append('-DUSE_PYTHON=1') - if self.options.no_python: - self.configure_args.remove('-DUSE_PYTHON=1') if self.options.use_ninja: self.configure_args.append('-GNinja') -- cgit v1.2.3 From be7af24250260c52668ffa27b93c8a45f68b58d5 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 30 Jan 2013 16:59:42 -0600 Subject: Upgrade to Boost 1.52 --- acprep | 2 +- lib/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/acprep b/acprep index 26f8d8b2..b83d1f19 100755 --- a/acprep +++ b/acprep @@ -99,7 +99,7 @@ class CommandLineApp(object): force_exit = True # If true, always ends run() with sys.exit() log_handler = None - boost_major = "1_50" + boost_major = "1_52" options = { 'debug': False, diff --git a/lib/Makefile b/lib/Makefile index 68755f18..ddbe0585 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -6,7 +6,7 @@ STOW_ROOT = /usr/local/Cellar/boost PRODUCTS = $(HOME)/Products GCC_VERSION = 4.7 -BOOST_VERSION = 1_50_0 +BOOST_VERSION = 1_52_0 CC = gcc-mp-$(GCC_VERSION) ifeq ($(CC),clang) -- cgit v1.2.3 From 7e0666b013eeb99c142b453107d1df530ba68c6c Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 30 Jan 2013 16:59:55 -0600 Subject: build.sh now installs into Homebrew's Cellar --- tools/build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/build.sh b/tools/build.sh index e79689e3..ba563e34 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -5,6 +5,7 @@ shift 1 JOBS=-j$(sysctl -n hw.activecpu) OPTIONS="$flavor --debug --python --ninja --doxygen $JOBS" +OPTIONS="$OPTIONS --prefix /usr/local/Cellar/ledger/HEAD" time ( \ cd ~/src/ledger ; \ -- cgit v1.2.3 From 2b245f823b0cab9aad74a5c0b59dc6de66dee21a Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 30 Jan 2013 17:00:07 -0600 Subject: Added missing call to timelog.close() --- src/textual.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/textual.cc b/src/textual.cc index 6106914f..b19ce79a 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -282,6 +282,10 @@ void instance_t::parse() } } +#if defined(TIMELOG_SUPPORT) + timelog.close(); +#endif // TIMELOG_SUPPORT + TRACE_STOP(instance_parse, 1); } -- cgit v1.2.3 From ccca974dadc9c57805aeb47565eecd4e25c9d368 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 30 Jan 2013 17:00:22 -0600 Subject: Use -O3 with Clang instead of -O4 --- acprep | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/acprep b/acprep index b83d1f19..36481f4a 100755 --- a/acprep +++ b/acprep @@ -666,8 +666,10 @@ class PrepareBuild(CommandLineApp): self.configure_args.append('-DCMAKE_CXX_COMPILER:PATH=/usr/local/bin/clang++') if self.current_flavor == 'opt': - self.configure_args.append('-DCMAKE_CXX_FLAGS_RELEASE:STRING=-O4') - self.configure_args.append('-DCMAKE_CXX_LINK_FLAGS_RELEASE:STRING=-O4') + self.configure_args.append('-DCMAKE_CXX_FLAGS_RELEASE:STRING=-O3') + self.configure_args.append('-DCMAKE_EXE_LINKER_FLAGS:STRING=-O3') + self.configure_args.append('-DCMAKE_SHARED_LINKER_FLAGS:STRING=-O3') + self.configure_args.append('-DCMAKE_MODULE_LINKER_FLAGS:STRING=-O3') #else: # self.CXXFLAGS.append('-g -O1 -faddress-sanitizer') # self.LDFLAGS.append('-g -O1 -faddress-sanitizer') -- cgit v1.2.3 From 19eb2cab1bfc45ccd0634a8e3d2efe392126fcf1 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Wed, 30 Jan 2013 16:43:47 -0700 Subject: Divorces 25A099C9 from the actual amount.h source file This test appears to test the garbage input handling on ledger. garbage-input.dat has been added to the test directory for use by this test, allowing development with amount.h to proceed without tripping this particular test inappropriately --- test/garbage-input.dat | 793 +++++++++++++++++++++++++++++++++++++++++++++ test/regress/25A099C9.test | 42 +-- 2 files changed, 814 insertions(+), 21 deletions(-) create mode 100644 test/garbage-input.dat diff --git a/test/garbage-input.dat b/test/garbage-input.dat new file mode 100644 index 00000000..1b7d2101 --- /dev/null +++ b/test/garbage-input.dat @@ -0,0 +1,793 @@ +/* + * Copyright (c) 2003-2012, 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. + */ + +/** + * @defgroup math Mathematical objects + */ + +/** + * @file amount.h + * @author John Wiegley + * + * @ingroup math + * + * @brief Basic type for handling commoditized math: amount_t + * + * An amount is the most basic numerical type in Ledger, and relies on + * commodity.h to represent commoditized amounts, which allows Ledger to + * handle mathematical expressions involving disparate commodities. + * + * Amounts can be of virtually infinite size and precision. When + * division or multiplication is performed, the precision is + * automatically expanded to include as many extra digits as necessary + * to avoid losing information. + */ +#ifndef _AMOUNT_H +#define _AMOUNT_H + +#include "utils.h" +#include "times.h" +#include "flags.h" + +namespace ledger { + +class commodity_t; +struct annotation_t; +struct keep_details_t; + +DECLARE_EXCEPTION(amount_error, std::runtime_error); + +enum parse_flags_enum_t { + PARSE_DEFAULT = 0x00, + PARSE_PARTIAL = 0x01, + PARSE_SINGLE = 0x02, + PARSE_NO_MIGRATE = 0x04, + PARSE_NO_REDUCE = 0x08, + PARSE_NO_ASSIGN = 0x10, + PARSE_NO_ANNOT = 0x20, + PARSE_OP_CONTEXT = 0x40, + PARSE_SOFT_FAIL = 0x80 +}; + +typedef basic_flags_t parse_flags_t; + +/** + * @brief Encapsulate infinite-precision commoditized amounts + * + * Used to represent commoditized infinite-precision numbers, and + * uncommoditized, plain numbers. In the commoditized case, commodities + * keep track of how they are used, and are always displayed back to the + * user after the same fashion. For uncommoditized numbers, no display + * truncation is ever done. In both cases, internal precision is always + * kept to an excessive degree. + */ +class amount_t + : public ordered_field_operators > > > +{ +public: + /** Ready the amount subsystem for use. + @note Normally called by session_t::initialize(). */ + static void initialize(); + /** Shutdown the amount subsystem and free all resources. + @note Normally called by session_t::shutdown(). */ + static void shutdown(); + + static bool is_initialized; + + /** The amount's decimal precision. */ + typedef uint_least16_t precision_t; + + /** Number of places of precision by which values are extended to + avoid losing precision during division and multiplication. */ + static const std::size_t extend_by_digits = 6U; + + /** If amounts should be streamed using to_fullstring() rather than + to_string(), so that complete precision is always displayed no matter + what the precision of an individual commodity may be. */ + static bool stream_fullstrings; + +protected: + void _copy(const amount_t& amt); + void _dup(); + void _clear(); + void _release(); + + struct bigint_t; + + bigint_t * quantity; + commodity_t * commodity_; + +public: + /** @name Constructors + @{ */ + + /** Creates a value for which is_null() is true, and which has no + value or commodity. If used in a value expression it evaluates to + zero, and its commodity equals \c commodity_t::null_commodity. */ + amount_t() : quantity(NULL), commodity_(NULL) { + TRACE_CTOR(amount_t, ""); + } + + /** Convert a double to an amount. As much precision as possible is + decoded from the binary floating point number. */ + amount_t(const double val); + + /** Convert an unsigned long to an amount. It's precision is zero. */ + amount_t(const unsigned long val); + + /** Convert a long to an amount. It's precision is zero, and the sign + is preserved. */ + amount_t(const long val); + + /** Parse a string as an (optionally commoditized) amount. If no + commodity is present, the resulting commodity is \c + commodity_t::null_commodity. The number may be of infinite + precision. */ + explicit amount_t(const string& val) : quantity(NULL) { + parse(val); + TRACE_CTOR(amount_t, "const string&"); + } + /** Parse a pointer to a C string as an (optionally commoditized) + amount. If no commodity is present, the resulting commodity is \c + commodity_t::null_commodity. The number may be of infinite + precision. */ + explicit amount_t(const char * val) : quantity(NULL) { + assert(val); + parse(val); + TRACE_CTOR(amount_t, "const char *"); + } + + /*@}*/ + + /** Create an amount whose display precision is never truncated, even + if the amount uses a commodity (which normally causes "round on + streaming" to occur). This function is mostly used by debugging + code and unit tests. This is the proper way to specify \c + $100.005, where display of the extra digit precision is required. + If a regular constructor were used, the amount would stream as \c + $100.01, even though its internal value equals \c $100.005. */ + static amount_t exact(const string& value); + + /** Release the reference count held for the underlying \c + amount_t::bigint_t object. */ + ~amount_t() { + TRACE_DTOR(amount_t); + if (quantity) + _release(); + } + + /** @name Assignment and copy + @{*/ + + /** Copy an amount object. Copies are very efficient, using a + copy-on-write model. Until the copy is changed, it refers to the + same memory used by the original via reference counting. The \c + amount_t::bigint_t class in amount.cc maintains the reference. */ + amount_t(const amount_t& amt) : quantity(NULL) { + if (amt.quantity) + _copy(amt); + else + commodity_ = NULL; + TRACE_CTOR(amount_t, "copy"); + } + /** Copy an amount object, applying the given commodity annotation + details afterward. This is equivalent to doing a normal copy + (@see amount_t(const amount_t&)) and then calling + amount_t::annotate(). */ + amount_t(const amount_t& amt, const annotation_t& details) : quantity(NULL) { + assert(amt.quantity); + _copy(amt); + annotate(details); + TRACE_CTOR(amount_t, "const amount_t&, const annotation_t&"); + } + /** Assign an amount object. This is like copying if the amount was + null beforehand, otherwise the previous value's reference is must + be freed. */ + amount_t& operator=(const amount_t& amt); + + amount_t& operator=(const double val) { + return *this = amount_t(val); + } + amount_t& operator=(const unsigned long val) { + return *this = amount_t(val); + } + amount_t& operator=(const long val) { + return *this = amount_t(val); + } + + /* Assign a string to an amount. This causes the contents of the + string to be parsed, look for a commoditized or uncommoditized + amount specifier. */ + amount_t& operator=(const string& str) { + return *this = amount_t(str); + } + amount_t& operator=(const char * str) { + assert(str); + return *this = amount_t(str); + } + + /*@}*/ + + /** @name Comparison + @{ */ + + /** Compare two amounts, returning a number less than zero if \p amt + is greater, exactly zero if they are equal, and greater than zero + if \p amt is less. This method is used to implement all of the + other comparison methods.*/ + int compare(const amount_t& amt) const; + + /** Test two amounts for equality. First the commodity pointers are + quickly tested, then the multi-precision values themselves must be + compared. */ + bool operator==(const amount_t& amt) const; + + template + bool operator==(const T& val) const { + return compare(val) == 0; + } + template + bool operator<(const T& amt) const { + return compare(amt) < 0; + } + template + bool operator>(const T& amt) const { + return compare(amt) > 0; + } + + /*@}*/ + + /** @name Binary arithmetic + */ + /*@{*/ + + amount_t& operator+=(const amount_t& amt); + amount_t& operator-=(const amount_t& amt); + amount_t& operator*=(const amount_t& amt) { + return multiply(amt); + } + amount_t& multiply(const amount_t& amt, bool ignore_commodity = false); + + /** Divide two amounts while extending the precision to preserve the + accuracy of the result. For example, if \c 10 is divided by \c 3, + the result ends up having a precision of \link + amount_t::extend_by_digits \endlink place to avoid losing internal + resolution. */ + amount_t& operator/=(const amount_t& amt); + + /*@}*/ + + /** @name Unary arithmetic + @{ */ + + /** Return an amount's internal precision. To find the precision it + should be displayed at -- assuming it was not created using + amount_t::exact() -- use the following expression instead: + @code + amount.commodity().precision() + @endcode */ + precision_t precision() const; + bool keep_precision() const; + void set_keep_precision(const bool keep = true) const; + precision_t display_precision() const; + + /** Returns the negated value of an amount. + @see operator-() + */ + amount_t negated() const { + amount_t temp(*this); + temp.in_place_negate(); + return temp; + } + void in_place_negate(); + + amount_t operator-() const { + return negated(); + } + + /** Returns the absolute value of an amount. Equivalent to: + @code + (x < * 0) ? - x : x + @endcode + */ + amount_t abs() const { + if (sign() < 0) + return negated(); + return *this; + } + + amount_t inverted() const { + amount_t temp(*this); + temp.in_place_invert(); + return temp; + } + void in_place_invert(); + + /** Yields an amount whose display precision when output is truncated + to the display precision of its commodity. This is normally the + default state of an amount, but if one has become unrounded, this + sets the "keep precision" state back to false. + @see set_keep_precision */ + amount_t rounded() const { + amount_t temp(*this); + temp.in_place_round(); + return temp; + } + void in_place_round(); + + /** Yields an amount which has lost all of its extra precision, beyond what + the display precision of the commodity would have printed. */ + amount_t truncated() const { + amount_t temp(*this); + temp.in_place_truncate(); + return temp; + } + void in_place_truncate(); + + /** Yields an amount which has lost all of its extra precision, beyond what + the display precision of the commodity would have printed. */ + amount_t floored() const { + amount_t temp(*this); + temp.in_place_floor(); + return temp; + } + void in_place_floor(); + + /** Yields an amount which has lost all of its extra precision, beyond what + the display precision of the commodity would have printed. */ + amount_t ceilinged() const { + amount_t temp(*this); + temp.in_place_ceiling(); + return temp; + } + void in_place_ceiling(); + + /** Yields an amount whose display precision is never truncated, even + though its commodity normally displays only rounded values. */ + amount_t unrounded() const { + amount_t temp(*this); + temp.in_place_unround(); + return temp; + } + void in_place_unround(); + + /** reduces a value to its most basic commodity form, for amounts that + utilize "scaling commodities". For example, an amount of \c 1h + after reduction will be \c 3600s. + */ + amount_t reduced() const { + amount_t temp(*this); + temp.in_place_reduce(); + return temp; + } + void in_place_reduce(); + + /** unreduce(), if used with a "scaling commodity", yields the most + compact form greater than one. That is, \c 3599s will unreduce to + \c 59.98m, while \c 3601 unreduces to \c 1h. + */ + amount_t unreduced() const { + amount_t temp(*this); + temp.in_place_unreduce(); + return temp; + } + void in_place_unreduce(); + + /** Returns the historical value for an amount -- the default moment + returns the most recently known price -- based on the price history + for the given commodity (or determined automatically, if none is + provided). For example, if the amount were 10 AAPL, and + on Apr 10, 2000 each share of \c AAPL was worth \c $10, then + calling value() for that moment in time would yield the amount \c + $100.00. + */ + optional + value(const datetime_t& moment = datetime_t(), + const commodity_t * in_terms_of = NULL) const; + + optional price() const; + + /*@}*/ + + /** @name Truth tests + */ + /*@{*/ + + /** Truth tests. An amount may be truth test in several ways: + + sign() returns an integer less than, greater than, or equal to + zero depending on whether the amount is negative, zero, or + greater than zero. Note that this function tests the actual + value of the amount -- using its internal precision -- and not + the display value. To test its display value, use: + `round().sign()'. + + is_nonzero(), or operator bool, returns true if an amount's + display value is not zero. + + is_zero() returns true if an amount's display value is zero. + Thus, $0.0001 is considered zero if the current display precision + for dollars is two decimal places. + + is_realzero() returns true if an amount's actual value is zero. + Thus, $0.0001 is never considered realzero. + + is_null() returns true if an amount has no value and no + commodity. This only occurs if an uninitialized amount has never + been assigned a value. + */ + int sign() const; + + operator bool() const { + return is_nonzero(); + } + bool is_nonzero() const { + return ! is_zero(); + } + + bool is_zero() const; + bool is_realzero() const { + return sign() == 0; + } + + bool is_null() const { + if (! quantity) { + assert(! commodity_); + return true; + } + return false; + } + + /*@}*/ + + /** @name Conversion + */ + /*@{*/ + + /** Conversion methods. An amount may be converted to the same types + it can be constructed from -- with the exception of unsigned + long. Implicit conversions are not allowed in C++ (though they + are in Python), rather the following conversion methods must be + called explicitly: + + to_double([bool]) returns an amount as a double. If the optional + boolean argument is true (the default), an exception is thrown if + the conversion would lose information. + + to_long([bool]) returns an amount as a long integer. If the + optional boolean argument is true (the default), an exception is + thrown if the conversion would lose information. + + fits_in_long() returns true if to_long() would not lose + precision. + + to_string() returns an amount'ss "display value" as a string -- + after rounding the value according to the commodity's default + precision. It is equivalent to: `round().to_fullstring()'. + + to_fullstring() returns an amount's "internal value" as a string, + without any rounding. + + quantity_string() returns an amount's "display value", but + without any commodity. Note that this is different from + `number().to_string()', because in that case the commodity has + been stripped and the full, internal precision of the amount + would be displayed. + */ + double to_double() const; + long to_long() const; + bool fits_in_long() const; + + operator string() const { + return to_string(); + } + string to_string() const; + string to_fullstring() const; + string quantity_string() const; + + /*@}*/ + + /** @name Commodity methods + */ + /*@{*/ + + /** The following methods relate to an + amount's commodity: + + commodity() returns an amount's commodity. If the amount has no + commodity, the value returned is the `null_commodity'. + + has_commodity() returns true if the amount has a commodity. + + set_commodity(commodity_t) sets an amount's commodity to the + given value. Note that this merely sets the current amount to + that commodity, it does not "observe" the amount for possible + changes in the maximum display precision of the commodity, the + way that `parse' does. + + clear_commodity() sets an amount's commodity to null, such that + has_commodity() afterwards returns false. + + number() returns a commodity-less version of an amount. This is + useful for accessing just the numeric portion of an amount. + */ + commodity_t * commodity_ptr() const; + commodity_t& commodity() const { + return *commodity_ptr(); + } + + bool has_commodity() const; + void set_commodity(commodity_t& comm) { + if (! quantity) + *this = 0L; + commodity_ = &comm; + } + amount_t with_commodity(const commodity_t& comm) const { + if (commodity_ == &comm) { + return *this; + } else { + amount_t tmp(*this); + tmp.set_commodity(const_cast(comm)); + return tmp; + } + } + void clear_commodity() { + commodity_ = NULL; + } + + amount_t number() const { + if (! has_commodity()) + return *this; + + amount_t temp(*this); + temp.clear_commodity(); + return temp; + } + + /*@}*/ + + /** @name Commodity annotations + */ + /*@{*/ + + /** An amount's commodity may be annotated with special details, such as the + price it was purchased for, when it was acquired, or an arbitrary note, + identifying perhaps the lot number of an item. + + annotate_commodity(amount_t price, [datetime_t date, string tag]) + sets the annotations for the current amount's commodity. Only + the price argument is required, although it can be passed as + `none' if no price is desired. + + commodity_annotated() returns true if an amount's commodity has + any annotation details associated with it. + + annotation_details() returns all of the details of an annotated + commodity's annotations. The structure returns will evaluate as + boolean false if there are no details. + + strip_annotations() returns an amount whose commodity's annotations have + been stripped. + */ + void annotate(const annotation_t& details); + bool has_annotation() const; + + annotation_t& annotation(); + const annotation_t& annotation() const { + return const_cast(*this).annotation(); + } + + /** If the lot price is considered whenever working with commoditized + values. + + Let's say a user adds two values of the following form: + @code + 10 AAPL + 10 AAPL {$20} + @endcode + + This expression adds ten shares of Apple stock with another ten + shares that were purchased for \c $20 a share. If \c keep_price + is false, the result of this expression is an amount equal to + 20 AAPL. If \c keep_price is \c true the expression + yields an exception for adding amounts with different commodities. + In that case, a \link balance_t \endlink object must be used to + store the combined sum. */ + amount_t strip_annotations(const keep_details_t& what_to_keep) const; + + /*@}*/ + + /** @name Parsing + */ + /*@{*/ + + /** The `flags' argument of both parsing may be one or more of the + following: + + PARSE_NO_MIGRATE means to not pay attention to the way an + amount is used. Ordinarily, if an amount were $100.001, for + example, it would cause the default display precision for $ to be + "widened" to three decimal places. If PARSE_NO_MIGRATE is + used, the commodity's default display precision is not changed. + + PARSE_NO_REDUCE means not to call in_place_reduce() on the + resulting amount after it is parsed. + + These parsing methods observe the amounts they parse (unless + PARSE_NO_MIGRATE is true), and set the display details of + the corresponding commodity accordingly. This way, amounts do + not require commodities to be pre-defined in any way, but merely + displays them back to the user in the same fashion as it saw them + used. + + There is also a static convenience method called + `parse_conversion' which can be used to define a relationship + between scaling commodity values. For example, Ledger uses it to + define the relationships among various time values: + + @code + amount_t::parse_conversion("1.0m", "60s"); // a minute is 60 seconds + amount_t::parse_conversion("1.0h", "60m"); // an hour is 60 minutes + @endcode + + The method parse() is used to parse an amount from an input stream + or a string. A global operator>>() is also defined which simply + calls parse on the input stream. The parse() method has two forms: + + parse(istream, flags_t) parses an amount from the given input + stream. + + parse(string, flags_t) parses an amount from the given string. + + parse(string, flags_t) also parses an amount from a string. + */ + bool parse(std::istream& in, + const parse_flags_t& flags = PARSE_DEFAULT); + bool parse(const string& str, + const parse_flags_t& flags = PARSE_DEFAULT) { + std::istringstream stream(str); + bool result = parse(stream, flags); + return result; + } + + static void parse_conversion(const string& larger_str, + const string& smaller_str); + + /*@}*/ + + /** @name Printing + */ + /*@{*/ + + /** An amount may be output to a stream using the `print' method. There is + also a global operator<< defined which simply calls print for an amount + on the given stream. There is one form of the print method, which takes + one required argument and two arguments with default values: + + print(ostream, bool omit_commodity = false, bool full_precision = false) + prints an amounts to the given output stream, using its commodity's + default display characteristics. If `omit_commodity' is true, the + commodity will not be displayed, only the amount (although the + commodity's display precision is still used). If `full_precision' is + true, the full internal precision of the amount is displayed, regardless + of its commodity's display precision. + */ +#define AMOUNT_PRINT_NO_FLAGS 0x00 +#define AMOUNT_PRINT_RIGHT_JUSTIFY 0x01 +#define AMOUNT_PRINT_COLORIZE 0x02 +#define AMOUNT_PRINT_NO_COMPUTED_ANNOTATIONS 0x04 +#define AMOUNT_PRINT_ELIDE_COMMODITY_QUOTES 0x08 + + void print(std::ostream& out, + const uint_least8_t flags = AMOUNT_PRINT_NO_FLAGS) const; + + /*@}*/ + + /** @name Debugging + */ + /*@{*/ + + /** There are two methods defined to help with debugging: + + dump(ostream) dumps an amount to an output stream. There is + little different from print(), it simply surrounds the display + value with a marker, for example "AMOUNT($1.00)". This code is + used by other dumping code elsewhere in Ledger. + + valid() returns true if an amount is valid. This ensures that if + an amount has a commodity, it has a valid value pointer, for + example, even if that pointer simply points to a zero value. + */ + void dump(std::ostream& out) const { + out << "AMOUNT("; + print(out); + out << ")"; + } + + bool valid() const; + +#if HAVE_BOOST_SERIALIZATION +private: + /** Serialization. */ + + friend class boost::serialization::access; + + template + void serialize(Archive& ar, const unsigned int /* version */); +#endif // HAVE_BOOST_SERIALIZATION + + /*@}*/ +}; + +inline amount_t amount_t::exact(const string& value) { + amount_t temp; + temp.parse(value, PARSE_NO_MIGRATE); + return temp; +} + +inline string amount_t::to_string() const { + std::ostringstream bufstream; + print(bufstream); + return bufstream.str(); +} + +inline string amount_t::to_fullstring() const { + std::ostringstream bufstream; + unrounded().print(bufstream); + return bufstream.str(); +} + +inline string amount_t::quantity_string() const { + std::ostringstream bufstream; + number().print(bufstream); + return bufstream.str(); +} + +inline std::ostream& operator<<(std::ostream& out, const amount_t& amt) { + if (amount_t::stream_fullstrings) + amt.unrounded().print(out); + else + amt.print(out); + return out; +} +inline std::istream& operator>>(std::istream& in, amount_t& amt) { + amt.parse(in); + return in; +} + +void put_amount(property_tree::ptree& pt, const amount_t& amt, + bool wrap = true, bool commodity_details = false); + +} // namespace ledger + +#endif // _AMOUNT_H diff --git a/test/regress/25A099C9.test b/test/regress/25A099C9.test index fb362a4b..e511c799 100644 --- a/test/regress/25A099C9.test +++ b/test/regress/25A099C9.test @@ -1,43 +1,43 @@ -test -f src/amount.h reg -> 20 +test -f test/garbage-input.dat reg -> 20 __ERROR__ -While parsing file "$sourcepath/src/amount.h", line 2: +While parsing file "$sourcepath/test/garbage-input.dat", line 2: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 33: +While parsing file "$sourcepath/test/garbage-input.dat", line 33: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 37: +While parsing file "$sourcepath/test/garbage-input.dat", line 37: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 66: +While parsing file "$sourcepath/test/garbage-input.dat", line 66: Error: No quantity specified for amount -While parsing file "$sourcepath/src/amount.h", line 69: +While parsing file "$sourcepath/test/garbage-input.dat", line 69: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 83: +While parsing file "$sourcepath/test/garbage-input.dat", line 83: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 93: +While parsing file "$sourcepath/test/garbage-input.dat", line 93: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 99: +While parsing file "$sourcepath/test/garbage-input.dat", line 99: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 121: +While parsing file "$sourcepath/test/garbage-input.dat", line 121: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 132: +While parsing file "$sourcepath/test/garbage-input.dat", line 132: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 711: +While parsing file "$sourcepath/test/garbage-input.dat", line 711: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 741: +While parsing file "$sourcepath/test/garbage-input.dat", line 741: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 749: +While parsing file "$sourcepath/test/garbage-input.dat", line 749: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/src/amount.h", line 752: +While parsing file "$sourcepath/test/garbage-input.dat", line 752: Error: Invalid date/time: line amount_t amoun -While parsing file "$sourcepath/src/amount.h", line 758: +While parsing file "$sourcepath/test/garbage-input.dat", line 758: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 764: +While parsing file "$sourcepath/test/garbage-input.dat", line 764: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 770: +While parsing file "$sourcepath/test/garbage-input.dat", line 770: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 776: +While parsing file "$sourcepath/test/garbage-input.dat", line 776: Error: Invalid date/time: line std::ostream& -While parsing file "$sourcepath/src/amount.h", line 783: +While parsing file "$sourcepath/test/garbage-input.dat", line 783: Error: Invalid date/time: line std::istream& -While parsing file "$sourcepath/src/amount.h", line 789: +While parsing file "$sourcepath/test/garbage-input.dat", line 789: Error: Unexpected whitespace at beginning of line end test -- cgit v1.2.3 From 0e16ce75f0c219cb83568c1a5b2362bd5028768d Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Wed, 30 Jan 2013 21:50:23 -0700 Subject: Add ability to reconcile new account without switching recon buffers Show cleared balance on command Update documentation --- doc/ledger3.texi | 6 +++++- lisp/ldg-reconcile.el | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index ee4c990b..79ce0b0d 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -2502,13 +2502,17 @@ all of the uncleared transactions. The reconcile buffer has several functions: @item C-x C-s to save changes (to the ledger file as well). @item q - quite the reconcile mode + quit the reconcile mode @item n p next line or previous line @item A add entry @item D delete entry + @item g + reconcile new account + @item b + show cleared balance in mini-buffer @item C-l refresh display @end table diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 011bf400..aaccfb07 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -26,6 +26,7 @@ (defun ledger-display-balance () "Calculate the cleared balance of the account being reconciled" + (interactive) (let ((buffer ledger-buf) (account ledger-acct)) (with-temp-buffer @@ -64,6 +65,11 @@ (forward-line) (ledger-display-balance))) +(defun ledger-reconcile-new-account (account) + (interactive "sAccount to reconcile: ") + (set (make-local-variable 'ledger-acct) account) + (ledger-reconcile-refresh)) + (defun ledger-reconcile-refresh () (interactive) (let ((inhibit-read-only t) @@ -203,10 +209,12 @@ (define-key map [? ] 'ledger-reconcile-toggle) (define-key map [?a] 'ledger-reconcile-add) (define-key map [?d] 'ledger-reconcile-delete) + (define-key map [?g] 'ledger-reconcile-new-account) (define-key map [?n] 'next-line) (define-key map [?p] 'previous-line) (define-key map [?s] 'ledger-reconcile-save) (define-key map [?q] 'ledger-reconcile-quit) + (define-key map [?b] 'ledger-display-balance) (define-key map [menu-bar] (make-sparse-keymap "ldg-recon-menu")) (define-key map [menu-bar ldg-recon-menu] (cons "Reconcile" map)) @@ -220,6 +228,9 @@ (define-key map [menu-bar ldg-recon-menu add] '("Add Entry" . ledger-reconcile-add)) (define-key map [menu-bar ldg-recon-menu tog] '("Toggle Entry" . ledger-reconcile-toggle)) (define-key map [menu-bar ldg-recon-menu sep3] '("--")) + (define-key map [menu-bar ldg-recon-menu bal] '("Show Cleared Balance" . ledger-display-balance)) + (define-key map [menu-bar ldg-recon-menu sep4] '("--")) + (define-key map [menu-bar ldg-recon-menu rna] '("Reconcile New Account" . ledger-reconcile-new-account)) (define-key map [menu-bar ldg-recon-menu ref] '("Refresh" . ledger-reconcile-refresh)) (define-key map [menu-bar ldg-recon-menu sav] '("Save" . ledger-reconcile-save)) -- cgit v1.2.3 From 9e9d99e9187093b459525e3fd7e654d57000c3c4 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 31 Jan 2013 04:56:12 -0600 Subject: Removed an unnecessary if. Fixes #140 --- src/report.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/report.cc b/src/report.cc index d90d22e4..d0b64650 100644 --- a/src/report.cc +++ b/src/report.cc @@ -693,8 +693,7 @@ value_t report_t::fn_round(call_scope_t& args) value_t report_t::fn_roundto(call_scope_t& args) { - if(args.has(1)) - return args[0].roundto(args.get(1)); + return args[0].roundto(args.get(1)); } value_t report_t::fn_unround(call_scope_t& args) -- cgit v1.2.3 From 5c91124955b2c570b071dc81ac971f9c75b406cf Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 31 Jan 2013 15:13:00 -0700 Subject: WIP. ledger-sort-region still drops the first transaction in the region. --- lisp/ldg-mode.el | 4 ++-- lisp/ldg-xact.el | 35 +++++++++++++++++++++++------------ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 128dfeac..9efe7618 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -82,7 +82,7 @@ customizable to ease retro-entry.") (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-entry) (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) - (define-key map [(control ?c) (control ?s)] 'ledger-sort) + (define-key map [(control ?c) (control ?s)] 'ledger-sort-buffer) (define-key map [(control ?c) (control ?t)] 'ledger-test-run) (define-key map [tab] 'pcomplete) (define-key map [(control ?i)] 'pcomplete) @@ -109,7 +109,7 @@ customizable to ease retro-entry.") (define-key map [menu-bar ldg-menu sm] '("Set Month" . ledger-set-month)) (define-key map [menu-bar ldg-menu sy] '("Set Year" . ledger-set-year)) (define-key map [menu-bar ldg-menu s1] '("--")) - (define-key map [menu-bar ldg-menu so] '("Sort Buffer" . ledger-sort)) + (define-key map [menu-bar ldg-menu so] '("Sort Buffer or Region" . ledger-sort-buffer)) (define-key map [menu-bar ldg-menu s2] '("--")) (define-key map [menu-bar ldg-menu te] '("Toggle Current Posting" . ledger-toggle-current)) (define-key map [menu-bar ldg-menu tt] '("Toggle Current Transaction" . ledger-toggle-current-entry)) diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index 11e6fbaf..8907f58e 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -22,21 +22,32 @@ ;; A sample entry sorting function, which works if entry dates are of ;; the form YYYY/mm/dd. -(defun ledger-sort () - (interactive) - (save-excursion - (goto-char (point-min)) - (sort-subr - nil - (function - (lambda () +(defun ledger-next-record-function () (if (re-search-forward (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) (goto-char (match-beginning 0)) - (goto-char (point-max))))) - (function - (lambda () - (forward-paragraph)))))) + (goto-char (point-max)))) + +(defun ledger-end-record-function () + (forward-paragraph)) + +(defun ledger-sort-region (beg end) + (interactive "r") ;load beg and end from point and mark automagically + (save-excursion + (save-restriction + (narrow-to-region beg end) + (goto-char (point-min)) + (message "%s %s %s" beg end (point-min)) + (let ((inhibit-field-text-motion t)) + (sort-subr + nil + 'ledger-next-record-function + 'ledger-end-record-function))))) + +(defun ledger-sort-buffer () + (interactive) + (ledger-sort-region (point-min) (point-max))) + (provide 'ldg-xact) \ No newline at end of file -- cgit v1.2.3 From 7cb3b099867b0537ae055431dc33454836eb0bc6 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 31 Jan 2013 22:15:10 -0700 Subject: Customizable font-locking Moved font code into separate file. created faces that can be customized in using the emacs customizations menu group ledger-faces --- lisp/ldg-fonts.el | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lisp/ldg-mode.el | 13 ---------- lisp/ldg-new.el | 1 + 3 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 lisp/ldg-fonts.el diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el new file mode 100644 index 00000000..9f98a9fd --- /dev/null +++ b/lisp/ldg-fonts.el @@ -0,0 +1,73 @@ +;;; ldg-fonts.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + + +(defgroup ledger-faces nil "Ledger mode highlighting" :group 'ledger) +(defface ledger-font-uncleared-face + `((t :foreground "green" :weight bold )) + "Default face for Ledger" + :group 'ledger-faces) + +(defface ledger-font-cleared-face + `((t :foreground "grey70" :weight normal )) + "Default face for cleared (*) transactions" + :group 'ledger-faces) + +(defface ledger-font-pending-face + `((t :foreground "yellow" :weight normal )) + "Default face for pending (!) transactions" + :group 'ledger-faces) + +(defface ledger-font-other-face + `((t :foreground "yellow" )) + "Default face for other transactions" + :group 'ledger-faces) + +(defface ledger-font-posting-account-face + `((t :foreground "lightblue" )) + "Face for Ledger accounts" + :group 'ledger-faces) + +(defface ledger-font-posting-amount-face + `((t :foreground "yellow" )) + "Face for Ledger amounts" + :group 'ledger-faces) + +(defface ledger-font-comment-face + `((t :foreground "orange" )) + "Face for Ledger comments" + :group 'ledger-faces) + + +(defvar ledger-font-lock-keywords + '(("^[0-9]+[-/.=][-/.=0-9]+\\s-\\!\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 'ledger-font-pending-face) + ("^[0-9]+[-/.=][-/.=0-9]+\\s-\\*\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 'ledger-font-cleared-face) + ("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 'ledger-font-uncleared-face) + ("^\\s-+\\([*]\\s-*\\)?\\(\\([[(]\\)?[^*: + ]+?:\\([^]); + ]\\|\\s-\\)+?\\([])]\\)?\\)\\( \\| \\|$\\)" + 2 'ledger-font-posting-account-face) ; works + ("\\( \\| \\|^\\)\\(;.*\\)" 2 'ledger-font-comment-face) ; works + ("^\\([~=].+\\)" 1 ledger-font-other-face) + ("^\\([A-Za-z]+ .+\\)" 1 ledger-font-other-face)) + "Expressions to highlight in Ledger mode.") + +(provide 'ldg-fonts) \ No newline at end of file diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 128dfeac..10497749 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -38,19 +38,6 @@ customizable to ease retro-entry.") :type 'string :group 'ledger) -(defvar bold 'bold) -(defvar ledger-font-lock-keywords - '(("\\( \\| \\|^\\)\\(;.*\\)" 2 font-lock-comment-face) - ("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 bold) - ;;("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" - ;; 2 font-lock-type-face) - ("^\\s-+\\([*]\\s-*\\)?\\(\\([[(]\\)?[^*: - ]+?:\\([^]); - ]\\|\\s-\\)+?\\([])]\\)?\\)\\( \\| \\|$\\)" - 2 font-lock-keyword-face) - ("^\\([~=].+\\)" 1 font-lock-function-name-face) - ("^\\([A-Za-z]+ .+\\)" 1 font-lock-function-name-face)) - "Expressions to highlight in Ledger mode.") (defvar ledger-mode-abbrev-table) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index d9e0fc60..4793f662 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -43,6 +43,7 @@ (require 'ldg-test) (require 'ldg-texi) (require 'ldg-xact) +(require 'ldg-fonts) ;(autoload #'ledger-mode "ldg-mode" nil t) ;(autoload #'ledger-fully-complete-entry "ldg-complete" nil t) ;(autoload #'ledger-toggle-current "ldg-state" nil t) -- cgit v1.2.3 From 0675208a63837b0ce6802b5124bb90514f07b5e0 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 1 Feb 2013 10:19:47 -0700 Subject: Add regional sort facility to ledger mode C-c C-s now bound to ledger-sort-region. ledger-sort-region is smart and find the beginning of the first xact within the region and the beginning of the first xact AFTER the region so that it can keep posing structure intact --- doc/ledger3.texi | 2 +- lisp/ldg-mode.el | 5 +++-- lisp/ldg-new.el | 1 + lisp/ldg-sort.el | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lisp/ldg-xact.el | 26 ------------------------ 5 files changed, 67 insertions(+), 29 deletions(-) create mode 100644 lisp/ldg-sort.el diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 79ce0b0d..ac0208bd 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -2376,7 +2376,7 @@ reconcile uncleared entries related to an account @item C-c C-d delete the current entry @item C-c C-s -sort all entries in the journal by date. Drop comments outside of entries +sort all entries in the region. @item C-c C-o C-r run a ledger report @item C-C C-o C-g diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 6179747d..001ec8eb 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -69,7 +69,7 @@ customizable to ease retro-entry.") (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-entry) (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) - (define-key map [(control ?c) (control ?s)] 'ledger-sort-buffer) + (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) (define-key map [(control ?c) (control ?t)] 'ledger-test-run) (define-key map [tab] 'pcomplete) (define-key map [(control ?i)] 'pcomplete) @@ -96,7 +96,8 @@ customizable to ease retro-entry.") (define-key map [menu-bar ldg-menu sm] '("Set Month" . ledger-set-month)) (define-key map [menu-bar ldg-menu sy] '("Set Year" . ledger-set-year)) (define-key map [menu-bar ldg-menu s1] '("--")) - (define-key map [menu-bar ldg-menu so] '("Sort Buffer or Region" . ledger-sort-buffer)) + (define-key map [menu-bar ldg-menu so1] '("Sort Buffer" . ledger-sort-buffer)) + (define-key map [menu-bar ldg-menu so2] '("Sort Region" . ledger-sort-region)) (define-key map [menu-bar ldg-menu s2] '("--")) (define-key map [menu-bar ldg-menu te] '("Toggle Current Posting" . ledger-toggle-current)) (define-key map [menu-bar ldg-menu tt] '("Toggle Current Transaction" . ledger-toggle-current-entry)) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index 4793f662..c885cf21 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -43,6 +43,7 @@ (require 'ldg-test) (require 'ldg-texi) (require 'ldg-xact) +(require 'ldg-sort) (require 'ldg-fonts) ;(autoload #'ledger-mode "ldg-mode" nil t) ;(autoload #'ledger-fully-complete-entry "ldg-complete" nil t) diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el new file mode 100644 index 00000000..e1988413 --- /dev/null +++ b/lisp/ldg-sort.el @@ -0,0 +1,62 @@ +;;; ldg-xact.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + +;; A sample entry sorting function, which works if entry dates are of +;; the form YYYY/mm/dd. + +(defun ledger-next-record-function () + (if (re-search-forward + (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" + "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) + (goto-char (match-beginning 0)) + (goto-char (point-max)))) + +(defun ledger-end-record-function () + (forward-paragraph)) + +(defun ledger-sort-region (beg end) + (interactive "r") ;load beg and end from point and mark automagically + (let ((new-beg beg) + (new-end end)) + (save-excursion + (save-restriction + (ledger-next-record-function) ;make sure point is at the beginning of a xact + (message "beg: %s end: %s" new-beg new-end) + (setq new-beg (point)) + (goto-char end) + (ledger-next-record-function) ;make sure end of region is at the beginning of + ;next record after the region + (setq new-end (point)) + (narrow-to-region beg end) + (goto-char (point-min)) + + (let ((inhibit-field-text-motion t)) + (sort-subr + nil + 'ledger-next-record-function + 'ledger-end-record-function)))))) + +(defun ledger-sort-buffer () + (interactive) + (ledger-sort-region (point-min) (point-max))) + + +(provide 'ldg-sort) \ No newline at end of file diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index 8907f58e..1df7d79a 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -22,32 +22,6 @@ ;; A sample entry sorting function, which works if entry dates are of ;; the form YYYY/mm/dd. -(defun ledger-next-record-function () - (if (re-search-forward - (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" - "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) - (goto-char (match-beginning 0)) - (goto-char (point-max)))) - -(defun ledger-end-record-function () - (forward-paragraph)) - -(defun ledger-sort-region (beg end) - (interactive "r") ;load beg and end from point and mark automagically - (save-excursion - (save-restriction - (narrow-to-region beg end) - (goto-char (point-min)) - (message "%s %s %s" beg end (point-min)) - (let ((inhibit-field-text-motion t)) - (sort-subr - nil - 'ledger-next-record-function - 'ledger-end-record-function))))) - -(defun ledger-sort-buffer () - (interactive) - (ledger-sort-region (point-min) (point-max))) (provide 'ldg-xact) \ No newline at end of file -- cgit v1.2.3 From edd82b2639e8a4d1f865dfae898caf678a9e7cbd Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 1 Feb 2013 11:39:48 -0700 Subject: Add custom faces to the reconciler --- lisp/ldg-fonts.el | 15 +++++++++++++++ lisp/ldg-reconcile.el | 17 +++++++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index 9f98a9fd..2b7717c6 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -56,6 +56,21 @@ "Face for Ledger comments" :group 'ledger-faces) +(defface ledger-font-reconciler-uncleared-face + `((t :foreground "green" :weight normal )) + "Default face for uncleared transactions in the reconcile window" + :group 'ledger-faces) + +(defface ledger-font-reconciler-cleared-face + `((t :foreground "grey70" :weight normal )) + "Default face for cleared (*) transactions in the reconcile window" + :group 'ledger-faces) + +(defface ledger-font-reconciler-pending-face + `((t :foreground "yellow" :weight normal )) + "Default face for pending (!) transactions in the reconcile window" + :group 'ledger-faces) + (defvar ledger-font-lock-keywords '(("^[0-9]+[-/.=][-/.=0-9]+\\s-\\!\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 'ledger-font-pending-face) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index aaccfb07..02d0662a 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -55,13 +55,17 @@ (with-current-buffer ledger-buf (goto-char (cdr where)) (setq cleared (ledger-toggle-current-entry))) + ;remove the existing face and add the new face + (remove-text-properties (line-beginning-position) + (line-end-position) + (list 'face)) (if cleared (add-text-properties (line-beginning-position) (line-end-position) - (list 'face 'bold)) - (remove-text-properties (line-beginning-position) - (line-end-position) - (list 'face)))) + (list 'face 'ledger-font-reconciler-cleared-face )) + (add-text-properties (line-beginning-position) + (line-end-position) + (list 'face 'ledger-font-reconciler-uncleared-face )))) (forward-line) (ledger-display-balance))) @@ -172,10 +176,11 @@ (nth 4 item) (nth 1 xact) (nth 2 xact))) (if (nth 3 xact) (set-text-properties beg (1- (point)) - (list 'face 'bold + (list 'face 'ledger-font-reconciler-cleared-face 'where where)) (set-text-properties beg (1- (point)) - (list 'where where)))) + (list 'face 'ledger-font-reconciler-uncleared-face + 'where where)))) (setq index (1+ index))))) (goto-char (point-min)) (set-buffer-modified-p nil) -- cgit v1.2.3 From 36e77bd357e41dc02b79617401845640d02963f6 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 1 Feb 2013 16:15:51 -0700 Subject: Check for ledger executable and version Altered menu creation so that menu functions are disable if there is no ledger executable available command keys will also warn if ledger isn't working remove a debug message from leg-sort --- lisp/ldg-exec.el | 31 +++++++++++++++++++++++++ lisp/ldg-mode.el | 70 +++++++++++++++++++++++++++++++------------------------- lisp/ldg-sort.el | 1 - 3 files changed, 70 insertions(+), 32 deletions(-) diff --git a/lisp/ldg-exec.el b/lisp/ldg-exec.el index ab041fec..f13cfa5a 100644 --- a/lisp/ldg-exec.el +++ b/lisp/ldg-exec.el @@ -19,6 +19,12 @@ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. +(defconst ledger-version-needed "3.0.0" + "The version of ledger executable needed for interactive features") + +(defvar ledger-works nil + "Flag showing whether the ledger binary can support ledger-mode interactive features") + (defgroup ledger-exec nil "Interface to the Ledger command-line accounting program." :group 'ledger) @@ -52,4 +58,29 @@ (read (current-buffer)) (kill-buffer (current-buffer))))) +(defun ledger-version-greater-p (needed) + "verify the ledger binary is usable for ledger-mode" + (let ((buffer ledger-buf) + (version-strings '()) + (version-number)) + (with-temp-buffer + (ledger-exec-ledger buffer (current-buffer) "--version") + (goto-char (point-min)) + (delete-horizontal-space) + (setq version-strings (split-string + (buffer-substring-no-properties (point) + (+ (point) 12)))) + (if (and (string-match (regexp-quote "Ledger") (car version-strings)) + (or (string= needed (car (cdr version-strings))) + (string< needed (car (cdr version-strings))))) + t + nil)))) + +(defun ledger-check-version () + (interactive) + (setq ledger-works (ledger-version-greater-p ledger-version-needed)) + (if ledger-works + (message "Good Ledger Version") + (message "Bad Ledger Version"))) + (provide 'ldg-exec) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 001ec8eb..91bfb973 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -41,10 +41,18 @@ customizable to ease retro-entry.") (defvar ledger-mode-abbrev-table) +(defmacro ledger-run-if-works (func-to-call) + "Macro to run func-to-call only if the ledger-works variable is non-nil" + `(lambda () + (interactive) + (if ledger-works + (funcall ,func-to-call) + (message "Cannot run ledger, check your ledger executable")))) ;;;###autoload (define-derived-mode ledger-mode text-mode "Ledger" "A mode for editing ledger data files." + (ledger-check-version) (ledger-post-setup) (set (make-local-variable 'comment-start) " ; ") @@ -62,50 +70,50 @@ customizable to ease retro-entry.") (set (make-local-variable 'pcomplete-termination-string) "") (let ((map (current-local-map))) - (define-key map [(control ?c) (control ?a)] 'ledger-add-entry) + (define-key map [(control ?c) (control ?a)] (ledger-run-if-works 'ledger-add-entry)) (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-entry) - (define-key map [(control ?c) (control ?y)] 'ledger-set-year) - (define-key map [(control ?c) (control ?m)] 'ledger-set-month) + (define-key map [(control ?c) (control ?y)] (ledger-run-if-works 'ledger-set-year)) + (define-key map [(control ?c) (control ?m)] (ledger-run-if-works 'ledger-set-month)) (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-entry) - (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) + (define-key map [(control ?c) (control ?r)] (ledger-run-if-works 'ledger-reconcile)) (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) - (define-key map [(control ?c) (control ?t)] 'ledger-test-run) + (define-key map [(control ?c) (control ?t)] (ledger-run-if-works 'ledger-test-run)) (define-key map [tab] 'pcomplete) (define-key map [(control ?i)] 'pcomplete) (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry) - (define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report) - (define-key map [(control ?c) (control ?o) (control ?g)] 'ledger-report-goto) - (define-key map [(control ?c) (control ?o) (control ?a)] 'ledger-report-redo) - (define-key map [(control ?c) (control ?o) (control ?s)] 'ledger-report-save) - (define-key map [(control ?c) (control ?o) (control ?e)] 'ledger-report-edit) - (define-key map [(control ?c) (control ?o) (control ?k)] 'ledger-report-kill) + (define-key map [(control ?c) (control ?o) (control ?r)] (ledger-run-if-works 'ledger-report)) + (define-key map [(control ?c) (control ?o) (control ?g)] (ledger-run-if-works 'ledger-report-goto)) + (define-key map [(control ?c) (control ?o) (control ?a)] (ledger-run-if-works 'ledger-report-redo)) + (define-key map [(control ?c) (control ?o) (control ?s)] (ledger-run-if-works 'ledger-report-save)) + (define-key map [(control ?c) (control ?o) (control ?e)] (ledger-run-if-works 'ledger-report-edit)) + (define-key map [(control ?c) (control ?o) (control ?k)] (ledger-run-if-works 'ledger-report-kill)) (define-key map [menu-bar] (make-sparse-keymap "ldg-menu")) (define-key map [menu-bar ldg-menu] (cons "Ledger" map)) - (define-key map [menu-bar ldg-menu lrk] '("Kill Report" . ledger-report-kill)) - (define-key map [menu-bar ldg-menu lre] '("Edit Report" . ledger-report-edit)) - (define-key map [menu-bar ldg-menu lrs] '("Save Report" . ledger-report-save)) - (define-key map [menu-bar ldg-menu lrr] '("Re-run Report" . ledger-report-redo)) - (define-key map [menu-bar ldg-menu lrg] '("Goto Report" . ledger-report-goto)) - (define-key map [menu-bar ldg-menu lr] '("Run Report" . ledger-report)) - (define-key map [menu-bar ldg-menu s5] '("--")) - (define-key map [menu-bar ldg-menu sm] '("Set Month" . ledger-set-month)) - (define-key map [menu-bar ldg-menu sy] '("Set Year" . ledger-set-year)) - (define-key map [menu-bar ldg-menu s1] '("--")) - (define-key map [menu-bar ldg-menu so1] '("Sort Buffer" . ledger-sort-buffer)) - (define-key map [menu-bar ldg-menu so2] '("Sort Region" . ledger-sort-region)) - (define-key map [menu-bar ldg-menu s2] '("--")) - (define-key map [menu-bar ldg-menu te] '("Toggle Current Posting" . ledger-toggle-current)) - (define-key map [menu-bar ldg-menu tt] '("Toggle Current Transaction" . ledger-toggle-current-entry)) - (define-key map [menu-bar ldg-menu s4] '("--")) - (define-key map [menu-bar ldg-menu de] '("Delete Entry" . ledger-delete-current-entry)) - (define-key map [menu-bar ldg-menu ae] '("Add Entry" . ledger-add-entry)) - (define-key map [menu-bar ldg-menu s3] '("--")) - (define-key map [menu-bar ldg-menu re] '("Reconcile Account" . ledger-reconcile)))) + (define-key map [report-kill] '(menu-item "Kill Report" ledger-report-kill :enable ledger-works)) + (define-key map [report-edit] '(menu-item "Edit Report" ledger-report-edit :enable ledger-works)) + (define-key map [report-save] '(menu-item "Save Report" ledger-report-save :enable ledger-works)) + (define-key map [report-rrun] '(menu-item "Re-run Report" ledger-report-redo :enable ledger-works)) + (define-key map [report-goto] '(menu-item "Goto Report" ledger-report-goto :enable ledger-works)) + (define-key map [report-run] '(menu-item "Run Report" ledger-report :enable ledger-works)) + (define-key map [sep5] '(menu-item "--")) + (define-key map [set-month] '(menu-item "Set Month" ledger-set-month :enable ledger-works)) + (define-key map [set-year] '(menu-item "Set Year" ledger-set-year :enable ledger-works)) + (define-key map [sep1] '("--")) + (define-key map [sort-buff] '(menu-item "Sort Buffer" ledger-sort-buffer)) + (define-key map [sort-reg] '(menu-item "Sort Region" ledger-sort-region :enable mark-active)) + (define-key map [sep2] '(menu-item "--")) + (define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current)) + (define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-entry)) + (define-key map [sep4] '(menu-item "--")) + (define-key map [delete-xact] '(menu-item "Delete Entry" ledger-delete-current-entry)) + (define-key map [add-xact] '(menu-item "Add Entry" ledger-add-entry :enable ledger-works)) + (define-key map [sep3] '(menu-item "--")) + (define-key map [reconcile] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works)))) (defun ledger-time-less-p (t1 t2) "Say whether time value T1 is less than time value T2." diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el index e1988413..9cecefa4 100644 --- a/lisp/ldg-sort.el +++ b/lisp/ldg-sort.el @@ -39,7 +39,6 @@ (save-excursion (save-restriction (ledger-next-record-function) ;make sure point is at the beginning of a xact - (message "beg: %s end: %s" new-beg new-end) (setq new-beg (point)) (goto-char end) (ledger-next-record-function) ;make sure end of region is at the beginning of -- cgit v1.2.3 From 37ea7f9b1fdb4fda416f1e35141e4778f1a3c138 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 1 Feb 2013 21:28:36 -0700 Subject: Updated developer section --- doc/ledger3.texi | 742 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 396 insertions(+), 346 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index ac0208bd..be7d7e98 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -77,8 +77,8 @@ twinkling in their father's CRT. * Budgeting and Forecasting:: * Value Expressions:: * Format Strings:: -* Ledger for Developers:: * Extending with Python:: +* Ledger for Developers:: * Major Changes from version 2.6:: * Example Data File:: * Miscellaneous Notes:: @@ -4093,7 +4093,6 @@ of the balance. * Primary Financial Reports:: Reports in other formats:: Reports about * Reports in other Formats:: * Reports about your Journals:: -* Developer Commands:: @end menu @node Primary Financial Reports, Reports in other Formats, Reporting Commands, Reporting Commands @@ -4774,7 +4773,7 @@ by Ledger. This is useful for generating and tidying up pricedb database files. -@node Reports about your Journals, Developer Commands, Reports in other Formats, Reporting Commands +@node Reports about your Journals, , Reports in other Formats, Reporting Commands @section Reports about your Journals @menu @@ -4879,199 +4878,6 @@ macbook-2:$ -@node Developer Commands, , Reports about your Journals, Reporting Commands -@section Developer Commands -@menu -* echo:: -* reload:: -* source:: -* Debug Options:: -* Pre-commands:: -@end menu - -@node echo, reload, Developer Commands, Developer Commands -@subsection @command{echo} -This command simply echos its argument back to the output. - - -@node reload, source, echo, Developer Commands -@subsection @command{reload} -Forces ledger to reload any journal files. This function exists to -support external programs controlling a running ledger process and does -nothing for a command line user. - -@node source, Debug Options, reload, Developer Commands -@subsection @command{source} -The @code{source} command take a journal file as an argument and parses -it checking for errors, no other reports are generated, and no other -arguments are necessary. Ledger will return success if no errors are -found. - -@node Debug Options, Pre-commands, source, Developer Commands -@subsection Debug Options - -These options are primarily for Ledger developers, but may be of some -use to a user trying something new. - -@table @code - @item --args-only -ignore init -files and environment variables for the ledger run. - -@item --verify -enable additional assertions during run-time. This causes a significant -slowdown. When combined with @code{--debug} ledger will produce -memory trace information. - -@item --debug "argument" -If Ledger has been built with debug options this will provide extra data -during the run. The following are the available arguments to debug: - -@multitable @columnfractions .32 .43 .27 -@item @code{account.display} @tab @code{expr.calc.when} @tab @code{org.next_amount} -@item @code{accounts.sorted} @tab @code{expr.compile} @tab @code{org.next_total} -@item @code{amount.convert} @tab @code{filters.changed_value} @tab @code{parser.error} -@item @code{amount.is_zero} @tab @code{filters.changed_value.rounding} @tab @code{pool.commodities} -@item @code{amount.parse} @tab @code{filters.collapse} @tab @code{post.assign} -@item @code{amount.price} @tab @code{filters.forecast} @tab @code{python.init} -@item @code{amount.truncate} @tab @code{filters.revalued} @tab @code{python.interp} -@item @code{amount.unround} @tab @code{format.abbrev} @tab @code{query.mask} -@item @code{amounts.commodities} @tab @code{format.expr} @tab @code{report.predicate} -@item @code{amounts.refs} @tab @code{generate.post} @tab @code{scope.symbols} -@item @code{archive.journal} @tab @code{generate.post.string} @tab @code{textual.include} -@item @code{auto.columns} @tab @code{item.meta} @tab @code{textual.parse} -@item @code{budget.generate} @tab @code{ledger.read} @tab @code{timelog} -@item @code{commodity.annotated.strip} @tab @code{ledger.validate} @tab @code{times.epoch} -@item @code{commodity.annotations} @tab @code{lookup} @tab @code{times.interval} -@item @code{commodity.compare} @tab @code{lookup.account} @tab @code{times.parse} -@item @code{commodity.download} @tab @code{mask.match} @tab @code{value.sort} -@item @code{commodity.prices.add} @tab @code{memory.counts} @tab @code{value.storage.refcount} -@item @code{commodity.prices.find} @tab @code{memory.counts.live} @tab @code{xact.extend} -@item @code{convert.csv} @tab @code{memory.debug} @tab @code{xact.extend.cleared} -@item @code{csv.mappings} @tab @code{op.cons} @tab @code{xact.extend.fail} -@item @code{csv.parse} @tab @code{op.memory} @tab @code{xact.finalize} -@item @code{draft.xact} @tab @code{option.args} -@item @code{expr.calc} @tab @code{option.names} -@end multitable - -@item --trace INTEGER_TRACE_LEVEL -Enable tracing. The integer specifies the level of trace desired: -@multitable @columnfractions .3 .7 -@item @code{LOG_OFF} @tab 0 -@item @code{LOG_CRIT} @tab 1 -@item @code{LOG_FATAL} @tab 2 -@item @code{LOG_ASSERT} @tab 3 -@item @code{LOG_ERROR} @tab 4 -@item @code{LOG_VERIFY} @tab 5 -@item @code{LOG_WARN} @tab 6 -@item @code{LOG_INFO} @tab 7 -@item @code{LOG_EXCEPT} @tab 8 -@item @code{LOG_DEBUG} @tab 9 -@item @code{LOG_TRACE} @tab 10 -@item @code{LOG_ALL} @tab 11 -@end multitable - -@item --verbose -Print detailed information on the execution of Ledger. - -@item --version -Print version information and exit. -@end table - -@node Pre-commands, , Debug Options, Developer Commands -@subsection Pre-Commands -Pre-commands are useful when you aren't sure how a command or option -will work. -@table @code -@item args -evaluate the given arguments against the following model transaction: -@smallexample -2004/05/27 Book Store - ; This note applies to all postings. :SecondTag: - Expenses:Books 20 BOOK @@ $10 - ; Metadata: Some Value - ; Typed:: $100 + $200 - ; :ExampleTag: - ; Here follows a note describing the posting. - Liabilities:MasterCard $-200.00 -@end smallexample -@item eval -evaluate the given value expression against the model transaction -@item expr "LIMIT EXPRESSION" -Print details of how ledger parses the given limit expression and apply -it against a model transaction. -@item format "FORMATTING" -Print details of how ledger uses the given formatting description and -apply it against a model transaction. -@item generate -Randomly generates syntactically valid Ledger data from a seed. Used by the -GenerateTests harness for development testing -@item parse -Print details of how ledger uses the given value expression description -and apply it against a model transaction. -@item period -evaluate the given period and report how Ledger interprets it: -@smallexample -20:22:21 ~/ledger (next)> ledger period "this year" ---- Period expression tokens --- -TOK_THIS: this -TOK_YEAR: year -END_REACHED: - ---- Before stabilization --- - range: in year 2011 - ---- After stabilization --- - range: in year 2011 - start: 11-Jan-01 - finish: 12-Jan-01 - ---- Sample dates in range (max. 20) --- - 1: 11-Jan-01 -@end smallexample -@item query -evaluate the given query and report how Ledger interprets it against the -model transaction: - -@smallexample -20:25:42 ~/ledger (next)> ledger query "/Book/" ---- Input arguments --- -("/Book/") - ---- Context is first posting of the following transaction --- -2004/05/27 Book Store - ; This note applies to all postings. :SecondTag: - Expenses:Books 20 BOOK @@ $10 - ; Metadata: Some Value - ; Typed:: $100 + $200 - ; :ExampleTag: - ; Here follows a note describing the posting. - Liabilities:MasterCard $-200.00 - ---- Input expression --- -(account =~ /Book/) - ---- Text as parsed --- -(account =~ /Book/) - ---- Expression tree --- -0x7fd639c0da40 O_MATCH (1) -0x7fd639c10170 IDENT: account (1) -0x7fd639c10780 VALUE: /Book/ (1) - ---- Compiled tree --- -0x7fd639c10520 O_MATCH (1) -0x7fd639c0d6c0 IDENT: account (1) -0x7fd639c0d680 FUNCTION (1) -0x7fd639c10780 VALUE: /Book/ (1) - ---- Calculated value --- -true -@end smallexample -@item template -Shows the insertion template that a @code{draft} or @code{xact} sub-command generates. -This is a debugging command. -@end table @node Command-line Syntax, Budgeting and Forecasting, Reporting Commands, Top @chapter Command-line Syntax @@ -7241,7 +7047,7 @@ Useful specifying a date in plain terms. For example, you could say @item @code{value_date } @tab @code{} @tab @end multitable -@node Format Strings, Ledger for Developers, Value Expressions, Top +@node Format Strings, Extending with Python, Value Expressions, Top @chapter Format Strings @menu @@ -7667,49 +7473,206 @@ line number in @code{filename} where posting's entry for posting ends, abbreviat - - - -@node Ledger for Developers, Extending with Python, Format Strings, Top -@chapter Ledger for Developers +@node Extending with Python, Ledger for Developers, Format Strings, Top +@chapter Extending with Python +Python can be used to extend your Ledger +experience. But first, a word must be said about Ledger's data model, so that +other things make sense later. @menu -* Internal Design:: -* Journal File Format:: +* Basic data traversal:: +* Raw vs. Cooked:: +* Queries:: +* Embedded Python:: +* Amounts:: @end menu -@node Internal Design, Journal File Format, Ledger for Developers, Ledger for Developers -@section Internal Design -Ledger is developed as a tiered set of functionality, where lower tiers -know nothing about the higher tiers. In fact, multiple libraries are -built during the development the process, and link unit tests to these -libraries, so that it is a link error for a lower tier to violate this -modularity. - -Those tiers are: +@node Basic data traversal, Raw vs. Cooked, Extending with Python, Extending with Python +@section Basic data traversal -@itemize -@item Utility code +Every interaction with Ledger happens in the context of a Session. Even if +you don't create a session manually, one is created for you by the top-level +interface functions. The Session is where objects live like the Commodity's +that Amount's refer to. - There's lots of general utility in Ledger for doing time parsing, using - Boost.Regex, error handling, etc. It's all done in a way that can be - reused in other projects as needed. +The make a Session useful, you must read a Journal into it, using the function +`@code{read_journal}`. This reads Ledger data from the given file, populates a +Journal object within the current Session, and returns a reference to that +Journal object. -@item Commoditized Amounts (amount_t, commodity_t and friends) +Within the Journal live all the Transaction's, Posting's, and other objects +related to your data. There are also AutomatedTransaction's and +PeriodicTransaction's, etc. - An numerical abstraction combining multi-precision rational numbers (via - GMP) with commodities. These structures can be manipulated like regular - numbers in either C++ or Python (as Amount objects). +Here is how you would traverse all the postings in your data file: +@smallexample -@item Commodity Pool + import ledger - Commodities are all owned by a commodity pool, so that future parsing of - amounts can link to the same commodity and established a consistent price - history and record of formatting details. + for xact in ledger.read_journal("sample.dat").xacts: + for post in xact.posts: + print "Transferring %s to/from %s" % (post.amount, post.account) +@end smallexample -@item Balances +@node Raw vs. Cooked, Queries, Basic data traversal, Extending with Python +@section Raw vs. Cooked - Adds the concept of multiple amounts with varying commodities. Supports +Ledger data exists in one of two forms: raw and cooked. Raw objects are what +you get from a traversal like the above, and represent exactly what was seen +in the data file. Consider this journal: + +@smallexample + = true + (Assets:Cash) $100 + + 2012-03-01 KFC + Expenses:Food $100 + Assets:Credit +@end smallexample + + +In this case, the @emph{raw} regular transaction in this file is: + +@smallexample + 2012-03-01 KFC + Expenses:Food $100 + Assets:Credit +@end smallexample + +While the @emph{cooked} form is: + +@smallexample + 2012-03-01 KFC + Expenses:Food $100 + Assets:Credit $-100 + (Assets:Cash) $100 +@end smallexample + +So the easy way to think about raw vs. cooked is that raw is the unprocessed +data, and cooked has had all considerations applied. + +When you traverse a Journal by iterating its transactions, you are generally +looking at raw data. In order to look at cooked data, you must generate a +report of some kind by querying the journal: + +@smallexample + for post in ledger.read_journal("sample.dat").query("food"): + print "Transferring %s to/from %s" % (post.amount, post.account) +@end smallexample + +The reason why queries iterate over postings instead of transactions is that +queries often return only a ``slice'' of the transactions they apply to. You +can always get at a matching posting's transaction by looking at its "xact" +member: + +@smallexample + last_xact = None + for post in ledger.read_journal("sample.dat").query(""): + if post.xact != last_xact: + for post in post.xact.posts: + print "Transferring %s to/from %s" % (post.amount, + post.account) + last_xact = post.xact +@end smallexample + +This query ends up reporting every cooked posting in the Journal, but does it +transaction-wise. It relies on the fact that an unsorted report returns +postings in the exact order they were parsed from the journal file. + +@node Queries, Embedded Python, Raw vs. Cooked, Extending with Python +@section Queries + +The Journal.query() method accepts every argument you can specify on the +command-line, including --options. + +Since a query ``cooks'' the journal it applies to, only one query may be active +for that journal at a given time. Once the query object is gone (after the +for loop), then the data reverts back to its raw state. + +@node Embedded Python, Amounts, Queries, Extending with Python +@section Embedded Python + +Can you embed Python into your data files using the 'python' directive: + +@smallexample + python + import so + def check_path(path_value): + print "%s => %s" % (str(path_value), os.path.isfile(str(path_value))) + return os.path.isfile(str(path_value)) + + tag PATH + assert check_path(value) + + 2012-02-29 KFC + ; PATH: somebogusfile.dat + Expenses:Food $20 + Assets:Cash +@end smallexample + +Any Python functions you define this way become immediately available as +valexpr functions. + +@node Amounts, , Embedded Python, Extending with Python +@section Amounts + +When numbers come from Ledger, like post.amount, the type of the value is +Amount. It can be used just like an ordinary number, except that addition +and subtraction are restricted to amounts with the same commodity. If you +need to create sums of multiple commodities, use a Balance. For example: + +@smallexample + total = Balance() + for post in ledger.read_journal("sample.dat").query(""): + total += post.amount + print total +@end smallexample + + + + +@node Ledger for Developers, Major Changes from version 2.6, Extending with Python, Top +@chapter Ledger for Developers + +@menu +* Internal Design:: +* Journal File Format:: +* Developer Commands:: +* Ledger Development Environment:: +@end menu + +@node Internal Design, Journal File Format, Ledger for Developers, Ledger for Developers +@section Internal Design +Ledger is developed as a tiered set of functionality, where lower tiers +know nothing about the higher tiers. In fact, multiple libraries are +built during the development the process, and link unit tests to these +libraries, so that it is a link error for a lower tier to violate this +modularity. + +Those tiers are: + +@itemize +@item Utility code + + There's lots of general utility in Ledger for doing time parsing, using + Boost.Regex, error handling, etc. It's all done in a way that can be + reused in other projects as needed. + +@item Commoditized Amounts (amount_t, commodity_t and friends) + + An numerical abstraction combining multi-precision rational numbers (via + GMP) with commodities. These structures can be manipulated like regular + numbers in either C++ or Python (as Amount objects). + +@item Commodity Pool + + Commodities are all owned by a commodity pool, so that future parsing of + amounts can link to the same commodity and established a consistent price + history and record of formatting details. + +@item Balances + + Adds the concept of multiple amounts with varying commodities. Supports simple arithmetic, and multiplication and division with non-commoditized values. @@ -7902,7 +7865,7 @@ And that's Ledger in a nutshell. All the rest are details, such as which value expressions each journal item exposes, how many filters currently exist, which options the report and session scopes define, etc. -@node Journal File Format, , Internal Design, Ledger for Developers +@node Journal File Format, Developer Commands, Internal Design, Ledger for Developers @section Journal File Format for Developers This chapter offers a complete description of the journal data format, @@ -8168,163 +8131,250 @@ considered a primary. In fact, when Ledger goes about ensures that all transactions balance to zero, it only ever asks this of primary commodities. -@node Extending with Python, Major Changes from version 2.6, Ledger for Developers, Top -@chapter Extending with Python -Python can be used to extend your Ledger -experience. But first, a word must be said about Ledger's data model, so that -other things make sense later. - +@node Developer Commands, Ledger Development Environment, Journal File Format, Ledger for Developers +@section Developer Commands @menu -* Basic data traversal:: -* Raw vs. Cooked:: -* Queries:: -* Embedded Python:: -* Amounts:: +* echo:: +* reload:: +* source:: +* Debug Options:: +* Pre-commands:: @end menu -@node Basic data traversal, Raw vs. Cooked, Extending with Python, Extending with Python -@section Basic data traversal +@node echo, reload, Developer Commands, Developer Commands +@subsection @command{echo} +This command simply echos its argument back to the output. -Every interaction with Ledger happens in the context of a Session. Even if -you don't create a session manually, one is created for you by the top-level -interface functions. The Session is where objects live like the Commodity's -that Amount's refer to. -The make a Session useful, you must read a Journal into it, using the function -`@code{read_journal}`. This reads Ledger data from the given file, populates a -Journal object within the current Session, and returns a reference to that -Journal object. +@node reload, source, echo, Developer Commands +@subsection @command{reload} +Forces ledger to reload any journal files. This function exists to +support external programs controlling a running ledger process and does +nothing for a command line user. -Within the Journal live all the Transaction's, Posting's, and other objects -related to your data. There are also AutomatedTransaction's and -PeriodicTransaction's, etc. +@node source, Debug Options, reload, Developer Commands +@subsection @command{source} +The @code{source} command take a journal file as an argument and parses +it checking for errors, no other reports are generated, and no other +arguments are necessary. Ledger will return success if no errors are +found. -Here is how you would traverse all the postings in your data file: -@smallexample +@node Debug Options, Pre-commands, source, Developer Commands +@subsection Debug Options - import ledger +These options are primarily for Ledger developers, but may be of some +use to a user trying something new. - for xact in ledger.read_journal("sample.dat").xacts: - for post in xact.posts: - print "Transferring %s to/from %s" % (post.amount, post.account) -@end smallexample +@table @code + @item --args-only +ignore init +files and environment variables for the ledger run. -@node Raw vs. Cooked, Queries, Basic data traversal, Extending with Python -@section Raw vs. Cooked +@item --verify +enable additional assertions during run-time. This causes a significant +slowdown. When combined with @code{--debug} ledger will produce +memory trace information. -Ledger data exists in one of two forms: raw and cooked. Raw objects are what -you get from a traversal like the above, and represent exactly what was seen -in the data file. Consider this journal: +@item --debug "argument" +If Ledger has been built with debug options this will provide extra data +during the run. The following are the available arguments to debug: -@smallexample - = true - (Assets:Cash) $100 +@multitable @columnfractions .32 .43 .27 +@item @code{account.display} @tab @code{expr.calc.when} @tab @code{org.next_amount} +@item @code{accounts.sorted} @tab @code{expr.compile} @tab @code{org.next_total} +@item @code{amount.convert} @tab @code{filters.changed_value} @tab @code{parser.error} +@item @code{amount.is_zero} @tab @code{filters.changed_value.rounding} @tab @code{pool.commodities} +@item @code{amount.parse} @tab @code{filters.collapse} @tab @code{post.assign} +@item @code{amount.price} @tab @code{filters.forecast} @tab @code{python.init} +@item @code{amount.truncate} @tab @code{filters.revalued} @tab @code{python.interp} +@item @code{amount.unround} @tab @code{format.abbrev} @tab @code{query.mask} +@item @code{amounts.commodities} @tab @code{format.expr} @tab @code{report.predicate} +@item @code{amounts.refs} @tab @code{generate.post} @tab @code{scope.symbols} +@item @code{archive.journal} @tab @code{generate.post.string} @tab @code{textual.include} +@item @code{auto.columns} @tab @code{item.meta} @tab @code{textual.parse} +@item @code{budget.generate} @tab @code{ledger.read} @tab @code{timelog} +@item @code{commodity.annotated.strip} @tab @code{ledger.validate} @tab @code{times.epoch} +@item @code{commodity.annotations} @tab @code{lookup} @tab @code{times.interval} +@item @code{commodity.compare} @tab @code{lookup.account} @tab @code{times.parse} +@item @code{commodity.download} @tab @code{mask.match} @tab @code{value.sort} +@item @code{commodity.prices.add} @tab @code{memory.counts} @tab @code{value.storage.refcount} +@item @code{commodity.prices.find} @tab @code{memory.counts.live} @tab @code{xact.extend} +@item @code{convert.csv} @tab @code{memory.debug} @tab @code{xact.extend.cleared} +@item @code{csv.mappings} @tab @code{op.cons} @tab @code{xact.extend.fail} +@item @code{csv.parse} @tab @code{op.memory} @tab @code{xact.finalize} +@item @code{draft.xact} @tab @code{option.args} +@item @code{expr.calc} @tab @code{option.names} +@end multitable - 2012-03-01 KFC - Expenses:Food $100 - Assets:Credit -@end smallexample +@item --trace INTEGER_TRACE_LEVEL +Enable tracing. The integer specifies the level of trace desired: +@multitable @columnfractions .3 .7 +@item @code{LOG_OFF} @tab 0 +@item @code{LOG_CRIT} @tab 1 +@item @code{LOG_FATAL} @tab 2 +@item @code{LOG_ASSERT} @tab 3 +@item @code{LOG_ERROR} @tab 4 +@item @code{LOG_VERIFY} @tab 5 +@item @code{LOG_WARN} @tab 6 +@item @code{LOG_INFO} @tab 7 +@item @code{LOG_EXCEPT} @tab 8 +@item @code{LOG_DEBUG} @tab 9 +@item @code{LOG_TRACE} @tab 10 +@item @code{LOG_ALL} @tab 11 +@end multitable +@item --verbose +Print detailed information on the execution of Ledger. -In this case, the @emph{raw} regular transaction in this file is: +@item --version +Print version information and exit. +@end table +@node Pre-commands, , Debug Options, Developer Commands +@subsection Pre-Commands +Pre-commands are useful when you aren't sure how a command or option +will work. +@table @code +@item args +evaluate the given arguments against the following model transaction: @smallexample - 2012-03-01 KFC - Expenses:Food $100 - Assets:Credit +2004/05/27 Book Store + ; This note applies to all postings. :SecondTag: + Expenses:Books 20 BOOK @@ $10 + ; Metadata: Some Value + ; Typed:: $100 + $200 + ; :ExampleTag: + ; Here follows a note describing the posting. + Liabilities:MasterCard $-200.00 @end smallexample - -While the @emph{cooked} form is: - +@item eval +evaluate the given value expression against the model transaction +@item expr "LIMIT EXPRESSION" +Print details of how ledger parses the given limit expression and apply +it against a model transaction. +@item format "FORMATTING" +Print details of how ledger uses the given formatting description and +apply it against a model transaction. +@item generate +Randomly generates syntactically valid Ledger data from a seed. Used by the +GenerateTests harness for development testing +@item parse +Print details of how ledger uses the given value expression description +and apply it against a model transaction. +@item period +evaluate the given period and report how Ledger interprets it: @smallexample - 2012-03-01 KFC - Expenses:Food $100 - Assets:Credit $-100 - (Assets:Cash) $100 -@end smallexample +20:22:21 ~/ledger (next)> ledger period "this year" +--- Period expression tokens --- +TOK_THIS: this +TOK_YEAR: year +END_REACHED: -So the easy way to think about raw vs. cooked is that raw is the unprocessed -data, and cooked has had all considerations applied. +--- Before stabilization --- + range: in year 2011 -When you traverse a Journal by iterating its transactions, you are generally -looking at raw data. In order to look at cooked data, you must generate a -report of some kind by querying the journal: +--- After stabilization --- + range: in year 2011 + start: 11-Jan-01 + finish: 12-Jan-01 -@smallexample - for post in ledger.read_journal("sample.dat").query("food"): - print "Transferring %s to/from %s" % (post.amount, post.account) +--- Sample dates in range (max. 20) --- + 1: 11-Jan-01 @end smallexample - -The reason why queries iterate over postings instead of transactions is that -queries often return only a ``slice'' of the transactions they apply to. You -can always get at a matching posting's transaction by looking at its "xact" -member: +@item query +evaluate the given query and report how Ledger interprets it against the +model transaction: @smallexample - last_xact = None - for post in ledger.read_journal("sample.dat").query(""): - if post.xact != last_xact: - for post in post.xact.posts: - print "Transferring %s to/from %s" % (post.amount, - post.account) - last_xact = post.xact -@end smallexample +20:25:42 ~/ledger (next)> ledger query "/Book/" +--- Input arguments --- +("/Book/") -This query ends up reporting every cooked posting in the Journal, but does it -transaction-wise. It relies on the fact that an unsorted report returns -postings in the exact order they were parsed from the journal file. +--- Context is first posting of the following transaction --- +2004/05/27 Book Store + ; This note applies to all postings. :SecondTag: + Expenses:Books 20 BOOK @@ $10 + ; Metadata: Some Value + ; Typed:: $100 + $200 + ; :ExampleTag: + ; Here follows a note describing the posting. + Liabilities:MasterCard $-200.00 -@node Queries, Embedded Python, Raw vs. Cooked, Extending with Python -@section Queries +--- Input expression --- +(account =~ /Book/) -The Journal.query() method accepts every argument you can specify on the -command-line, including --options. +--- Text as parsed --- +(account =~ /Book/) -Since a query ``cooks'' the journal it applies to, only one query may be active -for that journal at a given time. Once the query object is gone (after the -for loop), then the data reverts back to its raw state. +--- Expression tree --- +0x7fd639c0da40 O_MATCH (1) +0x7fd639c10170 IDENT: account (1) +0x7fd639c10780 VALUE: /Book/ (1) -@node Embedded Python, Amounts, Queries, Extending with Python -@section Embedded Python +--- Compiled tree --- +0x7fd639c10520 O_MATCH (1) +0x7fd639c0d6c0 IDENT: account (1) +0x7fd639c0d680 FUNCTION (1) +0x7fd639c10780 VALUE: /Book/ (1) -Can you embed Python into your data files using the 'python' directive: +--- Calculated value --- +true +@end smallexample +@item template +Shows the insertion template that a @code{draft} or @code{xact} sub-command generates. +This is a debugging command. +@end table -@smallexample - python - import so - def check_path(path_value): - print "%s => %s" % (str(path_value), os.path.isfile(str(path_value))) - return os.path.isfile(str(path_value)) +@node Ledger Development Environment, , Developer Commands, Ledger for Developers +@section Ledger Development Environment - tag PATH - assert check_path(value) +@menu +* acrep build configuration tool:: +* Testing Framework:: +@end menu - 2012-02-29 KFC - ; PATH: somebogusfile.dat - Expenses:Food $20 - Assets:Cash -@end smallexample +@node acrep build configuration tool, Testing Framework, Ledger Development Environment, Ledger Development Environment +@subsection @code{acprep} build configuration tool -Any Python functions you define this way become immediately available as -valexpr functions. +@node Testing Framework, , acrep build configuration tool, Ledger Development Environment +@subsection Testing Framework +Ledger source ships with a farily complete set of tests to verify that +all is well, and no old errors have been resurfaced. Tests are run +individually with @code{ctest}. All tests can be run using @code{make +check} or @code{ninja check} depending on which build tool you prefer. -@node Amounts, , Embedded Python, Extending with Python -@section Amounts +Once built, the ledger executable resides under the @file{build} +subdirectory in the source tree. Tests are built and stored in the test +subdirectory for the build. For example, +@file{~/ledger/build/ledger/opt/test}. -When numbers come from Ledger, like post.amount, the type of the value is -Amount. It can be used just like an ordinary number, except that addition -and subtraction are restricted to amounts with the same commodity. If you -need to create sums of multiple commodities, use a Balance. For example: +@menu +* Running Tests:: +* Writing Tests:: +@end menu -@smallexample - total = Balance() - for post in ledger.read_journal("sample.dat").query(""): - total += post.amount - print total -@end smallexample +@node Running Tests, Writing Tests, Testing Framework, Testing Framework +@subsubsection Running Tests + +The complete test sweet can be run from the build directory using the +check option for the build tool you use. For example, @code{make +check}. The entire test suit tast around a minute for the optimized +built and many times longer for the debug version. While developing and +debugging, running individual tests can save a great deal of time. + +Individual tests can be run fron the @file{test} subdirectory of the +build location. To execute a single test use @code{ctest -V -R regex}, +where the regex mathes the name of the test you want to build. + +There are nearly 300 tests stored under the @file{test} sudirectoro +tmain source distribution. They are broken into two broad categories, +baseline and regression. To run the @file{5FBF2ED8} test, for example, +issue @code{ctest -V -R "5FB"}. +@node Writing Tests, , Running Tests, Testing Framework +@subsubsection Writing Tests -@node Major Changes from version 2.6, Example Data File, Extending with Python, Top +@node Major Changes from version 2.6, Example Data File, Ledger for Developers, Top @chapter Major Changes from version 2.6 @itemize -- cgit v1.2.3 From c875de881a3998ec9a9815acded80f381701e711 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 1 Feb 2013 21:59:51 -0700 Subject: Fixed key-binges The fancy lambdas detecting whether or not the command could be run weren't passing interactive arguments --- lisp/ldg-mode.el | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 91bfb973..c6d899de 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -41,14 +41,6 @@ customizable to ease retro-entry.") (defvar ledger-mode-abbrev-table) -(defmacro ledger-run-if-works (func-to-call) - "Macro to run func-to-call only if the ledger-works variable is non-nil" - `(lambda () - (interactive) - (if ledger-works - (funcall ,func-to-call) - (message "Cannot run ledger, check your ledger executable")))) - ;;;###autoload (define-derived-mode ledger-mode text-mode "Ledger" "A mode for editing ledger data files." @@ -70,25 +62,29 @@ customizable to ease retro-entry.") (set (make-local-variable 'pcomplete-termination-string) "") (let ((map (current-local-map))) - (define-key map [(control ?c) (control ?a)] (ledger-run-if-works 'ledger-add-entry)) +; (define-key map [(control ?c) (control ?a)] '(lambda (account) +; (interactive "sAccount:") +; (if ledger-works +; (ledger-add-entry account)))) + (define-key map [(control ?c) (control ?a)] 'ledger-add-entry) (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-entry) - (define-key map [(control ?c) (control ?y)] (ledger-run-if-works 'ledger-set-year)) - (define-key map [(control ?c) (control ?m)] (ledger-run-if-works 'ledger-set-month)) + (define-key map [(control ?c) (control ?y)] 'ledger-set-year) + (define-key map [(control ?c) (control ?m)] 'ledger-set-month) (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-entry) - (define-key map [(control ?c) (control ?r)] (ledger-run-if-works 'ledger-reconcile)) + (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) - (define-key map [(control ?c) (control ?t)] (ledger-run-if-works 'ledger-test-run)) + (define-key map [(control ?c) (control ?t)] 'ledger-test-run) (define-key map [tab] 'pcomplete) (define-key map [(control ?i)] 'pcomplete) (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry) - (define-key map [(control ?c) (control ?o) (control ?r)] (ledger-run-if-works 'ledger-report)) - (define-key map [(control ?c) (control ?o) (control ?g)] (ledger-run-if-works 'ledger-report-goto)) - (define-key map [(control ?c) (control ?o) (control ?a)] (ledger-run-if-works 'ledger-report-redo)) - (define-key map [(control ?c) (control ?o) (control ?s)] (ledger-run-if-works 'ledger-report-save)) - (define-key map [(control ?c) (control ?o) (control ?e)] (ledger-run-if-works 'ledger-report-edit)) - (define-key map [(control ?c) (control ?o) (control ?k)] (ledger-run-if-works 'ledger-report-kill)) + (define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report) + (define-key map [(control ?c) (control ?o) (control ?g)] 'ledger-report-goto) + (define-key map [(control ?c) (control ?o) (control ?a)] 'ledger-report-redo) + (define-key map [(control ?c) (control ?o) (control ?s)] 'ledger-report-save) + (define-key map [(control ?c) (control ?o) (control ?e)] 'ledger-report-edit) + (define-key map [(control ?c) (control ?o) (control ?k)] 'ledger-report-kill) (define-key map [menu-bar] (make-sparse-keymap "ldg-menu")) -- cgit v1.2.3 From 7c618e541d4c1e5e4ac476b6724abf2ec97a38b2 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 1 Feb 2013 22:34:28 -0700 Subject: Added menu and keybinding for ledger-post-edit-amount editing the amount with calc is too cool for school. I can't believe I didn't see it before. It is in the docs now as well. --- doc/ledger3.texi | 13 +++++++++++++ lisp/ldg-mode.el | 11 ++++++----- lisp/ldg-post.el | 5 ----- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index be7d7e98..815c770b 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -2403,6 +2403,7 @@ kill the ledger report buffer * Manual Entry Support:: * Automagically Adding new entries:: * Clearing Transactions:: +* Calculating Values with EMACS Calc:: @end menu @node Manual Entry Support, Automagically Adding new entries, Working with entries, Working with entries @@ -2487,6 +2488,18 @@ If, for some reason you need to clear a specific posting in the transaction you can type @code{C-c C-c} and the posting at point will be toggled. +@node Calculating Values with EMACS Calc, , Clearing Transactions, Working with entries +@subsubsection Calculating Values with EMACS Calc + +EMACS come with a very power calculator built in. You can use it to +easily insert calculated amounts directly into your ledger buffer. From +the menu, select @code{Calc on Amount}. Calc will pull the current +amount to the top of the calc stack. Calulate the value as you normally +would with an RPN calculator. When you have the desired value on thetop +of the calc stack, press @code{y}, and calc will insert the value +in place of the previous amount. + + @node Reconciling accounts, Generating Reports, Working with entries, Using EMACS @subsection Reconciling accounts diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index c6d899de..c185c198 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -62,10 +62,6 @@ customizable to ease retro-entry.") (set (make-local-variable 'pcomplete-termination-string) "") (let ((map (current-local-map))) -; (define-key map [(control ?c) (control ?a)] '(lambda (account) -; (interactive "sAccount:") -; (if ledger-works -; (ledger-add-entry account)))) (define-key map [(control ?c) (control ?a)] 'ledger-add-entry) (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-entry) (define-key map [(control ?c) (control ?y)] 'ledger-set-year) @@ -75,6 +71,7 @@ customizable to ease retro-entry.") (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) (define-key map [(control ?c) (control ?t)] 'ledger-test-run) + (define-key map [(control ?c) (control ?v)] 'ledger-post-edit-amount) (define-key map [tab] 'pcomplete) (define-key map [(control ?i)] 'pcomplete) (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) @@ -86,7 +83,9 @@ customizable to ease retro-entry.") (define-key map [(control ?c) (control ?o) (control ?e)] 'ledger-report-edit) (define-key map [(control ?c) (control ?o) (control ?k)] 'ledger-report-kill) - + (define-key map [(meta ?p)] 'ledger-post-prev-xact) + (define-key map [(meta ?n)] 'ledger-post-next-xact) + (define-key map [menu-bar] (make-sparse-keymap "ldg-menu")) (define-key map [menu-bar ldg-menu] (cons "Ledger" map)) @@ -106,6 +105,8 @@ customizable to ease retro-entry.") (define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current)) (define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-entry)) (define-key map [sep4] '(menu-item "--")) + (define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount)) + (define-key map [sep] '(menu-item "--")) (define-key map [delete-xact] '(menu-item "Delete Entry" ledger-delete-current-entry)) (define-key map [add-xact] '(menu-item "Add Entry" ledger-add-entry :enable ledger-works)) (define-key map [sep3] '(menu-item "--")) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 7cb525a7..14a8cdad 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -183,11 +183,6 @@ This is done so that the last digit falls in COLUMN, which defaults to 52." (goto-char (match-end ledger-regex-post-line-group-account)))) (defun ledger-post-setup () - (let ((map (current-local-map))) - (define-key map [(meta ?p)] 'ledger-post-prev-xact) - (define-key map [(meta ?n)] 'ledger-post-next-xact) - (define-key map [(control ?c) (control ?c)] 'ledger-post-pick-account) - (define-key map [(control ?c) (control ?e)] 'ledger-post-edit-amount)) (if ledger-post-auto-adjust-amounts (add-hook 'after-change-functions 'ledger-post-maybe-align t t)) (add-hook 'after-save-hook #'(lambda () (setq ledger-post-current-list nil)))) -- cgit v1.2.3 From cf76c2559904740e7ea7f99965c01814d3799349 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sat, 2 Feb 2013 09:15:03 -0700 Subject: If there is no XACT code print blank, not "nil" --- lisp/ldg-reconcile.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 02d0662a..753c2fa5 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -172,7 +172,9 @@ (point-marker))))))) (insert (format "%s %-4s %-30s %-30s %15s\n" (format-time-string "%Y/%m/%d" (nth 2 item)) - (nth 3 item) + (if (nth 3 item) + (nth 3 item) + "") (nth 4 item) (nth 1 xact) (nth 2 xact))) (if (nth 3 xact) (set-text-properties beg (1- (point)) -- cgit v1.2.3 From 01b8416f240ab7070f62a9f38b9cd575d1fa6056 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sat, 2 Feb 2013 09:44:31 -0700 Subject: Fix bug 795 858, printing "(null)" instead of empty string "" --- src/value.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/value.cc b/src/value.cc index 3df8f3c7..902987a7 100644 --- a/src/value.cc +++ b/src/value.cc @@ -1847,7 +1847,7 @@ void value_t::print(std::ostream& _out, switch (type()) { case VOID: - out << "(null)"; + out << ""; break; case BOOLEAN: -- cgit v1.2.3 From 595a8afa44ad3f30995556fbee36ac16024e7c23 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sat, 2 Feb 2013 15:59:46 -0700 Subject: Fixes bug 377. Ledger now complains if it is given only a directory as input. --- src/context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context.h b/src/context.h index 9fe0613b..fd3575ab 100644 --- a/src/context.h +++ b/src/context.h @@ -117,7 +117,7 @@ inline parse_context_t open_for_reading(const path& pathname, #else filename = filesystem::complete(filename, cwd); #endif - if (! exists(filename)) + if (! exists(filename) || is_directory(filename)) throw_(std::runtime_error, _f("Cannot read journal file %1%") % filename); -- cgit v1.2.3 From 989f86974750ae4ae32645386d749e94e66eb27d Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 3 Feb 2013 08:26:56 -0600 Subject: Bump format parsing buffer to 64K --- src/format.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/format.cc b/src/format.cc index d29c87b3..14bb2430 100644 --- a/src/format.cc +++ b/src/format.cc @@ -129,7 +129,7 @@ format_t::element_t * format_t::parse_elements(const string& fmt, element_t * current = NULL; - char buf[1024]; + static char buf[65535]; char * q = buf; for (const char * p = fmt.c_str(); *p; p++) { -- cgit v1.2.3 From c4c088b55b2528292cf8b84eb36632f7d4343075 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Mon, 4 Feb 2013 10:08:34 -0700 Subject: Fixed ledger-post-edit-amount so that it can be called from the and of an account with a null amount. It automagically determines if the account has two spaces after and if not inserts them. --- lisp/ldg-post.el | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 14a8cdad..dc033bf8 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -156,16 +156,23 @@ This is done so that the last digit falls in COLUMN, which defaults to 52." (defun ledger-post-edit-amount () (interactive) (goto-char (line-beginning-position)) - (when (re-search-forward ledger-post-line-regexp (line-end-position) t) - (goto-char (match-end ledger-regex-post-line-group-account)) - (when (re-search-forward "[-.,0-9]+" (line-end-position) t) - (let ((val (match-string 0))) - (goto-char (match-beginning 0)) - (delete-region (match-beginning 0) (match-end 0)) - (calc) - (while (string-match "," val) - (setq val (replace-match "" nil nil val))) - (calc-eval val 'push))))) + (when (re-search-forward ledger-post-line-regexp (line-end-position) t) + (goto-char (match-end ledger-regex-post-line-group-account)) ;go to the and of the account + (let ((end-of-amount (re-search-forward "[-.,0-9]+" (line-end-position) t))) ;determine if the is an amount to edit + (if end-of-amount + (let ((val (match-string 0))) + (goto-char (match-beginning 0)) + (delete-region (match-beginning 0) (match-end 0)) + (calc) + (while (string-match "," val) + (setq val (replace-match "" nil nil val))) ;gets rid of commas + (calc-eval val 'push)) ;edit the amount + (progn ;make sure there are two spaces after the account name and go to calc + (if (search-backward " " (- (point) 3) t) + (goto-char (line-end-position)) + (insert " ")) + (calc)) + )))) (defun ledger-post-prev-xact () (interactive) -- cgit v1.2.3 From bc5563289cd838f1bb33b86706927fae2e0d670f Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Tue, 5 Feb 2013 00:08:42 -0600 Subject: Fixed bug with --day-break option --- src/timelog.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/timelog.cc b/src/timelog.cc index 9516ba17..acd8a4fa 100644 --- a/src/timelog.cc +++ b/src/timelog.cc @@ -169,10 +169,8 @@ void time_log_t::close() foreach (account_t * account, accounts) { DEBUG("timelog", "Clocking out from account " << account->fullname()); - clock_out_from_timelog(time_xacts, - time_xact_t(none, CURRENT_TIME(), account), - context); - context.count++; + context.count += clock_out_from_timelog + (time_xacts, time_xact_t(none, CURRENT_TIME(), account), context); } assert(time_xacts.empty()); } -- cgit v1.2.3 From 71de1e6cdcdea280f5bf63a8a2e3d7a22411c663 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 5 Feb 2013 11:07:36 -0700 Subject: Enh 246 add code folding to ledger mode Based on loccur. Hides everything but the xacts that match a regex. Linked to reconcile mode so that when you reconcile an account on xacts with that account are shown. Documentation updated --- doc/ledger3.texi | 51 +++++++++- lisp/ldg-mode.el | 5 +- lisp/ldg-new.el | 2 + lisp/ldg-occur.el | 252 ++++++++++++++++++++++++++++++++++++++++++++++++++ lisp/ldg-reconcile.el | 165 ++++++++++++++++++--------------- 5 files changed, 394 insertions(+), 81 deletions(-) create mode 100644 lisp/ldg-occur.el diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 815c770b..ce062104 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -2367,6 +2367,8 @@ add a new entry, based on previous entries toggle cleared status of an entire entry @item C-c C-c toggle cleared status of an individual posting +@item C-c C-f +toggle folding mode. When on shows only transactions that meet a given REGEX @item C-c C-y set default year for entry mode @item C-c C-m @@ -2401,12 +2403,13 @@ kill the ledger report buffer @subsection Working with entries @menu * Manual Entry Support:: +* Hiding Transactions:: * Automagically Adding new entries:: * Clearing Transactions:: * Calculating Values with EMACS Calc:: @end menu -@node Manual Entry Support, Automagically Adding new entries, Working with entries, Working with entries +@node Manual Entry Support, Hiding Transactions, Working with entries, Working with entries @subsubsection Manual Entry Support @cindex completion @@ -2427,8 +2430,38 @@ habit to get in to prevent misspellings of accounts. Remember Ledger does not validate the names of payees or account so a misspelled account will be interpreted as a new account by ledger. +@node Hiding Transactions, Automagically Adding new entries, Manual Entry Support, Working with entries +@subsubsection Hiding Transactions + +There are several ways to organize Ledger data files. You can use a +master file and @code{include} one file for each real bank or brokerage +account, separate files for major expense categories, a mix of those +ideas, or throw every transaction in to one giant file. The biggest +drawback to uing one file is that it can get confusing finding specific +transactions in the file. + +Ledger mode has a special transaction hiding mode that you can use to +hide all transactions except those that meet a regular expression you +provide. By default this command is bound to @code{C-c C-f}. EMACS +will ask for a regular expression, which at its simplest is just text +you want to match. For example, lets say you want to review the +transactions in your checking account named @code{"Assets:Checking"}. +Type @code{C-c C-f}, then type @code{Checking} in the minibuffer. EMACS +will hide all other transactions and highlight the remaining +transactions. You can edit them without fear that your other +transaction have had anything done, they are only hidden from view. + +The color used to highlight the xaction can be customized in the EMACS +customization menu. It is called @code{ledger-occur-xact-face}, and can +be changed to alter any charactistic of a font that you want. If you +don't want any highlighting, simply set +@code{ledger-occur-use-face-unfolded} to @code{nil} in the customization +menu. + +To clear the highlighting and show all transactions, type @code{C-c C-f} +again. -@node Automagically Adding new entries, Clearing Transactions, Manual Entry Support, Working with entries +@node Automagically Adding new entries, Clearing Transactions, Hiding Transactions, Working with entries @subsubsection Automagically Adding new entries @cindex new transactions in EMACS @cindex EMACS, adding new transactions @@ -2463,7 +2496,7 @@ ordered by date, not at the bottom of the file. If you need to include spaces in the payee name, then surrond the name of the payee with double quotes, otherwise ledger will interpret the second part of the name as an account. -@node Clearing Transactions, , Automagically Adding new entries, Working with entries +@node Clearing Transactions, Calculating Values with EMACS Calc, Automagically Adding new entries, Working with entries @subsubsection Clearing Transactions and Postings @cindex clearing transactions in EMACS @cindex EMACS, clear transaction @@ -2491,7 +2524,7 @@ toggled. @node Calculating Values with EMACS Calc, , Clearing Transactions, Working with entries @subsubsection Calculating Values with EMACS Calc -EMACS come with a very power calculator built in. You can use it to +EMACS come with a very powerful calculator built in. You can use it to easily insert calculated amounts directly into your ledger buffer. From the menu, select @code{Calc on Amount}. Calc will pull the current amount to the top of the calc stack. Calulate the value as you normally @@ -2529,6 +2562,14 @@ all of the uncleared transactions. The reconcile buffer has several functions: @item C-l refresh display @end table + +By default the reconcile mode uses transaction hiding to show only +transaction eligible for your reconcile. Th reconcile widow itself will +only show a summary of uncleared transaction while the main buffer will +show all transaction meeting the regex, cleared or not. This behavior +can be disabled by setting @code{ledger-fold-on-reconcile} to nil in the +emacs customization menus. + @node Generating Reports, , Reconciling accounts, Using EMACS @subsection Generating Reports @@ -2539,7 +2580,7 @@ retyping the command line, or writing shell scripts for simple one line commands. To generate a report, select the @code{Run Reports} menu, or type -@code{C-c C-o C-r}. Emacs will prompt for a report name. If it +@code{C-c C-o C-r}. EMACS will prompt for a report name. If it recognizes the name it will run the report again. If it is a new name, or blank it will respond by giving you an example command line to edit. Hitting return willrun the report and present it in a new buffer. diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index c185c198..4c55cdc0 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -72,6 +72,7 @@ customizable to ease retro-entry.") (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) (define-key map [(control ?c) (control ?t)] 'ledger-test-run) (define-key map [(control ?c) (control ?v)] 'ledger-post-edit-amount) + (define-key map [(control ?c) (control ?f)] 'ledger-occur) (define-key map [tab] 'pcomplete) (define-key map [(control ?i)] 'pcomplete) (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) @@ -110,7 +111,9 @@ customizable to ease retro-entry.") (define-key map [delete-xact] '(menu-item "Delete Entry" ledger-delete-current-entry)) (define-key map [add-xact] '(menu-item "Add Entry" ledger-add-entry :enable ledger-works)) (define-key map [sep3] '(menu-item "--")) - (define-key map [reconcile] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works)))) + (define-key map [reconcile] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works)) + (define-key map [reconcile] '(menu-item "Hide Xacts" ledger-occur)) + )) (defun ledger-time-less-p (t1 t2) "Say whether time value T1 is less than time value T2." diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index c885cf21..1d7d5cac 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -45,6 +45,8 @@ (require 'ldg-xact) (require 'ldg-sort) (require 'ldg-fonts) +(require 'ldg-occur) + ;(autoload #'ledger-mode "ldg-mode" nil t) ;(autoload #'ledger-fully-complete-entry "ldg-complete" nil t) ;(autoload #'ledger-toggle-current "ldg-state" nil t) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el new file mode 100644 index 00000000..9cf7f3b1 --- /dev/null +++ b/lisp/ldg-occur.el @@ -0,0 +1,252 @@ +;;; ldg-mode.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + + + + +;;; Commentary: +;; Provide code folding to ledger mode. Adapted from original loccur +;; mode by Alexey Veretennikov +;; +;; Adapted to ledger mode by Craig Earls + +;;; Code: + +(defface ledger-occur-folded-face + `((t :foreground "grey70" :invisible t )) + "Default face for Ledger occur mode hidden transactions" + :group 'ledger-faces) + +(defface ledger-occur-xact-face + `((t :background "blue" :weight normal )) + "Default face for Ledger occur mode shown transactions" + :group 'ledger-faces) + +(defconst ledger-occur-overlay-property-name 'ledger-occur-custom-buffer-grep) + +(defcustom ledger-occur-use-face-unfolded t + "if non-nil use a custom face for xacts shown in ledger-occur mode" + :group 'ledger) +(make-variable-buffer-local 'ledger-occur-use-face-unfolded) + + +(defvar ledger-occur-mode nil) ;; name of the minor mode, shown in the mode-line +(make-variable-buffer-local 'ledger-occur-mode) + +(or (assq 'ledger-occur-mode minor-mode-alist) + (nconc minor-mode-alist + (list '(ledger-occur-mode ledger-occur-mode)))) + +(defvar ledger-occur-history nil + "History of previously searched expressions for the prompt") +(make-variable-buffer-local 'ledger-occur-history) + +(defvar ledger-occur-last-match nil + "Last match found") +(make-variable-buffer-local 'ledger-occur-last-match) + +(defvar ledger-occur-overlay-list nil + "A list of currently active overlays to the ledger buffer.") +(make-variable-buffer-local 'ledger-occur-overlay-list) + + +(defun ledger-occur-mode (regex buffer) + (save-excursion + (set-buffer buffer) + (setq ledger-occur-mode + (if (or ledger-occur-mode + (null regex) + (zerop (length regex))) + nil + (concat " Ledger-Folded: " regex))) + (force-mode-line-update) + (ledger-occur-remove-overlays) + (if ledger-occur-mode + (let* ((buffer-matches (ledger-occur-find-matches regex)) + (ovl-bounds (ledger-occur-create-xact-overlay-bounds buffer-matches))) + (setq ledger-occur-overlay-list + (ledger-occur-create-xact-overlays ovl-bounds)) + (setq ledger-occur-overlay-list + (append ledger-occur-overlay-list + (ledger-occur-create-folded-overlays buffer-matches))) + (setq ledger-occur-last-match regex)) + (recenter)))) + +(defun ledger-occur (regex) + "Perform a simple grep in current buffer for the regular + expression REGEX + + This command hides all xact from the current buffer except + those containing the regular expression REGEX. A second call + of the function unhides lines again" + (interactive + (if ledger-occur-mode + (list nil) + (list (read-string (concat "Regexp<" (ledger-occur-prompt) + ">: ") "" 'ledger-occur-history )))) + (if (string-equal "" regex) (setq regex (ledger-occur-prompt))) + (ledger-occur-mode regex (current-buffer))) + +(defun ledger-occur-prompt () + "Returns the default value of the prompt. + + Default value for prompt is a current word or active + region(selection), if its size is 1 line" + (let ((prompt + (if (and transient-mark-mode + mark-active) + (let ((pos1 (region-beginning)) + (pos2 (region-end))) + ;; Check if the start and the of an active region is on + ;; the same line + (if (= (line-number-at-pos pos1) + (line-number-at-pos pos2)) + (buffer-substring-no-properties pos1 pos2))) + (current-word)))) + prompt)) + +(defun ledger-occur-create-folded-overlays(buffer-matches) + (let ((overlays + (let ((prev-end (point-min)) + (temp (point-max))) + (mapcar (lambda (match) + (progn + (setq temp prev-end) ;need a swap so that the + ;last form in the lambda + ;is the (make-overlay) + (setq prev-end (1+ (cadr match))) ;add 1 so + ;that we skip + ;the empty + ;line after + ;the xact + (make-overlay + temp + (car match) + (current-buffer) t nil))) + buffer-matches)))) + (mapcar (lambda (ovl) + (overlay-put ovl ledger-occur-overlay-property-name t) + (overlay-put ovl 'invisible t) + (overlay-put ovl 'intangible t)) + (push (make-overlay (cadr (car(last buffer-matches))) + (point-max) + (current-buffer) t nil) overlays)))) + + +(defun ledger-occur-create-xact-overlays (ovl-bounds) + (let ((overlays + (mapcar (lambda (bnd) + (make-overlay + (car bnd) + (cadr bnd) + (current-buffer) t nil)) + ovl-bounds))) + (mapcar (lambda (ovl) + (overlay-put ovl ledger-occur-overlay-property-name t) + (if ledger-occur-use-face-unfolded + (overlay-put ovl 'face 'ledger-occur-xact-face ))) + overlays))) + +(defun ledger-occur-change-regex (regex buffer) + "use this function to programatically change the overlays, + rather than quitting out and restarting" + (progn + (set-buffer buffer) + (setq ledger-occur-mode nil) + (force-mode-line-update) + (ledger-occur-mode regex buffer) + (recenter))) + +(defun ledger-occur-quit-buffer (buffer) + "quits hidings transaction in the given buffer. Used for + coordinating ledger-occur with other buffers, like reconcile" + (progn + (set-buffer buffer) + (setq ledger-occur-mode nil) + (force-mode-line-update) + (ledger-occur-remove-overlays) + (recenter))) + +(defun ledger-occur-remove-overlays () + (interactive) + (remove-overlays (point-min) + (point-max) ledger-occur-overlay-property-name t) + (setq ledger-occur-overlay-list nil)) + + +(defun ledger-occur-create-xact-overlay-bounds (buffer-matches) + (let ((prev-end (point-min)) + (overlays (list))) + (when buffer-matches + (mapcar (lambda (line) + (push (list (car line) (cadr line)) overlays) + (setq prev-end (cadr line))) + buffer-matches) + (setq overlays (nreverse overlays))))) + +(defun ledger-occur-find-xact-extents (pos) + "return point for beginning of xact and and of xact containing + position. Requires empty line separating xacts" + (interactive "d") + (save-excursion + (goto-char pos) + (let ((end-pos pos) + (beg-pos pos)) + (backward-paragraph) + (next-line) + (beginning-of-line) + (setq beg-pos (point)) + (forward-paragraph) + (previous-line) + (end-of-line) + (setq end-pos (1+ (point))) + (list beg-pos end-pos)))) + +(defun ledger-occur-find-matches (regex) + "Returns a list of 2-number tuples, specifying begnning of the + line and end of a line containing matching xact" + (save-excursion + (goto-char (point-min)) + ;; Set initial values for variables + (let ((curpoint nil) + (endpoint nil) + (lines (list))) + ;; Search loop + (while (not (eobp)) + (setq curpoint (point)) + ;; if something found + (when (setq endpoint (re-search-forward regex nil 'end)) + (save-excursion + (let ((bounds (ledger-occur-find-xact-extents (match-beginning 0)))) + (push bounds lines) + (setq curpoint (cadr bounds)))) ;move to the end of the + ;xact, no need to search + ;inside it more + (goto-char curpoint)) + (forward-line 1)) + (setq lines (nreverse lines))))) + + +(provide 'ldg-occur) + +;;; ldg-occur.el ends here diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 753c2fa5..0cac33c5 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -24,6 +24,12 @@ (defvar ledger-buf nil) (defvar ledger-acct nil) +(defcustom ledger-fold-on-reconcile t + "if t, limit transactions shown in main buffer to those + matching the reconcile regex" + :group 'ledger) +(make-variable-buffer-local 'ledger-fold-on-reconcilex) + (defun ledger-display-balance () "Calculate the cleared balance of the account being reconciled" (interactive) @@ -55,10 +61,10 @@ (with-current-buffer ledger-buf (goto-char (cdr where)) (setq cleared (ledger-toggle-current-entry))) - ;remove the existing face and add the new face + ;remove the existing face and add the new face (remove-text-properties (line-beginning-position) - (line-end-position) - (list 'face)) + (line-end-position) + (list 'face)) (if cleared (add-text-properties (line-beginning-position) (line-end-position) @@ -72,7 +78,11 @@ (defun ledger-reconcile-new-account (account) (interactive "sAccount to reconcile: ") (set (make-local-variable 'ledger-acct) account) - (ledger-reconcile-refresh)) + (let ((buf (current-buffer))) + (if ledger-fold-on-reconcile + (ledger-occur-change-regex account ledger-buf)) + (set-buffer buf) + (ledger-reconcile-refresh))) (defun ledger-reconcile-refresh () (interactive) @@ -125,7 +135,10 @@ (defun ledger-reconcile-quit () (interactive) - (kill-buffer (current-buffer))) + (let ((buf ledger-buf)) + (kill-buffer (current-buffer)) + (if ledger-fold-on-reconcile + (ledger-occur-quit-buffer buf)))) (defun ledger-reconcile-finish () (interactive) @@ -144,49 +157,49 @@ (defun ledger-do-reconcile () "get the uncleared transactions in the account and display them in the *Reconcile* buffer" - (let* ((buf ledger-buf) + (let* ((buf ledger-buf) (account ledger-acct) (items (with-temp-buffer (ledger-exec-ledger buf (current-buffer) "--uncleared" "--real" - "emacs" account) + "emacs" account) (goto-char (point-min)) (unless (eobp) (unless (looking-at "(") (error (buffer-string))) (read (current-buffer)))))) - (dolist (item items) - (let ((index 1)) - (dolist (xact (nthcdr 5 item)) - (let ((beg (point)) - (where - (with-current-buffer buf - (cons - (nth 0 item) - (if ledger-clear-whole-entries - (save-excursion - (goto-line (nth 1 item)) - (point-marker)) - (save-excursion - (goto-line (nth 0 xact)) - (point-marker))))))) - (insert (format "%s %-4s %-30s %-30s %15s\n" - (format-time-string "%Y/%m/%d" (nth 2 item)) - (if (nth 3 item) - (nth 3 item) - "") - (nth 4 item) (nth 1 xact) (nth 2 xact))) - (if (nth 3 xact) - (set-text-properties beg (1- (point)) - (list 'face 'ledger-font-reconciler-cleared-face - 'where where)) - (set-text-properties beg (1- (point)) - (list 'face 'ledger-font-reconciler-uncleared-face - 'where where)))) - (setq index (1+ index))))) - (goto-char (point-min)) - (set-buffer-modified-p nil) - (toggle-read-only t))) + (dolist (item items) + (let ((index 1)) + (dolist (xact (nthcdr 5 item)) + (let ((beg (point)) + (where + (with-current-buffer buf + (cons + (nth 0 item) + (if ledger-clear-whole-entries + (save-excursion + (goto-line (nth 1 item)) + (point-marker)) + (save-excursion + (goto-line (nth 0 xact)) + (point-marker))))))) + (insert (format "%s %-4s %-30s %-30s %15s\n" + (format-time-string "%Y/%m/%d" (nth 2 item)) + (if (nth 3 item) + (nth 3 item) + "") + (nth 4 item) (nth 1 xact) (nth 2 xact))) + (if (nth 3 xact) + (set-text-properties beg (1- (point)) + (list 'face 'ledger-font-reconciler-cleared-face + 'where where)) + (set-text-properties beg (1- (point)) + (list 'face 'ledger-font-reconciler-uncleared-face + 'where where)))) + (setq index (1+ index))))) + (goto-char (point-min)) + (set-buffer-modified-p nil) + (toggle-read-only t))) (defun ledger-reconcile (account) @@ -196,6 +209,8 @@ (if rbuf (kill-buffer rbuf)) (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save) + (if ledger-fold-on-reconcile + (ledger-occur-mode account buf)) (with-current-buffer (pop-to-buffer (get-buffer-create "*Reconcile*")) (ledger-reconcile-mode) @@ -206,41 +221,41 @@ (defvar ledger-reconcile-mode-abbrev-table) (define-derived-mode ledger-reconcile-mode text-mode "Reconcile" - "A mode for reconciling ledger entries." - (let ((map (make-sparse-keymap))) - (define-key map [(control ?m)] 'ledger-reconcile-visit) - (define-key map [return] 'ledger-reconcile-visit) - (define-key map [(control ?c) (control ?c)] 'ledger-reconcile-finish) - (define-key map [(control ?x) (control ?s)] 'ledger-reconcile-save) - (define-key map [(control ?l)] 'ledger-reconcile-refresh) - (define-key map [? ] 'ledger-reconcile-toggle) - (define-key map [?a] 'ledger-reconcile-add) - (define-key map [?d] 'ledger-reconcile-delete) - (define-key map [?g] 'ledger-reconcile-new-account) - (define-key map [?n] 'next-line) - (define-key map [?p] 'previous-line) - (define-key map [?s] 'ledger-reconcile-save) - (define-key map [?q] 'ledger-reconcile-quit) - (define-key map [?b] 'ledger-display-balance) - - (define-key map [menu-bar] (make-sparse-keymap "ldg-recon-menu")) - (define-key map [menu-bar ldg-recon-menu] (cons "Reconcile" map)) - (define-key map [menu-bar ldg-recon-menu qui] '("Quit" . ledger-reconcile-quit)) - (define-key map [menu-bar ldg-recon-menu sep1] '("--")) - (define-key map [menu-bar ldg-recon-menu pre] '("Previous Entry" . previous-line)) - (define-key map [menu-bar ldg-recon-menu vis] '("Visit Entry" . ledger-reconcile-visit)) - (define-key map [menu-bar ldg-recon-menu nex] '("Next Entry" . next-line)) - (define-key map [menu-bar ldg-recon-menu sep2] '("--")) - (define-key map [menu-bar ldg-recon-menu del] '("Delete Entry" . ledger-reconcile-delete)) - (define-key map [menu-bar ldg-recon-menu add] '("Add Entry" . ledger-reconcile-add)) - (define-key map [menu-bar ldg-recon-menu tog] '("Toggle Entry" . ledger-reconcile-toggle)) - (define-key map [menu-bar ldg-recon-menu sep3] '("--")) - (define-key map [menu-bar ldg-recon-menu bal] '("Show Cleared Balance" . ledger-display-balance)) - (define-key map [menu-bar ldg-recon-menu sep4] '("--")) - (define-key map [menu-bar ldg-recon-menu rna] '("Reconcile New Account" . ledger-reconcile-new-account)) - (define-key map [menu-bar ldg-recon-menu ref] '("Refresh" . ledger-reconcile-refresh)) - (define-key map [menu-bar ldg-recon-menu sav] '("Save" . ledger-reconcile-save)) - - (use-local-map map))) + "A mode for reconciling ledger entries." + (let ((map (make-sparse-keymap))) + (define-key map [(control ?m)] 'ledger-reconcile-visit) + (define-key map [return] 'ledger-reconcile-visit) + (define-key map [(control ?c) (control ?c)] 'ledger-reconcile-finish) + (define-key map [(control ?x) (control ?s)] 'ledger-reconcile-save) + (define-key map [(control ?l)] 'ledger-reconcile-refresh) + (define-key map [? ] 'ledger-reconcile-toggle) + (define-key map [?a] 'ledger-reconcile-add) + (define-key map [?d] 'ledger-reconcile-delete) + (define-key map [?g] 'ledger-reconcile-new-account) + (define-key map [?n] 'next-line) + (define-key map [?p] 'previous-line) + (define-key map [?s] 'ledger-reconcile-save) + (define-key map [?q] 'ledger-reconcile-quit) + (define-key map [?b] 'ledger-display-balance) + + (define-key map [menu-bar] (make-sparse-keymap "ldg-recon-menu")) + (define-key map [menu-bar ldg-recon-menu] (cons "Reconcile" map)) + (define-key map [menu-bar ldg-recon-menu qui] '("Quit" . ledger-reconcile-quit)) + (define-key map [menu-bar ldg-recon-menu sep1] '("--")) + (define-key map [menu-bar ldg-recon-menu pre] '("Previous Entry" . previous-line)) + (define-key map [menu-bar ldg-recon-menu vis] '("Visit Entry" . ledger-reconcile-visit)) + (define-key map [menu-bar ldg-recon-menu nex] '("Next Entry" . next-line)) + (define-key map [menu-bar ldg-recon-menu sep2] '("--")) + (define-key map [menu-bar ldg-recon-menu del] '("Delete Entry" . ledger-reconcile-delete)) + (define-key map [menu-bar ldg-recon-menu add] '("Add Entry" . ledger-reconcile-add)) + (define-key map [menu-bar ldg-recon-menu tog] '("Toggle Entry" . ledger-reconcile-toggle)) + (define-key map [menu-bar ldg-recon-menu sep3] '("--")) + (define-key map [menu-bar ldg-recon-menu bal] '("Show Cleared Balance" . ledger-display-balance)) + (define-key map [menu-bar ldg-recon-menu sep4] '("--")) + (define-key map [menu-bar ldg-recon-menu rna] '("Reconcile New Account" . ledger-reconcile-new-account)) + (define-key map [menu-bar ldg-recon-menu ref] '("Refresh" . ledger-reconcile-refresh)) + (define-key map [menu-bar ldg-recon-menu sav] '("Save" . ledger-reconcile-save)) + + (use-local-map map))) (provide 'ldg-reconcile) \ No newline at end of file -- cgit v1.2.3 From 41469e9943986d909ee7cfa5fe977a57f6900431 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 5 Feb 2013 12:24:30 -0700 Subject: Grammar cleanup --- doc/ledger3.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index ce062104..95025d41 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -2564,7 +2564,7 @@ all of the uncleared transactions. The reconcile buffer has several functions: @end table By default the reconcile mode uses transaction hiding to show only -transaction eligible for your reconcile. Th reconcile widow itself will +transaction eligible for your reconcile. The reconcile widow itself will only show a summary of uncleared transaction while the main buffer will show all transaction meeting the regex, cleared or not. This behavior can be disabled by setting @code{ledger-fold-on-reconcile} to nil in the -- cgit v1.2.3 From d67c42207fa75b0b4715705b577a228eec05729a Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 5 Feb 2013 12:25:19 -0700 Subject: Code cleanup to get rid of some elisp compiler warnings. --- lisp/ldg-occur.el | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index 9cf7f3b1..09cca45b 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -71,7 +71,7 @@ (defun ledger-occur-mode (regex buffer) - (save-excursion + (progn (set-buffer buffer) (setq ledger-occur-mode (if (or ledger-occur-mode @@ -198,10 +198,10 @@ (let ((prev-end (point-min)) (overlays (list))) (when buffer-matches - (mapcar (lambda (line) - (push (list (car line) (cadr line)) overlays) - (setq prev-end (cadr line))) - buffer-matches) + (mapc (lambda (line) + (push (list (car line) (cadr line)) overlays) + (setq prev-end (cadr line))) + buffer-matches) (setq overlays (nreverse overlays))))) (defun ledger-occur-find-xact-extents (pos) @@ -213,11 +213,11 @@ (let ((end-pos pos) (beg-pos pos)) (backward-paragraph) - (next-line) + (forward-line) (beginning-of-line) (setq beg-pos (point)) (forward-paragraph) - (previous-line) + (forward-line -1) (end-of-line) (setq end-pos (1+ (point))) (list beg-pos end-pos)))) @@ -240,8 +240,8 @@ (let ((bounds (ledger-occur-find-xact-extents (match-beginning 0)))) (push bounds lines) (setq curpoint (cadr bounds)))) ;move to the end of the - ;xact, no need to search - ;inside it more + ;xact, no need to search + ;inside it more (goto-char curpoint)) (forward-line 1)) (setq lines (nreverse lines))))) -- cgit v1.2.3 From 4d7c4929395421eb039f0d03afafaf55cffd686d Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 5 Feb 2013 12:33:42 -0700 Subject: Lisp code cleanup Most of the files have been touched several times and the indentation structure was wrong. I ran all the files through the emacs indent region function to get back to a baseline --- lisp/ldg-complete.el | 50 +++++++-------- lisp/ldg-exec.el | 4 +- lisp/ldg-fonts.el | 2 +- lisp/ldg-mode.el | 176 +++++++++++++++++++++++++-------------------------- lisp/ldg-new.el | 6 +- lisp/ldg-post.el | 44 ++++++------- lisp/ldg-regex.el | 130 ++++++++++++++++++------------------- lisp/ldg-register.el | 14 ++-- lisp/ldg-report.el | 106 +++++++++++++++---------------- lisp/ldg-sort.el | 14 ++-- lisp/ldg-state.el | 60 +++++++++--------- lisp/ldg-test.el | 8 +-- lisp/ldg-texi.el | 18 +++--- 13 files changed, 316 insertions(+), 316 deletions(-) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index 85546156..996df558 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -89,9 +89,9 @@ (let ((entry (assoc (car elements) root))) (if entry (setq root (cdr entry)) - (setq entry (cons (car elements) (list t))) - (nconc root (list entry)) - (setq root (cdr entry)))) + (setq entry (cons (car elements) (list t))) + (nconc root (list entry)) + (setq root (cdr entry)))) (setq elements (cdr elements))))))))) (defun ledger-accounts () @@ -106,18 +106,18 @@ (setq prefix (concat prefix (and prefix ":") (car elements)) root (cdr entry)) - (setq root nil elements nil))) + (setq root nil elements nil))) (setq elements (cdr elements))) (and root (sort (mapcar (function (lambda (x) - (let ((term (if prefix - (concat prefix ":" (car x)) - (car x)))) - (if (> (length (cdr x)) 1) - (concat term ":") - term)))) + (let ((term (if prefix + (concat prefix ":" (car x)) + (car x)))) + (if (> (length (cdr x)) 1) + (concat term ":") + term)))) (cdr root)) 'string-lessp)))) @@ -129,21 +129,21 @@ (ledger-thing-at-point)) 'entry) (if (null current-prefix-arg) (ledger-entries) ; this completes against entry names - (progn - (let ((text (buffer-substring (line-beginning-position) - (line-end-position)))) - (delete-region (line-beginning-position) - (line-end-position)) - (condition-case err - (ledger-add-entry text t) - ((error) - (insert text)))) - (forward-line) - (goto-char (line-end-position)) - (search-backward ";" (line-beginning-position) t) - (skip-chars-backward " \t0123456789.,") - (throw 'pcompleted t))) - (ledger-accounts))))) + (progn + (let ((text (buffer-substring (line-beginning-position) + (line-end-position)))) + (delete-region (line-beginning-position) + (line-end-position)) + (condition-case err + (ledger-add-entry text t) + ((error) + (insert text)))) + (forward-line) + (goto-char (line-end-position)) + (search-backward ";" (line-beginning-position) t) + (skip-chars-backward " \t0123456789.,") + (throw 'pcompleted t))) + (ledger-accounts))))) (defun ledger-fully-complete-entry () "Do appropriate completion for the thing at point" diff --git a/lisp/ldg-exec.el b/lisp/ldg-exec.el index f13cfa5a..e9cefd20 100644 --- a/lisp/ldg-exec.el +++ b/lisp/ldg-exec.el @@ -68,8 +68,8 @@ (goto-char (point-min)) (delete-horizontal-space) (setq version-strings (split-string - (buffer-substring-no-properties (point) - (+ (point) 12)))) + (buffer-substring-no-properties (point) + (+ (point) 12)))) (if (and (string-match (regexp-quote "Ledger") (car version-strings)) (or (string= needed (car (cdr version-strings))) (string< needed (car (cdr version-strings))))) diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index 2b7717c6..6032e361 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -52,7 +52,7 @@ :group 'ledger-faces) (defface ledger-font-comment-face - `((t :foreground "orange" )) + `((t :foreground "orange" )) "Face for Ledger comments" :group 'ledger-faces) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 4c55cdc0..226009c6 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -43,77 +43,77 @@ customizable to ease retro-entry.") ;;;###autoload (define-derived-mode ledger-mode text-mode "Ledger" - "A mode for editing ledger data files." - (ledger-check-version) - (ledger-post-setup) - - (set (make-local-variable 'comment-start) " ; ") - (set (make-local-variable 'comment-end) "") - (set (make-local-variable 'indent-tabs-mode) nil) - - (if (boundp 'font-lock-defaults) - (set (make-local-variable 'font-lock-defaults) - '(ledger-font-lock-keywords nil t))) - - (set (make-local-variable 'pcomplete-parse-arguments-function) - 'ledger-parse-arguments) - (set (make-local-variable 'pcomplete-command-completion-function) - 'ledger-complete-at-point) - (set (make-local-variable 'pcomplete-termination-string) "") - - (let ((map (current-local-map))) - (define-key map [(control ?c) (control ?a)] 'ledger-add-entry) - (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-entry) - (define-key map [(control ?c) (control ?y)] 'ledger-set-year) - (define-key map [(control ?c) (control ?m)] 'ledger-set-month) - (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) - (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-entry) - (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) - (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) - (define-key map [(control ?c) (control ?t)] 'ledger-test-run) - (define-key map [(control ?c) (control ?v)] 'ledger-post-edit-amount) - (define-key map [(control ?c) (control ?f)] 'ledger-occur) - (define-key map [tab] 'pcomplete) - (define-key map [(control ?i)] 'pcomplete) - (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) - (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry) - (define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report) - (define-key map [(control ?c) (control ?o) (control ?g)] 'ledger-report-goto) - (define-key map [(control ?c) (control ?o) (control ?a)] 'ledger-report-redo) - (define-key map [(control ?c) (control ?o) (control ?s)] 'ledger-report-save) - (define-key map [(control ?c) (control ?o) (control ?e)] 'ledger-report-edit) - (define-key map [(control ?c) (control ?o) (control ?k)] 'ledger-report-kill) - - (define-key map [(meta ?p)] 'ledger-post-prev-xact) - (define-key map [(meta ?n)] 'ledger-post-next-xact) - - (define-key map [menu-bar] (make-sparse-keymap "ldg-menu")) - (define-key map [menu-bar ldg-menu] (cons "Ledger" map)) - - (define-key map [report-kill] '(menu-item "Kill Report" ledger-report-kill :enable ledger-works)) - (define-key map [report-edit] '(menu-item "Edit Report" ledger-report-edit :enable ledger-works)) - (define-key map [report-save] '(menu-item "Save Report" ledger-report-save :enable ledger-works)) - (define-key map [report-rrun] '(menu-item "Re-run Report" ledger-report-redo :enable ledger-works)) - (define-key map [report-goto] '(menu-item "Goto Report" ledger-report-goto :enable ledger-works)) - (define-key map [report-run] '(menu-item "Run Report" ledger-report :enable ledger-works)) - (define-key map [sep5] '(menu-item "--")) - (define-key map [set-month] '(menu-item "Set Month" ledger-set-month :enable ledger-works)) - (define-key map [set-year] '(menu-item "Set Year" ledger-set-year :enable ledger-works)) - (define-key map [sep1] '("--")) - (define-key map [sort-buff] '(menu-item "Sort Buffer" ledger-sort-buffer)) - (define-key map [sort-reg] '(menu-item "Sort Region" ledger-sort-region :enable mark-active)) - (define-key map [sep2] '(menu-item "--")) - (define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current)) - (define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-entry)) - (define-key map [sep4] '(menu-item "--")) - (define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount)) - (define-key map [sep] '(menu-item "--")) - (define-key map [delete-xact] '(menu-item "Delete Entry" ledger-delete-current-entry)) - (define-key map [add-xact] '(menu-item "Add Entry" ledger-add-entry :enable ledger-works)) - (define-key map [sep3] '(menu-item "--")) - (define-key map [reconcile] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works)) - (define-key map [reconcile] '(menu-item "Hide Xacts" ledger-occur)) - )) + "A mode for editing ledger data files." + (ledger-check-version) + (ledger-post-setup) + + (set (make-local-variable 'comment-start) " ; ") + (set (make-local-variable 'comment-end) "") + (set (make-local-variable 'indent-tabs-mode) nil) + + (if (boundp 'font-lock-defaults) + (set (make-local-variable 'font-lock-defaults) + '(ledger-font-lock-keywords nil t))) + + (set (make-local-variable 'pcomplete-parse-arguments-function) + 'ledger-parse-arguments) + (set (make-local-variable 'pcomplete-command-completion-function) + 'ledger-complete-at-point) + (set (make-local-variable 'pcomplete-termination-string) "") + + (let ((map (current-local-map))) + (define-key map [(control ?c) (control ?a)] 'ledger-add-entry) + (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-entry) + (define-key map [(control ?c) (control ?y)] 'ledger-set-year) + (define-key map [(control ?c) (control ?m)] 'ledger-set-month) + (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) + (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-entry) + (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) + (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) + (define-key map [(control ?c) (control ?t)] 'ledger-test-run) + (define-key map [(control ?c) (control ?v)] 'ledger-post-edit-amount) + (define-key map [(control ?c) (control ?f)] 'ledger-occur) + (define-key map [tab] 'pcomplete) + (define-key map [(control ?i)] 'pcomplete) + (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) + (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry) + (define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report) + (define-key map [(control ?c) (control ?o) (control ?g)] 'ledger-report-goto) + (define-key map [(control ?c) (control ?o) (control ?a)] 'ledger-report-redo) + (define-key map [(control ?c) (control ?o) (control ?s)] 'ledger-report-save) + (define-key map [(control ?c) (control ?o) (control ?e)] 'ledger-report-edit) + (define-key map [(control ?c) (control ?o) (control ?k)] 'ledger-report-kill) + + (define-key map [(meta ?p)] 'ledger-post-prev-xact) + (define-key map [(meta ?n)] 'ledger-post-next-xact) + + (define-key map [menu-bar] (make-sparse-keymap "ldg-menu")) + (define-key map [menu-bar ldg-menu] (cons "Ledger" map)) + + (define-key map [report-kill] '(menu-item "Kill Report" ledger-report-kill :enable ledger-works)) + (define-key map [report-edit] '(menu-item "Edit Report" ledger-report-edit :enable ledger-works)) + (define-key map [report-save] '(menu-item "Save Report" ledger-report-save :enable ledger-works)) + (define-key map [report-rrun] '(menu-item "Re-run Report" ledger-report-redo :enable ledger-works)) + (define-key map [report-goto] '(menu-item "Goto Report" ledger-report-goto :enable ledger-works)) + (define-key map [report-run] '(menu-item "Run Report" ledger-report :enable ledger-works)) + (define-key map [sep5] '(menu-item "--")) + (define-key map [set-month] '(menu-item "Set Month" ledger-set-month :enable ledger-works)) + (define-key map [set-year] '(menu-item "Set Year" ledger-set-year :enable ledger-works)) + (define-key map [sep1] '("--")) + (define-key map [sort-buff] '(menu-item "Sort Buffer" ledger-sort-buffer)) + (define-key map [sort-reg] '(menu-item "Sort Region" ledger-sort-region :enable mark-active)) + (define-key map [sep2] '(menu-item "--")) + (define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current)) + (define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-entry)) + (define-key map [sep4] '(menu-item "--")) + (define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount)) + (define-key map [sep] '(menu-item "--")) + (define-key map [delete-xact] '(menu-item "Delete Entry" ledger-delete-current-entry)) + (define-key map [add-xact] '(menu-item "Add Entry" ledger-add-entry :enable ledger-works)) + (define-key map [sep3] '(menu-item "--")) + (define-key map [reconcile] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works)) + (define-key map [reconcile] '(menu-item "Hide Xacts" ledger-occur)) + )) (defun ledger-time-less-p (t1 t2) "Say whether time value T1 is less than time value T2." @@ -133,8 +133,8 @@ Return the difference in the format of a time value." (ledger-iterate-entries (function (lambda (start date mark desc) - (if (ledger-time-less-p moment date) - (throw 'found t))))))) + (if (ledger-time-less-p moment date) + (throw 'found t))))))) (defun ledger-iterate-entries (callback) (goto-char (point-min)) @@ -149,18 +149,18 @@ Return the difference in the format of a time value." (let ((found (match-string 2))) (if found (setq current-year (string-to-number found)) - (let ((start (match-beginning 0)) - (year (match-string 3)) - (month (string-to-number (match-string 4))) - (day (string-to-number (match-string 5))) - (mark (match-string 6)) - (desc (match-string 7))) - (if (and year (> (length year) 0)) - (setq year (string-to-number year))) - (funcall callback start - (encode-time 0 0 0 day month - (or year current-year)) - mark desc))))) + (let ((start (match-beginning 0)) + (year (match-string 3)) + (month (string-to-number (match-string 4))) + (day (string-to-number (match-string 5))) + (mark (match-string 6)) + (desc (match-string 7))) + (if (and year (> (length year) 0)) + (setq year (string-to-number year))) + (funcall callback start + (encode-time 0 0 0 day month + (or year current-year)) + mark desc))))) (forward-line)))) (defun ledger-set-year (newyear) @@ -168,14 +168,14 @@ Return the difference in the format of a time value." (interactive "p") (if (= newyear 1) (setq ledger-year (read-string "Year: " (ledger-current-year))) - (setq ledger-year (number-to-string newyear)))) + (setq ledger-year (number-to-string newyear)))) (defun ledger-set-month (newmonth) "Set ledger's idea of the current month to the prefix argument." (interactive "p") (if (= newmonth 1) (setq ledger-month (read-string "Month: " (ledger-current-month))) - (setq ledger-month (format "%02d" newmonth)))) + (setq ledger-month (format "%02d" newmonth)))) (defun ledger-add-entry (entry-text &optional insert-at-point) (interactive (list @@ -202,7 +202,7 @@ Return the difference in the format of a time value." (goto-char (point-min)) (if (looking-at "Error: ") (error (buffer-string)) - (buffer-string))) + (buffer-string))) "\n")))) (defun ledger-current-entry-bounds () diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index 1d7d5cac..3ee48897 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -47,9 +47,9 @@ (require 'ldg-fonts) (require 'ldg-occur) -;(autoload #'ledger-mode "ldg-mode" nil t) -;(autoload #'ledger-fully-complete-entry "ldg-complete" nil t) -;(autoload #'ledger-toggle-current "ldg-state" nil t) + ;(autoload #'ledger-mode "ldg-mode" nil t) + ;(autoload #'ledger-fully-complete-entry "ldg-complete" nil t) + ;(autoload #'ledger-toggle-current "ldg-state" nil t) (autoload #'ledger-texi-update-test "ldg-texi" nil t) (autoload #'ledger-texi-update-examples "ldg-texi" nil t) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index dc033bf8..411911d9 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -66,16 +66,16 @@ PROMPT is a string to prompt with. CHOICES is a list of strings to choose from." (cond - (ledger-post-use-iswitchb - (let* ((iswitchb-use-virtual-buffers nil) - (iswitchb-make-buflist-hook - (lambda () - (setq iswitchb-temp-buflist choices)))) - (iswitchb-read-buffer prompt))) - (ledger-post-use-ido - (ido-completing-read prompt choices)) - (t - (completing-read prompt choices)))) + (ledger-post-use-iswitchb + (let* ((iswitchb-use-virtual-buffers nil) + (iswitchb-make-buflist-hook + (lambda () + (setq iswitchb-temp-buflist choices)))) + (iswitchb-read-buffer prompt))) + (ledger-post-use-ido + (ido-completing-read prompt choices)) + (t + (completing-read prompt choices)))) (defvar ledger-post-current-list nil) @@ -96,12 +96,12 @@ to choose from." (match-end ledger-regex-post-line-group-account)) (insert account) (cond - ((> existing-len account-len) - (insert (make-string (- existing-len account-len) ? ))) - ((< existing-len account-len) - (dotimes (n (- account-len existing-len)) - (if (looking-at "[ \t]\\( [ \t]\\|\t\\)") - (delete-char 1))))))) + ((> existing-len account-len) + (insert (make-string (- existing-len account-len) ? ))) + ((< existing-len account-len) + (dotimes (n (- account-len existing-len)) + (if (looking-at "[ \t]\\( [ \t]\\|\t\\)") + (delete-char 1))))))) (goto-char pos))) (defun ledger-next-amount (&optional end) @@ -130,12 +130,12 @@ This is done so that the last digit falls in COLUMN, which defaults to 52." (setq adjust (- target-col col)) (if (< col target-col) (insert (make-string (- target-col col) ? )) - (move-to-column target-col) - (if (looking-back " ") - (delete-char (- col target-col)) - (skip-chars-forward "^ \t") - (delete-horizontal-space) - (insert " "))) + (move-to-column target-col) + (if (looking-back " ") + (delete-char (- col target-col)) + (skip-chars-forward "^ \t") + (delete-horizontal-space) + (insert " "))) (forward-line)))))) (defun ledger-post-align-amount () diff --git a/lisp/ldg-regex.el b/lisp/ldg-regex.el index f2f83937..680063f7 100644 --- a/lisp/ldg-regex.el +++ b/lisp/ldg-regex.el @@ -27,10 +27,10 @@ (defmacro ledger-define-regexp (name regex docs &rest args) "Simplify the creation of a Ledger regex and helper functions." (let ((defs - (list - `(defconst - ,(intern (concat "ledger-" (symbol-name name) "-regexp")) - ,(eval regex)))) + (list + `(defconst + ,(intern (concat "ledger-" (symbol-name name) "-regexp")) + ,(eval regex)))) (addend 0) last-group) (if (null args) (progn @@ -38,82 +38,82 @@ defs (list `(defconst - ,(intern - (concat "ledger-regex-" (symbol-name name) "-group")) + ,(intern + (concat "ledger-regex-" (symbol-name name) "-group")) 1))) (nconc defs (list `(defconst - ,(intern (concat "ledger-regex-" (symbol-name name) - "-group--count")) + ,(intern (concat "ledger-regex-" (symbol-name name) + "-group--count")) 1))) (nconc defs (list `(defmacro - ,(intern (concat "ledger-regex-" (symbol-name name))) - (&optional string) + ,(intern (concat "ledger-regex-" (symbol-name name))) + (&optional string) ,(format "Return the match string for the %s" name) (match-string ,(intern (concat "ledger-regex-" (symbol-name name) "-group")) string))))) - - (dolist (arg args) - (let (var grouping target) - (if (symbolp arg) - (setq var arg target arg) - (assert (listp arg)) - (if (= 2 (length arg)) - (setq var (car arg) - target (cadr arg)) - (setq var (car arg) - grouping (cadr arg) - target (caddr arg)))) - - (if (and last-group - (not (eq last-group (or grouping target)))) - (incf addend - (symbol-value - (intern-soft (concat "ledger-regex-" - (symbol-name last-group) - "-group--count"))))) - (nconc - defs - (list - `(defconst - ,(intern (concat "ledger-regex-" (symbol-name name) - "-group-" (symbol-name var))) - ,(+ addend - (symbol-value - (intern-soft - (if grouping - (concat "ledger-regex-" (symbol-name grouping) - "-group-" (symbol-name target)) - (concat "ledger-regex-" (symbol-name target) - "-group")))))))) - (nconc - defs - (list - `(defmacro - ,(intern (concat "ledger-regex-" (symbol-name name) - "-" (symbol-name var))) - (&optional string) - ,(format "Return the sub-group match for the %s %s." - name var) - (match-string - ,(intern (concat "ledger-regex-" (symbol-name name) - "-group-" (symbol-name var))) - string)))) - - (setq last-group (or grouping target)))) - - (nconc defs - (list - `(defconst ,(intern (concat "ledger-regex-" (symbol-name name) - "-group--count")) - ,(length args))))) + + (dolist (arg args) + (let (var grouping target) + (if (symbolp arg) + (setq var arg target arg) + (assert (listp arg)) + (if (= 2 (length arg)) + (setq var (car arg) + target (cadr arg)) + (setq var (car arg) + grouping (cadr arg) + target (caddr arg)))) + + (if (and last-group + (not (eq last-group (or grouping target)))) + (incf addend + (symbol-value + (intern-soft (concat "ledger-regex-" + (symbol-name last-group) + "-group--count"))))) + (nconc + defs + (list + `(defconst + ,(intern (concat "ledger-regex-" (symbol-name name) + "-group-" (symbol-name var))) + ,(+ addend + (symbol-value + (intern-soft + (if grouping + (concat "ledger-regex-" (symbol-name grouping) + "-group-" (symbol-name target)) + (concat "ledger-regex-" (symbol-name target) + "-group")))))))) + (nconc + defs + (list + `(defmacro + ,(intern (concat "ledger-regex-" (symbol-name name) + "-" (symbol-name var))) + (&optional string) + ,(format "Return the sub-group match for the %s %s." + name var) + (match-string + ,(intern (concat "ledger-regex-" (symbol-name name) + "-group-" (symbol-name var))) + string)))) + + (setq last-group (or grouping target)))) + + (nconc defs + (list + `(defconst ,(intern (concat "ledger-regex-" (symbol-name name) + "-group--count")) + ,(length args))))) (cons 'progn defs))) diff --git a/lisp/ldg-register.el b/lisp/ldg-register.el index 4c397049..adb37a1a 100644 --- a/lisp/ldg-register.el +++ b/lisp/ldg-register.el @@ -37,8 +37,8 @@ :group 'ledger-register) (defface ledger-register-pending-face - '((((background light)) (:weight bold)) - (((background dark)) (:weight bold))) + '((((background light)) (:weight bold)) + (((background dark)) (:weight bold))) "Face used to highlight pending entries in a register report." :group 'ledger-register) @@ -55,9 +55,9 @@ (save-excursion (goto-line (nth 1 post)) (point-marker)) - (save-excursion - (goto-line (nth 0 xact)) - (point-marker))))))) + (save-excursion + (goto-line (nth 0 xact)) + (point-marker))))))) (insert (format ledger-register-line-format (format-time-string ledger-register-date-format (nth 2 post)) @@ -66,8 +66,8 @@ (set-text-properties beg (1- (point)) (list 'face 'ledger-register-pending-face 'where where)) - (set-text-properties beg (1- (point)) - (list 'where where)))) + (set-text-properties beg (1- (point)) + (list 'where where)))) (setq index (1+ index))))) (goto-char (point-min)) ) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 394c12e7..3b831825 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -39,7 +39,7 @@ the substitution. See the documentation of the individual functions in that variable for more information on the behavior of each specifier." :type '(repeat (list (string :tag "Report Name") - (string :tag "Command Line"))) + (string :tag "Command Line"))) :group 'ledger) (defcustom ledger-report-format-specifiers @@ -73,40 +73,40 @@ text that should replace the format specifier." (defvar ledger-report-mode-abbrev-table) (define-derived-mode ledger-report-mode text-mode "Ledger-Report" - "A mode for viewing ledger reports." - (let ((map (make-sparse-keymap))) - (define-key map [? ] 'scroll-up) - (define-key map [backspace] 'scroll-down) - (define-key map [?r] 'ledger-report-redo) - (define-key map [?s] 'ledger-report-save) - (define-key map [?k] 'ledger-report-kill) - (define-key map [?e] 'ledger-report-edit) - (define-key map [?q] 'ledger-report-quit) - (define-key map [(control ?c) (control ?l) (control ?r)] - 'ledger-report-redo) - (define-key map [(control ?c) (control ?l) (control ?S)] - 'ledger-report-save) - (define-key map [(control ?c) (control ?l) (control ?k)] - 'ledger-report-kill) - (define-key map [(control ?c) (control ?l) (control ?e)] - 'ledger-report-edit) - (define-key map [(control ?c) (control ?c)] 'ledger-report-visit-source) - - - (define-key map [menu-bar] (make-sparse-keymap "ldg-rep")) - (define-key map [menu-bar ldg-rep] (cons "Reports" map)) - - (define-key map [menu-bar ldg-rep lrq] '("Quit" . ledger-report-quit)) - (define-key map [menu-bar ldg-rep s2] '("--")) - (define-key map [menu-bar ldg-rep lrd] '("Scroll Down" . scroll-down)) - (define-key map [menu-bar ldg-rep lru] '("Scroll Up" . scroll-up)) - (define-key map [menu-bar ldg-rep s1] '("--")) - (define-key map [menu-bar ldg-rep lrk] '("Kill Report" . ledger-report-kill)) - (define-key map [menu-bar ldg-rep lrr] '("Re-run Report" . ledger-report-redo)) - (define-key map [menu-bar ldg-rep lre] '("Edit Report" . ledger-report-edit)) - (define-key map [menu-bar ldg-rep lrs] '("Save Report" . ledger-report-save)) - - (use-local-map map))) + "A mode for viewing ledger reports." + (let ((map (make-sparse-keymap))) + (define-key map [? ] 'scroll-up) + (define-key map [backspace] 'scroll-down) + (define-key map [?r] 'ledger-report-redo) + (define-key map [?s] 'ledger-report-save) + (define-key map [?k] 'ledger-report-kill) + (define-key map [?e] 'ledger-report-edit) + (define-key map [?q] 'ledger-report-quit) + (define-key map [(control ?c) (control ?l) (control ?r)] + 'ledger-report-redo) + (define-key map [(control ?c) (control ?l) (control ?S)] + 'ledger-report-save) + (define-key map [(control ?c) (control ?l) (control ?k)] + 'ledger-report-kill) + (define-key map [(control ?c) (control ?l) (control ?e)] + 'ledger-report-edit) + (define-key map [(control ?c) (control ?c)] 'ledger-report-visit-source) + + + (define-key map [menu-bar] (make-sparse-keymap "ldg-rep")) + (define-key map [menu-bar ldg-rep] (cons "Reports" map)) + + (define-key map [menu-bar ldg-rep lrq] '("Quit" . ledger-report-quit)) + (define-key map [menu-bar ldg-rep s2] '("--")) + (define-key map [menu-bar ldg-rep lrd] '("Scroll Down" . scroll-down)) + (define-key map [menu-bar ldg-rep lru] '("Scroll Up" . scroll-up)) + (define-key map [menu-bar ldg-rep s1] '("--")) + (define-key map [menu-bar ldg-rep lrk] '("Kill Report" . ledger-report-kill)) + (define-key map [menu-bar ldg-rep lrr] '("Re-run Report" . ledger-report-redo)) + (define-key map [menu-bar ldg-rep lre] '("Edit Report" . ledger-report-edit)) + (define-key map [menu-bar ldg-rep lrs] '("Save Report" . ledger-report-save)) + + (use-local-map map))) (defun ledger-report-read-name () "Read the name of a ledger report to use, with completion. @@ -201,13 +201,13 @@ this variable would be set in a file local variable comment block at the end of a ledger file which is included in some other file." (if ledger-master-file (expand-file-name ledger-master-file) - (buffer-file-name))) + (buffer-file-name))) (defun ledger-read-string-with-default (prompt default) (let ((default-prompt (concat prompt (if default (concat " (" default "): ") - ": ")))) + ": ")))) (read-string default-prompt nil nil default))) (defun ledger-report-payee-format-specifier () @@ -234,7 +234,7 @@ the default." (default (if (eq (ledger-context-line-type context) 'acct-transaction) (regexp-quote (ledger-context-field-value context 'account)) - nil))) + nil))) (ledger-read-string-with-default "Account" default))) (defun ledger-report-expand-format-specifiers (report-cmd) @@ -248,9 +248,9 @@ the default." (with-current-buffer ledger-buf (shell-quote-argument (funcall f)))) t t expanded-cmd)) - (progn - (set-window-configuration ledger-original-window-cfg) - (error "Invalid ledger report format specifier '%s'" specifier))))) + (progn + (set-window-configuration ledger-original-window-cfg) + (error "Invalid ledger report format specifier '%s'" specifier))))) expanded-cmd)) (defun ledger-report-cmd (report-name edit) @@ -280,12 +280,12 @@ the default." (shell-command (if register-report (concat cmd " --prepend-format='%(filename):%(beg_line):'") - cmd) t nil) + cmd) t nil) (when register-report (goto-char data-pos) (while (re-search-forward "^\\([^:]+\\)?:\\([0-9]+\\)?:" nil t) (let ((file (match-string 1)) - (line (string-to-number (match-string 2)))) + (line (string-to-number (match-string 2)))) (delete-region (match-beginning 0) (match-end 0)) (set-text-properties (line-beginning-position) (line-end-position) (list 'ledger-source (cons file (save-window-excursion @@ -307,14 +307,14 @@ the default." (widen) (if (markerp line-or-marker) (goto-char line-or-marker) - (goto-char (point-min)) - (forward-line (1- line-or-marker)) - (re-search-backward "^[0-9]+") - (beginning-of-line) - (let ((start-of-txn (point))) - (forward-paragraph) - (narrow-to-region start-of-txn (point)) - (backward-paragraph)))))) + (goto-char (point-min)) + (forward-line (1- line-or-marker)) + (re-search-backward "^[0-9]+") + (beginning-of-line) + (let ((start-of-txn (point))) + (forward-paragraph) + (narrow-to-region start-of-txn (point)) + (backward-paragraph)))))) (defun ledger-report-goto () "Goto the ledger report buffer." @@ -487,7 +487,7 @@ specified line, returns nil." (let ((left (forward-line offset))) (if (not (equal left 0)) nil - (ledger-context-at-point))))) + (ledger-context-at-point))))) (defun ledger-context-line-type (context-info) (nth 0 context-info)) @@ -525,6 +525,6 @@ specified line, returns nil." (let ((context-info (ledger-context-other-line i))) (if (eq (ledger-context-line-type context-info) 'entry) (ledger-context-field-value context-info 'payee) - nil)))) + nil)))) (provide 'ldg-report) diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el index 9cecefa4..86e3fa0a 100644 --- a/lisp/ldg-sort.el +++ b/lisp/ldg-sort.el @@ -23,11 +23,11 @@ ;; the form YYYY/mm/dd. (defun ledger-next-record-function () - (if (re-search-forward - (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" - "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) - (goto-char (match-beginning 0)) - (goto-char (point-max)))) + (if (re-search-forward + (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" + "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) + (goto-char (match-beginning 0)) + (goto-char (point-max)))) (defun ledger-end-record-function () (forward-paragraph)) @@ -42,7 +42,7 @@ (setq new-beg (point)) (goto-char end) (ledger-next-record-function) ;make sure end of region is at the beginning of - ;next record after the region + ;next record after the region (setq new-end (point)) (narrow-to-region beg end) (goto-char (point-min)) @@ -55,7 +55,7 @@ (defun ledger-sort-buffer () (interactive) - (ledger-sort-region (point-min) (point-max))) + (ledger-sort-region (point-min) (point-max))) (provide 'ldg-sort) \ No newline at end of file diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index 03017b25..41c0d8f2 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -28,9 +28,9 @@ (if (not (null state)) (if (and style (eq style 'cleared)) 'cleared) - (if (and style (eq style 'pending)) - 'pending - 'cleared))) + (if (and style (eq style 'pending)) + 'pending + 'cleared))) (defun ledger-entry-state () (save-excursion @@ -106,23 +106,23 @@ dropped." (progn (insert "* ") (setq inserted t))) - (if (and style (eq style 'pending)) - (progn - (insert "! ") - (setq inserted t)) - (progn - (insert "* ") - (setq inserted t)))) + (if (and style (eq style 'pending)) + (progn + (insert "! ") + (setq inserted t)) + (progn + (insert "* ") + (setq inserted t)))) (if (and inserted (re-search-forward "\\(\t\\| [ \t]\\)" (line-end-position) t)) (cond - ((looking-at "\t") - (delete-char 1)) - ((looking-at " [ \t]") - (delete-char 2)) - ((looking-at " ") - (delete-char 1)))) + ((looking-at "\t") + (delete-char 1)) + ((looking-at " [ \t]") + (delete-char 2)) + ((looking-at " ") + (delete-char 1)))) (setq clear inserted))))) ;; Clean up the entry so that it displays minimally (save-excursion @@ -135,12 +135,12 @@ dropped." (skip-chars-forward " \t") (let ((cleared (if (member (char-after) '(?\* ?\!)) (char-after) - ? ))) + ? ))) (if first (setq state cleared first nil) - (if (/= state cleared) - (setq hetero t)))) + (if (/= state cleared) + (setq hetero t)))) (forward-line)) (when (and (not hetero) (/= state ? )) (goto-char (car bounds)) @@ -162,12 +162,12 @@ dropped." (if (re-search-forward "\\(\t\\| [ \t]\\)" (line-end-position) t) (cond - ((looking-at "\t") - (delete-char 1)) - ((looking-at " [ \t]") - (delete-char 2)) - ((looking-at " ") - (delete-char 1))))))) + ((looking-at "\t") + (delete-char 1)) + ((looking-at " [ \t]") + (delete-char 2)) + ((looking-at " ") + (delete-char 1))))))) clear)) (defun ledger-toggle-current (&optional style) @@ -186,7 +186,7 @@ dropped." (forward-line) (goto-char (line-beginning-position)))) (ledger-toggle-current-entry style)) - (ledger-toggle-current-transaction style))) + (ledger-toggle-current-transaction style))) (defun ledger-toggle-current-entry (&optional style) (interactive) @@ -201,10 +201,10 @@ dropped." (delete-char 1) (if (and style (eq style 'cleared)) (insert " *"))) - (if (and style (eq style 'pending)) - (insert " ! ") - (insert " * ")) - (setq clear t)))) + (if (and style (eq style 'pending)) + (insert " ! ") + (insert " * ")) + (setq clear t)))) clear)) (provide 'ldg-state) diff --git a/lisp/ldg-test.el b/lisp/ldg-test.el index 2036ea7b..7667a05e 100644 --- a/lisp/ldg-test.el +++ b/lisp/ldg-test.el @@ -67,9 +67,9 @@ (ledger-mode) (if input (insert input) - (insert "2012-03-17 Payee\n") - (insert " Expenses:Food $20\n") - (insert " Assets:Cash\n")) + (insert "2012-03-17 Payee\n") + (insert " Expenses:Food $20\n") + (insert " Assets:Cash\n")) (insert "\ntest reg\n") (if output (insert output)) @@ -90,7 +90,7 @@ (let ((prev-directory default-directory)) (cd ledger-source-directory) (unwind-protect - (async-shell-command (format "\"%s\" %s" command args)) + (async-shell-command (format "\"%s\" %s" command args)) (cd prev-directory))))))) (provide 'ldg-test) diff --git a/lisp/ldg-texi.el b/lisp/ldg-texi.el index fefa7d2b..53e050ce 100644 --- a/lisp/ldg-texi.el +++ b/lisp/ldg-texi.el @@ -94,17 +94,17 @@ (if (string-match "\\$LEDGER" command) (replace-match (format "%s -f \"%s\" %s" ledger-path data-file ledger-normalization-args) t t command) - (concat (format "%s -f \"%s\" %s " ledger-path - data-file ledger-normalization-args) command))) + (concat (format "%s -f \"%s\" %s " ledger-path + data-file ledger-normalization-args) command))) (defun ledger-texi-invoke-command (command) (with-temp-buffer (shell-command command t (current-buffer)) - (if (= (point-min) (point-max)) - (progn - (push-mark nil t) - (message "Command '%s' yielded no result at %d" command (point)) - (ding)) - (buffer-string)))) + (if (= (point-min) (point-max)) + (progn + (push-mark nil t) + (message "Command '%s' yielded no result at %d" command (point)) + (ding)) + (buffer-string)))) (defun ledger-texi-write-test-data (name input) (let ((path (expand-file-name name temporary-file-directory))) @@ -149,7 +149,7 @@ (let ((section-name (if (string= section "smex") "smallexample" - "example")) + "example")) (output (ledger-texi-invoke-command (ledger-texi-expand-command command data-file)))) (insert "@" section-name ?\n output -- cgit v1.2.3 From 3d34a61ed595ab708ef101f07d7c68df1362f2e8 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 5 Feb 2013 14:50:59 -0700 Subject: Correct misspelling --- doc/ledger3.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 95025d41..a8f1d4b1 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -7220,7 +7220,7 @@ Inserts the ending line of that transaction within the file. @c @code{%D} gives the user more control over the way dates are output. @item d -Returns the data according to the default format. If the transaction +Returns the date according to the default format. If the transaction has an effective date, it prints @code{[ACTUAL_DATE=EFFECTIVE_DATE]}. @item X -- cgit v1.2.3 From e3431c4bffd57c39e96779a8449fe08679857448 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 7 Feb 2013 09:12:44 -0700 Subject: reconcile mode windowing improvements * reconcile mode now places its window at the bottom of the ledger window it was called form and minimizes its height to the size of the recon buffer. * It all specifically informs the user if there are no uncleared items. * When reconcile mode is entered it sets the ledger-occur mode and scrolls the bottom of the visible buffer to the bottom of the ledger window ensuring transactions are visible. --- lisp/ldg-reconcile.el | 191 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 115 insertions(+), 76 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 0cac33c5..22ad5bc1 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -23,12 +23,14 @@ (defvar ledger-buf nil) (defvar ledger-acct nil) +(defcustom ledger-recon-buffer-name "*Reconcile*" + "Name to use for reconciliation window" + :group 'ledger) (defcustom ledger-fold-on-reconcile t "if t, limit transactions shown in main buffer to those matching the reconcile regex" :group 'ledger) -(make-variable-buffer-local 'ledger-fold-on-reconcilex) (defun ledger-display-balance () "Calculate the cleared balance of the account being reconciled" @@ -95,7 +97,7 @@ (forward-line line))) (defun ledger-reconcile-refresh-after-save () - (let ((buf (get-buffer "*Reconcile*"))) + (let ((buf (get-buffer ledger-recon-buffer-name))) (if buf (with-current-buffer buf (ledger-reconcile-refresh) @@ -136,6 +138,9 @@ (defun ledger-reconcile-quit () (interactive) (let ((buf ledger-buf)) + ;Make sure you delete the window before you delete the buffer, + ;otherwise, madness ensues + (delete-window (get-buffer-window (current-buffer))) (kill-buffer (current-buffer)) (if ledger-fold-on-reconcile (ledger-occur-quit-buffer buf)))) @@ -155,107 +160,141 @@ (forward-line 1))) (ledger-reconcile-save)) +(defun ledger-marker-where-xact-is (emacs-xact) + "find the position of the xact in the ledger-buf buffer using + the emacs output from ledger, return a marker to the beginning + of the xact in the buffer" + (let ((buf ledger-buf)) + (with-current-buffer buf ;use the ledger-buf buffer + (cons + (nth 0 item) + (if ledger-clear-whole-entries ;determines whether to + ;clear on the payee line + ;or posting line + (save-excursion + (goto-line (nth 1 item)) + (point-marker)) + (save-excursion + (goto-line (nth 0 xact)) + (point-marker))))))) + (defun ledger-do-reconcile () - "get the uncleared transactions in the account and display them in the *Reconcile* buffer" + "get the uncleared transactions in the account and display them + in the *Reconcile* buffer" (let* ((buf ledger-buf) (account ledger-acct) (items - (with-temp-buffer - (ledger-exec-ledger buf (current-buffer) "--uncleared" "--real" - "emacs" account) + (with-temp-buffer + (ledger-exec-ledger buf (current-buffer) + "--uncleared" "--real" "emacs" account) (goto-char (point-min)) (unless (eobp) (unless (looking-at "(") (error (buffer-string))) - (read (current-buffer)))))) - (dolist (item items) - (let ((index 1)) - (dolist (xact (nthcdr 5 item)) - (let ((beg (point)) - (where - (with-current-buffer buf - (cons - (nth 0 item) - (if ledger-clear-whole-entries - (save-excursion - (goto-line (nth 1 item)) - (point-marker)) - (save-excursion - (goto-line (nth 0 xact)) - (point-marker))))))) - (insert (format "%s %-4s %-30s %-30s %15s\n" - (format-time-string "%Y/%m/%d" (nth 2 item)) - (if (nth 3 item) - (nth 3 item) - "") - (nth 4 item) (nth 1 xact) (nth 2 xact))) - (if (nth 3 xact) - (set-text-properties beg (1- (point)) - (list 'face 'ledger-font-reconciler-cleared-face - 'where where)) - (set-text-properties beg (1- (point)) - (list 'face 'ledger-font-reconciler-uncleared-face - 'where where)))) - (setq index (1+ index))))) + (read (current-buffer)))))) + (if (> (length items) 0) + (dolist (item items) + (let ((index 1)) + (dolist (xact (nthcdr 5 item)) + (let ((beg (point)) + (where (ledger-marker-where-xact-is item))) + (insert (format "%s %-4s %-30s %-30s %15s\n" + (format-time-string "%Y/%m/%d" (nth 2 item)) + (if (nth 3 item) + (nth 3 item) + "") + (nth 4 item) (nth 1 xact) (nth 2 xact))) + (if (nth 3 xact) + (set-text-properties beg (1- (point)) + (list 'face 'ledger-font-reconciler-cleared-face + 'where where)) + (set-text-properties beg (1- (point)) + (list 'face 'ledger-font-reconciler-uncleared-face + 'where where)))) + (setq index (1+ index))))) + (insert (concat "There are no uncleared entries for " account))) (goto-char (point-min)) (set-buffer-modified-p nil) - (toggle-read-only t))) + (toggle-read-only t) + ; this next piece of code ensures that the last of the visible + ; transactions in the ledger buffer is at the bottom of the + ; main window. The key to this is to ensure the window is selected + ; when the buffer point is moved and recentered. If they aren't + ; strange things happen. + + (let + ((recon-window (get-buffer-window (get-buffer ledger-recon-buffer-name)))) + (fit-window-to-buffer recon-window) + (with-current-buffer buf + (select-window (get-buffer-window buf)) + (goto-char (point-max)) + (recenter -1)) + + (select-window recon-window)))) (defun ledger-reconcile (account) (interactive "sAccount to reconcile: ") (let ((buf (current-buffer)) - (rbuf (get-buffer "*Reconcile*"))) + (rbuf (get-buffer ledger-recon-buffer-name))) (if rbuf - (kill-buffer rbuf)) + (progn + (quit-window (get-buffer-window rbuf)) + (kill-buffer rbuf))) (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save) (if ledger-fold-on-reconcile (ledger-occur-mode account buf)) + + ;create the *Reconcile* window directly below the ledger buffer. (with-current-buffer - (pop-to-buffer (get-buffer-create "*Reconcile*")) + (progn + (set-window-buffer + (split-window (get-buffer-window (current-buffer)) nil nil) + (get-buffer-create ledger-recon-buffer-name)) + (get-buffer ledger-recon-buffer-name)) (ledger-reconcile-mode) (set (make-local-variable 'ledger-buf) buf) (set (make-local-variable 'ledger-acct) account) - (ledger-do-reconcile)))) + (ledger-do-reconcile)))) (defvar ledger-reconcile-mode-abbrev-table) (define-derived-mode ledger-reconcile-mode text-mode "Reconcile" - "A mode for reconciling ledger entries." - (let ((map (make-sparse-keymap))) - (define-key map [(control ?m)] 'ledger-reconcile-visit) - (define-key map [return] 'ledger-reconcile-visit) - (define-key map [(control ?c) (control ?c)] 'ledger-reconcile-finish) - (define-key map [(control ?x) (control ?s)] 'ledger-reconcile-save) - (define-key map [(control ?l)] 'ledger-reconcile-refresh) - (define-key map [? ] 'ledger-reconcile-toggle) - (define-key map [?a] 'ledger-reconcile-add) - (define-key map [?d] 'ledger-reconcile-delete) - (define-key map [?g] 'ledger-reconcile-new-account) - (define-key map [?n] 'next-line) - (define-key map [?p] 'previous-line) - (define-key map [?s] 'ledger-reconcile-save) - (define-key map [?q] 'ledger-reconcile-quit) - (define-key map [?b] 'ledger-display-balance) - - (define-key map [menu-bar] (make-sparse-keymap "ldg-recon-menu")) - (define-key map [menu-bar ldg-recon-menu] (cons "Reconcile" map)) - (define-key map [menu-bar ldg-recon-menu qui] '("Quit" . ledger-reconcile-quit)) - (define-key map [menu-bar ldg-recon-menu sep1] '("--")) - (define-key map [menu-bar ldg-recon-menu pre] '("Previous Entry" . previous-line)) - (define-key map [menu-bar ldg-recon-menu vis] '("Visit Entry" . ledger-reconcile-visit)) - (define-key map [menu-bar ldg-recon-menu nex] '("Next Entry" . next-line)) - (define-key map [menu-bar ldg-recon-menu sep2] '("--")) - (define-key map [menu-bar ldg-recon-menu del] '("Delete Entry" . ledger-reconcile-delete)) - (define-key map [menu-bar ldg-recon-menu add] '("Add Entry" . ledger-reconcile-add)) - (define-key map [menu-bar ldg-recon-menu tog] '("Toggle Entry" . ledger-reconcile-toggle)) - (define-key map [menu-bar ldg-recon-menu sep3] '("--")) - (define-key map [menu-bar ldg-recon-menu bal] '("Show Cleared Balance" . ledger-display-balance)) - (define-key map [menu-bar ldg-recon-menu sep4] '("--")) - (define-key map [menu-bar ldg-recon-menu rna] '("Reconcile New Account" . ledger-reconcile-new-account)) - (define-key map [menu-bar ldg-recon-menu ref] '("Refresh" . ledger-reconcile-refresh)) - (define-key map [menu-bar ldg-recon-menu sav] '("Save" . ledger-reconcile-save)) + "A mode for reconciling ledger entries." + (let ((map (make-sparse-keymap))) + (define-key map [(control ?m)] 'ledger-reconcile-visit) + (define-key map [return] 'ledger-reconcile-visit) + (define-key map [(control ?c) (control ?c)] 'ledger-reconcile-finish) + (define-key map [(control ?x) (control ?s)] 'ledger-reconcile-save) + (define-key map [(control ?l)] 'ledger-reconcile-refresh) + (define-key map [? ] 'ledger-reconcile-toggle) + (define-key map [?a] 'ledger-reconcile-add) + (define-key map [?d] 'ledger-reconcile-delete) + (define-key map [?g] 'ledger-reconcile-new-account) + (define-key map [?n] 'next-line) + (define-key map [?p] 'previous-line) + (define-key map [?s] 'ledger-reconcile-save) + (define-key map [?q] 'ledger-reconcile-quit) + (define-key map [?b] 'ledger-display-balance) + + (define-key map [menu-bar] (make-sparse-keymap "ldg-recon-menu")) + (define-key map [menu-bar ldg-recon-menu] (cons "Reconcile" map)) + (define-key map [menu-bar ldg-recon-menu qui] '("Quit" . ledger-reconcile-quit)) + (define-key map [menu-bar ldg-recon-menu sep1] '("--")) + (define-key map [menu-bar ldg-recon-menu pre] '("Previous Entry" . previous-line)) + (define-key map [menu-bar ldg-recon-menu vis] '("Visit Entry" . ledger-reconcile-visit)) + (define-key map [menu-bar ldg-recon-menu nex] '("Next Entry" . next-line)) + (define-key map [menu-bar ldg-recon-menu sep2] '("--")) + (define-key map [menu-bar ldg-recon-menu del] '("Delete Entry" . ledger-reconcile-delete)) + (define-key map [menu-bar ldg-recon-menu add] '("Add Entry" . ledger-reconcile-add)) + (define-key map [menu-bar ldg-recon-menu tog] '("Toggle Entry" . ledger-reconcile-toggle)) + (define-key map [menu-bar ldg-recon-menu sep3] '("--")) + (define-key map [menu-bar ldg-recon-menu bal] '("Show Cleared Balance" . ledger-display-balance)) + (define-key map [menu-bar ldg-recon-menu sep4] '("--")) + (define-key map [menu-bar ldg-recon-menu rna] '("Reconcile New Account" . ledger-reconcile-new-account)) + (define-key map [menu-bar ldg-recon-menu ref] '("Refresh" . ledger-reconcile-refresh)) + (define-key map [menu-bar ldg-recon-menu sav] '("Save" . ledger-reconcile-save)) - (use-local-map map))) + (use-local-map map))) (provide 'ldg-reconcile) \ No newline at end of file -- cgit v1.2.3 From 869c40c070a1abd8a02f8817a43cfc1488c0b1bc Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 7 Feb 2013 10:16:31 -0700 Subject: Reconcile visit now recanters on the xact selected --- lisp/ldg-reconcile.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 22ad5bc1..2d591de5 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -126,7 +126,8 @@ (let ((where (get-text-property (point) 'where))) (when (is-stdin (car where)) (switch-to-buffer-other-window ledger-buf) - (goto-char (cdr where))))) + (goto-char (cdr where)) + (recenter)))) (defun ledger-reconcile-save () (interactive) -- cgit v1.2.3 From 867b84c52ea13563d0b507ae0756898cb416ef45 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 7 Feb 2013 11:30:34 -0700 Subject: code formatting cleanup. --- lisp/ldg-report.el | 68 +++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 3b831825..cdef6ded 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -73,40 +73,40 @@ text that should replace the format specifier." (defvar ledger-report-mode-abbrev-table) (define-derived-mode ledger-report-mode text-mode "Ledger-Report" - "A mode for viewing ledger reports." - (let ((map (make-sparse-keymap))) - (define-key map [? ] 'scroll-up) - (define-key map [backspace] 'scroll-down) - (define-key map [?r] 'ledger-report-redo) - (define-key map [?s] 'ledger-report-save) - (define-key map [?k] 'ledger-report-kill) - (define-key map [?e] 'ledger-report-edit) - (define-key map [?q] 'ledger-report-quit) - (define-key map [(control ?c) (control ?l) (control ?r)] - 'ledger-report-redo) - (define-key map [(control ?c) (control ?l) (control ?S)] - 'ledger-report-save) - (define-key map [(control ?c) (control ?l) (control ?k)] - 'ledger-report-kill) - (define-key map [(control ?c) (control ?l) (control ?e)] - 'ledger-report-edit) - (define-key map [(control ?c) (control ?c)] 'ledger-report-visit-source) - - - (define-key map [menu-bar] (make-sparse-keymap "ldg-rep")) - (define-key map [menu-bar ldg-rep] (cons "Reports" map)) - - (define-key map [menu-bar ldg-rep lrq] '("Quit" . ledger-report-quit)) - (define-key map [menu-bar ldg-rep s2] '("--")) - (define-key map [menu-bar ldg-rep lrd] '("Scroll Down" . scroll-down)) - (define-key map [menu-bar ldg-rep lru] '("Scroll Up" . scroll-up)) - (define-key map [menu-bar ldg-rep s1] '("--")) - (define-key map [menu-bar ldg-rep lrk] '("Kill Report" . ledger-report-kill)) - (define-key map [menu-bar ldg-rep lrr] '("Re-run Report" . ledger-report-redo)) - (define-key map [menu-bar ldg-rep lre] '("Edit Report" . ledger-report-edit)) - (define-key map [menu-bar ldg-rep lrs] '("Save Report" . ledger-report-save)) - - (use-local-map map))) + "A mode for viewing ledger reports." + (let ((map (make-sparse-keymap))) + (define-key map [? ] 'scroll-up) + (define-key map [backspace] 'scroll-down) + (define-key map [?r] 'ledger-report-redo) + (define-key map [?s] 'ledger-report-save) + (define-key map [?k] 'ledger-report-kill) + (define-key map [?e] 'ledger-report-edit) + (define-key map [?q] 'ledger-report-quit) + (define-key map [(control ?c) (control ?l) (control ?r)] + 'ledger-report-redo) + (define-key map [(control ?c) (control ?l) (control ?S)] + 'ledger-report-save) + (define-key map [(control ?c) (control ?l) (control ?k)] + 'ledger-report-kill) + (define-key map [(control ?c) (control ?l) (control ?e)] + 'ledger-report-edit) + (define-key map [(control ?c) (control ?c)] 'ledger-report-visit-source) + + + (define-key map [menu-bar] (make-sparse-keymap "ldg-rep")) + (define-key map [menu-bar ldg-rep] (cons "Reports" map)) + + (define-key map [menu-bar ldg-rep lrq] '("Quit" . ledger-report-quit)) + (define-key map [menu-bar ldg-rep s2] '("--")) + (define-key map [menu-bar ldg-rep lrd] '("Scroll Down" . scroll-down)) + (define-key map [menu-bar ldg-rep lru] '("Scroll Up" . scroll-up)) + (define-key map [menu-bar ldg-rep s1] '("--")) + (define-key map [menu-bar ldg-rep lrk] '("Kill Report" . ledger-report-kill)) + (define-key map [menu-bar ldg-rep lrr] '("Re-run Report" . ledger-report-redo)) + (define-key map [menu-bar ldg-rep lre] '("Edit Report" . ledger-report-edit)) + (define-key map [menu-bar ldg-rep lrs] '("Save Report" . ledger-report-save)) + + (use-local-map map))) (defun ledger-report-read-name () "Read the name of a ledger report to use, with completion. -- cgit v1.2.3 From 29f409ce723e65df7cfa28be059627a084297aba Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 7 Feb 2013 22:40:57 -0700 Subject: Added ability to add xact with date only. ledger-add-entry now checks to see if more than the date was given at the prompt. If there is only a date it inserts the dat at the correct place in the ledger and puts the point at the end of the line for entering transaction details --- lisp/ldg-mode.el | 168 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 86 insertions(+), 82 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 226009c6..f71bb58e 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -43,77 +43,77 @@ customizable to ease retro-entry.") ;;;###autoload (define-derived-mode ledger-mode text-mode "Ledger" - "A mode for editing ledger data files." - (ledger-check-version) - (ledger-post-setup) - - (set (make-local-variable 'comment-start) " ; ") - (set (make-local-variable 'comment-end) "") - (set (make-local-variable 'indent-tabs-mode) nil) - - (if (boundp 'font-lock-defaults) - (set (make-local-variable 'font-lock-defaults) - '(ledger-font-lock-keywords nil t))) - - (set (make-local-variable 'pcomplete-parse-arguments-function) - 'ledger-parse-arguments) - (set (make-local-variable 'pcomplete-command-completion-function) - 'ledger-complete-at-point) - (set (make-local-variable 'pcomplete-termination-string) "") - - (let ((map (current-local-map))) - (define-key map [(control ?c) (control ?a)] 'ledger-add-entry) - (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-entry) - (define-key map [(control ?c) (control ?y)] 'ledger-set-year) - (define-key map [(control ?c) (control ?m)] 'ledger-set-month) - (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) - (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-entry) - (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) - (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) - (define-key map [(control ?c) (control ?t)] 'ledger-test-run) - (define-key map [(control ?c) (control ?v)] 'ledger-post-edit-amount) - (define-key map [(control ?c) (control ?f)] 'ledger-occur) - (define-key map [tab] 'pcomplete) - (define-key map [(control ?i)] 'pcomplete) - (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) - (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry) - (define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report) - (define-key map [(control ?c) (control ?o) (control ?g)] 'ledger-report-goto) - (define-key map [(control ?c) (control ?o) (control ?a)] 'ledger-report-redo) - (define-key map [(control ?c) (control ?o) (control ?s)] 'ledger-report-save) - (define-key map [(control ?c) (control ?o) (control ?e)] 'ledger-report-edit) - (define-key map [(control ?c) (control ?o) (control ?k)] 'ledger-report-kill) - - (define-key map [(meta ?p)] 'ledger-post-prev-xact) - (define-key map [(meta ?n)] 'ledger-post-next-xact) - - (define-key map [menu-bar] (make-sparse-keymap "ldg-menu")) - (define-key map [menu-bar ldg-menu] (cons "Ledger" map)) - - (define-key map [report-kill] '(menu-item "Kill Report" ledger-report-kill :enable ledger-works)) - (define-key map [report-edit] '(menu-item "Edit Report" ledger-report-edit :enable ledger-works)) - (define-key map [report-save] '(menu-item "Save Report" ledger-report-save :enable ledger-works)) - (define-key map [report-rrun] '(menu-item "Re-run Report" ledger-report-redo :enable ledger-works)) - (define-key map [report-goto] '(menu-item "Goto Report" ledger-report-goto :enable ledger-works)) - (define-key map [report-run] '(menu-item "Run Report" ledger-report :enable ledger-works)) - (define-key map [sep5] '(menu-item "--")) - (define-key map [set-month] '(menu-item "Set Month" ledger-set-month :enable ledger-works)) - (define-key map [set-year] '(menu-item "Set Year" ledger-set-year :enable ledger-works)) - (define-key map [sep1] '("--")) - (define-key map [sort-buff] '(menu-item "Sort Buffer" ledger-sort-buffer)) - (define-key map [sort-reg] '(menu-item "Sort Region" ledger-sort-region :enable mark-active)) - (define-key map [sep2] '(menu-item "--")) - (define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current)) - (define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-entry)) - (define-key map [sep4] '(menu-item "--")) - (define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount)) - (define-key map [sep] '(menu-item "--")) - (define-key map [delete-xact] '(menu-item "Delete Entry" ledger-delete-current-entry)) - (define-key map [add-xact] '(menu-item "Add Entry" ledger-add-entry :enable ledger-works)) - (define-key map [sep3] '(menu-item "--")) - (define-key map [reconcile] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works)) - (define-key map [reconcile] '(menu-item "Hide Xacts" ledger-occur)) - )) + "A mode for editing ledger data files." + (ledger-check-version) + (ledger-post-setup) + + (set (make-local-variable 'comment-start) " ; ") + (set (make-local-variable 'comment-end) "") + (set (make-local-variable 'indent-tabs-mode) nil) + + (if (boundp 'font-lock-defaults) + (set (make-local-variable 'font-lock-defaults) + '(ledger-font-lock-keywords nil t))) + + (set (make-local-variable 'pcomplete-parse-arguments-function) + 'ledger-parse-arguments) + (set (make-local-variable 'pcomplete-command-completion-function) + 'ledger-complete-at-point) + (set (make-local-variable 'pcomplete-termination-string) "") + + (let ((map (current-local-map))) + (define-key map [(control ?c) (control ?a)] 'ledger-add-entry) + (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-entry) + (define-key map [(control ?c) (control ?y)] 'ledger-set-year) + (define-key map [(control ?c) (control ?m)] 'ledger-set-month) + (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) + (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-entry) + (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) + (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) + (define-key map [(control ?c) (control ?t)] 'ledger-test-run) + (define-key map [(control ?c) (control ?v)] 'ledger-post-edit-amount) + (define-key map [(control ?c) (control ?f)] 'ledger-occur) + (define-key map [tab] 'pcomplete) + (define-key map [(control ?i)] 'pcomplete) + (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) + (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry) + (define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report) + (define-key map [(control ?c) (control ?o) (control ?g)] 'ledger-report-goto) + (define-key map [(control ?c) (control ?o) (control ?a)] 'ledger-report-redo) + (define-key map [(control ?c) (control ?o) (control ?s)] 'ledger-report-save) + (define-key map [(control ?c) (control ?o) (control ?e)] 'ledger-report-edit) + (define-key map [(control ?c) (control ?o) (control ?k)] 'ledger-report-kill) + + (define-key map [(meta ?p)] 'ledger-post-prev-xact) + (define-key map [(meta ?n)] 'ledger-post-next-xact) + + (define-key map [menu-bar] (make-sparse-keymap "ldg-menu")) + (define-key map [menu-bar ldg-menu] (cons "Ledger" map)) + + (define-key map [report-kill] '(menu-item "Kill Report" ledger-report-kill :enable ledger-works)) + (define-key map [report-edit] '(menu-item "Edit Report" ledger-report-edit :enable ledger-works)) + (define-key map [report-save] '(menu-item "Save Report" ledger-report-save :enable ledger-works)) + (define-key map [report-rrun] '(menu-item "Re-run Report" ledger-report-redo :enable ledger-works)) + (define-key map [report-goto] '(menu-item "Goto Report" ledger-report-goto :enable ledger-works)) + (define-key map [report-run] '(menu-item "Run Report" ledger-report :enable ledger-works)) + (define-key map [sep5] '(menu-item "--")) + (define-key map [set-month] '(menu-item "Set Month" ledger-set-month :enable ledger-works)) + (define-key map [set-year] '(menu-item "Set Year" ledger-set-year :enable ledger-works)) + (define-key map [sep1] '("--")) + (define-key map [sort-buff] '(menu-item "Sort Buffer" ledger-sort-buffer)) + (define-key map [sort-reg] '(menu-item "Sort Region" ledger-sort-region :enable mark-active)) + (define-key map [sep2] '(menu-item "--")) + (define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current)) + (define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-entry)) + (define-key map [sep4] '(menu-item "--")) + (define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount)) + (define-key map [sep] '(menu-item "--")) + (define-key map [delete-xact] '(menu-item "Delete Entry" ledger-delete-current-entry)) + (define-key map [add-xact] '(menu-item "Add Entry" ledger-add-entry :enable ledger-works)) + (define-key map [sep3] '(menu-item "--")) + (define-key map [reconcile] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works)) + (define-key map [reconcile] '(menu-item "Hide Xacts" ledger-occur)) + )) (defun ledger-time-less-p (t1 t2) "Say whether time value T1 is less than time value T2." @@ -193,17 +193,21 @@ Return the difference in the format of a time value." (string-to-number (match-string 2 date)) (string-to-number (match-string 1 date))))) (ledger-find-slot date))) - (save-excursion - (insert - (with-temp-buffer - (setq exit-code - (apply #'ledger-exec-ledger ledger-buf ledger-buf "entry" - (mapcar 'eval args))) - (goto-char (point-min)) - (if (looking-at "Error: ") - (error (buffer-string)) - (buffer-string))) - "\n")))) + (if (> (length args) 1) + (save-excursion + (insert + (with-temp-buffer + (setq exit-code + (apply #'ledger-exec-ledger ledger-buf ledger-buf "entry" + (mapcar 'eval args))) + (goto-char (point-min)) + (if (looking-at "Error: ") + (error (buffer-string)) + (buffer-string))) + "\n")) + (progn + (insert (car args) " \n\n") + (end-of-line -1))))) (defun ledger-current-entry-bounds () (save-excursion -- cgit v1.2.3 From ca554f6b5b407415a006be3550b67536acd312a7 Mon Sep 17 00:00:00 2001 From: Rémi Vanicat Date: Fri, 8 Feb 2013 10:40:48 +0100 Subject: Add € and £ to currency one could use in new ledger mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lisp/ldg-post.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 05b9d352..5d5381ae 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -84,7 +84,7 @@ to choose from." (goto-char pos))) (defun ledger-next-amount (&optional end) - (when (re-search-forward "\\( \\|\t\\| \t\\)[ \t]*-?\\([A-Z$]+ *\\)?\\(-?[0-9,]+?\\)\\(.[0-9]+\\)?\\( *[A-Z$]+\\)?\\([ \t]*@@?[^\n;]+?\\)?\\([ \t]+;.+?\\)?$" (marker-position end) t) + (when (re-search-forward "\\( \\|\t\\| \t\\)[ \t]*-?\\([A-Z$€£]+ *\\)?\\(-?[0-9,]+?\\)\\(.[0-9]+\\)?\\( *[A-Z$€£]+\\)?\\([ \t]*@@?[^\n;]+?\\)?\\([ \t]+;.+?\\)?$" (marker-position end) t) (goto-char (match-beginning 0)) (skip-syntax-forward " ") (- (or (match-end 4) -- cgit v1.2.3 From bdf404112e81b74a0cec668222c373150a0bc5ce Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 8 Feb 2013 07:41:42 -0700 Subject: Corrected reentering when entering leg-occur mode --- lisp/ldg-occur.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index 09cca45b..2958c94c 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -89,8 +89,9 @@ (setq ledger-occur-overlay-list (append ledger-occur-overlay-list (ledger-occur-create-folded-overlays buffer-matches))) - (setq ledger-occur-last-match regex)) - (recenter)))) + (setq ledger-occur-last-match regex) + (select-window (get-buffer-window buffer)))) + (recenter))) (defun ledger-occur (regex) "Perform a simple grep in current buffer for the regular -- cgit v1.2.3 From 3b44a9fd2aec421eee2136088edd07efeb330f92 Mon Sep 17 00:00:00 2001 From: Rémi Vanicat Date: Fri, 8 Feb 2013 18:05:29 +0100 Subject: In ledger-reconcile, use a function to get where the transaction is. --- lisp/ldg-reconcile.el | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 2d591de5..04c84e63 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -53,14 +53,18 @@ (equal file "") (equal file "/dev/stdin"))) +(defun ledger-reconcile-get-buffer (where) + (when (is-stdin (car where)) + ledger-buf)) + (defun ledger-reconcile-toggle () (interactive) (let ((where (get-text-property (point) 'where)) (account ledger-acct) (inhibit-read-only t) cleared) - (when (is-stdin (car where)) - (with-current-buffer ledger-buf + (when (ledger-reconcile-get-buffer where) + (with-current-buffer (ledger-reconcile-get-buffer where) (goto-char (cdr where)) (setq cleared (ledger-toggle-current-entry))) ;remove the existing face and add the new face @@ -112,8 +116,8 @@ (defun ledger-reconcile-delete () (interactive) (let ((where (get-text-property (point) 'where))) - (when (is-stdin (car where)) - (with-current-buffer ledger-buf + (when (ledger-reconcile-get-buffer where) + (with-current-buffer (ledger-reconcile-get-buffer where) (goto-char (cdr where)) (ledger-delete-current-entry)) (let ((inhibit-read-only t)) @@ -124,8 +128,8 @@ (defun ledger-reconcile-visit () (interactive) (let ((where (get-text-property (point) 'where))) - (when (is-stdin (car where)) - (switch-to-buffer-other-window ledger-buf) + (when (ledger-reconcile-get-buffer where) + (switch-to-buffer-other-window (ledger-reconcile-get-buffer where)) (goto-char (cdr where)) (recenter)))) @@ -154,8 +158,8 @@ (let ((where (get-text-property (point) 'where)) (face (get-text-property (point) 'face))) (if (and (eq face 'bold) - (when (is-stdin (car where)))) - (with-current-buffer ledger-buf + (ledger-reconcile-get-buffer where)) + (with-current-buffer (ledger-reconcile-get-buffer where) (goto-char (cdr where)) (ledger-toggle-current 'cleared)))) (forward-line 1))) @@ -298,4 +302,4 @@ (use-local-map map))) -(provide 'ldg-reconcile) \ No newline at end of file +(provide 'ldg-reconcile) -- cgit v1.2.3 From 21968b1e126df258842a6a45d2141f2923f7b023 Mon Sep 17 00:00:00 2001 From: Rémi Vanicat Date: Fri, 8 Feb 2013 18:16:57 +0100 Subject: In ledger-reconcile, open file where transaction are, and store it. --- lisp/ldg-reconcile.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 04c84e63..ae8de63f 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -169,10 +169,12 @@ "find the position of the xact in the ledger-buf buffer using the emacs output from ledger, return a marker to the beginning of the xact in the buffer" - (let ((buf ledger-buf)) + (let ((buf (if (is-stdin emacs-xact) + ledger-buf + (find-file-noselect (nth 0 item))))) (with-current-buffer buf ;use the ledger-buf buffer (cons - (nth 0 item) + buf (if ledger-clear-whole-entries ;determines whether to ;clear on the payee line ;or posting line -- cgit v1.2.3 From 0b63dc0f84236b30e771a7c3b9867cfc5a3965be Mon Sep 17 00:00:00 2001 From: Rémi Vanicat Date: Fri, 8 Feb 2013 18:17:55 +0100 Subject: In ledger-reconcile-get-buffer, return the stored buffer --- lisp/ldg-reconcile.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index ae8de63f..2bdd6026 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -54,8 +54,8 @@ (equal file "/dev/stdin"))) (defun ledger-reconcile-get-buffer (where) - (when (is-stdin (car where)) - ledger-buf)) + (when (bufferp (car where)) + (car where))) (defun ledger-reconcile-toggle () (interactive) -- cgit v1.2.3 From e304cdfdbbd081e36925135f90b9ec052e8478ce Mon Sep 17 00:00:00 2001 From: Rémi Vanicat Date: Fri, 8 Feb 2013 18:35:14 +0100 Subject: After reconciling, save all buffer that need to be saved. --- lisp/ldg-reconcile.el | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 2bdd6026..ee87b1b8 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -22,6 +22,7 @@ ;; Reconcile mode (defvar ledger-buf nil) +(defvar ledger-bufs nil) (defvar ledger-acct nil) (defcustom ledger-recon-buffer-name "*Reconcile*" "Name to use for reconciliation window" @@ -135,8 +136,9 @@ (defun ledger-reconcile-save () (interactive) - (with-current-buffer ledger-buf - (save-buffer)) + (dolist (buf (cons ledger-buf ledger-bufs)) + (with-current-buffer buf + (save-buffer))) (set-buffer-modified-p nil) (ledger-display-balance)) @@ -199,12 +201,14 @@ (unless (looking-at "(") (error (buffer-string))) (read (current-buffer)))))) + (setq ledger-bufs ()) (if (> (length items) 0) (dolist (item items) (let ((index 1)) (dolist (xact (nthcdr 5 item)) (let ((beg (point)) (where (ledger-marker-where-xact-is item))) + (add-to-list 'ledger-bufs (car where)) (insert (format "%s %-4s %-30s %-30s %15s\n" (format-time-string "%Y/%m/%d" (nth 2 item)) (if (nth 3 item) -- cgit v1.2.3 From 8f214f38305d5b0b20ddb5da36bc9e4b8c183e23 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 8 Feb 2013 15:24:00 -0700 Subject: Revert "Merge pull request #147 from vanicat/t/where-are-transaction" This reverts commit 9a411e898acdd52e432ea84914467233e740c67e, reversing changes made to bdf404112e81b74a0cec668222c373150a0bc5ce. --- lisp/ldg-reconcile.el | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index ee87b1b8..2d591de5 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -22,7 +22,6 @@ ;; Reconcile mode (defvar ledger-buf nil) -(defvar ledger-bufs nil) (defvar ledger-acct nil) (defcustom ledger-recon-buffer-name "*Reconcile*" "Name to use for reconciliation window" @@ -54,18 +53,14 @@ (equal file "") (equal file "/dev/stdin"))) -(defun ledger-reconcile-get-buffer (where) - (when (bufferp (car where)) - (car where))) - (defun ledger-reconcile-toggle () (interactive) (let ((where (get-text-property (point) 'where)) (account ledger-acct) (inhibit-read-only t) cleared) - (when (ledger-reconcile-get-buffer where) - (with-current-buffer (ledger-reconcile-get-buffer where) + (when (is-stdin (car where)) + (with-current-buffer ledger-buf (goto-char (cdr where)) (setq cleared (ledger-toggle-current-entry))) ;remove the existing face and add the new face @@ -117,8 +112,8 @@ (defun ledger-reconcile-delete () (interactive) (let ((where (get-text-property (point) 'where))) - (when (ledger-reconcile-get-buffer where) - (with-current-buffer (ledger-reconcile-get-buffer where) + (when (is-stdin (car where)) + (with-current-buffer ledger-buf (goto-char (cdr where)) (ledger-delete-current-entry)) (let ((inhibit-read-only t)) @@ -129,16 +124,15 @@ (defun ledger-reconcile-visit () (interactive) (let ((where (get-text-property (point) 'where))) - (when (ledger-reconcile-get-buffer where) - (switch-to-buffer-other-window (ledger-reconcile-get-buffer where)) + (when (is-stdin (car where)) + (switch-to-buffer-other-window ledger-buf) (goto-char (cdr where)) (recenter)))) (defun ledger-reconcile-save () (interactive) - (dolist (buf (cons ledger-buf ledger-bufs)) - (with-current-buffer buf - (save-buffer))) + (with-current-buffer ledger-buf + (save-buffer)) (set-buffer-modified-p nil) (ledger-display-balance)) @@ -160,8 +154,8 @@ (let ((where (get-text-property (point) 'where)) (face (get-text-property (point) 'face))) (if (and (eq face 'bold) - (ledger-reconcile-get-buffer where)) - (with-current-buffer (ledger-reconcile-get-buffer where) + (when (is-stdin (car where)))) + (with-current-buffer ledger-buf (goto-char (cdr where)) (ledger-toggle-current 'cleared)))) (forward-line 1))) @@ -171,12 +165,10 @@ "find the position of the xact in the ledger-buf buffer using the emacs output from ledger, return a marker to the beginning of the xact in the buffer" - (let ((buf (if (is-stdin emacs-xact) - ledger-buf - (find-file-noselect (nth 0 item))))) + (let ((buf ledger-buf)) (with-current-buffer buf ;use the ledger-buf buffer (cons - buf + (nth 0 item) (if ledger-clear-whole-entries ;determines whether to ;clear on the payee line ;or posting line @@ -201,14 +193,12 @@ (unless (looking-at "(") (error (buffer-string))) (read (current-buffer)))))) - (setq ledger-bufs ()) (if (> (length items) 0) (dolist (item items) (let ((index 1)) (dolist (xact (nthcdr 5 item)) (let ((beg (point)) (where (ledger-marker-where-xact-is item))) - (add-to-list 'ledger-bufs (car where)) (insert (format "%s %-4s %-30s %-30s %15s\n" (format-time-string "%Y/%m/%d" (nth 2 item)) (if (nth 3 item) @@ -308,4 +298,4 @@ (use-local-map map))) -(provide 'ldg-reconcile) +(provide 'ldg-reconcile) \ No newline at end of file -- cgit v1.2.3 From e3be9686e4780778fe26124e37151009c8f66446 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 8 Feb 2013 17:02:58 -0700 Subject: Added vanicat's multii file extensions. There was a strange interact with some more recent parts of the code that exposed bugs I hadn't seen before. --- lisp/ldg-reconcile.el | 76 ++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 2d591de5..ed974a1e 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -22,6 +22,7 @@ ;; Reconcile mode (defvar ledger-buf nil) +(defvar ledger-bufs nil) (defvar ledger-acct nil) (defcustom ledger-recon-buffer-name "*Reconcile*" "Name to use for reconciliation window" @@ -53,17 +54,27 @@ (equal file "") (equal file "/dev/stdin"))) +(defun ledger-reconcile-get-buffer (where) +; (when (is-stdin (car where)) +; ledger-buf)) + (if (bufferp (car where)) + (car where) + (error "buffer not set"))) + + (defun ledger-reconcile-toggle () (interactive) (let ((where (get-text-property (point) 'where)) (account ledger-acct) (inhibit-read-only t) cleared) - (when (is-stdin (car where)) - (with-current-buffer ledger-buf +; (when (is-stdin (car where)) +; (with-current-buffer ledger-buf + (when (ledger-reconcile-get-buffer where) + (with-current-buffer (ledger-reconcile-get-buffer where) (goto-char (cdr where)) (setq cleared (ledger-toggle-current-entry))) - ;remove the existing face and add the new face + ;remove the existing face and add the new face (remove-text-properties (line-beginning-position) (line-end-position) (list 'face)) @@ -112,8 +123,8 @@ (defun ledger-reconcile-delete () (interactive) (let ((where (get-text-property (point) 'where))) - (when (is-stdin (car where)) - (with-current-buffer ledger-buf + (when (ledger-reconcile-get-buffer where) + (with-current-buffer (ledger-reconcile-get-buffer where) (goto-char (cdr where)) (ledger-delete-current-entry)) (let ((inhibit-read-only t)) @@ -123,16 +134,21 @@ (defun ledger-reconcile-visit () (interactive) - (let ((where (get-text-property (point) 'where))) - (when (is-stdin (car where)) - (switch-to-buffer-other-window ledger-buf) + (let* ((where (get-text-property (point) 'where)) + (target-buffer (ledger-reconcile-get-buffer + where))) + (when target-buffer + (switch-to-buffer-other-window target-buffer) (goto-char (cdr where)) (recenter)))) (defun ledger-reconcile-save () (interactive) - (with-current-buffer ledger-buf - (save-buffer)) +; (with-current-buffer ledger-buf +; (save-buffer)) + (dolist (buf (cons ledger-buf ledger-bufs)) + (with-current-buffer buf + (save-buffer))) (set-buffer-modified-p nil) (ledger-display-balance)) @@ -146,38 +162,19 @@ (if ledger-fold-on-reconcile (ledger-occur-quit-buffer buf)))) -(defun ledger-reconcile-finish () - (interactive) - (save-excursion - (goto-char (point-min)) - (while (not (eobp)) - (let ((where (get-text-property (point) 'where)) - (face (get-text-property (point) 'face))) - (if (and (eq face 'bold) - (when (is-stdin (car where)))) - (with-current-buffer ledger-buf - (goto-char (cdr where)) - (ledger-toggle-current 'cleared)))) - (forward-line 1))) - (ledger-reconcile-save)) - (defun ledger-marker-where-xact-is (emacs-xact) "find the position of the xact in the ledger-buf buffer using - the emacs output from ledger, return a marker to the beginning - of the xact in the buffer" - (let ((buf ledger-buf)) - (with-current-buffer buf ;use the ledger-buf buffer + the emacs output from ledger, return the buffer and a marker + to the beginning of the xact in that buffer" + (let ((buf (if (is-stdin (nth 0 emacs-xact)) + ledger-buf + (find-file-noselect (nth 0 emacs-xact))))) + (with-current-buffer buf (cons - (nth 0 item) - (if ledger-clear-whole-entries ;determines whether to - ;clear on the payee line - ;or posting line - (save-excursion - (goto-line (nth 1 item)) - (point-marker)) - (save-excursion - (goto-line (nth 0 xact)) - (point-marker))))))) + buf + (save-excursion + (goto-line (nth 1 emacs-xact)) + (point-marker)))))) (defun ledger-do-reconcile () "get the uncleared transactions in the account and display them @@ -265,7 +262,6 @@ (let ((map (make-sparse-keymap))) (define-key map [(control ?m)] 'ledger-reconcile-visit) (define-key map [return] 'ledger-reconcile-visit) - (define-key map [(control ?c) (control ?c)] 'ledger-reconcile-finish) (define-key map [(control ?x) (control ?s)] 'ledger-reconcile-save) (define-key map [(control ?l)] 'ledger-reconcile-refresh) (define-key map [? ] 'ledger-reconcile-toggle) -- cgit v1.2.3 From 5f67cfbec73863608639a7b8507191236cbac800 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 8 Feb 2013 17:16:12 -0700 Subject: Added ability to have ledger buffer track the xact under point in recon window controllable using ledger-buffer-tracks-reconcile-buffer --- lisp/ldg-reconcile.el | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index ed974a1e..395266e3 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -24,6 +24,7 @@ (defvar ledger-buf nil) (defvar ledger-bufs nil) (defvar ledger-acct nil) + (defcustom ledger-recon-buffer-name "*Reconcile*" "Name to use for reconciliation window" :group 'ledger) @@ -33,6 +34,12 @@ matching the reconcile regex" :group 'ledger) +(defcustom ledger-buffer-tracks-reconcile-buffer t + "if t, then when the cursor is moved to a new xact in the recon + window, then that transaction will be shown in its source + buffer." + :group 'ledger) + (defun ledger-display-balance () "Calculate the cleared balance of the account being reconciled" (interactive) @@ -231,6 +238,22 @@ (select-window recon-window)))) +(defun ledger-reconcile-track-xact () + (if (or (eq this-command 'next-line) + (eq this-command 'previous-line) + (eq this-command 'mouse-set-point)) + (let* ((where (get-text-property (point) 'where)) + (target-buffer (ledger-reconcile-get-buffer + where)) + (cur-buf (current-buffer))) + (when target-buffer + (switch-to-buffer-other-window target-buffer) + (goto-char (cdr where)) + (recenter) + (switch-to-buffer-other-window cur-buf) + )))) + + (defun ledger-reconcile (account) (interactive "sAccount to reconcile: ") (let ((buf (current-buffer)) @@ -240,6 +263,7 @@ (quit-window (get-buffer-window rbuf)) (kill-buffer rbuf))) (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save) + (add-hook 'post-command-hook 'ledger-reconcile-track-xact) (if ledger-fold-on-reconcile (ledger-occur-mode account buf)) -- cgit v1.2.3 From 7fe1506ea1bb0cb971fa7d0d83ef789c7daeee80 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 8 Feb 2013 17:20:56 -0700 Subject: code cleanup --- lisp/ldg-mode.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index f71bb58e..4754e423 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -28,17 +28,16 @@ (defvar ledger-year (ledger-current-year) "Start a ledger session with the current year, but make it customizable to ease retro-entry.") + (defvar ledger-month (ledger-current-month) "Start a ledger session with the current month, but make it customizable to ease retro-entry.") - (defcustom ledger-default-acct-transaction-indent " " "Default indentation for account transactions in an entry." :type 'string :group 'ledger) - (defvar ledger-mode-abbrev-table) ;;;###autoload -- cgit v1.2.3 From 222af8a047d5656a2b1070fbe49e66161e46f34f Mon Sep 17 00:00:00 2001 From: hrj Date: Sat, 9 Feb 2013 10:09:27 +0530 Subject: Update README.md Updated instructions for Ubuntu 12.04 Dropping some of the obsolete packages and dropping the specific version numbers in favour of generic ones. --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e44fd7b2..5ab146e2 100644 --- a/README.md +++ b/README.md @@ -95,12 +95,12 @@ You can even just install the current Ledger **RELEASE** directly: ### Ubuntu If you're going to build on Ubuntu, `sudo apt-get install ...` the -following packages (current as of Ubuntu Hardy): +following packages (current as of Ubuntu 12.04): sudo apt-get install build-essential cmake zlib1g-dev libbz2-dev - python-dev bjam cvs gettext libgmp3-dev libmpfr-dev libboost1.35-dev - libboost-regex1.35-dev libboost-date-time1.35-dev - libboost-filesystem1.35-dev libboost-python1.35-dev texinfo lcov + python-dev gettext libgmp3-dev libmpfr-dev libboost-dev + libboost-regex-dev libboost-date-time-dev + libboost-filesystem-dev libboost-python-dev texinfo lcov sloccount Or, for Ubuntu Karmic: @@ -159,5 +159,5 @@ Now that you're up and running, here are a few resources to keep in mind: If you have ideas you'd like to share, the best way is either to e-mail me a patch (I prefer attachments over pasted text), or to get an account on GitHub. -Once you do, fork the [Ledger project](http://github.com/jwiegley/ledger), +Once you do, fork the [Ledger project](http://github.com/ledger/ledger), hack as much as you like, then send me a pull request via GitHub. -- cgit v1.2.3 From 73f336ae7c89e6f1b5f38c32fe398f39ad3667b5 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 8 Feb 2013 22:49:39 -0700 Subject: Improved the visit function. Made the window position configurable. Removed after-save hook on quit --- lisp/ldg-reconcile.el | 115 ++++++++++++++++++++++++++------------------------ 1 file changed, 61 insertions(+), 54 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 395266e3..463eb9cf 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -40,6 +40,11 @@ buffer." :group 'ledger) +(defcustom ledger-reconcile-force-window-bottom nil + "If t make the reconcile window appear along the bottom of the + register window and resize" + :group 'ledger) + (defun ledger-display-balance () "Calculate the cleared balance of the account being reconciled" (interactive) @@ -62,8 +67,6 @@ (equal file "/dev/stdin"))) (defun ledger-reconcile-get-buffer (where) -; (when (is-stdin (car where)) -; ledger-buf)) (if (bufferp (car where)) (car where) (error "buffer not set"))) @@ -139,15 +142,19 @@ (delete-region (point) (1+ (line-end-position))) (set-buffer-modified-p t))))) -(defun ledger-reconcile-visit () - (interactive) - (let* ((where (get-text-property (point) 'where)) - (target-buffer (ledger-reconcile-get-buffer - where))) - (when target-buffer - (switch-to-buffer-other-window target-buffer) - (goto-char (cdr where)) - (recenter)))) +(defun ledger-reconcile-visit (&optional come-back) + (progn + (beginning-of-line) + (let* ((where (get-text-property (1+ (point)) 'where)) + (target-buffer (ledger-reconcile-get-buffer + where)) + (cur-buf (current-buffer))) + (when target-buffer + (switch-to-buffer-other-window target-buffer) + (goto-char (cdr where)) + (recenter) + (if come-back + (switch-to-buffer-other-window cur-buf)))))) (defun ledger-reconcile-save () (interactive) @@ -162,6 +169,9 @@ (defun ledger-reconcile-quit () (interactive) (let ((buf ledger-buf)) + (with-current-buffer ledger-buf + (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t)) + ;Make sure you delete the window before you delete the buffer, ;otherwise, madness ensues (delete-window (get-buffer-window (current-buffer))) @@ -198,25 +208,28 @@ (error (buffer-string))) (read (current-buffer)))))) (if (> (length items) 0) - (dolist (item items) - (let ((index 1)) - (dolist (xact (nthcdr 5 item)) - (let ((beg (point)) - (where (ledger-marker-where-xact-is item))) - (insert (format "%s %-4s %-30s %-30s %15s\n" - (format-time-string "%Y/%m/%d" (nth 2 item)) - (if (nth 3 item) - (nth 3 item) - "") - (nth 4 item) (nth 1 xact) (nth 2 xact))) - (if (nth 3 xact) - (set-text-properties beg (1- (point)) - (list 'face 'ledger-font-reconciler-cleared-face - 'where where)) - (set-text-properties beg (1- (point)) - (list 'face 'ledger-font-reconciler-uncleared-face - 'where where)))) - (setq index (1+ index))))) + (progn + (dolist (item items) + (let ((index 1)) + (dolist (xact (nthcdr 5 item)) + (let ((beg (point)) + (where (ledger-marker-where-xact-is item))) + (insert (format "%s %-4s %-30s %-30s %15s\n" + (format-time-string "%Y/%m/%d" (nth 2 item)) + (if (nth 3 item) + (nth 3 item) + "") + (nth 4 item) (nth 1 xact) (nth 2 xact))) + (if (nth 3 xact) + (set-text-properties beg (1- (point)) + (list 'face 'ledger-font-reconciler-cleared-face + 'where where)) + (set-text-properties beg (1- (point)) + (list 'face 'ledger-font-reconciler-uncleared-face + 'where where)))) + (setq index (1+ index))))) + (goto-char (point-max)) + (delete-char -1)) (insert (concat "There are no uncleared entries for " account))) (goto-char (point-min)) (set-buffer-modified-p nil) @@ -236,23 +249,16 @@ (goto-char (point-max)) (recenter -1)) - (select-window recon-window)))) + (select-window recon-window) + (add-hook 'post-command-hook 'ledger-reconcile-track-xact nil t) + (ledger-reconcile-visit t)))) (defun ledger-reconcile-track-xact () - (if (or (eq this-command 'next-line) - (eq this-command 'previous-line) - (eq this-command 'mouse-set-point)) - (let* ((where (get-text-property (point) 'where)) - (target-buffer (ledger-reconcile-get-buffer - where)) - (cur-buf (current-buffer))) - (when target-buffer - (switch-to-buffer-other-window target-buffer) - (goto-char (cdr where)) - (recenter) - (switch-to-buffer-other-window cur-buf) - )))) - + (if (member this-command (list 'next-line + 'previous-line + 'mouse-set-point + 'ledger-reconcile-toggle)) + (ledger-reconcile-visit t))) (defun ledger-reconcile (account) (interactive "sAccount to reconcile: ") @@ -262,18 +268,20 @@ (progn (quit-window (get-buffer-window rbuf)) (kill-buffer rbuf))) - (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save) - (add-hook 'post-command-hook 'ledger-reconcile-track-xact) + (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save nil t) (if ledger-fold-on-reconcile (ledger-occur-mode account buf)) - ;create the *Reconcile* window directly below the ledger buffer. (with-current-buffer - (progn - (set-window-buffer - (split-window (get-buffer-window (current-buffer)) nil nil) - (get-buffer-create ledger-recon-buffer-name)) - (get-buffer ledger-recon-buffer-name)) + (if ledger-reconcile-force-window-bottom + ;create the *Reconcile* window directly below the ledger + ;buffer. + (progn + (set-window-buffer + (split-window (get-buffer-window (current-buffer)) nil nil) + (get-buffer-create ledger-recon-buffer-name)) + (get-buffer ledger-recon-buffer-name)) + (pop-to-buffer (get-buffer-create ledger-recon-buffer-name))) (ledger-reconcile-mode) (set (make-local-variable 'ledger-buf) buf) (set (make-local-variable 'ledger-acct) account) @@ -286,7 +294,6 @@ (let ((map (make-sparse-keymap))) (define-key map [(control ?m)] 'ledger-reconcile-visit) (define-key map [return] 'ledger-reconcile-visit) - (define-key map [(control ?x) (control ?s)] 'ledger-reconcile-save) (define-key map [(control ?l)] 'ledger-reconcile-refresh) (define-key map [? ] 'ledger-reconcile-toggle) (define-key map [?a] 'ledger-reconcile-add) -- cgit v1.2.3 From 73f8c10d8e65de56a5708f6a93da340861bd9646 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 8 Feb 2013 23:42:52 -0700 Subject: More reconcile-visit bug squashing. --- lisp/ldg-reconcile.el | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 463eb9cf..5314f554 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -32,17 +32,20 @@ (defcustom ledger-fold-on-reconcile t "if t, limit transactions shown in main buffer to those matching the reconcile regex" + :type 'boolean :group 'ledger) (defcustom ledger-buffer-tracks-reconcile-buffer t "if t, then when the cursor is moved to a new xact in the recon window, then that transaction will be shown in its source buffer." + :type 'boolean :group 'ledger) (defcustom ledger-reconcile-force-window-bottom nil "If t make the reconcile window appear along the bottom of the register window and resize" + :type 'boolean :group 'ledger) (defun ledger-display-balance () @@ -146,8 +149,9 @@ (progn (beginning-of-line) (let* ((where (get-text-property (1+ (point)) 'where)) - (target-buffer (ledger-reconcile-get-buffer - where)) + (target-buffer (if where + (ledger-reconcile-get-buffer where) + nil)) (cur-buf (current-buffer))) (when target-buffer (switch-to-buffer-other-window target-buffer) -- cgit v1.2.3 From cf6a23b2fe27e67536bd389737ed0e3379c2ae14 Mon Sep 17 00:00:00 2001 From: Rémi Vanicat Date: Sat, 9 Feb 2013 11:16:52 +0100 Subject: Unconditionally activate the occur stuff in ledger-occur-mode Well, we still deactivate it when regex is nil, but the function should not look at previous value of ledger-occur-mode: - the interactive function (ledger-occur) already do it, we don't need to do it there, - caller that want to deactivate the occur stuff only have to call ledger-occur with a nil regex - the old behavior make ledger-reconcile to turn off occur stuff if it was already turn on, when what we do want is that the occur stuff change to the new account. --- lisp/ldg-occur.el | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index 2958c94c..5a7c8ed7 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -69,13 +69,14 @@ "A list of currently active overlays to the ledger buffer.") (make-variable-buffer-local 'ledger-occur-overlay-list) - (defun ledger-occur-mode (regex buffer) + "Higlight transaction that match REGEX, hiding others + +When REGEX is nil, unhide everything, and remove higlight" (progn (set-buffer buffer) (setq ledger-occur-mode - (if (or ledger-occur-mode - (null regex) + (if (or (null regex) (zerop (length regex))) nil (concat " Ledger-Folded: " regex))) -- cgit v1.2.3 From d3964b66d556557b16053aa781220d298dc60d3a Mon Sep 17 00:00:00 2001 From: Rémi Vanicat Date: Sat, 9 Feb 2013 11:33:33 +0100 Subject: In ledger-occur, hide nothing if there is no match This could cause error when reconciling transaction that are included. Some message should be shown to explain why nothing happen when interactively call ledger-occur. --- lisp/ldg-occur.el | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index 5a7c8ed7..e830f339 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -128,31 +128,32 @@ When REGEX is nil, unhide everything, and remove higlight" prompt)) (defun ledger-occur-create-folded-overlays(buffer-matches) - (let ((overlays - (let ((prev-end (point-min)) - (temp (point-max))) - (mapcar (lambda (match) - (progn - (setq temp prev-end) ;need a swap so that the + (if buffer-matches + (let ((overlays + (let ((prev-end (point-min)) + (temp (point-max))) + (mapcar (lambda (match) + (progn + (setq temp prev-end) ;need a swap so that the ;last form in the lambda ;is the (make-overlay) - (setq prev-end (1+ (cadr match))) ;add 1 so + (setq prev-end (1+ (cadr match))) ;add 1 so ;that we skip ;the empty ;line after ;the xact - (make-overlay - temp - (car match) - (current-buffer) t nil))) - buffer-matches)))) - (mapcar (lambda (ovl) - (overlay-put ovl ledger-occur-overlay-property-name t) - (overlay-put ovl 'invisible t) - (overlay-put ovl 'intangible t)) - (push (make-overlay (cadr (car(last buffer-matches))) - (point-max) - (current-buffer) t nil) overlays)))) + (make-overlay + temp + (car match) + (current-buffer) t nil))) + buffer-matches)))) + (mapcar (lambda (ovl) + (overlay-put ovl ledger-occur-overlay-property-name t) + (overlay-put ovl 'invisible t) + (overlay-put ovl 'intangible t)) + (push (make-overlay (cadr (car(last buffer-matches))) + (point-max) + (current-buffer) t nil) overlays))))) (defun ledger-occur-create-xact-overlays (ovl-bounds) -- cgit v1.2.3 From 0f83f779a627964f7f9044afd383b7a9152545b9 Mon Sep 17 00:00:00 2001 From: Rémi Vanicat Date: Sat, 9 Feb 2013 14:42:52 +0100 Subject: On move event, save excursion before calling ledger-reconcile-visit Otherwise, ledger-reconcile-visit might undo last move --- lisp/ldg-reconcile.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 5314f554..e0ba1ea7 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -262,7 +262,8 @@ 'previous-line 'mouse-set-point 'ledger-reconcile-toggle)) - (ledger-reconcile-visit t))) + (save-excursion + (ledger-reconcile-visit t)))) (defun ledger-reconcile (account) (interactive "sAccount to reconcile: ") -- cgit v1.2.3 From 47c3f6d353f37a265659595a4836c7524a62f7c4 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sat, 9 Feb 2013 07:27:47 -0700 Subject: Cleaned up a defcustom that was lacking a type --- lisp/ldg-occur.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index 2958c94c..0f1f4616 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -46,6 +46,7 @@ (defcustom ledger-occur-use-face-unfolded t "if non-nil use a custom face for xacts shown in ledger-occur mode" + :type 'boolean :group 'ledger) (make-variable-buffer-local 'ledger-occur-use-face-unfolded) -- cgit v1.2.3 From 69efea6c543bb128422633239e7618f0d0eda6cf Mon Sep 17 00:00:00 2001 From: Rémi Vanicat Date: Sat, 9 Feb 2013 19:29:04 +0100 Subject: Take care to not delete some random buffer when exiting reconcile --- lisp/ldg-reconcile.el | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index e0ba1ea7..b475ebb7 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -172,14 +172,15 @@ (defun ledger-reconcile-quit () (interactive) - (let ((buf ledger-buf)) + (let ((buf ledger-buf) + (reconcile-buf (current-buffer))) (with-current-buffer ledger-buf (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t)) ;Make sure you delete the window before you delete the buffer, ;otherwise, madness ensues - (delete-window (get-buffer-window (current-buffer))) - (kill-buffer (current-buffer)) + (delete-window (get-buffer-window reconcile-buf)) + (kill-buffer (reconcile-buf)) (if ledger-fold-on-reconcile (ledger-occur-quit-buffer buf)))) -- cgit v1.2.3 From 2b55ef7dab335f2ae914912d8e541f6228f57f19 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sat, 9 Feb 2013 17:45:31 -0700 Subject: Added menu entry to customize ledger mode --- lisp/ldg-mode.el | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 4754e423..83b5e5b4 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -98,6 +98,9 @@ customizable to ease retro-entry.") (define-key map [sep5] '(menu-item "--")) (define-key map [set-month] '(menu-item "Set Month" ledger-set-month :enable ledger-works)) (define-key map [set-year] '(menu-item "Set Year" ledger-set-year :enable ledger-works)) + (define-key map [cust] '(menu-item "Customize Ledger Mode" (lambda () + (interactive) + (customize-group 'ledger)))) (define-key map [sep1] '("--")) (define-key map [sort-buff] '(menu-item "Sort Buffer" ledger-sort-buffer)) (define-key map [sort-reg] '(menu-item "Sort Region" ledger-sort-region :enable mark-active)) -- cgit v1.2.3 From 114be62d248723bfae12e383b168f364857d8793 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sat, 9 Feb 2013 17:47:09 -0700 Subject: Correct error that prevented clearing postings if ledger--clear-whole-entires was nil --- lisp/ldg-reconcile.el | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index e0ba1ea7..e5048a8c 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -81,12 +81,10 @@ (account ledger-acct) (inhibit-read-only t) cleared) -; (when (is-stdin (car where)) -; (with-current-buffer ledger-buf (when (ledger-reconcile-get-buffer where) (with-current-buffer (ledger-reconcile-get-buffer where) (goto-char (cdr where)) - (setq cleared (ledger-toggle-current-entry))) + (setq cleared (ledger-toggle-current))) ;remove the existing face and add the new face (remove-text-properties (line-beginning-position) (line-end-position) @@ -146,6 +144,7 @@ (set-buffer-modified-p t))))) (defun ledger-reconcile-visit (&optional come-back) + (interactive) (progn (beginning-of-line) (let* ((where (get-text-property (1+ (point)) 'where)) @@ -162,8 +161,6 @@ (defun ledger-reconcile-save () (interactive) -; (with-current-buffer ledger-buf -; (save-buffer)) (dolist (buf (cons ledger-buf ledger-bufs)) (with-current-buffer buf (save-buffer))) @@ -194,7 +191,9 @@ (cons buf (save-excursion - (goto-line (nth 1 emacs-xact)) + (if ledger-clear-whole-entries + (goto-line (nth 1 emacs-xact)) + (goto-line (nth 0 (nth 5 emacs-xact)))) (point-marker)))))) (defun ledger-do-reconcile () @@ -262,8 +261,9 @@ 'previous-line 'mouse-set-point 'ledger-reconcile-toggle)) - (save-excursion - (ledger-reconcile-visit t)))) + (if ledger-buffer-tracks-reconcile-buffer + (save-excursion + (ledger-reconcile-visit t))))) (defun ledger-reconcile (account) (interactive "sAccount to reconcile: ") -- cgit v1.2.3 From 6fce572806eb39b5ba607bd5336adb6ca3ac2295 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sat, 9 Feb 2013 21:03:58 -0700 Subject: ledger-mode now highlights the xact under point. This can be configured with ledger-highlight-xact-under-point and ledger-font-highlight-face --- lisp/ldg-fonts.el | 5 +++++ lisp/ldg-mode.el | 6 ++++-- lisp/ldg-occur.el | 19 +------------------ lisp/ldg-reconcile.el | 1 + 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index 6032e361..62192881 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -31,6 +31,11 @@ "Default face for cleared (*) transactions" :group 'ledger-faces) +(defface ledger-font-highlight-face + `((t :background "#003366" :weight normal )) + "Default face for transaction under point" + :group 'ledger-faces) + (defface ledger-font-pending-face `((t :foreground "yellow" :weight normal )) "Default face for pending (!) transactions" diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 83b5e5b4..a2c87048 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -60,6 +60,9 @@ customizable to ease retro-entry.") 'ledger-complete-at-point) (set (make-local-variable 'pcomplete-termination-string) "") + (add-hook 'post-command-hook 'ledger-highlight-xact-under-point nil t) + (make-variable-buffer-local 'highlight-overlay) + (let ((map (current-local-map))) (define-key map [(control ?c) (control ?a)] 'ledger-add-entry) (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-entry) @@ -114,8 +117,7 @@ customizable to ease retro-entry.") (define-key map [add-xact] '(menu-item "Add Entry" ledger-add-entry :enable ledger-works)) (define-key map [sep3] '(menu-item "--")) (define-key map [reconcile] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works)) - (define-key map [reconcile] '(menu-item "Hide Xacts" ledger-occur)) - )) + (define-key map [reconcile] '(menu-item "Hide Xacts" ledger-occur)))) (defun ledger-time-less-p (t1 t2) "Say whether time value T1 is less than time value T2." diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index d498b9e4..1afb0e90 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -208,23 +208,6 @@ When REGEX is nil, unhide everything, and remove higlight" buffer-matches) (setq overlays (nreverse overlays))))) -(defun ledger-occur-find-xact-extents (pos) - "return point for beginning of xact and and of xact containing - position. Requires empty line separating xacts" - (interactive "d") - (save-excursion - (goto-char pos) - (let ((end-pos pos) - (beg-pos pos)) - (backward-paragraph) - (forward-line) - (beginning-of-line) - (setq beg-pos (point)) - (forward-paragraph) - (forward-line -1) - (end-of-line) - (setq end-pos (1+ (point))) - (list beg-pos end-pos)))) (defun ledger-occur-find-matches (regex) "Returns a list of 2-number tuples, specifying begnning of the @@ -241,7 +224,7 @@ When REGEX is nil, unhide everything, and remove higlight" ;; if something found (when (setq endpoint (re-search-forward regex nil 'end)) (save-excursion - (let ((bounds (ledger-occur-find-xact-extents (match-beginning 0)))) + (let ((bounds (ledger-find-xact-extents (match-beginning 0)))) (push bounds lines) (setq curpoint (cadr bounds)))) ;move to the end of the ;xact, no need to search diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index e5048a8c..ed3fbcb5 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -156,6 +156,7 @@ (switch-to-buffer-other-window target-buffer) (goto-char (cdr where)) (recenter) + (ledger-highlight-xact-under-point) (if come-back (switch-to-buffer-other-window cur-buf)))))) -- cgit v1.2.3 From 0c8a660d6035d34a82a1cacaa47b93acafc9d47e Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sat, 9 Feb 2013 21:05:08 -0700 Subject: Forgot to stage ldg-xact.el in the last commit --- lisp/ldg-xact.el | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index 1df7d79a..e7402652 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -22,6 +22,46 @@ ;; A sample entry sorting function, which works if entry dates are of ;; the form YYYY/mm/dd. +(defcustom ledger-highlight-xact-under-point t + "If t highlight xact under point" + :type 'boolean + :group 'ledger) + +(defvar highlight-overlay (list)) + +(defun ledger-find-xact-extents (pos) + "return point for beginning of xact and and of xact containing + position. Requires empty line separating xacts" + (interactive "d") + (save-excursion + (goto-char pos) + (let ((end-pos pos) + (beg-pos pos)) + (backward-paragraph) + (forward-line) + (beginning-of-line) + (setq beg-pos (point)) + (forward-paragraph) + (forward-line -1) + (end-of-line) + (setq end-pos (1+ (point))) + (list beg-pos end-pos)))) + + +(defun ledger-highlight-xact-under-point () + (if ledger-highlight-xact-under-point + (let ((exts (ledger-find-xact-extents (point))) + (ovl highlight-overlay)) + (if (not highlight-overlay) + (setq ovl + (setq highlight-overlay + (make-overlay (car exts) + (cadr exts) + (current-buffer) t nil))) + (move-overlay ovl (car exts) (cadr exts))) + (overlay-put ovl 'face 'ledger-font-highlight-face) + (overlay-put ovl 'priority 100)))) + (provide 'ldg-xact) \ No newline at end of file -- cgit v1.2.3 From e757b969efd3dba04e2f0fbe21e88f4081f785b2 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sun, 10 Feb 2013 09:47:56 -0700 Subject: fixe minor error in merge from vanicat --- lisp/ldg-reconcile.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index afecf2eb..3c258d13 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -178,7 +178,7 @@ ;Make sure you delete the window before you delete the buffer, ;otherwise, madness ensues (delete-window (get-buffer-window reconcile-buf)) - (kill-buffer (reconcile-buf)) + (kill-buffer reconcile-buf) (if ledger-fold-on-reconcile (ledger-occur-quit-buffer buf)))) -- cgit v1.2.3 From 30c95ea9bba5ebe2e202a3dda3af6431ea21337c Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sun, 10 Feb 2013 10:11:15 -0700 Subject: Changes keybinding for edit amount to C-c C-b Thierry rightly pointed out that C-c C-v was a much older emacs command and I shouldn't stomp on it. --- lisp/ldg-mode.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index a2c87048..26d0ed68 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -73,7 +73,7 @@ customizable to ease retro-entry.") (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) (define-key map [(control ?c) (control ?t)] 'ledger-test-run) - (define-key map [(control ?c) (control ?v)] 'ledger-post-edit-amount) + (define-key map [(control ?c) (control ?b)] 'ledger-post-edit-amount) (define-key map [(control ?c) (control ?f)] 'ledger-occur) (define-key map [tab] 'pcomplete) (define-key map [(control ?i)] 'pcomplete) -- cgit v1.2.3 From e460316774e9e0f61d447dfde16e92313eb30535 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sun, 10 Feb 2013 20:11:03 -0700 Subject: Fixes bug 885, highlighting was removing bolding Inadvertantly left a :weight in the highlight face that was over ring the base face weight --- lisp/ldg-fonts.el | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index 62192881..6ddc811c 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -27,17 +27,17 @@ :group 'ledger-faces) (defface ledger-font-cleared-face - `((t :foreground "grey70" :weight normal )) + `((t :foreground "#657b83" :weight normal )) "Default face for cleared (*) transactions" :group 'ledger-faces) (defface ledger-font-highlight-face - `((t :background "#003366" :weight normal )) + `((t :background "#eee8d5")) "Default face for transaction under point" :group 'ledger-faces) (defface ledger-font-pending-face - `((t :foreground "yellow" :weight normal )) + `((t :foreground "#cb4b16" :weight normal )) "Default face for pending (!) transactions" :group 'ledger-faces) @@ -47,7 +47,7 @@ :group 'ledger-faces) (defface ledger-font-posting-account-face - `((t :foreground "lightblue" )) + `((t :foreground "#268bd2" )) "Face for Ledger accounts" :group 'ledger-faces) @@ -57,22 +57,22 @@ :group 'ledger-faces) (defface ledger-font-comment-face - `((t :foreground "orange" )) + `((t :foreground "#93a1a1" :slant italic)) "Face for Ledger comments" :group 'ledger-faces) (defface ledger-font-reconciler-uncleared-face - `((t :foreground "green" :weight normal )) + `((t :foreground "#dc322f" :weight bold )) "Default face for uncleared transactions in the reconcile window" :group 'ledger-faces) (defface ledger-font-reconciler-cleared-face - `((t :foreground "grey70" :weight normal )) + `((t :foreground "#657b83" :weight normal )) "Default face for cleared (*) transactions in the reconcile window" :group 'ledger-faces) (defface ledger-font-reconciler-pending-face - `((t :foreground "yellow" :weight normal )) + `((t :foreground "#cb4b16" :weight normal )) "Default face for pending (!) transactions in the reconcile window" :group 'ledger-faces) -- cgit v1.2.3 From eef9245eb810820643a5960426265edd5578c656 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Mon, 11 Feb 2013 09:11:03 -0700 Subject: Face reorganization and better color theme Moved all face definitions to leg-fonts.el. Change default colors to Solarize color theme http://ethanschoonover.com/solarized --- lisp/ldg-fonts.el | 14 ++++++++++++-- lisp/ldg-occur.el | 10 ---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index 6ddc811c..d72c9403 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -22,7 +22,7 @@ (defgroup ledger-faces nil "Ledger mode highlighting" :group 'ledger) (defface ledger-font-uncleared-face - `((t :foreground "green" :weight bold )) + `((t :foreground "#dc322f" :weight bold )) "Default face for Ledger" :group 'ledger-faces) @@ -32,7 +32,7 @@ :group 'ledger-faces) (defface ledger-font-highlight-face - `((t :background "#eee8d5")) + `((t :background "white")) "Default face for transaction under point" :group 'ledger-faces) @@ -56,6 +56,16 @@ "Face for Ledger amounts" :group 'ledger-faces) +(defface ledger-occur-folded-face + `((t :foreground "grey70" :invisible t )) + "Default face for Ledger occur mode hidden transactions" + :group 'ledger-faces) + +(defface ledger-occur-xact-face + `((t :background "#eee8d5" )) + "Default face for Ledger occur mode shown transactions" + :group 'ledger-faces) + (defface ledger-font-comment-face `((t :foreground "#93a1a1" :slant italic)) "Face for Ledger comments" diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index 1afb0e90..bd5a49b1 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -32,16 +32,6 @@ ;;; Code: -(defface ledger-occur-folded-face - `((t :foreground "grey70" :invisible t )) - "Default face for Ledger occur mode hidden transactions" - :group 'ledger-faces) - -(defface ledger-occur-xact-face - `((t :background "blue" :weight normal )) - "Default face for Ledger occur mode shown transactions" - :group 'ledger-faces) - (defconst ledger-occur-overlay-property-name 'ledger-occur-custom-buffer-grep) (defcustom ledger-occur-use-face-unfolded t -- cgit v1.2.3 From e245e41d6bfb1ef8799d9174e2bc5c6687880aa8 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Mon, 11 Feb 2013 10:50:13 -0700 Subject: Bug 887. Remove folding if the reconcile buffer is killed This ensure adequate cleanup if the reconciliation buffer is killed vice quit from. --- lisp/ldg-reconcile.el | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 3c258d13..5f023eb5 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -170,17 +170,25 @@ (defun ledger-reconcile-quit () (interactive) + ;(ledger-reconcile-quit-cleanup) (let ((buf ledger-buf) - (reconcile-buf (current-buffer))) - (with-current-buffer ledger-buf + (recon-buf (get-buffer ledger-recon-buffer-name))) + ;Make sure you delete the window before you delete the buffer, + ;otherwise, madness ensues + (with-current-buffer recon-buf + (delete-window (get-buffer-window recon-buf)) + (kill-buffer recon-buf)) + (set-window-buffer (selected-window) buf))) + +(defun ledger-reconcile-quit-cleanup () + (interactive) + (let ((buf ledger-buf) + (reconcile-buf (get-buffer ledger-recon-buffer-name))) + (with-current-buffer buf (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t)) - - ;Make sure you delete the window before you delete the buffer, - ;otherwise, madness ensues - (delete-window (get-buffer-window reconcile-buf)) - (kill-buffer reconcile-buf) (if ledger-fold-on-reconcile - (ledger-occur-quit-buffer buf)))) + (ledger-occur-quit-buffer buf)))) + (defun ledger-marker-where-xact-is (emacs-xact) "find the position of the xact in the ledger-buf buffer using @@ -330,6 +338,8 @@ (define-key map [menu-bar ldg-recon-menu ref] '("Refresh" . ledger-reconcile-refresh)) (define-key map [menu-bar ldg-recon-menu sav] '("Save" . ledger-reconcile-save)) - (use-local-map map))) + (use-local-map map) + + (add-hook 'kill-buffer-hook 'ledger-reconcile-quit-cleanup nil t))) (provide 'ldg-reconcile) \ No newline at end of file -- cgit v1.2.3 From e615d8c615c43bf1e04b0a29747f05188fd46fbd Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Mon, 11 Feb 2013 11:05:43 -0700 Subject: Bug 883 overlays left in buffer if file reverted. --- lisp/ldg-mode.el | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 26d0ed68..0ff22417 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -38,6 +38,11 @@ customizable to ease retro-entry.") :type 'string :group 'ledger) +(defun ledger-remove-overlays () + (interactive) + "remove overlays formthe buffer, used if the buffer is reverted" + (remove-overlays)) + (defvar ledger-mode-abbrev-table) ;;;###autoload @@ -61,6 +66,7 @@ customizable to ease retro-entry.") (set (make-local-variable 'pcomplete-termination-string) "") (add-hook 'post-command-hook 'ledger-highlight-xact-under-point nil t) + (add-hook 'before-revert-hook 'ledger-remove-overlays nil t) (make-variable-buffer-local 'highlight-overlay) (let ((map (current-local-map))) -- cgit v1.2.3 From fa1702d68458e400d57d61b5cbec20ec4027dbb7 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Mon, 11 Feb 2013 11:12:50 -0700 Subject: Bug 886 Cannot unclear transaction on last line reconciliation buffer --- lisp/ldg-reconcile.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 5f023eb5..a53f2ade 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -97,6 +97,7 @@ (line-end-position) (list 'face 'ledger-font-reconciler-uncleared-face )))) (forward-line) + (beginning-of-line) (ledger-display-balance))) (defun ledger-reconcile-new-account (account) -- cgit v1.2.3 From d243f00b914ba68380a51696f4ac68e066119a99 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Mon, 11 Feb 2013 12:49:51 -0700 Subject: Bug 878 Cannot reconcile two posting with the same account in one xact --- lisp/ldg-reconcile.el | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index a53f2ade..d00abe1a 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -190,8 +190,7 @@ (if ledger-fold-on-reconcile (ledger-occur-quit-buffer buf)))) - -(defun ledger-marker-where-xact-is (emacs-xact) +(defun ledger-marker-where-xact-is (emacs-xact posting) "find the position of the xact in the ledger-buf buffer using the emacs output from ledger, return the buffer and a marker to the beginning of the xact in that buffer" @@ -204,15 +203,15 @@ (save-excursion (if ledger-clear-whole-entries (goto-line (nth 1 emacs-xact)) - (goto-line (nth 0 (nth 5 emacs-xact)))) - (point-marker)))))) + (goto-line (nth 0 posting))) + (1+ (point-marker))))))) ;Add 1 to make sure the marker is within the transaction (defun ledger-do-reconcile () "get the uncleared transactions in the account and display them in the *Reconcile* buffer" (let* ((buf ledger-buf) (account ledger-acct) - (items + (xacts (with-temp-buffer (ledger-exec-ledger buf (current-buffer) "--uncleared" "--real" "emacs" account) @@ -221,20 +220,20 @@ (unless (looking-at "(") (error (buffer-string))) (read (current-buffer)))))) - (if (> (length items) 0) + (if (> (length xacts) 0) (progn - (dolist (item items) + (dolist (xact xacts) (let ((index 1)) - (dolist (xact (nthcdr 5 item)) + (dolist (posting (nthcdr 5 xact)) (let ((beg (point)) - (where (ledger-marker-where-xact-is item))) + (where (ledger-marker-where-xact-is xact posting))) (insert (format "%s %-4s %-30s %-30s %15s\n" - (format-time-string "%Y/%m/%d" (nth 2 item)) - (if (nth 3 item) - (nth 3 item) + (format-time-string "%Y/%m/%d" (nth 2 xact)) + (if (nth 3 xact) + (nth 3 xact) "") - (nth 4 item) (nth 1 xact) (nth 2 xact))) - (if (nth 3 xact) + (nth 4 xact) (nth 1 posting) (nth 2 posting))) + (if (nth 3 posting) (set-text-properties beg (1- (point)) (list 'face 'ledger-font-reconciler-cleared-face 'where where)) -- cgit v1.2.3 From 36a00113d9fbe8fe18ff3adb4c4be80291f7066d Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Mon, 11 Feb 2013 16:26:41 -0700 Subject: Bug 879 cannot reconcile two ledger buffers --- lisp/ldg-reconcile.el | 101 +++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index d00abe1a..d59185b1 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -74,7 +74,6 @@ (car where) (error "buffer not set"))) - (defun ledger-reconcile-toggle () (interactive) (let ((where (get-text-property (point) 'where)) @@ -100,15 +99,6 @@ (beginning-of-line) (ledger-display-balance))) -(defun ledger-reconcile-new-account (account) - (interactive "sAccount to reconcile: ") - (set (make-local-variable 'ledger-acct) account) - (let ((buf (current-buffer))) - (if ledger-fold-on-reconcile - (ledger-occur-change-regex account ledger-buf)) - (set-buffer buf) - (ledger-reconcile-refresh))) - (defun ledger-reconcile-refresh () (interactive) (let ((inhibit-read-only t) @@ -152,7 +142,7 @@ (target-buffer (if where (ledger-reconcile-get-buffer where) nil)) - (cur-buf (current-buffer))) + (cur-buf (get-buffer ledger-recon-buffer-name))) (when target-buffer (switch-to-buffer-other-window target-buffer) (goto-char (cdr where)) @@ -171,11 +161,11 @@ (defun ledger-reconcile-quit () (interactive) - ;(ledger-reconcile-quit-cleanup) + (ledger-reconcile-quit-cleanup) (let ((buf ledger-buf) (recon-buf (get-buffer ledger-recon-buffer-name))) - ;Make sure you delete the window before you delete the buffer, - ;otherwise, madness ensues + ;Make sure you delete the window before you delete the buffer, + ;otherwise, madness ensues (with-current-buffer recon-buf (delete-window (get-buffer-window recon-buf)) (kill-buffer recon-buf)) @@ -186,9 +176,9 @@ (let ((buf ledger-buf) (reconcile-buf (get-buffer ledger-recon-buffer-name))) (with-current-buffer buf - (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t)) - (if ledger-fold-on-reconcile - (ledger-occur-quit-buffer buf)))) + (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t) + (if ledger-fold-on-reconcile + (ledger-occur-quit-buffer buf))))) (defun ledger-marker-where-xact-is (emacs-xact posting) "find the position of the xact in the ledger-buf buffer using @@ -219,11 +209,10 @@ (unless (eobp) (unless (looking-at "(") (error (buffer-string))) - (read (current-buffer)))))) + (read (current-buffer)))))) ;current-buffer is the *temp* created above (if (> (length xacts) 0) (progn (dolist (xact xacts) - (let ((index 1)) (dolist (posting (nthcdr 5 xact)) (let ((beg (point)) (where (ledger-marker-where-xact-is xact posting))) @@ -239,18 +228,17 @@ 'where where)) (set-text-properties beg (1- (point)) (list 'face 'ledger-font-reconciler-uncleared-face - 'where where)))) - (setq index (1+ index))))) + 'where where)))) )) (goto-char (point-max)) - (delete-char -1)) + (delete-char -1)) ;gets rid of the extra line feed at the bottom of the list (insert (concat "There are no uncleared entries for " account))) (goto-char (point-min)) (set-buffer-modified-p nil) (toggle-read-only t) ; this next piece of code ensures that the last of the visible - ; transactions in the ledger buffer is at the bottom of the - ; main window. The key to this is to ensure the window is selected + ; transactions in the ledger buffer is at the bottom of the main + ; window. The key to this is to ensure the window is selected ; when the buffer point is moved and recentered. If they aren't ; strange things happen. @@ -278,32 +266,44 @@ (defun ledger-reconcile (account) (interactive "sAccount to reconcile: ") (let ((buf (current-buffer)) - (rbuf (get-buffer ledger-recon-buffer-name))) - (if rbuf - (progn - (quit-window (get-buffer-window rbuf)) - (kill-buffer rbuf))) - (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save nil t) - (if ledger-fold-on-reconcile - (ledger-occur-mode account buf)) - - (with-current-buffer - (if ledger-reconcile-force-window-bottom - ;create the *Reconcile* window directly below the ledger - ;buffer. - (progn - (set-window-buffer - (split-window (get-buffer-window (current-buffer)) nil nil) - (get-buffer-create ledger-recon-buffer-name)) - (get-buffer ledger-recon-buffer-name)) - (pop-to-buffer (get-buffer-create ledger-recon-buffer-name))) - (ledger-reconcile-mode) - (set (make-local-variable 'ledger-buf) buf) - (set (make-local-variable 'ledger-acct) account) - (ledger-do-reconcile)))) + (rbuf (get-buffer ledger-recon-buffer-name))) ;this means only one *Reconcile* buffer, ever + (if rbuf ; *Reconcile* already exists + (with-current-buffer rbuf + (set 'ledger-acct account) ; already buffer local + (if (not (eq buf rbuf)) + (progn ; called from some other ledger-mode buffer + (ledger-reconcile-quit-cleanup) + (set 'ledger-buf buf))) ; should already be buffer-local + (if ledger-fold-on-reconcile + (ledger-occur-change-regex account ledger-buf)) + (set-buffer (get-buffer ledger-recon-buffer-name)) + (ledger-reconcile-refresh)) + + (progn ; no recon-buffer, starting from scratch. + (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save nil t) + (if ledger-fold-on-reconcile + (ledger-occur-mode account buf)) + + (with-current-buffer + (if ledger-reconcile-force-window-bottom + ;create the *Reconcile* window directly below the ledger buffer. + (progn + (set-window-buffer + (split-window (get-buffer-window buf) nil nil) + (get-buffer-create ledger-recon-buffer-name)) + (get-buffer ledger-recon-buffer-name)) + (pop-to-buffer (get-buffer-create ledger-recon-buffer-name))) + (ledger-reconcile-mode) + (set (make-local-variable 'ledger-buf) buf) + (set (make-local-variable 'ledger-acct) account) + (ledger-do-reconcile)))))) (defvar ledger-reconcile-mode-abbrev-table) +(defun ledger-reconcile-display-internals () + (interactive) + (message "%S %S" ledger-acct ledger-buf)) + (define-derived-mode ledger-reconcile-mode text-mode "Reconcile" "A mode for reconciling ledger entries." (let ((map (make-sparse-keymap))) @@ -313,12 +313,13 @@ (define-key map [? ] 'ledger-reconcile-toggle) (define-key map [?a] 'ledger-reconcile-add) (define-key map [?d] 'ledger-reconcile-delete) - (define-key map [?g] 'ledger-reconcile-new-account) + (define-key map [?g] 'ledger-reconcile); (define-key map [?n] 'next-line) (define-key map [?p] 'previous-line) (define-key map [?s] 'ledger-reconcile-save) (define-key map [?q] 'ledger-reconcile-quit) (define-key map [?b] 'ledger-display-balance) + (define-key map [?i] 'ledger-reconcile-display-internals) (define-key map [menu-bar] (make-sparse-keymap "ldg-recon-menu")) (define-key map [menu-bar ldg-recon-menu] (cons "Reconcile" map)) @@ -334,10 +335,10 @@ (define-key map [menu-bar ldg-recon-menu sep3] '("--")) (define-key map [menu-bar ldg-recon-menu bal] '("Show Cleared Balance" . ledger-display-balance)) (define-key map [menu-bar ldg-recon-menu sep4] '("--")) - (define-key map [menu-bar ldg-recon-menu rna] '("Reconcile New Account" . ledger-reconcile-new-account)) + (define-key map [menu-bar ldg-recon-menu rna] '("Reconcile New Account" . ledger-reconcile)) (define-key map [menu-bar ldg-recon-menu ref] '("Refresh" . ledger-reconcile-refresh)) (define-key map [menu-bar ldg-recon-menu sav] '("Save" . ledger-reconcile-save)) - + (use-local-map map) (add-hook 'kill-buffer-hook 'ledger-reconcile-quit-cleanup nil t))) -- cgit v1.2.3 From e3b37ac19edfa5ff8e766258f38d1632b667848e Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 12 Feb 2013 10:35:27 -0700 Subject: Lisp code cleanup. Mostly went through and clarified variable names. Rather than "entry" for everything, use "transaction" and "posting" as appropriate to improve readability. --- lisp/ldg-complete.el | 28 +++++++++++++++------------- lisp/ldg-mode.el | 26 +++++++++++++------------- lisp/ldg-new.el | 4 ---- lisp/ldg-post.el | 5 ++--- lisp/ldg-reconcile.el | 23 ++++++++++++++++++++--- lisp/ldg-register.el | 2 +- lisp/ldg-report.el | 2 +- lisp/ldg-state.el | 16 ++++++++-------- 8 files changed, 60 insertions(+), 46 deletions(-) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index 996df558..b56a85ed 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -30,10 +30,10 @@ (goto-char (line-beginning-position)) (cond ((looking-at "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.+?)\\)?\\s-+") (goto-char (match-end 0)) - 'entry) + 'transaction) ((looking-at "^\\s-+\\([*!]\\s-+\\)?[[(]?\\(.\\)") (goto-char (match-beginning 2)) - 'transaction) + 'posting) ((looking-at "^\\(sun\\|mon\\|tue\\|wed\\|thu\\|fri\\|sat\\)\\s-+") (goto-char (match-end 0)) 'entry) @@ -57,24 +57,26 @@ args))) (cons (reverse args) (reverse begins))))) -(defun ledger-entries () +(defun ledger-payees () (let ((origin (point)) - entries-list) + payees-list) (save-excursion (goto-char (point-min)) (while (re-search-forward (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" - "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) + "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) ;matches first line of transaction (unless (and (>= origin (match-beginning 0)) (< origin (match-end 0))) - (setq entries-list (cons (match-string-no-properties 3) - entries-list))))) - (pcomplete-uniqify-list (nreverse entries-list)))) + (setq payees-list (cons (match-string-no-properties 3) + payees-list))))) ;add the payee to the list + (pcomplete-uniqify-list (nreverse payees-list)))) (defvar ledger-account-tree nil) (defun ledger-find-accounts () - (let ((origin (point)) account-path elements) + (let ((origin (point)) + account-path + elements) (save-excursion (setq ledger-account-tree (list t)) (goto-char (point-min)) @@ -126,16 +128,16 @@ (interactive) (while (pcomplete-here (if (eq (save-excursion - (ledger-thing-at-point)) 'entry) + (ledger-thing-at-point)) 'transaction) (if (null current-prefix-arg) - (ledger-entries) ; this completes against entry names + (ledger-payees) ; this completes against payee names (progn (let ((text (buffer-substring (line-beginning-position) (line-end-position)))) (delete-region (line-beginning-position) (line-end-position)) (condition-case err - (ledger-add-entry text t) + (ledger-add-transaction text t) ((error) (insert text)))) (forward-line) @@ -151,7 +153,7 @@ (let ((name (caar (ledger-parse-arguments))) xacts) (save-excursion - (when (eq 'entry (ledger-thing-at-point)) + (when (eq 'transaction (ledger-thing-at-point)) (when (re-search-backward (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" (regexp-quote name) "\\(\t\\|\n\\| [ \t]\\)") nil t) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 0ff22417..628b4b8a 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -70,8 +70,8 @@ customizable to ease retro-entry.") (make-variable-buffer-local 'highlight-overlay) (let ((map (current-local-map))) - (define-key map [(control ?c) (control ?a)] 'ledger-add-entry) - (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-entry) + (define-key map [(control ?c) (control ?a)] 'ledger-add-transaction) + (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-transaction) (define-key map [(control ?c) (control ?y)] 'ledger-set-year) (define-key map [(control ?c) (control ?m)] 'ledger-set-month) (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) @@ -119,8 +119,8 @@ customizable to ease retro-entry.") (define-key map [sep4] '(menu-item "--")) (define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount)) (define-key map [sep] '(menu-item "--")) - (define-key map [delete-xact] '(menu-item "Delete Entry" ledger-delete-current-entry)) - (define-key map [add-xact] '(menu-item "Add Entry" ledger-add-entry :enable ledger-works)) + (define-key map [delete-xact] '(menu-item "Delete Entry" ledger-delete-current-transaction)) + (define-key map [add-xact] '(menu-item "Add Transaction" ledger-add-transaction :enable ledger-works)) (define-key map [sep3] '(menu-item "--")) (define-key map [reconcile] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works)) (define-key map [reconcile] '(menu-item "Hide Xacts" ledger-occur)))) @@ -140,13 +140,13 @@ Return the difference in the format of a time value." (defun ledger-find-slot (moment) (catch 'found - (ledger-iterate-entries + (ledger-iterate-transactions (function (lambda (start date mark desc) (if (ledger-time-less-p moment date) (throw 'found t))))))) -(defun ledger-iterate-entries (callback) +(defun ledger-iterate-transactions (callback) (goto-char (point-min)) (let* ((now (current-time)) (current-year (nth 5 (decode-time now)))) @@ -187,11 +187,11 @@ Return the difference in the format of a time value." (setq ledger-month (read-string "Month: " (ledger-current-month))) (setq ledger-month (format "%02d" newmonth)))) -(defun ledger-add-entry (entry-text &optional insert-at-point) +(defun ledger-add-transaction (transaction-text &optional insert-at-point) (interactive (list - (read-string "Entry: " (concat ledger-year "/" ledger-month "/")))) + (read-string "Transaction: " (concat ledger-year "/" ledger-month "/")))) (let* ((args (with-temp-buffer - (insert entry-text) + (insert transaction-text) (eshell-parse-arguments (point-min) (point-max)))) (ledger-buf (current-buffer)) exit-code) @@ -208,7 +208,7 @@ Return the difference in the format of a time value." (insert (with-temp-buffer (setq exit-code - (apply #'ledger-exec-ledger ledger-buf ledger-buf "entry" + (apply #'ledger-exec-ledger ledger-buf ledger-buf "xact" (mapcar 'eval args))) (goto-char (point-min)) (if (looking-at "Error: ") @@ -219,7 +219,7 @@ Return the difference in the format of a time value." (insert (car args) " \n\n") (end-of-line -1))))) -(defun ledger-current-entry-bounds () +(defun ledger-current-transaction-bounds () (save-excursion (when (or (looking-at "^[0-9]") (re-search-backward "^[0-9]" nil t)) @@ -228,9 +228,9 @@ Return the difference in the format of a time value." (forward-line)) (cons (copy-marker beg) (point-marker)))))) -(defun ledger-delete-current-entry () +(defun ledger-delete-current-transaction () (interactive) - (let ((bounds (ledger-current-entry-bounds))) + (let ((bounds (ledger-current-transaction-bounds))) (delete-region (car bounds) (cdr bounds)))) (provide 'ldg-mode) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index 3ee48897..ad21564a 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -47,10 +47,6 @@ (require 'ldg-fonts) (require 'ldg-occur) - ;(autoload #'ledger-mode "ldg-mode" nil t) - ;(autoload #'ledger-fully-complete-entry "ldg-complete" nil t) - ;(autoload #'ledger-toggle-current "ldg-state" nil t) - (autoload #'ledger-texi-update-test "ldg-texi" nil t) (autoload #'ledger-texi-update-examples "ldg-texi" nil t) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index ff664b1d..7b6ac9d5 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -158,7 +158,7 @@ This is done so that the last digit falls in COLUMN, which defaults to 52." (goto-char (line-beginning-position)) (when (re-search-forward ledger-post-line-regexp (line-end-position) t) (goto-char (match-end ledger-regex-post-line-group-account)) ;go to the and of the account - (let ((end-of-amount (re-search-forward "[-.,0-9]+" (line-end-position) t))) ;determine if the is an amount to edit + (let ((end-of-amount (re-search-forward "[-.,0-9]+" (line-end-position) t))) ;determine if there is an amount to edit (if end-of-amount (let ((val (match-string 0))) (goto-char (match-beginning 0)) @@ -171,8 +171,7 @@ This is done so that the last digit falls in COLUMN, which defaults to 52." (if (search-backward " " (- (point) 3) t) (goto-char (line-end-position)) (insert " ")) - (calc)) - )))) + (calc)))))) (defun ledger-post-prev-xact () (interactive) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index d59185b1..6179428f 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -119,7 +119,7 @@ (defun ledger-reconcile-add () (interactive) (with-current-buffer ledger-buf - (call-interactively #'ledger-add-entry)) + (call-interactively #'ledger-add-transaction)) (ledger-reconcile-refresh)) (defun ledger-reconcile-delete () @@ -128,7 +128,7 @@ (when (ledger-reconcile-get-buffer where) (with-current-buffer (ledger-reconcile-get-buffer where) (goto-char (cdr where)) - (ledger-delete-current-entry)) + (ledger-delete-current-transaction)) (let ((inhibit-read-only t)) (goto-char (line-beginning-position)) (delete-region (point) (1+ (line-end-position))) @@ -159,6 +159,23 @@ (set-buffer-modified-p nil) (ledger-display-balance)) +(defun ledger-reconcile-finish () + "Mark all pending transactions as cleared, save the buffers and exit reconcile mode" + (interactive) + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (let ((where (get-text-property (point) 'where)) + (face (get-text-property (point) 'face))) + (if (and (eq face 'bold) + (when (is-stdin (car where)))) + (with-current-buffer ledger-buf + (goto-char (cdr where)) + (ledger-toggle-current 'cleared)))) + (forward-line 1))) + (ledger-reconcile-save)) + + (defun ledger-reconcile-quit () (interactive) (ledger-reconcile-quit-cleanup) @@ -191,7 +208,7 @@ (cons buf (save-excursion - (if ledger-clear-whole-entries + (if ledger-clear-whole-transactions (goto-line (nth 1 emacs-xact)) (goto-line (nth 0 posting))) (1+ (point-marker))))))) ;Add 1 to make sure the marker is within the transaction diff --git a/lisp/ldg-register.el b/lisp/ldg-register.el index adb37a1a..6e98f20d 100644 --- a/lisp/ldg-register.el +++ b/lisp/ldg-register.el @@ -51,7 +51,7 @@ (with-current-buffer data-buffer (cons (nth 0 post) - (if ledger-clear-whole-entries + (if ledger-clear-whole-transactions (save-excursion (goto-line (nth 1 post)) (point-marker)) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index cdef6ded..2bb83516 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -216,7 +216,7 @@ end of a ledger file which is included in some other file." The user is prompted to enter a payee and that is substitued. If point is in an entry, the payee for that entry is used as the default." - ;; It is intended copmletion should be available on existing + ;; It is intended completion should be available on existing ;; payees, but the list of possible completions needs to be ;; developed to allow this. (ledger-read-string-with-default "Payee" (regexp-quote (ledger-entry-payee)))) diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index 41c0d8f2..ac0511f8 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -19,8 +19,8 @@ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. -(defcustom ledger-clear-whole-entries nil - "If non-nil, clear whole entries, not individual transactions." +(defcustom ledger-clear-whole-transactions nil + "If non-nil, clear whole transactions, not individual postings." :type 'boolean :group 'ledger) @@ -32,7 +32,7 @@ 'pending 'cleared))) -(defun ledger-entry-state () +(defun ledger-transaction-state () (save-excursion (when (or (looking-at "^[0-9]") (re-search-backward "^[0-9]" nil t)) @@ -42,13 +42,13 @@ ((looking-at "\\*\\s-*") 'cleared) (t nil))))) -(defun ledger-transaction-state () +(defun ledger-posting-state () (save-excursion (goto-char (line-beginning-position)) (skip-syntax-forward " ") (cond ((looking-at "!\\s-*") 'pending) ((looking-at "\\*\\s-*") 'cleared) - (t (ledger-entry-state))))) + (t (ledger-transaction-state))))) (defun ledger-toggle-current-transaction (&optional style) "Toggle the cleared status of the transaction under point. @@ -172,15 +172,15 @@ dropped." (defun ledger-toggle-current (&optional style) (interactive) - (if (or ledger-clear-whole-entries - (eq 'entry (ledger-thing-at-point))) + (if (or ledger-clear-whole-transactions + (eq 'transaction (ledger-thing-at-point))) (progn (save-excursion (forward-line) (goto-char (line-beginning-position)) (while (and (not (eolp)) (save-excursion - (not (eq 'entry (ledger-thing-at-point))))) + (not (eq 'transaction (ledger-thing-at-point))))) (if (looking-at "\\s-+[*!]") (ledger-toggle-current-transaction nil)) (forward-line) -- cgit v1.2.3 From 316055ff86978c29839d0d3058b3a9a7dda047bb Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 12 Feb 2013 10:39:07 -0700 Subject: More code cleanup --- lisp/ldg-state.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index ac0511f8..443cb350 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -62,7 +62,7 @@ achieved more certainly by passing the entry to ledger for formatting, but doing so causes inline math expressions to be dropped." (interactive) - (let ((bounds (ledger-current-entry-bounds)) + (let ((bounds (ledger-current-transaction-bounds)) clear cleared) ;; Uncompact the entry, to make it easier to toggle the ;; transaction -- cgit v1.2.3 From 28659c58c3b0531e0f5fb01b298fcb8a8f63991e Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 12 Feb 2013 15:11:36 -0700 Subject: Bug 892 re-enable pending mode and reconcile-finish This should do it, and it should work across multiple files. --- lisp/ldg-mode.el | 2 +- lisp/ldg-reconcile.el | 49 ++++++++++++++++++--------- lisp/ldg-state.el | 93 +++++++++++++++++++++++++++++++-------------------- 3 files changed, 91 insertions(+), 53 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 628b4b8a..95b02fdd 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -75,7 +75,7 @@ customizable to ease retro-entry.") (define-key map [(control ?c) (control ?y)] 'ledger-set-year) (define-key map [(control ?c) (control ?m)] 'ledger-set-month) (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) - (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-entry) + (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-transaction) (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) (define-key map [(control ?c) (control ?t)] 'ledger-test-run) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 6179428f..61db2472 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -48,6 +48,12 @@ :type 'boolean :group 'ledger) +(defcustom ledger-reconcile-toggle-to-pending t + "if true then toggle between uncleared and pending. + reconcile-finish will mark all pending posting cleared. " + :type 'boolean + :group 'ledger) + (defun ledger-display-balance () "Calculate the cleared balance of the account being reconciled" (interactive) @@ -79,22 +85,29 @@ (let ((where (get-text-property (point) 'where)) (account ledger-acct) (inhibit-read-only t) - cleared) + status) (when (ledger-reconcile-get-buffer where) (with-current-buffer (ledger-reconcile-get-buffer where) (goto-char (cdr where)) - (setq cleared (ledger-toggle-current))) + (setq status (ledger-toggle-current (if ledger-reconcile-toggle-to-pending + 'pending + 'cleared)))) ;remove the existing face and add the new face (remove-text-properties (line-beginning-position) (line-end-position) (list 'face)) - (if cleared - (add-text-properties (line-beginning-position) - (line-end-position) - (list 'face 'ledger-font-reconciler-cleared-face )) - (add-text-properties (line-beginning-position) - (line-end-position) - (list 'face 'ledger-font-reconciler-uncleared-face )))) + (cond ((eq status 'pending) + (add-text-properties (line-beginning-position) + (line-end-position) + (list 'face 'ledger-font-reconciler-pending-face ))) + ((eq status 'cleared) + (add-text-properties (line-beginning-position) + (line-end-position) + (list 'face 'ledger-font-reconciler-cleared-face ))) + (t + (add-text-properties (line-beginning-position) + (line-end-position) + (list 'face 'ledger-font-reconciler-uncleared-face ))))) (forward-line) (beginning-of-line) (ledger-display-balance))) @@ -167,9 +180,8 @@ (while (not (eobp)) (let ((where (get-text-property (point) 'where)) (face (get-text-property (point) 'face))) - (if (and (eq face 'bold) - (when (is-stdin (car where)))) - (with-current-buffer ledger-buf + (if (eq face 'ledger-font-reconciler-pending-face) + (with-current-buffer (ledger-reconcile-get-buffer where) (goto-char (cdr where)) (ledger-toggle-current 'cleared)))) (forward-line 1))) @@ -240,9 +252,13 @@ "") (nth 4 xact) (nth 1 posting) (nth 2 posting))) (if (nth 3 posting) - (set-text-properties beg (1- (point)) - (list 'face 'ledger-font-reconciler-cleared-face - 'where where)) + (if (eq (nth 3 posting) 'pending) + (set-text-properties beg (1- (point)) + (list 'face 'ledger-font-reconciler-pending-face + 'where where)) + (set-text-properties beg (1- (point)) + (list 'face 'ledger-font-reconciler-cleared-face + 'where where))) (set-text-properties beg (1- (point)) (list 'face 'ledger-font-reconciler-uncleared-face 'where where)))) )) @@ -327,6 +343,7 @@ (define-key map [(control ?m)] 'ledger-reconcile-visit) (define-key map [return] 'ledger-reconcile-visit) (define-key map [(control ?l)] 'ledger-reconcile-refresh) + (define-key map [(control ?c) (control ?c)] 'ledger-reconcile-finish) (define-key map [? ] 'ledger-reconcile-toggle) (define-key map [?a] 'ledger-reconcile-add) (define-key map [?d] 'ledger-reconcile-delete) @@ -353,6 +370,8 @@ (define-key map [menu-bar ldg-recon-menu bal] '("Show Cleared Balance" . ledger-display-balance)) (define-key map [menu-bar ldg-recon-menu sep4] '("--")) (define-key map [menu-bar ldg-recon-menu rna] '("Reconcile New Account" . ledger-reconcile)) + (define-key map [menu-bar ldg-recon-menu sep5] '("--")) + (define-key map [menu-bar ldg-recon-menu fin] '("Finish" . ledger-reconcile-finish)) (define-key map [menu-bar ldg-recon-menu ref] '("Refresh" . ledger-reconcile-refresh)) (define-key map [menu-bar ldg-recon-menu sav] '("Save" . ledger-reconcile-save)) diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index 443cb350..7c499d3e 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -50,11 +50,26 @@ ((looking-at "\\*\\s-*") 'cleared) (t (ledger-transaction-state))))) -(defun ledger-toggle-current-transaction (&optional style) +(defun ledger-char-from-state (state) + (if state + (if (eq state 'pending) + "!" + "*") + "")) + +(defun ledger-state-from-char (state-char) + (cond ((eql state-char ?\!) + 'pending) + ((eql state-char ?\*) + 'cleared) + (t + nil))) + +(defun ledger-toggle-current-posting (&optional style) "Toggle the cleared status of the transaction under point. Optional argument STYLE may be `pending' or `cleared', depending on which type of status the caller wishes to indicate (default is -`cleared'). +`cleared'). Returns the new status as 'pending 'cleared or nil. This function is rather complicated because it must preserve both the overall formatting of the ledger entry, as well as ensuring that the most minimal display format is used. This could be @@ -63,15 +78,16 @@ formatting, but doing so causes inline math expressions to be dropped." (interactive) (let ((bounds (ledger-current-transaction-bounds)) - clear cleared) + new-status cur-status) ;; Uncompact the entry, to make it easier to toggle the ;; transaction - (save-excursion - (goto-char (car bounds)) - (skip-chars-forward "0-9./= \t") - (setq cleared (and (member (char-after) '(?\* ?\!)) - (char-after))) - (when cleared + (save-excursion ;this excursion unclears the posting + (goto-char (car bounds)) ;beginning of xact + (skip-chars-forward "0-9./= \t") ;skip the date + (setq cur-status (and (member (char-after) '(?\* ?\!)) + (ledger-state-from-char (char-after)))) ;if the next char is !, * store it + ;;if cur-status if !, or * then delete the marker + (when cur-status (let ((here (point))) (skip-chars-forward "*! ") (let ((width (- (point) here))) @@ -82,17 +98,19 @@ dropped." (forward-line) (while (looking-at "[ \t]") (skip-chars-forward " \t") - (insert cleared " ") + (insert (ledger-char-from-state cur-status) " ") (if (search-forward " " (line-end-position) t) (delete-char 2)) - (forward-line)))) - ;; Toggle the individual transaction - (save-excursion + (forward-line)) + (setq new-status nil))) + + ;;this excursion marks the posting pending or cleared + (save-excursion (goto-char (line-beginning-position)) (when (looking-at "[ \t]") (skip-chars-forward " \t") (let ((here (point)) - (cleared (member (char-after) '(?\* ?\!)))) + (cur-status (ledger-state-from-char (char-after)))) (skip-chars-forward "*! ") (let ((width (- (point) here))) (when (> width 0) @@ -101,18 +119,18 @@ dropped." (if (search-forward " " (line-end-position) t) (insert (make-string width ? )))))) (let (inserted) - (if cleared + (if cur-status (if (and style (eq style 'cleared)) (progn (insert "* ") - (setq inserted t))) + (setq inserted 'cleared))) (if (and style (eq style 'pending)) (progn (insert "! ") - (setq inserted t)) + (setq inserted 'pending)) (progn (insert "* ") - (setq inserted t)))) + (setq inserted 'cleared)))) (if (and inserted (re-search-forward "\\(\t\\| [ \t]\\)" (line-end-position) t)) @@ -123,26 +141,25 @@ dropped." (delete-char 2)) ((looking-at " ") (delete-char 1)))) - (setq clear inserted))))) - ;; Clean up the entry so that it displays minimally + (setq new-status inserted))))) + + ;; This excursion cleans up the entry so that it displays minimally (save-excursion (goto-char (car bounds)) (forward-line) (let ((first t) - (state ? ) + (state nil) (hetero nil)) (while (and (not hetero) (looking-at "[ \t]")) (skip-chars-forward " \t") - (let ((cleared (if (member (char-after) '(?\* ?\!)) - (char-after) - ? ))) + (let ((cur-status (ledger-state-from-char (char-after)))) (if first - (setq state cleared + (setq state cur-status first nil) - (if (/= state cleared) + (if (not (eq state cur-status)) (setq hetero t)))) (forward-line)) - (when (and (not hetero) (/= state ? )) + (when (and (not hetero) (not (eq state nil))) (goto-char (car bounds)) (forward-line) (while (looking-at "[ \t]") @@ -158,7 +175,8 @@ dropped." (forward-line)) (goto-char (car bounds)) (skip-chars-forward "0-9./= \t") - (insert state " ") + (insert (ledger-char-from-state state) " ") + (setq new-status state) (if (re-search-forward "\\(\t\\| [ \t]\\)" (line-end-position) t) (cond @@ -168,7 +186,7 @@ dropped." (delete-char 2)) ((looking-at " ") (delete-char 1))))))) - clear)) + new-status)) (defun ledger-toggle-current (&optional style) (interactive) @@ -182,21 +200,22 @@ dropped." (save-excursion (not (eq 'transaction (ledger-thing-at-point))))) (if (looking-at "\\s-+[*!]") - (ledger-toggle-current-transaction nil)) + (ledger-toggle-current-transaction style)) (forward-line) (goto-char (line-beginning-position)))) - (ledger-toggle-current-entry style)) - (ledger-toggle-current-transaction style))) + (ledger-toggle-current-transaction style)) + (ledger-toggle-current-posting style))) -(defun ledger-toggle-current-entry (&optional style) +(defun ledger-toggle-current-transaction (&optional style) (interactive) - (let (clear) + (let (status) (save-excursion (when (or (looking-at "^[0-9]") (re-search-backward "^[0-9]" nil t)) (skip-chars-forward "0-9./=") (delete-horizontal-space) - (if (member (char-after) '(?\* ?\!)) + (if (or (eq (ledger-state-from-char (char-after)) 'pending) + (eq (ledger-state-from-char (char-after)) 'cleared)) (progn (delete-char 1) (if (and style (eq style 'cleared)) @@ -204,7 +223,7 @@ dropped." (if (and style (eq style 'pending)) (insert " ! ") (insert " * ")) - (setq clear t)))) - clear)) + (setq status t)))) + status)) (provide 'ldg-state) -- cgit v1.2.3 From 5eb322c0a29bcf2ddaa30bfaab577f18bb1fd922 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 12 Feb 2013 16:04:02 -0700 Subject: Comment and code cleanup --- lisp/ldg-complete.el | 7 ++++--- lisp/ldg-mode.el | 4 ++-- lisp/ldg-occur.el | 21 ++++++++++----------- lisp/ldg-post.el | 18 ++++++++++-------- lisp/ldg-reconcile.el | 35 ++++++++++++++++++++--------------- lisp/ldg-register.el | 3 +-- lisp/ldg-sort.el | 11 +++++++---- lisp/ldg-state.el | 8 ++++---- 8 files changed, 58 insertions(+), 49 deletions(-) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index b56a85ed..b841bae9 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -64,11 +64,12 @@ (goto-char (point-min)) (while (re-search-forward (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" - "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) ;matches first line of transaction + "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) ;; matches first line (unless (and (>= origin (match-beginning 0)) (< origin (match-end 0))) (setq payees-list (cons (match-string-no-properties 3) - payees-list))))) ;add the payee to the list + payees-list))))) ;; add the payee + ;; to the list (pcomplete-uniqify-list (nreverse payees-list)))) (defvar ledger-account-tree nil) @@ -130,7 +131,7 @@ (if (eq (save-excursion (ledger-thing-at-point)) 'transaction) (if (null current-prefix-arg) - (ledger-payees) ; this completes against payee names + (ledger-payees) ;; this completes against payee names (progn (let ((text (buffer-substring (line-beginning-position) (line-end-position)))) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 95b02fdd..df277ee0 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -132,8 +132,8 @@ customizable to ease retro-entry.") (< (nth 1 t1) (nth 1 t2))))) (defun ledger-time-subtract (t1 t2) - "Subtract two time values. -Return the difference in the format of a time value." + "Subtract two time values. Return the difference in the format + of a time value." (let ((borrow (< (cadr t1) (cadr t2)))) (list (- (car t1) (car t2) (if borrow 1 0)) (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2))))) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index bd5a49b1..d53be09b 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -125,14 +125,13 @@ When REGEX is nil, unhide everything, and remove higlight" (temp (point-max))) (mapcar (lambda (match) (progn - (setq temp prev-end) ;need a swap so that the - ;last form in the lambda - ;is the (make-overlay) - (setq prev-end (1+ (cadr match))) ;add 1 so - ;that we skip - ;the empty - ;line after - ;the xact + (setq temp prev-end) ;; need a swap so that + ;; the last form in + ;; the lambda is the + ;; (make-overlay) + (setq prev-end (1+ (cadr match))) + ;; add 1 so that we skip the + ;; empty line after the xact (make-overlay temp (car match) @@ -216,9 +215,9 @@ When REGEX is nil, unhide everything, and remove higlight" (save-excursion (let ((bounds (ledger-find-xact-extents (match-beginning 0)))) (push bounds lines) - (setq curpoint (cadr bounds)))) ;move to the end of the - ;xact, no need to search - ;inside it more + (setq curpoint (cadr bounds)))) ;; move to the end of + ;; the xact, no need to + ;; search inside it more (goto-char curpoint)) (forward-line 1)) (setq lines (nreverse lines))))) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 7b6ac9d5..099db1c2 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -63,8 +63,8 @@ (defun ledger-post-completing-read (prompt choices) "Use iswitchb as a completing-read replacement to choose from choices. -PROMPT is a string to prompt with. CHOICES is a list of strings -to choose from." + PROMPT is a string to prompt with. CHOICES is a list of + strings to choose from." (cond (ledger-post-use-iswitchb (let* ((iswitchb-use-virtual-buffers nil) @@ -113,7 +113,8 @@ to choose from." (defun ledger-align-amounts (&optional column) "Align amounts in the current region. -This is done so that the last digit falls in COLUMN, which defaults to 52." + This is done so that the last digit falls in COLUMN, which + defaults to 52." (interactive "p") (if (or (null column) (= column 1)) (setq column ledger-post-amount-alignment-column)) @@ -157,17 +158,18 @@ This is done so that the last digit falls in COLUMN, which defaults to 52." (interactive) (goto-char (line-beginning-position)) (when (re-search-forward ledger-post-line-regexp (line-end-position) t) - (goto-char (match-end ledger-regex-post-line-group-account)) ;go to the and of the account - (let ((end-of-amount (re-search-forward "[-.,0-9]+" (line-end-position) t))) ;determine if there is an amount to edit + (goto-char (match-end ledger-regex-post-line-group-account)) ;; go to the and of the account + (let ((end-of-amount (re-search-forward "[-.,0-9]+" (line-end-position) t))) + ;; determine if there is an amount to edit (if end-of-amount (let ((val (match-string 0))) (goto-char (match-beginning 0)) (delete-region (match-beginning 0) (match-end 0)) (calc) (while (string-match "," val) - (setq val (replace-match "" nil nil val))) ;gets rid of commas - (calc-eval val 'push)) ;edit the amount - (progn ;make sure there are two spaces after the account name and go to calc + (setq val (replace-match "" nil nil val))) ;; gets rid of commas + (calc-eval val 'push)) ;; edit the amount + (progn ;;make sure there are two spaces after the account name and go to calc (if (search-backward " " (- (point) 3) t) (goto-char (line-end-position)) (insert " ")) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 61db2472..25d2e981 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -92,7 +92,7 @@ (setq status (ledger-toggle-current (if ledger-reconcile-toggle-to-pending 'pending 'cleared)))) - ;remove the existing face and add the new face + ;; remove the existing face and add the new face (remove-text-properties (line-beginning-position) (line-end-position) (list 'face)) @@ -193,8 +193,8 @@ (ledger-reconcile-quit-cleanup) (let ((buf ledger-buf) (recon-buf (get-buffer ledger-recon-buffer-name))) - ;Make sure you delete the window before you delete the buffer, - ;otherwise, madness ensues + ;; Make sure you delete the window before you delete the buffer, + ;; otherwise, madness ensues (with-current-buffer recon-buf (delete-window (get-buffer-window recon-buf)) (kill-buffer recon-buf)) @@ -223,7 +223,8 @@ (if ledger-clear-whole-transactions (goto-line (nth 1 emacs-xact)) (goto-line (nth 0 posting))) - (1+ (point-marker))))))) ;Add 1 to make sure the marker is within the transaction + (1+ (point-marker))))))) ;;Add 1 to make sure the marker is + ;;within the transaction (defun ledger-do-reconcile () "get the uncleared transactions in the account and display them @@ -269,11 +270,11 @@ (set-buffer-modified-p nil) (toggle-read-only t) - ; this next piece of code ensures that the last of the visible - ; transactions in the ledger buffer is at the bottom of the main - ; window. The key to this is to ensure the window is selected - ; when the buffer point is moved and recentered. If they aren't - ; strange things happen. + ;; this next piece of code ensures that the last of the visible + ;; transactions in the ledger buffer is at the bottom of the main + ;; window. The key to this is to ensure the window is selected + ;; when the buffer point is moved and recentered. If they aren't + ;; strange things happen. (let ((recon-window (get-buffer-window (get-buffer ledger-recon-buffer-name)))) @@ -299,20 +300,24 @@ (defun ledger-reconcile (account) (interactive "sAccount to reconcile: ") (let ((buf (current-buffer)) - (rbuf (get-buffer ledger-recon-buffer-name))) ;this means only one *Reconcile* buffer, ever - (if rbuf ; *Reconcile* already exists + (rbuf (get-buffer ledger-recon-buffer-name))) ;; this means + ;; only one + ;; *Reconcile* + ;; buffer, ever + (if rbuf ;; *Reconcile* already exists (with-current-buffer rbuf - (set 'ledger-acct account) ; already buffer local + (set 'ledger-acct account) ;; already buffer local (if (not (eq buf rbuf)) - (progn ; called from some other ledger-mode buffer + (progn ;; called from some other ledger-mode buffer (ledger-reconcile-quit-cleanup) - (set 'ledger-buf buf))) ; should already be buffer-local + (set 'ledger-buf buf))) ;; should already be + ;; buffer-local (if ledger-fold-on-reconcile (ledger-occur-change-regex account ledger-buf)) (set-buffer (get-buffer ledger-recon-buffer-name)) (ledger-reconcile-refresh)) - (progn ; no recon-buffer, starting from scratch. + (progn ;; no recon-buffer, starting from scratch. (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save nil t) (if ledger-fold-on-reconcile (ledger-occur-mode account buf)) diff --git a/lisp/ldg-register.el b/lisp/ldg-register.el index 6e98f20d..bfd8d360 100644 --- a/lisp/ldg-register.el +++ b/lisp/ldg-register.el @@ -69,8 +69,7 @@ (set-text-properties beg (1- (point)) (list 'where where)))) (setq index (1+ index))))) - (goto-char (point-min)) - ) + (goto-char (point-min))) (defun ledger-register-generate (&optional data-buffer &rest args) (let ((buf (or data-buffer (current-buffer)))) diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el index 86e3fa0a..8a1d9573 100644 --- a/lisp/ldg-sort.el +++ b/lisp/ldg-sort.el @@ -33,16 +33,19 @@ (forward-paragraph)) (defun ledger-sort-region (beg end) - (interactive "r") ;load beg and end from point and mark automagically + (interactive "r") ;; load beg and end from point and mark + ;; automagically (let ((new-beg beg) (new-end end)) (save-excursion (save-restriction - (ledger-next-record-function) ;make sure point is at the beginning of a xact + (ledger-next-record-function) ;; make sure point is at the + ;; beginning of a xact (setq new-beg (point)) (goto-char end) - (ledger-next-record-function) ;make sure end of region is at the beginning of - ;next record after the region + (ledger-next-record-function) ;; make sure end of region is at + ;; the beginning of next record + ;; after the region (setq new-end (point)) (narrow-to-region beg end) (goto-char (point-min)) diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index 7c499d3e..1ede3312 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -81,11 +81,11 @@ dropped." new-status cur-status) ;; Uncompact the entry, to make it easier to toggle the ;; transaction - (save-excursion ;this excursion unclears the posting - (goto-char (car bounds)) ;beginning of xact - (skip-chars-forward "0-9./= \t") ;skip the date + (save-excursion ;; this excursion unclears the posting + (goto-char (car bounds)) ;; beginning of xact + (skip-chars-forward "0-9./= \t") ;; skip the date (setq cur-status (and (member (char-after) '(?\* ?\!)) - (ledger-state-from-char (char-after)))) ;if the next char is !, * store it + (ledger-state-from-char (char-after)))) ;;if cur-status if !, or * then delete the marker (when cur-status (let ((here (point))) -- cgit v1.2.3 From a13bcd4109711ea756727c6e8a00a262ad220dae Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Tue, 12 Feb 2013 16:47:43 -0700 Subject: Bug 882 Calc mode doesn't play nice with decimal comma Added a few lines to transform the amount to decimal period format before pushing it to calc. --- lisp/ldg-post.el | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 099db1c2..8b0e3db6 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -45,6 +45,12 @@ :type 'boolean :group 'ledger-post) +(defcustom ledger-post-use-decimal-comma nil + "if non-nil the use commas as decimal separator. This only has + effect interfacing to calc mode in edit amount" + :type 'boolean + :group 'ledger-post) + (defun ledger-post-all-accounts () (let ((origin (point)) (ledger-post-list nil) @@ -166,8 +172,15 @@ (goto-char (match-beginning 0)) (delete-region (match-beginning 0) (match-end 0)) (calc) - (while (string-match "," val) - (setq val (replace-match "" nil nil val))) ;; gets rid of commas + (if ledger-post-use-decimal-comma + (progn + (while (string-match "\\." val) + (setq val (replace-match "" nil nil val))) ;; gets rid of periods + (while (string-match "," val) + (setq val (replace-match "." nil nil val)))) ;; switch to period separator + (progn + (while (string-match "," val) + (setq val (replace-match "" nil nil val))))) ;; gets rid of commas (calc-eval val 'push)) ;; edit the amount (progn ;;make sure there are two spaces after the account name and go to calc (if (search-backward " " (- (point) 3) t) -- cgit v1.2.3 From 24a9e422eb811224d4340905e68867181cb26861 Mon Sep 17 00:00:00 2001 From: Rémi Vanicat Date: Wed, 13 Feb 2013 15:54:01 +0100 Subject: In ledger-do-reconcile, don't act on windows when reconcile hasn't one Ledger-do-reconcile might be called indirectly (in the after-save-hook for example) and one might not want this buffer she has buried to show up again when she is saving another (even related) buffer. --- lisp/ldg-reconcile.el | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 25d2e981..03663b6b 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -276,17 +276,17 @@ ;; when the buffer point is moved and recentered. If they aren't ;; strange things happen. - (let - ((recon-window (get-buffer-window (get-buffer ledger-recon-buffer-name)))) - (fit-window-to-buffer recon-window) - (with-current-buffer buf - (select-window (get-buffer-window buf)) - (goto-char (point-max)) - (recenter -1)) - - (select-window recon-window) - (add-hook 'post-command-hook 'ledger-reconcile-track-xact nil t) - (ledger-reconcile-visit t)))) + (let ((recon-window (get-buffer-window (get-buffer ledger-recon-buffer-name)))) + (when recon-window + (fit-window-to-buffer recon-window) + (with-current-buffer buf + (select-window (get-buffer-window buf)) + (goto-char (point-max)) + (recenter -1)) + + (select-window recon-window) + (ledger-reconcile-visit t)) + (add-hook 'post-command-hook 'ledger-reconcile-track-xact nil t)))) (defun ledger-reconcile-track-xact () (if (member this-command (list 'next-line -- cgit v1.2.3 From 69673748017fdc9cfe99740d80a3184eef7ca163 Mon Sep 17 00:00:00 2001 From: Rémi Vanicat Date: Wed, 13 Feb 2013 17:03:48 +0100 Subject: Ensure that the reconcile buffer is shown when ledger-reconcile is called. --- lisp/ldg-reconcile.el | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 03663b6b..d295fd81 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -297,6 +297,15 @@ (save-excursion (ledger-reconcile-visit t))))) +(defun ledger-reconcile-open-windows (buf rbuf) + "Ensure that the reconcile buffer has its windows + +Spliting the windows of BUF if needed" + (if ledger-reconcile-force-window-bottom + ;;create the *Reconcile* window directly below the ledger buffer. + (set-window-buffer (split-window (get-buffer-window buf) nil nil) rbuf) + (pop-to-buffer rbuf))) + (defun ledger-reconcile (account) (interactive "sAccount to reconcile: ") (let ((buf (current-buffer)) @@ -315,6 +324,8 @@ (if ledger-fold-on-reconcile (ledger-occur-change-regex account ledger-buf)) (set-buffer (get-buffer ledger-recon-buffer-name)) + (unless (get-buffer-window rbuf) + (ledger-reconcile-open-windows buf rbuf)) (ledger-reconcile-refresh)) (progn ;; no recon-buffer, starting from scratch. @@ -322,19 +333,12 @@ (if ledger-fold-on-reconcile (ledger-occur-mode account buf)) - (with-current-buffer - (if ledger-reconcile-force-window-bottom - ;create the *Reconcile* window directly below the ledger buffer. - (progn - (set-window-buffer - (split-window (get-buffer-window buf) nil nil) - (get-buffer-create ledger-recon-buffer-name)) - (get-buffer ledger-recon-buffer-name)) - (pop-to-buffer (get-buffer-create ledger-recon-buffer-name))) + (with-current-buffer (get-buffer-create ledger-recon-buffer-name) + (ledger-reconcile-open-windows buf (current-buffer)) (ledger-reconcile-mode) (set (make-local-variable 'ledger-buf) buf) (set (make-local-variable 'ledger-acct) account) - (ledger-do-reconcile)))))) + (ledger-do-reconcile)))))) (defvar ledger-reconcile-mode-abbrev-table) -- cgit v1.2.3 From db9ae7dd042ecc49c2390b19a0670029cdb4e5fe Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Wed, 13 Feb 2013 09:36:44 -0700 Subject: Fixes workflow for using toggle-pending with clear-whole-transactions --- lisp/ldg-reconcile.el | 5 +++-- lisp/ldg-state.el | 13 +++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 25d2e981..cae27a01 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -83,7 +83,6 @@ (defun ledger-reconcile-toggle () (interactive) (let ((where (get-text-property (point) 'where)) - (account ledger-acct) (inhibit-read-only t) status) (when (ledger-reconcile-get-buffer where) @@ -173,7 +172,9 @@ (ledger-display-balance)) (defun ledger-reconcile-finish () - "Mark all pending transactions as cleared, save the buffers and exit reconcile mode" + "Mark all pending posting or transactions as cleared, depending + on ledger-reconcile-clear-whole-transactions, save the buffers + and exit reconcile mode" (interactive) (save-excursion (goto-char (point-min)) diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index 1ede3312..fad7d71c 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -219,11 +219,16 @@ dropped." (progn (delete-char 1) (if (and style (eq style 'cleared)) - (insert " *"))) + (progn + (insert " *") + (setq status 'cleared)))) (if (and style (eq style 'pending)) - (insert " ! ") - (insert " * ")) - (setq status t)))) + (progn + (insert " ! ") + (setq status 'pending)) + (progn + (insert " * ") + (setq status 'cleared)))))) status)) (provide 'ldg-state) -- cgit v1.2.3 From 6315c60e43e62397a8c5396ea1f591b61ea6fcdb Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Wed, 13 Feb 2013 12:34:09 -0700 Subject: Correct behavior of ledger report when entering a new report ledger-report-save would fail if you entered a new report with a name. It wouldn't save the customization to the disk, and if you tried to save manually it would complain about an identical command. --- lisp/ldg-report.el | 53 +++++++++++++++++++++++++---------------------------- lisp/ldg-xact.el | 11 +++++++++++ 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 2bb83516..552aebc0 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -69,6 +69,7 @@ text that should replace the format specifier." (defvar ledger-report-name-prompt-history nil) (defvar ledger-report-cmd-prompt-history nil) (defvar ledger-original-window-cfg nil) +(defvar ledger-report-saved nil) (defvar ledger-report-mode-abbrev-table) @@ -146,6 +147,7 @@ used to generate the buffer, navigating the buffer, etc." (with-current-buffer (pop-to-buffer (get-buffer-create ledger-report-buffer-name)) (ledger-report-mode) + (set (make-local-variable 'ledger-report-saved) nil) (set (make-local-variable 'ledger-buf) buf) (set (make-local-variable 'ledger-report-name) report-name) (set (make-local-variable 'ledger-original-window-cfg) wcfg) @@ -219,7 +221,7 @@ default." ;; It is intended completion should be available on existing ;; payees, but the list of possible completions needs to be ;; developed to allow this. - (ledger-read-string-with-default "Payee" (regexp-quote (ledger-entry-payee)))) + (ledger-read-string-with-default "Payee" (regexp-quote (ledger-xact-payee)))) (defun ledger-report-account-format-specifier () "Substitute an account name @@ -258,13 +260,15 @@ the default." (let ((report-cmd (car (cdr (assoc report-name ledger-reports))))) ;; logic for substitution goes here (when (or (null report-cmd) edit) - (setq report-cmd (ledger-report-read-command report-cmd))) + (setq report-cmd (ledger-report-read-command report-cmd)) + (setq ledger-report-saved nil)) ;; this is a new report, or edited report (setq report-cmd (ledger-report-expand-format-specifiers report-cmd)) (set (make-local-variable 'ledger-report-cmd) report-cmd) (or (string-empty-p report-name) (ledger-report-name-exists report-name) - (ledger-reports-add report-name report-cmd) - (ledger-reports-custom-save)) + (progn + (ledger-reports-add report-name report-cmd) + (ledger-reports-custom-save))) report-cmd)) (defun ledger-do-report (cmd) @@ -368,20 +372,23 @@ the default." (when (string-empty-p ledger-report-name) (setq ledger-report-name (ledger-report-read-new-name))) - (while (setq existing-name (ledger-report-name-exists ledger-report-name)) - (cond ((y-or-n-p (format "Overwrite existing report named '%s' " - ledger-report-name)) - (when (string-equal - ledger-report-cmd - (car (cdr (assq existing-name ledger-reports)))) - (error "Current command is identical to existing saved one")) - (setq ledger-reports - (assq-delete-all existing-name ledger-reports))) - (t - (setq ledger-report-name (ledger-report-read-new-name))))) - - (ledger-reports-add ledger-report-name ledger-report-cmd) - (ledger-reports-custom-save))) + (if (setq existing-name (ledger-report-name-exists ledger-report-name)) + (cond ((y-or-n-p (format "Overwrite existing report named '%s' " + ledger-report-name)) + (if (string-equal + ledger-report-cmd + (car (cdr (assq existing-name ledger-reports)))) + (message "Nothing to save. Current command is identical to existing saved one") + (progn + (setq ledger-reports + (assq-delete-all existing-name ledger-reports)) + (ledger-reports-add ledger-report-name ledger-report-cmd) + (ledger-reports-custom-save)))) + (t + (progn + (setq ledger-report-name (ledger-report-read-new-name)) + (ledger-reports-add ledger-report-name ledger-report-cmd) + (ledger-reports-custom-save))))))) (defconst ledger-line-config '((entry @@ -517,14 +524,4 @@ specified line, returns nil." (defun ledger-context-goto-field-end (context-info field-name) (goto-char (ledger-context-field-end-position context-info field-name))) -(defun ledger-entry-payee () - "Returns the payee of the entry containing point or nil." - (let ((i 0)) - (while (eq (ledger-context-line-type (ledger-context-other-line i)) 'acct-transaction) - (setq i (- i 1))) - (let ((context-info (ledger-context-other-line i))) - (if (eq (ledger-context-line-type context-info) 'entry) - (ledger-context-field-value context-info 'payee) - nil)))) - (provide 'ldg-report) diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index e7402652..ab2c34f4 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -64,4 +64,15 @@ (overlay-put ovl 'face 'ledger-font-highlight-face) (overlay-put ovl 'priority 100)))) +(defun ledger-xact-payee () + "Returns the payee of the entry containing point or nil." + (let ((i 0)) + (while (eq (ledger-context-line-type (ledger-context-other-line i)) 'acct-transaction) + (setq i (- i 1))) + (let ((context-info (ledger-context-other-line i))) + (if (eq (ledger-context-line-type context-info) 'entry) + (ledger-context-field-value context-info 'payee) + nil)))) + + (provide 'ldg-xact) \ No newline at end of file -- cgit v1.2.3 From 15d838d1f86b41e303e392d78eaac970311594cb Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Wed, 13 Feb 2013 13:23:04 -0700 Subject: Bug 893 Ledger reconcile loses alignment An earlier change to multi-file support stored the actual markers to the beginnings of the transaction/postings. When reconcile would insert characters it would invalidate those marker and after many items and been cleared could result in severe misalignment. This change brings back storing the line-numbers as reported by emacs. --- lisp/ldg-reconcile.el | 28 +++++++++++++--------------- lisp/ldg-xact.el | 2 ++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 822597f7..63ea522b 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -60,11 +60,11 @@ (let ((buffer ledger-buf) (account ledger-acct)) (with-temp-buffer - (ledger-exec-ledger buffer (current-buffer) "-C" "balance" account) + (ledger-exec-ledger buffer (current-buffer) "balance" "--limit" "cleared or pending" account) (goto-char (1- (point-max))) (goto-char (line-beginning-position)) (delete-horizontal-space) - (message "Cleared balance = %s" + (message "Current pending balance = %s" (buffer-substring-no-properties (point) (line-end-position)))))) @@ -87,7 +87,8 @@ status) (when (ledger-reconcile-get-buffer where) (with-current-buffer (ledger-reconcile-get-buffer where) - (goto-char (cdr where)) + (ledger-goto-line (cdr where)) + (forward-char) (setq status (ledger-toggle-current (if ledger-reconcile-toggle-to-pending 'pending 'cleared)))) @@ -139,7 +140,7 @@ (let ((where (get-text-property (point) 'where))) (when (ledger-reconcile-get-buffer where) (with-current-buffer (ledger-reconcile-get-buffer where) - (goto-char (cdr where)) + (ledger-goto-line (cdr where)) (ledger-delete-current-transaction)) (let ((inhibit-read-only t)) (goto-char (line-beginning-position)) @@ -157,7 +158,8 @@ (cur-buf (get-buffer ledger-recon-buffer-name))) (when target-buffer (switch-to-buffer-other-window target-buffer) - (goto-char (cdr where)) + (ledger-goto-line (cdr where)) + (forward-char) (recenter) (ledger-highlight-xact-under-point) (if come-back @@ -183,7 +185,7 @@ (face (get-text-property (point) 'face))) (if (eq face 'ledger-font-reconciler-pending-face) (with-current-buffer (ledger-reconcile-get-buffer where) - (goto-char (cdr where)) + (ledger-goto-line (cdr where)) (ledger-toggle-current 'cleared)))) (forward-line 1))) (ledger-reconcile-save)) @@ -217,15 +219,11 @@ (let ((buf (if (is-stdin (nth 0 emacs-xact)) ledger-buf (find-file-noselect (nth 0 emacs-xact))))) - (with-current-buffer buf - (cons - buf - (save-excursion - (if ledger-clear-whole-transactions - (goto-line (nth 1 emacs-xact)) - (goto-line (nth 0 posting))) - (1+ (point-marker))))))) ;;Add 1 to make sure the marker is - ;;within the transaction + (cons + buf + (if ledger-clear-whole-transactions + (nth 1 emacs-xact) ;; return line-no of xact + (nth 0 posting))))) ;; return line-no of posting (defun ledger-do-reconcile () "get the uncleared transactions in the account and display them diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index ab2c34f4..4b73b2ea 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -74,5 +74,7 @@ (ledger-context-field-value context-info 'payee) nil)))) +(defsubst ledger-goto-line (line-number) + (goto-char (point-min)) (forward-line (1- line-number))) (provide 'ldg-xact) \ No newline at end of file -- cgit v1.2.3 From d31913871fc2ca3ba26e12bb302df2dd93cdd3da Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Wed, 13 Feb 2013 15:53:16 -0700 Subject: Added rudimentary target checking to reconcile. --- doc/ledger3.texi | 12 ++++++- lisp/ldg-commodities.el | 93 +++++++++++++++++++++++++++++++++++++++++++++++++ lisp/ldg-new.el | 2 ++ lisp/ldg-reconcile.el | 56 +++++++++++++++++++++++------ 4 files changed, 152 insertions(+), 11 deletions(-) create mode 100644 lisp/ldg-commodities.el diff --git a/doc/ledger3.texi b/doc/ledger3.texi index a8f1d4b1..55732ceb 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -2542,7 +2542,7 @@ all of the uncleared transactions. The reconcile buffer has several functions: @table @code @item SPACE - toggles the cleared status of a transaction, and show cleared balance inthe minibuffer + toggles the cleared status of a transaction, and shows pending balance in the mini-buffer @item RETURN moves the cursor to that transaction in the ledger. @item C-x C-s @@ -2555,6 +2555,8 @@ all of the uncleared transactions. The reconcile buffer has several functions: add entry @item D delete entry + @item t + change target reconciliation amount @item g reconcile new account @item b @@ -2570,6 +2572,14 @@ show all transaction meeting the regex, cleared or not. This behavior can be disabled by setting @code{ledger-fold-on-reconcile} to nil in the emacs customization menus. +When you reconcile an account you nromally know the final balance you +are aiming at. When you enter the reconciliation mode ledger will ask +for a target balance. Enter the amount you are aiming for (the default +commodity can be chaged in the customization window). Each time you +toggle a posting to pending, ledger will calculate the new balance of +the account and display the new balance and the difference to make the +target. + @node Generating Reports, , Reconciling accounts, Using EMACS @subsection Generating Reports diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el new file mode 100644 index 00000000..94d2ddf0 --- /dev/null +++ b/lisp/ldg-commodities.el @@ -0,0 +1,93 @@ +;;; ldg-commodities.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + +;; A sample entry sorting function, which works if entry dates are of +;; the form YYYY/mm/dd. + + + + +;;; Commentary: +;; Helper functions to deal with commoditized numbers. A commoditized +;; number will be a cons of value and string where the string contains +;; the commodity + +;;; Code: + +(defcustom ledger-reconcile-default-commodity "$" + "the default commodity for use in target calculations in ledger reconcile" + :type 'string + :group 'ledger) + +(defun ledger-string-balance-to-commoditized-amount (str) + (let ((fields (split-string str "[\n\r]"))) ; break any balances + ; with multi commodities + ; into a list + (mapcar '(lambda (str) + (let* ((parts (split-string str)) ;break into number and commodity string + (first (car parts)) + (second (cadr parts))) + ;"^-*[1-9][0-9]*[.,][0-9]*" + (if (string-match "^-*[1-9]+" first) + (list (string-to-number first) second) + (list (string-to-number second) first)))) + fields))) + + +(defun -commodity (c1 c2) + (if (string= (cadr c1) (cadr c2)) + (list (- (car c1) (car c2)) (cadr c1)) + (error "Can't subtract different commodities %S from %S" c2 c1))) + +(defun +commodity (c1 c2) + (if (string= (cadr c1) (cadr c2)) + (list (+ (car c1) (car c2)) (cadr c1)) + (error "Can't add different commodities, %S to %S" c1 c2))) + +(defun ledger-commodity-to-string (c1) + (let ((val (number-to-string (car c1))) + (commodity (cadr c1))) + (if (> (length commodity) 1) + (concat val " " commodity) + (concat commodity " " val)))) + +(defun ledger-read-commodity-string (comm) + (interactive (list (read-from-minibuffer + (concat "Enter commoditized amount (" ledger-reconcile-default-commodity "): ")))) + (let ((parts (split-string comm))) + (if parts + (if (/= (length parts) 2) ;;assume a number was entered and use default commodity + (list (string-to-number (car parts)) + ledger-reconcile-default-commodity) + (let ((valp1 (string-to-number (car parts))) + (valp2 (string-to-number (cadr parts)))) + (cond ((and (= valp1 valp2) (= 0 valp1));; means neither contained a valid number (both = 0) + (list 0 "")) + ((and (/= 0 valp1) (= valp2 0)) + (list valp1 (cadr parts))) + ((and (/= 0 valp2) (= valp1 0)) + (list valp2 (car parts))) + (t + (error "cannot understand commodity")))))))) + +(provide 'ldg-commodities) + +;;; ldg-commodities.el ends here diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index ad21564a..3c56c108 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -46,6 +46,8 @@ (require 'ldg-sort) (require 'ldg-fonts) (require 'ldg-occur) +(require 'ldg-commodities) + (autoload #'ledger-texi-update-test "ldg-texi" nil t) (autoload #'ledger-texi-update-examples "ldg-texi" nil t) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 63ea522b..bb8d97f2 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -24,6 +24,7 @@ (defvar ledger-buf nil) (defvar ledger-bufs nil) (defvar ledger-acct nil) +(defvar ledger-target nil) (defcustom ledger-recon-buffer-name "*Reconcile*" "Name to use for reconciliation window" @@ -54,19 +55,42 @@ :type 'boolean :group 'ledger) -(defun ledger-display-balance () - "Calculate the cleared balance of the account being reconciled" + +(defun ledger-reconcile-get-balances () + "Calculate the cleared and uncleared balance of the account being reconciled, + return a list with the account, uncleared and cleared balances as numbers" (interactive) (let ((buffer ledger-buf) - (account ledger-acct)) + (account ledger-acct) + (val nil)) (with-temp-buffer - (ledger-exec-ledger buffer (current-buffer) "balance" "--limit" "cleared or pending" account) - (goto-char (1- (point-max))) - (goto-char (line-beginning-position)) - (delete-horizontal-space) - (message "Current pending balance = %s" - (buffer-substring-no-properties (point) - (line-end-position)))))) + (ledger-exec-ledger buffer (current-buffer) + ; note that in the line below, the --format option is + ; separated from the actual format string. emacs does not + ; split arguments like the shell does, so you need to + ; specify the individual fields in the command line. + "balance" "--limit" "cleared or pending" + "--format" "(\"%(amount)\")" account) + (setq val (read (buffer-substring-no-properties (point-min) (point-max))))))) + +(defun ledger-display-balance () + "Calculate the cleared balance of the account being reconciled" + (interactive) + (let* ((pending (car (ledger-string-balance-to-commoditized-amount + (car (ledger-reconcile-get-balances))))) + (target-delta (if ledger-target + (-commodity ledger-target pending) + nil))) + + (if target-delta + (message "Pending balance: %s, Difference from target: %s" + (ledger-commodity-to-string pending) + (ledger-commodity-to-string target-delta)) + (message "Pending balance: %s" + (ledger-commodity-to-string pending))))) + + + (defun is-stdin (file) "True if ledger file is standard input" @@ -323,6 +347,8 @@ Spliting the windows of BUF if needed" (if ledger-fold-on-reconcile (ledger-occur-change-regex account ledger-buf)) (set-buffer (get-buffer ledger-recon-buffer-name)) + (setq ledger-target + (call-interactively #'ledger-read-commodity-string)) (unless (get-buffer-window rbuf) (ledger-reconcile-open-windows buf rbuf)) (ledger-reconcile-refresh)) @@ -337,10 +363,18 @@ Spliting the windows of BUF if needed" (ledger-reconcile-mode) (set (make-local-variable 'ledger-buf) buf) (set (make-local-variable 'ledger-acct) account) + (set (make-local-variable 'ledger-target) + (call-interactively #'ledger-read-commodity-string)) (ledger-do-reconcile)))))) (defvar ledger-reconcile-mode-abbrev-table) +(defun ledger-reconcile-change-target () + (setq ledger-target (call-interactively #'ledger-read-commodity-string))) +; (setq ledger-target +; (if (and target (> (length target) 0)) +; (ledger-string-balance-to-commoditized-amount target)))) + (defun ledger-reconcile-display-internals () (interactive) (message "%S %S" ledger-acct ledger-buf)) @@ -358,6 +392,7 @@ Spliting the windows of BUF if needed" (define-key map [?g] 'ledger-reconcile); (define-key map [?n] 'next-line) (define-key map [?p] 'previous-line) + (define-key map [?t] 'ledger-reconcile-change-target) (define-key map [?s] 'ledger-reconcile-save) (define-key map [?q] 'ledger-reconcile-quit) (define-key map [?b] 'ledger-display-balance) @@ -376,6 +411,7 @@ Spliting the windows of BUF if needed" (define-key map [menu-bar ldg-recon-menu tog] '("Toggle Entry" . ledger-reconcile-toggle)) (define-key map [menu-bar ldg-recon-menu sep3] '("--")) (define-key map [menu-bar ldg-recon-menu bal] '("Show Cleared Balance" . ledger-display-balance)) + (define-key map [menu-bar ldg-recon-menu tgt] '("Change Target Balance" . ledger-reconcile-change-target)) (define-key map [menu-bar ldg-recon-menu sep4] '("--")) (define-key map [menu-bar ldg-recon-menu rna] '("Reconcile New Account" . ledger-reconcile)) (define-key map [menu-bar ldg-recon-menu sep5] '("--")) -- cgit v1.2.3 From c031fa4943760cc6ff8af56ce975ac289e04288e Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Wed, 13 Feb 2013 20:45:22 -0700 Subject: Added menu entry for complete entry. Refactored leg-complete to get rid of some side effect usage --- lisp/ldg-complete.el | 54 +++++++++++++++++++--------------------------------- lisp/ldg-mode.el | 3 ++- lisp/ldg-xact.el | 15 +++++++++++++++ 3 files changed, 37 insertions(+), 35 deletions(-) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index b841bae9..a0508a98 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -25,21 +25,6 @@ ;; In-place completion support -(defun ledger-thing-at-point () - (let ((here (point))) - (goto-char (line-beginning-position)) - (cond ((looking-at "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.+?)\\)?\\s-+") - (goto-char (match-end 0)) - 'transaction) - ((looking-at "^\\s-+\\([*!]\\s-+\\)?[[(]?\\(.\\)") - (goto-char (match-beginning 2)) - 'posting) - ((looking-at "^\\(sun\\|mon\\|tue\\|wed\\|thu\\|fri\\|sat\\)\\s-+") - (goto-char (match-end 0)) - 'entry) - (t - (ignore (goto-char here)))))) - (defun ledger-parse-arguments () "Parse whitespace separated arguments in the current region." (let* ((info (save-excursion @@ -57,7 +42,7 @@ args))) (cons (reverse args) (reverse begins))))) -(defun ledger-payees () +(defun ledger-payees-in-buffer () (let ((origin (point)) payees-list) (save-excursion @@ -72,36 +57,36 @@ ;; to the list (pcomplete-uniqify-list (nreverse payees-list)))) -(defvar ledger-account-tree nil) - -(defun ledger-find-accounts () +(defun ledger-find-accounts-in-buffer () + "search through buffer and build tree of accounts. Return tree + structure" (let ((origin (point)) - account-path - elements) + (account-tree (list t)) + (account-elements nil)) (save-excursion - (setq ledger-account-tree (list t)) (goto-char (point-min)) (while (re-search-forward "^[ \t]+\\([*!]\\s-+\\)?[[(]?\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)" nil t) (unless (and (>= origin (match-beginning 0)) (< origin (match-end 0))) - (setq account-path (match-string-no-properties 2)) - (setq elements (split-string account-path ":")) - (let ((root ledger-account-tree)) - (while elements - (let ((entry (assoc (car elements) root))) + (setq account-elements + (split-string + (match-string-no-properties 2) ":")) + (let ((root account-tree)) + (while account-elements + (let ((entry (assoc (car account-elements) root))) (if entry (setq root (cdr entry)) - (setq entry (cons (car elements) (list t))) + (setq entry (cons (car account-elements) (list t))) (nconc root (list entry)) (setq root (cdr entry)))) - (setq elements (cdr elements))))))))) + (setq account-elements (cdr account-elements))))))) + account-tree)) (defun ledger-accounts () - (ledger-find-accounts) (let* ((current (caar (ledger-parse-arguments))) (elements (and current (split-string current ":"))) - (root ledger-account-tree) + (root (ledger-find-accounts-in-buffer)) (prefix nil)) (while (cdr elements) (let ((entry (assoc (car elements) root))) @@ -131,7 +116,7 @@ (if (eq (save-excursion (ledger-thing-at-point)) 'transaction) (if (null current-prefix-arg) - (ledger-payees) ;; this completes against payee names + (ledger-payees-in-buffer) ;; this completes against payee names (progn (let ((text (buffer-substring (line-beginning-position) (line-end-position)))) @@ -149,7 +134,8 @@ (ledger-accounts))))) (defun ledger-fully-complete-entry () - "Do appropriate completion for the thing at point" + "Completes a transaction if there is another matching payee in + the buffer. Does not use ledger xact" (interactive) (let ((name (caar (ledger-parse-arguments))) xacts) @@ -157,7 +143,7 @@ (when (eq 'transaction (ledger-thing-at-point)) (when (re-search-backward (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" - (regexp-quote name) "\\(\t\\|\n\\| [ \t]\\)") nil t) + (regexp-quote name) ) nil t) ;; "\\(\t\\|\n\\| [ \t]\\)" (forward-line) (while (looking-at "^\\s-+") (setq xacts (cons (buffer-substring-no-properties diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index df277ee0..ea780279 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -120,7 +120,8 @@ customizable to ease retro-entry.") (define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount)) (define-key map [sep] '(menu-item "--")) (define-key map [delete-xact] '(menu-item "Delete Entry" ledger-delete-current-transaction)) - (define-key map [add-xact] '(menu-item "Add Transaction" ledger-add-transaction :enable ledger-works)) + (define-key map [cmp-xact] '(menu-item "Complete Transaction" ledger-fully-complete-entry)) + (define-key map [add-xact] '(menu-item "Add Transaction (ledger xact)" ledger-add-transaction :enable ledger-works)) (define-key map [sep3] '(menu-item "--")) (define-key map [reconcile] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works)) (define-key map [reconcile] '(menu-item "Hide Xacts" ledger-occur)))) diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index 4b73b2ea..306401af 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -77,4 +77,19 @@ (defsubst ledger-goto-line (line-number) (goto-char (point-min)) (forward-line (1- line-number))) +(defun ledger-thing-at-point () + (let ((here (point))) + (goto-char (line-beginning-position)) + (cond ((looking-at "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.+?)\\)?\\s-+") + (goto-char (match-end 0)) + 'transaction) + ((looking-at "^\\s-+\\([*!]\\s-+\\)?[[(]?\\(.\\)") + (goto-char (match-beginning 2)) + 'posting) + ((looking-at "^\\(sun\\|mon\\|tue\\|wed\\|thu\\|fri\\|sat\\)\\s-+") + (goto-char (match-end 0)) + 'entry) + (t + (ignore (goto-char here)))))) + (provide 'ldg-xact) \ No newline at end of file -- cgit v1.2.3 From 1074dec8adc3e4d04b3a9a370b787bd8144fa3fc Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 14 Feb 2013 09:49:00 -0700 Subject: Improved ledger-report visit source capabilities --- lisp/ldg-report.el | 91 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 43 deletions(-) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 552aebc0..7f053ce3 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -100,6 +100,7 @@ text that should replace the format specifier." (define-key map [menu-bar ldg-rep lrq] '("Quit" . ledger-report-quit)) (define-key map [menu-bar ldg-rep s2] '("--")) (define-key map [menu-bar ldg-rep lrd] '("Scroll Down" . scroll-down)) + (define-key map [menu-bar ldg-rep vis] '("Visit Source" . ledger-report-visit-source)) (define-key map [menu-bar ldg-rep lru] '("Scroll Up" . scroll-up)) (define-key map [menu-bar ldg-rep s1] '("--")) (define-key map [menu-bar ldg-rep lrk] '("Kill Report" . ledger-report-kill)) @@ -240,20 +241,19 @@ the default." (ledger-read-string-with-default "Account" default))) (defun ledger-report-expand-format-specifiers (report-cmd) - (let ((expanded-cmd report-cmd)) - (while (string-match "%(\\([^)]*\\))" expanded-cmd) - (let* ((specifier (match-string 1 expanded-cmd)) - (f (cdr (assoc specifier ledger-report-format-specifiers)))) - (if f - (setq expanded-cmd (replace-match - (save-match-data - (with-current-buffer ledger-buf - (shell-quote-argument (funcall f)))) - t t expanded-cmd)) - (progn - (set-window-configuration ledger-original-window-cfg) - (error "Invalid ledger report format specifier '%s'" specifier))))) - expanded-cmd)) + (save-match-data + (let ((expanded-cmd report-cmd)) + (set-match-data (list 0 0)) + (while (string-match "%(\\([^)]*\\))" expanded-cmd (match-end 0)) + (let* ((specifier (match-string 1 expanded-cmd)) + (f (cdr (assoc specifier ledger-report-format-specifiers)))) + (if f + (setq expanded-cmd (replace-match + (save-match-data + (with-current-buffer ledger-buf + (shell-quote-argument (funcall f)))) + t t expanded-cmd))))) + expanded-cmd))) (defun ledger-report-cmd (report-name edit) "Get the command line to run the report." @@ -280,45 +280,50 @@ the default." "\n\n") (let ((data-pos (point)) (register-report (string-match " reg\\(ister\\)? " cmd)) - files-in-report) + files-in-report) (shell-command - (if register-report - (concat cmd " --prepend-format='%(filename):%(beg_line):'") + ;; subtotal doe not produce identifiable transactions, so don't + ;; prepend location information for them + (if (and register-report + (not (string-match "--subtotal" cmd))) + (concat cmd " --prepend-format='%(filename):%(beg_line):'") cmd) t nil) (when register-report (goto-char data-pos) - (while (re-search-forward "^\\([^:]+\\)?:\\([0-9]+\\)?:" nil t) - (let ((file (match-string 1)) + (while (re-search-forward "^\\(/[^:]+\\)?:\\([0-9]+\\)?:" nil t) + (let ((file (match-string 1)) (line (string-to-number (match-string 2)))) - (delete-region (match-beginning 0) (match-end 0)) - (set-text-properties (line-beginning-position) (line-end-position) - (list 'ledger-source (cons file (save-window-excursion - (save-excursion - (find-file file) - (widen) - (goto-char (point-min)) - (forward-line (1- line)) - (point-marker)))))) - (end-of-line)))) + (delete-region (match-beginning 0) (match-end 0)) + (set-text-properties (line-beginning-position) (line-end-position) + (list 'ledger-source (cons file (save-window-excursion + (save-excursion + (find-file file) + (widen) + (ledger-goto-line line) + (point-marker)))))) + (end-of-line)))) (goto-char data-pos))) (defun ledger-report-visit-source () (interactive) - (let ((prop (get-text-property (point) 'ledger-source))) - (destructuring-bind (file . line-or-marker) prop - (find-file-other-window file) - (widen) - (if (markerp line-or-marker) - (goto-char line-or-marker) - (goto-char (point-min)) - (forward-line (1- line-or-marker)) - (re-search-backward "^[0-9]+") - (beginning-of-line) - (let ((start-of-txn (point))) - (forward-paragraph) - (narrow-to-region start-of-txn (point)) - (backward-paragraph)))))) + (let* ((prop (get-text-property (point) 'ledger-source)) + (file (if prop (car prop))) + (line-or-marker (if prop (cdr prop)))) + (if (and file line-or-marker) + (progn + (find-file-other-window file) + (widen) + (if (markerp line-or-marker) + (goto-char line-or-marker) + (goto-char (point-min)) + (forward-line (1- line-or-marker)) + (re-search-backward "^[0-9]+") + (beginning-of-line) + (let ((start-of-txn (point))) + (forward-paragraph) + (narrow-to-region start-of-txn (point)) + (backward-paragraph))))))) (defun ledger-report-goto () "Goto the ledger report buffer." -- cgit v1.2.3 From 30dc7e349db236d842cbe86fbf4972f0dbbbd10a Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 14 Feb 2013 10:05:53 -0700 Subject: Fix to target change function in leg-reconcile Took out the (interactive) statement and it needed to be there. --- lisp/ldg-reconcile.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index bb8d97f2..96a10afb 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -370,6 +370,7 @@ Spliting the windows of BUF if needed" (defvar ledger-reconcile-mode-abbrev-table) (defun ledger-reconcile-change-target () + (interactive) (setq ledger-target (call-interactively #'ledger-read-commodity-string))) ; (setq ledger-target ; (if (and target (> (length target) 0)) -- cgit v1.2.3 From 67201ee8508737cf35c5916953a7b30d01890780 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 14 Feb 2013 11:40:08 -0700 Subject: Add highlighting in the report window if the line is mapped to a file --- lisp/ldg-fonts.el | 5 +++++ lisp/ldg-report.el | 34 +++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index d72c9403..cf40c59d 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -86,6 +86,11 @@ "Default face for pending (!) transactions in the reconcile window" :group 'ledger-faces) +(defface ledger-font-report-clickable-face + `((t :foreground "#cb4b16" :weight normal )) + "Default face for pending (!) transactions in the reconcile window" + :group 'ledger-faces) + (defvar ledger-font-lock-keywords '(("^[0-9]+[-/.=][-/.=0-9]+\\s-\\!\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 'ledger-font-pending-face) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 7f053ce3..711af042 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -165,7 +165,8 @@ used to generate the buffer, navigating the buffer, etc." (defun ledger-report-name-exists (name) "Check to see if the given report name exists. -If name exists, returns the object naming the report, otherwise returns nil." + If name exists, returns the object naming the report, + otherwise returns nil." (unless (string-empty-p name) (car (assoc name ledger-reports)))) @@ -186,9 +187,10 @@ If name exists, returns the object naming the report, otherwise returns nil." (defun ledger-report-ledger-file-format-specifier () "Substitute the full path to master or current ledger file -The master file name is determined by the ledger-master-file buffer-local -variable which can be set using file variables. If it is set, it is used, -otherwise the current buffer file is used." + The master file name is determined by the ledger-master-file + buffer-local variable which can be set using file variables. + If it is set, it is used, otherwise the current buffer file is + used." (ledger-master-file)) ;; General helper functions @@ -198,10 +200,10 @@ otherwise the current buffer file is used." (defun ledger-master-file () "Return the master file for a ledger file. -The master file is either the file for the current ledger buffer or the -file specified by the buffer-local variable ledger-master-file. Typically -this variable would be set in a file local variable comment block at the -end of a ledger file which is included in some other file." + The master file is either the file for the current ledger buffer or the + file specified by the buffer-local variable ledger-master-file. Typically + this variable would be set in a file local variable comment block at the + end of a ledger file which is included in some other file." (if ledger-master-file (expand-file-name ledger-master-file) (buffer-file-name))) @@ -216,9 +218,9 @@ end of a ledger file which is included in some other file." (defun ledger-report-payee-format-specifier () "Substitute a payee name -The user is prompted to enter a payee and that is substitued. If -point is in an entry, the payee for that entry is used as the -default." + The user is prompted to enter a payee and that is substitued. If + point is in an entry, the payee for that entry is used as the + default." ;; It is intended completion should be available on existing ;; payees, but the list of possible completions needs to be ;; developed to allow this. @@ -227,10 +229,10 @@ default." (defun ledger-report-account-format-specifier () "Substitute an account name -The user is prompted to enter an account name, which can be any -regular expression identifying an account. If point is on an account -transaction line for an entry, the full account name on that line is -the default." + The user is prompted to enter an account name, which can be any + regular expression identifying an account. If point is on an account + transaction line for an entry, the full account name on that line is + the default." ;; It is intended completion should be available on existing account ;; names, but it remains to be implemented. (let* ((context (ledger-context-at-point)) @@ -301,6 +303,8 @@ the default." (widen) (ledger-goto-line line) (point-marker)))))) + (add-text-properties (line-beginning-position) (line-end-position) + (list 'face 'ledger-font-report-clickable-face)) (end-of-line)))) (goto-char data-pos))) -- cgit v1.2.3 From 6eb97a7c38ba236f7cf38f694e2f579b6406bae5 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 14 Feb 2013 13:20:16 -0700 Subject: Added a copy transaction function to ledger-mode --- lisp/ldg-mode.el | 12 +++++++----- lisp/ldg-xact.el | 24 ++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index ea780279..fc018853 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -71,16 +71,17 @@ customizable to ease retro-entry.") (let ((map (current-local-map))) (define-key map [(control ?c) (control ?a)] 'ledger-add-transaction) - (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-transaction) - (define-key map [(control ?c) (control ?y)] 'ledger-set-year) - (define-key map [(control ?c) (control ?m)] 'ledger-set-month) + (define-key map [(control ?c) (control ?b)] 'ledger-post-edit-amount) (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) + (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-transaction) (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-transaction) + (define-key map [(control ?c) (control ?f)] 'ledger-occur) + (define-key map [(control ?c) (control ?k)] 'ledger-copy-transaction) + (define-key map [(control ?c) (control ?m)] 'ledger-set-month) (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) (define-key map [(control ?c) (control ?t)] 'ledger-test-run) - (define-key map [(control ?c) (control ?b)] 'ledger-post-edit-amount) - (define-key map [(control ?c) (control ?f)] 'ledger-occur) + (define-key map [(control ?c) (control ?y)] 'ledger-set-year) (define-key map [tab] 'pcomplete) (define-key map [(control ?i)] 'pcomplete) (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) @@ -114,6 +115,7 @@ customizable to ease retro-entry.") (define-key map [sort-buff] '(menu-item "Sort Buffer" ledger-sort-buffer)) (define-key map [sort-reg] '(menu-item "Sort Region" ledger-sort-region :enable mark-active)) (define-key map [sep2] '(menu-item "--")) + (define-key map [copy-xact] '(menu-item "Copy Trans at Point" ledger-copy-transaction)) (define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current)) (define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-entry)) (define-key map [sep4] '(menu-item "--")) diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index 306401af..a1c768ca 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -27,8 +27,6 @@ :type 'boolean :group 'ledger) - - (defvar highlight-overlay (list)) (defun ledger-find-xact-extents (pos) @@ -92,4 +90,26 @@ (t (ignore (goto-char here)))))) +(defun ledger-copy-transaction-at-point (date) + (interactive (list + (read-string "Copy to date: " + (concat ledger-year "/" ledger-month "/")))) + (let* ((here (point)) + (extents (ledger-find-xact-extents (point))) + (transaction (buffer-substring (car extents) (cadr extents))) + encoded-date) + (if (string-match "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)" date) + (setq encoded-date + (encode-time 0 0 0 (string-to-number (match-string 3 date)) + (string-to-number (match-string 2 date)) + (string-to-number (match-string 1 date))))) + (ledger-find-slot encoded-date) + (insert transaction "\n") + (backward-paragraph) + (re-search-forward "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)") + (replace-match date) + (re-search-forward "[1-9][0-9]+\.[0-9]+"))) + + + (provide 'ldg-xact) \ No newline at end of file -- cgit v1.2.3 From d8f0b0fa83c6c6984f79dbb918e324a847cdb094 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 14 Feb 2013 15:37:13 -0700 Subject: Code commenting cleanup. --- lisp/ldg-commodities.el | 20 ++++++--- lisp/ldg-complete.el | 26 ++++++++---- lisp/ldg-exec.el | 18 ++++++-- lisp/ldg-fonts.el | 39 ++++++++++------- lisp/ldg-mode.el | 36 ++++++++++++---- lisp/ldg-new.el | 13 +++--- lisp/ldg-occur.el | 45 ++++++++++---------- lisp/ldg-post.el | 32 +++++++++++--- lisp/ldg-reconcile.el | 110 ++++++++++++++++++++++++++---------------------- lisp/ldg-report.el | 68 ++++++++++++++++++------------ lisp/ldg-sort.el | 15 +++++-- lisp/ldg-state.el | 25 +++++++++-- lisp/ldg-xact.el | 36 ++++++++++------ 13 files changed, 309 insertions(+), 174 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 94d2ddf0..c007816d 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -33,11 +33,12 @@ ;;; Code: (defcustom ledger-reconcile-default-commodity "$" - "the default commodity for use in target calculations in ledger reconcile" + "The default commodity for use in target calculations in ledger reconcile." :type 'string :group 'ledger) (defun ledger-string-balance-to-commoditized-amount (str) + "Return a commoditized amount (val, 'comm') from STR." (let ((fields (split-string str "[\n\r]"))) ; break any balances ; with multi commodities ; into a list @@ -48,29 +49,36 @@ ;"^-*[1-9][0-9]*[.,][0-9]*" (if (string-match "^-*[1-9]+" first) (list (string-to-number first) second) - (list (string-to-number second) first)))) + (list (string-to-number second) first)))) fields))) (defun -commodity (c1 c2) - (if (string= (cadr c1) (cadr c2)) + "Subtract C2 from C1, ensuring their commodities match." + (if (string= (cadr c1) (cadr c2)) (list (- (car c1) (car c2)) (cadr c1)) (error "Can't subtract different commodities %S from %S" c2 c1))) (defun +commodity (c1 c2) + "Add C1 and C2, ensuring their commodities match." (if (string= (cadr c1) (cadr c2)) (list (+ (car c1) (car c2)) (cadr c1)) (error "Can't add different commodities, %S to %S" c1 c2))) (defun ledger-commodity-to-string (c1) - (let ((val (number-to-string (car c1))) + "Return string representing C1. +Single character commodities are placed ahead of the value, +longer one are after the value." +(let ((val (number-to-string (car c1))) (commodity (cadr c1))) (if (> (length commodity) 1) (concat val " " commodity) (concat commodity " " val)))) (defun ledger-read-commodity-string (comm) - (interactive (list (read-from-minibuffer + "Return a commoditizd value (val 'comm') from COMM. +Assumes a space between the value and the commodity." + (interactive (list (read-from-minibuffer (concat "Enter commoditized amount (" ledger-reconcile-default-commodity "): ")))) (let ((parts (split-string comm))) (if parts @@ -86,7 +94,7 @@ ((and (/= 0 valp2) (= valp1 0)) (list valp2 (car parts))) (t - (error "cannot understand commodity")))))))) + (error "Cannot understand commodity")))))))) (provide 'ldg-commodities) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index a0508a98..82046e07 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -21,10 +21,16 @@ ;;(require 'esh-util) ;;(require 'esh-arg) + +;;; Commentary: +;; Functions providing payee and account auto complete. + (require 'pcomplete) ;; In-place completion support +;;; Code: + (defun ledger-parse-arguments () "Parse whitespace separated arguments in the current region." (let* ((info (save-excursion @@ -43,6 +49,7 @@ (cons (reverse args) (reverse begins))))) (defun ledger-payees-in-buffer () + "Scan buffer and return list of all payees." (let ((origin (point)) payees-list) (save-excursion @@ -58,9 +65,9 @@ (pcomplete-uniqify-list (nreverse payees-list)))) (defun ledger-find-accounts-in-buffer () - "search through buffer and build tree of accounts. Return tree - structure" - (let ((origin (point)) + "Search through buffer and build tree of accounts. +Return tree structure" + (let ((origin (point)) (account-tree (list t)) (account-elements nil)) (save-excursion @@ -69,8 +76,8 @@ "^[ \t]+\\([*!]\\s-+\\)?[[(]?\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)" nil t) (unless (and (>= origin (match-beginning 0)) (< origin (match-end 0))) - (setq account-elements - (split-string + (setq account-elements + (split-string (match-string-no-properties 2) ":")) (let ((root account-tree)) (while account-elements @@ -84,6 +91,7 @@ account-tree)) (defun ledger-accounts () + "Return a tree of all accounts in the buffer." (let* ((current (caar (ledger-parse-arguments))) (elements (and current (split-string current ":"))) (root (ledger-find-accounts-in-buffer)) @@ -110,7 +118,7 @@ 'string-lessp)))) (defun ledger-complete-at-point () - "Do appropriate completion for the thing at point" + "Do appropriate completion for the thing at point." (interactive) (while (pcomplete-here (if (eq (save-excursion @@ -134,8 +142,8 @@ (ledger-accounts))))) (defun ledger-fully-complete-entry () - "Completes a transaction if there is another matching payee in - the buffer. Does not use ledger xact" + "Completes a transaction if there is another matching payee in the buffer. +Does not use ledger xact" (interactive) (let ((name (caar (ledger-parse-arguments))) xacts) @@ -164,3 +172,5 @@ (goto-char (match-end 0)))))) (provide 'ldg-complete) + +;;; ldg-complete.el ends here diff --git a/lisp/ldg-exec.el b/lisp/ldg-exec.el index e9cefd20..af5dd3a8 100644 --- a/lisp/ldg-exec.el +++ b/lisp/ldg-exec.el @@ -19,11 +19,17 @@ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. + +;;; Commentary: +;; Code for executing ledger synchronously. + +;;; Code: + (defconst ledger-version-needed "3.0.0" - "The version of ledger executable needed for interactive features") + "The version of ledger executable needed for interactive features.") (defvar ledger-works nil - "Flag showing whether the ledger binary can support ledger-mode interactive features") + "Flag showing whether the ledger binary can support `ledger-mode' interactive features.") (defgroup ledger-exec nil "Interface to the Ledger command-line accounting program." @@ -35,7 +41,7 @@ :group 'ledger) (defun ledger-exec-ledger (input-buffer &optional output-buffer &rest args) - "Run Ledger." + "Run Ledger using INPUT-BUFFER and optionally capturing output in OUTPUT-BUFFER with ARGS." (if (null ledger-binary-path) (error "The variable `ledger-binary-path' has not been set")) (let ((buf (or input-buffer (current-buffer))) @@ -51,6 +57,7 @@ outbuf))) (defun ledger-exec-read (&optional input-buffer &rest args) + "Run ledger from option INPUT-BUFFER using ARGS, return a list structure of the ledger Emacs output." (with-current-buffer (apply #'ledger-exec-ledger input-buffer nil "emacs" args) (goto-char (point-min)) @@ -59,7 +66,7 @@ (kill-buffer (current-buffer))))) (defun ledger-version-greater-p (needed) - "verify the ledger binary is usable for ledger-mode" + "Verify the ledger binary is usable for `ledger-mode' (version greater than NEEDED)." (let ((buffer ledger-buf) (version-strings '()) (version-number)) @@ -77,6 +84,7 @@ nil)))) (defun ledger-check-version () + "Verify that ledger works and is modern enough." (interactive) (setq ledger-works (ledger-version-greater-p ledger-version-needed)) (if ledger-works @@ -84,3 +92,5 @@ (message "Bad Ledger Version"))) (provide 'ldg-exec) + +;;; ldg-exec.el ends here diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index cf40c59d..d760140c 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -20,48 +20,54 @@ ;; MA 02111-1307, USA. + +;;; Commentary: +;; All of the faces for ledger mode are defined here. + +;;; Code: + (defgroup ledger-faces nil "Ledger mode highlighting" :group 'ledger) -(defface ledger-font-uncleared-face +(defface ledger-font-uncleared-face `((t :foreground "#dc322f" :weight bold )) "Default face for Ledger" :group 'ledger-faces) -(defface ledger-font-cleared-face +(defface ledger-font-cleared-face `((t :foreground "#657b83" :weight normal )) "Default face for cleared (*) transactions" :group 'ledger-faces) -(defface ledger-font-highlight-face +(defface ledger-font-highlight-face `((t :background "white")) "Default face for transaction under point" :group 'ledger-faces) -(defface ledger-font-pending-face +(defface ledger-font-pending-face `((t :foreground "#cb4b16" :weight normal )) "Default face for pending (!) transactions" :group 'ledger-faces) -(defface ledger-font-other-face +(defface ledger-font-other-face `((t :foreground "yellow" )) "Default face for other transactions" :group 'ledger-faces) -(defface ledger-font-posting-account-face +(defface ledger-font-posting-account-face `((t :foreground "#268bd2" )) "Face for Ledger accounts" :group 'ledger-faces) -(defface ledger-font-posting-amount-face +(defface ledger-font-posting-amount-face `((t :foreground "yellow" )) "Face for Ledger amounts" :group 'ledger-faces) -(defface ledger-occur-folded-face +(defface ledger-occur-folded-face `((t :foreground "grey70" :invisible t )) "Default face for Ledger occur mode hidden transactions" :group 'ledger-faces) -(defface ledger-occur-xact-face +(defface ledger-occur-xact-face `((t :background "#eee8d5" )) "Default face for Ledger occur mode shown transactions" :group 'ledger-faces) @@ -71,22 +77,22 @@ "Face for Ledger comments" :group 'ledger-faces) -(defface ledger-font-reconciler-uncleared-face +(defface ledger-font-reconciler-uncleared-face `((t :foreground "#dc322f" :weight bold )) "Default face for uncleared transactions in the reconcile window" :group 'ledger-faces) -(defface ledger-font-reconciler-cleared-face +(defface ledger-font-reconciler-cleared-face `((t :foreground "#657b83" :weight normal )) "Default face for cleared (*) transactions in the reconcile window" :group 'ledger-faces) -(defface ledger-font-reconciler-pending-face +(defface ledger-font-reconciler-pending-face `((t :foreground "#cb4b16" :weight normal )) "Default face for pending (!) transactions in the reconcile window" :group 'ledger-faces) -(defface ledger-font-report-clickable-face +(defface ledger-font-report-clickable-face `((t :foreground "#cb4b16" :weight normal )) "Default face for pending (!) transactions in the reconcile window" :group 'ledger-faces) @@ -95,7 +101,7 @@ (defvar ledger-font-lock-keywords '(("^[0-9]+[-/.=][-/.=0-9]+\\s-\\!\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 'ledger-font-pending-face) ("^[0-9]+[-/.=][-/.=0-9]+\\s-\\*\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 'ledger-font-cleared-face) - ("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 'ledger-font-uncleared-face) + ("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 'ledger-font-uncleared-face) ("^\\s-+\\([*]\\s-*\\)?\\(\\([[(]\\)?[^*: ]+?:\\([^]); ]\\|\\s-\\)+?\\([])]\\)?\\)\\( \\| \\|$\\)" @@ -105,4 +111,7 @@ ("^\\([A-Za-z]+ .+\\)" 1 ledger-font-other-face)) "Expressions to highlight in Ledger mode.") -(provide 'ldg-fonts) \ No newline at end of file + +(provide 'ldg-fonts) + +;;; ldg-fonts.el ends here diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index fc018853..6cab7c9b 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -20,18 +20,24 @@ ;; MA 02111-1307, USA. + +;;; Commentary: +;; Most of the general ledger-mode code is here. + +;;; Code: + (defsubst ledger-current-year () + "The default current year for adding transactions." (format-time-string "%Y")) (defsubst ledger-current-month () + "The default current month for adding transactions." (format-time-string "%m")) (defvar ledger-year (ledger-current-year) - "Start a ledger session with the current year, but make it -customizable to ease retro-entry.") + "Start a ledger session with the current year, but make it customizable to ease retro-entry.") (defvar ledger-month (ledger-current-month) - "Start a ledger session with the current month, but make it -customizable to ease retro-entry.") + "Start a ledger session with the current month, but make it customizable to ease retro-entry.") (defcustom ledger-default-acct-transaction-indent " " "Default indentation for account transactions in an entry." @@ -39,7 +45,8 @@ customizable to ease retro-entry.") :group 'ledger) (defun ledger-remove-overlays () - (interactive) + "Remove all overlays from the ledger buffer." +(interactive) "remove overlays formthe buffer, used if the buffer is reverted" (remove-overlays)) @@ -135,13 +142,15 @@ customizable to ease retro-entry.") (< (nth 1 t1) (nth 1 t2))))) (defun ledger-time-subtract (t1 t2) - "Subtract two time values. Return the difference in the format - of a time value." + "Subtract two time values, T1 - T2. +Return the difference in the format of a time value." (let ((borrow (< (cadr t1) (cadr t2)))) (list (- (car t1) (car t2) (if borrow 1 0)) (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2))))) (defun ledger-find-slot (moment) + "Find the right place in the buffer for a transaction at MOMENT. +MOMENT is an encoded date" (catch 'found (ledger-iterate-transactions (function @@ -150,6 +159,7 @@ customizable to ease retro-entry.") (throw 'found t))))))) (defun ledger-iterate-transactions (callback) + "Iterate through each transaction call CALLBACK for each." (goto-char (point-min)) (let* ((now (current-time)) (current-year (nth 5 (decode-time now)))) @@ -177,20 +187,24 @@ customizable to ease retro-entry.") (forward-line)))) (defun ledger-set-year (newyear) - "Set ledger's idea of the current year to the prefix argument." + "Set ledger's idea of the current year to the prefix argument NEWYEAR." (interactive "p") (if (= newyear 1) (setq ledger-year (read-string "Year: " (ledger-current-year))) (setq ledger-year (number-to-string newyear)))) (defun ledger-set-month (newmonth) - "Set ledger's idea of the current month to the prefix argument." + "Set ledger's idea of the current month to the prefix argument NEWMONTH." (interactive "p") (if (= newmonth 1) (setq ledger-month (read-string "Month: " (ledger-current-month))) (setq ledger-month (format "%02d" newmonth)))) (defun ledger-add-transaction (transaction-text &optional insert-at-point) + "Use ledger xact TRANSACTION-TEXT to add a transaction to the buffer. +If INSERT-AT-POINT is non-nil insert the transaction +there, otherwise call `ledger-find-slot' to insert it at the +correct chronological place in the buffer." (interactive (list (read-string "Transaction: " (concat ledger-year "/" ledger-month "/")))) (let* ((args (with-temp-buffer @@ -223,6 +237,7 @@ customizable to ease retro-entry.") (end-of-line -1))))) (defun ledger-current-transaction-bounds () + "Return markers for the beginning and end of transaction surrounding point." (save-excursion (when (or (looking-at "^[0-9]") (re-search-backward "^[0-9]" nil t)) @@ -232,8 +247,11 @@ customizable to ease retro-entry.") (cons (copy-marker beg) (point-marker)))))) (defun ledger-delete-current-transaction () + "Delete the transaction surrounging point." (interactive) (let ((bounds (ledger-current-transaction-bounds))) (delete-region (car bounds) (cdr bounds)))) (provide 'ldg-mode) + +;;; ldg-mode.el ends here diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index 3c56c108..ab267747 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -31,7 +31,7 @@ ;; MA 02111-1307, USA. ;;; Commentary: - +;; Load up the ledger mode (require 'ldg-complete) (require 'ldg-exec) (require 'ldg-mode) @@ -49,6 +49,8 @@ (require 'ldg-commodities) +;;; Code: + (autoload #'ledger-texi-update-test "ldg-texi" nil t) (autoload #'ledger-texi-update-examples "ldg-texi" nil t) @@ -57,13 +59,12 @@ :group 'data) (defconst ledger-version "3.0" - "The version of ledger.el currently loaded") - -(provide 'ledger) + "The version of ledger.el currently loaded.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun ledger-create-test () + "Create a regression test." (interactive) (save-restriction (org-narrow-to-subtree) @@ -87,4 +88,6 @@ (delete-char 3) (forward-line 1)))))) -;;; ledger.el ends here +(provide 'ledger) + +;;; ldg-new.el ends here diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index d53be09b..417a3d2a 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -25,7 +25,7 @@ ;;; Commentary: ;; Provide code folding to ledger mode. Adapted from original loccur ;; mode by Alexey Veretennikov +;; com> ;; ;; Adapted to ledger mode by Craig Earls @@ -34,8 +34,8 @@ (defconst ledger-occur-overlay-property-name 'ledger-occur-custom-buffer-grep) -(defcustom ledger-occur-use-face-unfolded t - "if non-nil use a custom face for xacts shown in ledger-occur mode" +(defcustom ledger-occur-use-face-unfolded t + "If non-nil use a custom face for xacts shown in `ledger-occur' mode." :type 'boolean :group 'ledger) (make-variable-buffer-local 'ledger-occur-use-face-unfolded) @@ -49,11 +49,11 @@ (list '(ledger-occur-mode ledger-occur-mode)))) (defvar ledger-occur-history nil - "History of previously searched expressions for the prompt") + "History of previously searched expressions for the prompt.") (make-variable-buffer-local 'ledger-occur-history) (defvar ledger-occur-last-match nil - "Last match found") + "Last match found.") (make-variable-buffer-local 'ledger-occur-last-match) (defvar ledger-occur-overlay-list nil @@ -61,12 +61,12 @@ (make-variable-buffer-local 'ledger-occur-overlay-list) (defun ledger-occur-mode (regex buffer) - "Higlight transaction that match REGEX, hiding others + "Highlight transactions that match REGEX in BUFFER, hiding others. When REGEX is nil, unhide everything, and remove higlight" (progn (set-buffer buffer) - (setq ledger-occur-mode + (setq ledger-occur-mode (if (or (null regex) (zerop (length regex))) nil @@ -76,7 +76,7 @@ When REGEX is nil, unhide everything, and remove higlight" (if ledger-occur-mode (let* ((buffer-matches (ledger-occur-find-matches regex)) (ovl-bounds (ledger-occur-create-xact-overlay-bounds buffer-matches))) - (setq ledger-occur-overlay-list + (setq ledger-occur-overlay-list (ledger-occur-create-xact-overlays ovl-bounds)) (setq ledger-occur-overlay-list (append ledger-occur-overlay-list @@ -86,13 +86,12 @@ When REGEX is nil, unhide everything, and remove higlight" (recenter))) (defun ledger-occur (regex) - "Perform a simple grep in current buffer for the regular - expression REGEX + "Perform a simple grep in current buffer for the regular expression REGEX. This command hides all xact from the current buffer except - those containing the regular expression REGEX. A second call + those containing the regular expression REGEX. A second call of the function unhides lines again" - (interactive + (interactive (if ledger-occur-mode (list nil) (list (read-string (concat "Regexp<" (ledger-occur-prompt) @@ -101,7 +100,7 @@ When REGEX is nil, unhide everything, and remove higlight" (ledger-occur-mode regex (current-buffer))) (defun ledger-occur-prompt () - "Returns the default value of the prompt. + "Return the default value of the prompt. Default value for prompt is a current word or active region(selection), if its size is 1 line" @@ -129,7 +128,7 @@ When REGEX is nil, unhide everything, and remove higlight" ;; the last form in ;; the lambda is the ;; (make-overlay) - (setq prev-end (1+ (cadr match))) + (setq prev-end (1+ (cadr match))) ;; add 1 so that we skip the ;; empty line after the xact (make-overlay @@ -147,7 +146,9 @@ When REGEX is nil, unhide everything, and remove higlight" (defun ledger-occur-create-xact-overlays (ovl-bounds) - (let ((overlays + "Create the overlay for the visible transactions. +Argument OVL-BOUNDS contains bounds for the transactions to be left visible." + (let ((overlays (mapcar (lambda (bnd) (make-overlay (car bnd) @@ -161,8 +162,7 @@ When REGEX is nil, unhide everything, and remove higlight" overlays))) (defun ledger-occur-change-regex (regex buffer) - "use this function to programatically change the overlays, - rather than quitting out and restarting" + "Use this function to programatically change the overlays using REGEX in BUFFER, rather than quitting out and restarting." (progn (set-buffer buffer) (setq ledger-occur-mode nil) @@ -171,8 +171,8 @@ When REGEX is nil, unhide everything, and remove higlight" (recenter))) (defun ledger-occur-quit-buffer (buffer) - "quits hidings transaction in the given buffer. Used for - coordinating ledger-occur with other buffers, like reconcile" + "Quits hidings transaction in the given BUFFER. +Used for coordinating `ledger-occur' with other buffers, like reconcile." (progn (set-buffer buffer) (setq ledger-occur-mode nil) @@ -181,13 +181,15 @@ When REGEX is nil, unhide everything, and remove higlight" (recenter))) (defun ledger-occur-remove-overlays () + "Remove the transaction hiding overlays." (interactive) - (remove-overlays (point-min) + (remove-overlays (point-min) (point-max) ledger-occur-overlay-property-name t) (setq ledger-occur-overlay-list nil)) (defun ledger-occur-create-xact-overlay-bounds (buffer-matches) + "Use BUFFER-MATCHES to produce the overlay for the visible transactions." (let ((prev-end (point-min)) (overlays (list))) (when buffer-matches @@ -199,8 +201,7 @@ When REGEX is nil, unhide everything, and remove higlight" (defun ledger-occur-find-matches (regex) - "Returns a list of 2-number tuples, specifying begnning of the - line and end of a line containing matching xact" + "Return a list of 2-number tuples describing the beginning and start of transactions meeting REGEX." (save-excursion (goto-char (point-min)) ;; Set initial values for variables diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 8b0e3db6..bdbb4386 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -19,8 +19,14 @@ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. + +;;; Commentary: +;; Utility functions for dealing with postings. + (require 'ldg-regex) +;;; Code: + (defgroup ledger-post nil "" :group 'ledger) @@ -46,12 +52,13 @@ :group 'ledger-post) (defcustom ledger-post-use-decimal-comma nil - "if non-nil the use commas as decimal separator. This only has - effect interfacing to calc mode in edit amount" + "If non-nil the use commas as decimal separator. +This only has effect interfacing to calc mode in edit amount" :type 'boolean :group 'ledger-post) (defun ledger-post-all-accounts () + "Return a list of all accounts in the buffer." (let ((origin (point)) (ledger-post-list nil) account elements) @@ -68,8 +75,8 @@ (defvar iswitchb-temp-buflist) (defun ledger-post-completing-read (prompt choices) - "Use iswitchb as a completing-read replacement to choose from choices. - PROMPT is a string to prompt with. CHOICES is a list of + "Use iswitchb as a `completing-read' replacement to choose from choices. +PROMPT is a string to prompt with. CHOICES is a list of strings to choose from." (cond (ledger-post-use-iswitchb @@ -86,6 +93,7 @@ (defvar ledger-post-current-list nil) (defun ledger-post-pick-account () + "Insert an account entered by the user." (interactive) (let* ((account (ledger-post-completing-read @@ -111,6 +119,7 @@ (goto-char pos))) (defun ledger-next-amount (&optional end) + "Move point to the next amount, as long as it is not past END." (when (re-search-forward "\\( \\|\t\\| \t\\)[ \t]*-?\\([A-Z$€£]+ *\\)?\\(-?[0-9,]+?\\)\\(.[0-9]+\\)?\\( *[A-Z$€£]+\\)?\\([ \t]*@@?[^\n;]+?\\)?\\([ \t]+;.+?\\)?$" (marker-position end) t) (goto-char (match-beginning 0)) (skip-syntax-forward " ") @@ -119,7 +128,7 @@ (defun ledger-align-amounts (&optional column) "Align amounts in the current region. - This is done so that the last digit falls in COLUMN, which +This is done so that the last digit falls in COLUMN, which defaults to 52." (interactive "p") (if (or (null column) (= column 1)) @@ -146,6 +155,7 @@ (forward-line)))))) (defun ledger-post-align-amount () + "Align the amounts in this posting." (interactive) (save-excursion (set-mark (line-beginning-position)) @@ -153,6 +163,8 @@ (ledger-align-amounts))) (defun ledger-post-maybe-align (beg end len) + "Align amounts only if point is in a posting. +BEG, END, and LEN control how far it can align." (save-excursion (goto-char beg) (when (< end (line-end-position)) @@ -161,11 +173,12 @@ (ledger-post-align-amount))))) (defun ledger-post-edit-amount () + "Call 'calc-mode' and push the amount in the posting to the top of stack." (interactive) (goto-char (line-beginning-position)) - (when (re-search-forward ledger-post-line-regexp (line-end-position) t) + (when (re-search-forward ledger-post-line-regexp (line-end-position) t) (goto-char (match-end ledger-regex-post-line-group-account)) ;; go to the and of the account - (let ((end-of-amount (re-search-forward "[-.,0-9]+" (line-end-position) t))) + (let ((end-of-amount (re-search-forward "[-.,0-9]+" (line-end-position) t))) ;; determine if there is an amount to edit (if end-of-amount (let ((val (match-string 0))) @@ -189,6 +202,7 @@ (calc)))))) (defun ledger-post-prev-xact () + "Move point to the previous transaction." (interactive) (backward-paragraph) (when (re-search-backward ledger-xact-line-regexp nil t) @@ -197,6 +211,7 @@ (goto-char (match-end ledger-regex-post-line-group-account)))) (defun ledger-post-next-xact () + "Move point to the next transaction." (interactive) (when (re-search-forward ledger-xact-line-regexp nil t) (goto-char (match-beginning 0)) @@ -204,8 +219,11 @@ (goto-char (match-end ledger-regex-post-line-group-account)))) (defun ledger-post-setup () + "Configure `ledger-mode' to auto-align postings." (if ledger-post-auto-adjust-amounts (add-hook 'after-change-functions 'ledger-post-maybe-align t t)) (add-hook 'after-save-hook #'(lambda () (setq ledger-post-current-list nil)))) (provide 'ldg-post) + +;;; ldg-post.el ends here diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 96a10afb..b632a070 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -21,60 +21,64 @@ ;; Reconcile mode + +;;; Commentary: +;; + +;;; Code: + (defvar ledger-buf nil) (defvar ledger-bufs nil) (defvar ledger-acct nil) (defvar ledger-target nil) (defcustom ledger-recon-buffer-name "*Reconcile*" - "Name to use for reconciliation window" + "Name to use for reconciliation window." :group 'ledger) -(defcustom ledger-fold-on-reconcile t - "if t, limit transactions shown in main buffer to those - matching the reconcile regex" +(defcustom ledger-fold-on-reconcile t + "If t, limit transactions shown in main buffer to those matching the reconcile regex." :type 'boolean :group 'ledger) (defcustom ledger-buffer-tracks-reconcile-buffer t - "if t, then when the cursor is moved to a new xact in the recon - window, then that transaction will be shown in its source - buffer." + "If t, then when the cursor is moved to a new xact in the recon window. +Then that transaction will be shown in its source buffer." :type 'boolean :group 'ledger) (defcustom ledger-reconcile-force-window-bottom nil - "If t make the reconcile window appear along the bottom of the - register window and resize" + "If t make the reconcile window appear along the bottom of the register window and resize." :type 'boolean :group 'ledger) (defcustom ledger-reconcile-toggle-to-pending t - "if true then toggle between uncleared and pending. - reconcile-finish will mark all pending posting cleared. " + "If true then toggle between uncleared and pending. +reconcile-finish will mark all pending posting cleared." :type 'boolean :group 'ledger) (defun ledger-reconcile-get-balances () - "Calculate the cleared and uncleared balance of the account being reconciled, - return a list with the account, uncleared and cleared balances as numbers" + "Calculate the cleared and uncleared balance of the account. +Return a list with the account, uncleared and cleared balances as +numbers" (interactive) (let ((buffer ledger-buf) (account ledger-acct) (val nil)) (with-temp-buffer - (ledger-exec-ledger buffer (current-buffer) + (ledger-exec-ledger buffer (current-buffer) ; note that in the line below, the --format option is ; separated from the actual format string. emacs does not ; split arguments like the shell does, so you need to ; specify the individual fields in the command line. - "balance" "--limit" "cleared or pending" + "balance" "--limit" "cleared or pending" "--format" "(\"%(amount)\")" account) (setq val (read (buffer-substring-no-properties (point-min) (point-max))))))) (defun ledger-display-balance () - "Calculate the cleared balance of the account being reconciled" + "Calculate the cleared balance of the account being reconciled." (interactive) (let* ((pending (car (ledger-string-balance-to-commoditized-amount (car (ledger-reconcile-get-balances))))) @@ -83,28 +87,30 @@ nil))) (if target-delta - (message "Pending balance: %s, Difference from target: %s" + (message "Pending balance: %s, Difference from target: %s" (ledger-commodity-to-string pending) (ledger-commodity-to-string target-delta)) - (message "Pending balance: %s" + (message "Pending balance: %s" (ledger-commodity-to-string pending))))) (defun is-stdin (file) - "True if ledger file is standard input" + "True if ledger FILE is standard input." (or (equal file "") (equal file "") (equal file "/dev/stdin"))) (defun ledger-reconcile-get-buffer (where) + "Return a buffer from WHERE the transaction is." (if (bufferp (car where)) (car where) - (error "buffer not set"))) + (error "Buffer not set"))) (defun ledger-reconcile-toggle () + "Toggle the current transaction, and mark the recon window." (interactive) (let ((where (get-text-property (point) 'where)) (inhibit-read-only t) @@ -113,7 +119,7 @@ (with-current-buffer (ledger-reconcile-get-buffer where) (ledger-goto-line (cdr where)) (forward-char) - (setq status (ledger-toggle-current (if ledger-reconcile-toggle-to-pending + (setq status (ledger-toggle-current (if ledger-reconcile-toggle-to-pending 'pending 'cleared)))) ;; remove the existing face and add the new face @@ -128,7 +134,7 @@ (add-text-properties (line-beginning-position) (line-end-position) (list 'face 'ledger-font-reconciler-cleared-face ))) - (t + (t (add-text-properties (line-beginning-position) (line-end-position) (list 'face 'ledger-font-reconciler-uncleared-face ))))) @@ -137,6 +143,7 @@ (ledger-display-balance))) (defun ledger-reconcile-refresh () + "Force the reconciliation window to refresh." (interactive) (let ((inhibit-read-only t) (line (count-lines (point-min) (point)))) @@ -147,6 +154,7 @@ (forward-line line))) (defun ledger-reconcile-refresh-after-save () + "Refresh the recon-window after the ledger buffer is saved." (let ((buf (get-buffer ledger-recon-buffer-name))) (if buf (with-current-buffer buf @@ -154,12 +162,14 @@ (set-buffer-modified-p nil))))) (defun ledger-reconcile-add () + "Use ledger xact to add a new transaction." (interactive) (with-current-buffer ledger-buf (call-interactively #'ledger-add-transaction)) (ledger-reconcile-refresh)) (defun ledger-reconcile-delete () + "Delete the transactions pointed to in the recon window." (interactive) (let ((where (get-text-property (point) 'where))) (when (ledger-reconcile-get-buffer where) @@ -172,11 +182,12 @@ (set-buffer-modified-p t))))) (defun ledger-reconcile-visit (&optional come-back) + "Recenter ledger buffer on transaction and COME-BACK if non-nil." (interactive) (progn (beginning-of-line) (let* ((where (get-text-property (1+ (point)) 'where)) - (target-buffer (if where + (target-buffer (if where (ledger-reconcile-get-buffer where) nil)) (cur-buf (get-buffer ledger-recon-buffer-name))) @@ -190,6 +201,7 @@ (switch-to-buffer-other-window cur-buf)))))) (defun ledger-reconcile-save () + "Save the ledger buffer." (interactive) (dolist (buf (cons ledger-buf ledger-bufs)) (with-current-buffer buf @@ -198,9 +210,9 @@ (ledger-display-balance)) (defun ledger-reconcile-finish () - "Mark all pending posting or transactions as cleared, depending - on ledger-reconcile-clear-whole-transactions, save the buffers - and exit reconcile mode" + "Mark all pending posting or transactions as cleared. +Depends on ledger-reconcile-clear-whole-transactions, save the buffers +and exit reconcile mode" (interactive) (save-excursion (goto-char (point-min)) @@ -216,6 +228,7 @@ (defun ledger-reconcile-quit () + "Quite the reconcile window without saving ledger buffer." (interactive) (ledger-reconcile-quit-cleanup) (let ((buf ledger-buf) @@ -228,18 +241,18 @@ (set-window-buffer (selected-window) buf))) (defun ledger-reconcile-quit-cleanup () + "Cleanup all hooks established by reconcile mode." (interactive) (let ((buf ledger-buf) (reconcile-buf (get-buffer ledger-recon-buffer-name))) (with-current-buffer buf (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t) (if ledger-fold-on-reconcile - (ledger-occur-quit-buffer buf))))) + (ledger-occur-quit-buffer buf))))) (defun ledger-marker-where-xact-is (emacs-xact posting) - "find the position of the xact in the ledger-buf buffer using - the emacs output from ledger, return the buffer and a marker - to the beginning of the xact in that buffer" + "Find the position of the EMACS-XACT in the `ledger-buf'. +POSTING is used in `ledger-clear-whole-transactions' is nil." (let ((buf (if (is-stdin (nth 0 emacs-xact)) ledger-buf (find-file-noselect (nth 0 emacs-xact))))) @@ -250,13 +263,12 @@ (nth 0 posting))))) ;; return line-no of posting (defun ledger-do-reconcile () - "get the uncleared transactions in the account and display them - in the *Reconcile* buffer" + "Get the uncleared transactions in the account and display them in the *Reconcile* buffer." (let* ((buf ledger-buf) (account ledger-acct) (xacts - (with-temp-buffer - (ledger-exec-ledger buf (current-buffer) + (with-temp-buffer + (ledger-exec-ledger buf (current-buffer) "--uncleared" "--real" "emacs" account) (goto-char (point-min)) (unless (eobp) @@ -267,7 +279,7 @@ (progn (dolist (xact xacts) (dolist (posting (nthcdr 5 xact)) - (let ((beg (point)) + (let ((beg (point)) (where (ledger-marker-where-xact-is xact posting))) (insert (format "%s %-4s %-30s %-30s %15s\n" (format-time-string "%Y/%m/%d" (nth 2 xact)) @@ -278,13 +290,13 @@ (if (nth 3 posting) (if (eq (nth 3 posting) 'pending) (set-text-properties beg (1- (point)) - (list 'face 'ledger-font-reconciler-pending-face + (list 'face 'ledger-font-reconciler-pending-face 'where where)) (set-text-properties beg (1- (point)) - (list 'face 'ledger-font-reconciler-cleared-face + (list 'face 'ledger-font-reconciler-cleared-face 'where where))) (set-text-properties beg (1- (point)) - (list 'face 'ledger-font-reconciler-uncleared-face + (list 'face 'ledger-font-reconciler-uncleared-face 'where where)))) )) (goto-char (point-max)) (delete-char -1)) ;gets rid of the extra line feed at the bottom of the list @@ -312,6 +324,7 @@ (add-hook 'post-command-hook 'ledger-reconcile-track-xact nil t)))) (defun ledger-reconcile-track-xact () + "Force the ledger buffer to recenter on the transactionat point in the reconcile buffer." (if (member this-command (list 'next-line 'previous-line 'mouse-set-point @@ -321,15 +334,14 @@ (ledger-reconcile-visit t))))) (defun ledger-reconcile-open-windows (buf rbuf) - "Ensure that the reconcile buffer has its windows - -Spliting the windows of BUF if needed" + "Ensure that the ledger buffer BUF is split by RBUF." (if ledger-reconcile-force-window-bottom ;;create the *Reconcile* window directly below the ledger buffer. (set-window-buffer (split-window (get-buffer-window buf) nil nil) rbuf) (pop-to-buffer rbuf))) (defun ledger-reconcile (account) + "Start reconciling ACCOUNT." (interactive "sAccount to reconcile: ") (let ((buf (current-buffer)) (rbuf (get-buffer ledger-recon-buffer-name))) ;; this means @@ -339,7 +351,7 @@ Spliting the windows of BUF if needed" (if rbuf ;; *Reconcile* already exists (with-current-buffer rbuf (set 'ledger-acct account) ;; already buffer local - (if (not (eq buf rbuf)) + (if (not (eq buf rbuf)) (progn ;; called from some other ledger-mode buffer (ledger-reconcile-quit-cleanup) (set 'ledger-buf buf))) ;; should already be @@ -370,15 +382,9 @@ Spliting the windows of BUF if needed" (defvar ledger-reconcile-mode-abbrev-table) (defun ledger-reconcile-change-target () + "Change the traget amount for the reconciliation process." (interactive) (setq ledger-target (call-interactively #'ledger-read-commodity-string))) -; (setq ledger-target -; (if (and target (> (length target) 0)) -; (ledger-string-balance-to-commoditized-amount target)))) - -(defun ledger-reconcile-display-internals () - (interactive) - (message "%S %S" ledger-acct ledger-buf)) (define-derived-mode ledger-reconcile-mode text-mode "Reconcile" "A mode for reconciling ledger entries." @@ -397,7 +403,6 @@ Spliting the windows of BUF if needed" (define-key map [?s] 'ledger-reconcile-save) (define-key map [?q] 'ledger-reconcile-quit) (define-key map [?b] 'ledger-display-balance) - (define-key map [?i] 'ledger-reconcile-display-internals) (define-key map [menu-bar] (make-sparse-keymap "ldg-recon-menu")) (define-key map [menu-bar ldg-recon-menu] (cons "Reconcile" map)) @@ -424,4 +429,7 @@ Spliting the windows of BUF if needed" (add-hook 'kill-buffer-hook 'ledger-reconcile-quit-cleanup nil t))) -(provide 'ldg-reconcile) \ No newline at end of file +(provide 'ldg-reconcile) +(provide 'ldg-reconcile) + +;;; ldg-reconcile.el ends here diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 711af042..40e54935 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -19,6 +19,12 @@ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. + +;;; Commentary: +;; + +;;; Code: + (eval-when-compile (require 'cl)) @@ -34,7 +40,7 @@ contain format specifiers that are replaced with context sensitive information. Format specifiers have the format '%()' where is an identifier for the information to be replaced. The `ledger-report-format-specifiers' alist variable contains a mapping -from format specifier identifier to a lisp function that implements +from format specifier identifier to a Lisp function that implements the substitution. See the documentation of the individual functions in that variable for more information on the behavior of each specifier." @@ -46,7 +52,7 @@ specifier." '(("ledger-file" . ledger-report-ledger-file-format-specifier) ("payee" . ledger-report-payee-format-specifier) ("account" . ledger-report-account-format-specifier)) - "Alist mapping ledger report format specifiers to implementing functions + "An alist mapping ledger report format specifiers to implementing functions. The function is called with no parameters and expected to return the text that should replace the format specifier." @@ -121,13 +127,14 @@ The empty string and unknown names are allowed." (defun ledger-report (report-name edit) "Run a user-specified report from `ledger-reports'. -Prompts the user for the name of the report to run. If no name is -entered, the user will be prompted for a command line to run. The -command line specified or associated with the selected report name -is run and the output is made available in another buffer for viewing. -If a prefix argument is given and the user selects a valid report -name, the user is prompted with the corresponding command line for -editing before the command is run. +Prompts the user for the REPORT-NAME of the report to run or +EDIT. If no name is entered, the user will be prompted for a +command line to run. The command line specified or associated +with the selected report name is run and the output is made +available in another buffer for viewing. If a prefix argument is +given and the user selects a valid report name, the user is +prompted with the corresponding command line for editing before +the command is run. The output buffer will be in `ledger-report-mode', which defines commands for saving a new named report based on the command line @@ -159,11 +166,11 @@ used to generate the buffer, navigating the buffer, etc." (message "q to quit; r to redo; e to edit; k to kill; s to save; SPC and DEL to scroll")))) (defun string-empty-p (s) - "Check for the empty string." + "Check S for the empty string." (string-equal "" s)) (defun ledger-report-name-exists (name) - "Check to see if the given report name exists. + "Check to see if the given report NAME exists. If name exists, returns the object naming the report, otherwise returns nil." @@ -171,7 +178,7 @@ used to generate the buffer, navigating the buffer, etc." (car (assoc name ledger-reports)))) (defun ledger-reports-add (name cmd) - "Add a new report to `ledger-reports'." + "Add a new report NAME and CMD to `ledger-reports'." (setq ledger-reports (cons (list name cmd) ledger-reports))) (defun ledger-reports-custom-save () @@ -179,15 +186,15 @@ used to generate the buffer, navigating the buffer, etc." (customize-save-variable 'ledger-reports ledger-reports)) (defun ledger-report-read-command (report-cmd) - "Read the command line to create a report." + "Read the command line to create a report from REPORT-CMD." (read-from-minibuffer "Report command line: " (if (null report-cmd) "ledger " report-cmd) nil nil 'ledger-report-cmd-prompt-history)) (defun ledger-report-ledger-file-format-specifier () - "Substitute the full path to master or current ledger file + "Substitute the full path to master or current ledger file. - The master file name is determined by the ledger-master-file + The master file name is determined by the variable `ledger-master-file' buffer-local variable which can be set using file variables. If it is set, it is used, otherwise the current buffer file is used." @@ -201,7 +208,7 @@ used to generate the buffer, navigating the buffer, etc." "Return the master file for a ledger file. The master file is either the file for the current ledger buffer or the - file specified by the buffer-local variable ledger-master-file. Typically + file specified by the buffer-local variable `ledger-master-file'. Typically this variable would be set in a file local variable comment block at the end of a ledger file which is included in some other file." (if ledger-master-file @@ -209,6 +216,7 @@ used to generate the buffer, navigating the buffer, etc." (buffer-file-name))) (defun ledger-read-string-with-default (prompt default) + "Return user supplied string after PROMPT, or DEFAULT." (let ((default-prompt (concat prompt (if default (concat " (" default "): ") @@ -216,7 +224,7 @@ used to generate the buffer, navigating the buffer, etc." (read-string default-prompt nil nil default))) (defun ledger-report-payee-format-specifier () - "Substitute a payee name + "Substitute a payee name. The user is prompted to enter a payee and that is substitued. If point is in an entry, the payee for that entry is used as the @@ -227,7 +235,7 @@ used to generate the buffer, navigating the buffer, etc." (ledger-read-string-with-default "Payee" (regexp-quote (ledger-xact-payee)))) (defun ledger-report-account-format-specifier () - "Substitute an account name + "Substitute an account name. The user is prompted to enter an account name, which can be any regular expression identifying an account. If point is on an account @@ -243,6 +251,7 @@ used to generate the buffer, navigating the buffer, etc." (ledger-read-string-with-default "Account" default))) (defun ledger-report-expand-format-specifiers (report-cmd) + "Expand %(account) and %(payee) appearing in REPORT-CMD with thing under point." (save-match-data (let ((expanded-cmd report-cmd)) (set-match-data (list 0 0)) @@ -258,7 +267,8 @@ used to generate the buffer, navigating the buffer, etc." expanded-cmd))) (defun ledger-report-cmd (report-name edit) - "Get the command line to run the report." + "Get the command line to run the report name REPORT-NAME. +Optional EDIT the command." (let ((report-cmd (car (cdr (assoc report-name ledger-reports))))) ;; logic for substitution goes here (when (or (null report-cmd) edit) @@ -269,12 +279,12 @@ used to generate the buffer, navigating the buffer, etc." (or (string-empty-p report-name) (ledger-report-name-exists report-name) (progn - (ledger-reports-add report-name report-cmd) + (ledger-reports-add report-name report-cmd) (ledger-reports-custom-save))) report-cmd)) (defun ledger-do-report (cmd) - "Run a report command line." + "Run a report command line CMD." (goto-char (point-min)) (insert (format "Report: %s\n" ledger-report-name) (format "Command: %s\n" cmd) @@ -289,7 +299,8 @@ used to generate the buffer, navigating the buffer, etc." (if (and register-report (not (string-match "--subtotal" cmd))) (concat cmd " --prepend-format='%(filename):%(beg_line):'") - cmd) t nil) + cmd) + t nil) (when register-report (goto-char data-pos) (while (re-search-forward "^\\(/[^:]+\\)?:\\([0-9]+\\)?:" nil t) @@ -310,6 +321,7 @@ used to generate the buffer, navigating the buffer, etc." (defun ledger-report-visit-source () + "Visit the transaction under point in the report window." (interactive) (let* ((prop (get-text-property (point) 'ledger-source)) (file (if prop (car prop))) @@ -382,7 +394,7 @@ used to generate the buffer, navigating the buffer, etc." (setq ledger-report-name (ledger-report-read-new-name))) (if (setq existing-name (ledger-report-name-exists ledger-report-name)) - (cond ((y-or-n-p (format "Overwrite existing report named '%s' " + (cond ((y-or-n-p (format "Overwrite existing report named '%s'? " ledger-report-name)) (if (string-equal ledger-report-cmd @@ -395,7 +407,7 @@ used to generate the buffer, navigating the buffer, etc." (ledger-reports-custom-save)))) (t (progn - (setq ledger-report-name (ledger-report-read-new-name)) + (setq ledger-report-name (ledger-report-read-new-name)) (ledger-reports-add ledger-report-name ledger-report-cmd) (ledger-reports-custom-save))))))) @@ -424,9 +436,9 @@ used to generate the buffer, navigating the buffer, etc." (indent account)))))) (defun ledger-extract-context-info (line-type pos) - "Get context info for current line. + "Get context info for current line with LINE-TYPE. -Assumes point is at beginning of line, and the pos argument specifies +Assumes point is at beginning of line, and the POS argument specifies where the \"users\" point was." (let ((linfo (assoc line-type ledger-line-config)) found field fields) @@ -495,7 +507,7 @@ the fields in the line in a association list." '(unknown nil nil))))))) (defun ledger-context-other-line (offset) - "Return a list describing context of line offset for existing position. + "Return a list describing context of line OFFSET from existing position. Offset can be positive or negative. If run out of buffer before reaching specified line, returns nil." @@ -534,3 +546,5 @@ specified line, returns nil." (goto-char (ledger-context-field-end-position context-info field-name))) (provide 'ldg-report) + +;;; ldg-report.el ends here diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el index 8a1d9573..361eead8 100644 --- a/lisp/ldg-sort.el +++ b/lisp/ldg-sort.el @@ -19,10 +19,15 @@ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. -;; A sample entry sorting function, which works if entry dates are of -;; the form YYYY/mm/dd. + + +;;; Commentary: +;; + +;;; Code: (defun ledger-next-record-function () + "Move point to next transaction." (if (re-search-forward (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) @@ -30,9 +35,11 @@ (goto-char (point-max)))) (defun ledger-end-record-function () + "Move point to end of transaction." (forward-paragraph)) (defun ledger-sort-region (beg end) + "Sort the region from BEG to END in chronological order." (interactive "r") ;; load beg and end from point and mark ;; automagically (let ((new-beg beg) @@ -57,8 +64,10 @@ 'ledger-end-record-function)))))) (defun ledger-sort-buffer () + "Sort the entire buffer." (interactive) (ledger-sort-region (point-min) (point-max))) +(provide 'ldg-sort) -(provide 'ldg-sort) \ No newline at end of file +;;; ldg-sort.el ends here diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index fad7d71c..3e349e4e 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -19,12 +19,19 @@ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. + +;;; Commentary: +;; Utilities for dealing with transaction and posting status. + +;;; Code: + (defcustom ledger-clear-whole-transactions nil "If non-nil, clear whole transactions, not individual postings." :type 'boolean :group 'ledger) (defun ledger-toggle-state (state &optional style) + "Return the correct toggle state given the current STATE, and STYLE." (if (not (null state)) (if (and style (eq style 'cleared)) 'cleared) @@ -33,6 +40,7 @@ 'cleared))) (defun ledger-transaction-state () + "Return the state of the transaction at point." (save-excursion (when (or (looking-at "^[0-9]") (re-search-backward "^[0-9]" nil t)) @@ -43,6 +51,7 @@ (t nil))))) (defun ledger-posting-state () + "Return the state of the posting." (save-excursion (goto-char (line-beginning-position)) (skip-syntax-forward " ") @@ -51,6 +60,7 @@ (t (ledger-transaction-state))))) (defun ledger-char-from-state (state) + "Return the char representation of STATE." (if state (if (eq state 'pending) "!" @@ -58,6 +68,7 @@ "")) (defun ledger-state-from-char (state-char) + "Get state from STATE-CHAR." (cond ((eql state-char ?\!) 'pending) ((eql state-char ?\*) @@ -69,7 +80,7 @@ "Toggle the cleared status of the transaction under point. Optional argument STYLE may be `pending' or `cleared', depending on which type of status the caller wishes to indicate (default is -`cleared'). Returns the new status as 'pending 'cleared or nil. +`cleared'). Returns the new status as 'pending 'cleared or nil. This function is rather complicated because it must preserve both the overall formatting of the ledger entry, as well as ensuring that the most minimal display format is used. This could be @@ -87,7 +98,7 @@ dropped." (setq cur-status (and (member (char-after) '(?\* ?\!)) (ledger-state-from-char (char-after)))) ;;if cur-status if !, or * then delete the marker - (when cur-status + (when cur-status (let ((here (point))) (skip-chars-forward "*! ") (let ((width (- (point) here))) @@ -105,7 +116,7 @@ dropped." (setq new-status nil))) ;;this excursion marks the posting pending or cleared - (save-excursion + (save-excursion (goto-char (line-beginning-position)) (when (looking-at "[ \t]") (skip-chars-forward " \t") @@ -189,6 +200,7 @@ dropped." new-status)) (defun ledger-toggle-current (&optional style) + "Toggle the current thing at point with optional STYLE." (interactive) (if (or ledger-clear-whole-transactions (eq 'transaction (ledger-thing-at-point))) @@ -207,6 +219,7 @@ dropped." (ledger-toggle-current-posting style))) (defun ledger-toggle-current-transaction (&optional style) + "Toggle the transaction at point using optional STYLE." (interactive) (let (status) (save-excursion @@ -219,7 +232,7 @@ dropped." (progn (delete-char 1) (if (and style (eq style 'cleared)) - (progn + (progn (insert " *") (setq status 'cleared)))) (if (and style (eq style 'pending)) @@ -232,3 +245,7 @@ dropped." status)) (provide 'ldg-state) + +(provide 'ldg-state) + +;;; ldg-state.el ends here diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index a1c768ca..94a58542 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -19,19 +19,23 @@ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. -;; A sample entry sorting function, which works if entry dates are of -;; the form YYYY/mm/dd. + +;;; Commentary: +;; Utilites for running ledger synchronously. + +;;; Code: (defcustom ledger-highlight-xact-under-point t - "If t highlight xact under point" + "If t highlight xact under point." :type 'boolean :group 'ledger) (defvar highlight-overlay (list)) (defun ledger-find-xact-extents (pos) - "return point for beginning of xact and and of xact containing - position. Requires empty line separating xacts" + "Return point for beginning of xact and and of xact containing position. +Requires empty line separating xacts. Argument POS is a location +within the transaction." (interactive "d") (save-excursion (goto-char pos) @@ -49,7 +53,8 @@ (defun ledger-highlight-xact-under-point () - (if ledger-highlight-xact-under-point + "Move the highlight overlay to the current transaction." +(if ledger-highlight-xact-under-point (let ((exts (ledger-find-xact-extents (point))) (ovl highlight-overlay)) (if (not highlight-overlay) @@ -63,7 +68,7 @@ (overlay-put ovl 'priority 100)))) (defun ledger-xact-payee () - "Returns the payee of the entry containing point or nil." + "Return the payee of the entry containing point or nil." (let ((i 0)) (while (eq (ledger-context-line-type (ledger-context-other-line i)) 'acct-transaction) (setq i (- i 1))) @@ -73,10 +78,12 @@ nil)))) (defsubst ledger-goto-line (line-number) - (goto-char (point-min)) (forward-line (1- line-number))) + "Rapidly move point to line LINE-NUMBER." +(goto-char (point-min)) (forward-line (1- line-number))) (defun ledger-thing-at-point () - (let ((here (point))) + "Describe thing at points. Return 'transaction, 'posting, or nil." +(let ((here (point))) (goto-char (line-beginning-position)) (cond ((looking-at "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.+?)\\)?\\s-+") (goto-char (match-end 0)) @@ -91,9 +98,9 @@ (ignore (goto-char here)))))) (defun ledger-copy-transaction-at-point (date) - (interactive (list - (read-string "Copy to date: " - (concat ledger-year "/" ledger-month "/")))) + "Ask for a new DATE and copy the transaction under point to that date. Leave point on the first amount."(interactive (list + (read-string "Copy to date: " + (concat ledger-year "/" ledger-month "/")))) (let* ((here (point)) (extents (ledger-find-xact-extents (point))) (transaction (buffer-substring (car extents) (cadr extents))) @@ -112,4 +119,7 @@ -(provide 'ldg-xact) \ No newline at end of file +(provide 'ldg-xact) +(provide 'ldg-xact) + +;;; ldg-xact.el ends here -- cgit v1.2.3 From 089716fb13911ea6a1c044ed5d435809f9e2fff6 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Thu, 14 Feb 2013 19:38:42 -0700 Subject: Bug 894 Changing reconciliation account now repositions point in the Reconcile buffer correctly. --- lisp/ldg-reconcile.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index b632a070..ea8ff06e 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -74,7 +74,7 @@ numbers" ; split arguments like the shell does, so you need to ; specify the individual fields in the command line. "balance" "--limit" "cleared or pending" - "--format" "(\"%(amount)\")" account) + "--format" "(\"%(display_total)\")" account) (setq val (read (buffer-substring-no-properties (point-min) (point-max))))))) (defun ledger-display-balance () @@ -363,7 +363,8 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (call-interactively #'ledger-read-commodity-string)) (unless (get-buffer-window rbuf) (ledger-reconcile-open-windows buf rbuf)) - (ledger-reconcile-refresh)) + (ledger-reconcile-refresh) + (goto-char (point-min))) (progn ;; no recon-buffer, starting from scratch. (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save nil t) -- cgit v1.2.3 From 7f0693bcdc6829aaad100c52fcb16dacd89aed62 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 15 Feb 2013 06:14:33 -0700 Subject: Improved error reporting --- lisp/ldg-commodities.el | 6 ------ lisp/ldg-complete.el | 2 +- lisp/ldg-mode.el | 2 +- lisp/ldg-reconcile.el | 4 ++-- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index c007816d..ab5c8898 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -19,12 +19,6 @@ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. -;; A sample entry sorting function, which works if entry dates are of -;; the form YYYY/mm/dd. - - - - ;;; Commentary: ;; Helper functions to deal with commoditized numbers. A commoditized ;; number will be a cons of value and string where the string contains diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index 82046e07..1836eb2c 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -132,7 +132,7 @@ Return tree structure" (line-end-position)) (condition-case err (ledger-add-transaction text t) - ((error) + ((error "ledger-complete-at-point") (insert text)))) (forward-line) (goto-char (line-end-position)) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 6cab7c9b..6499d803 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -229,7 +229,7 @@ correct chronological place in the buffer." (mapcar 'eval args))) (goto-char (point-min)) (if (looking-at "Error: ") - (error (buffer-string)) + (error (concat "Error in ledger-add-transaction: " (buffer-string)) (buffer-string))) "\n")) (progn diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index ea8ff06e..bb4bec5e 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -107,7 +107,7 @@ numbers" "Return a buffer from WHERE the transaction is." (if (bufferp (car where)) (car where) - (error "Buffer not set"))) + (error "ledger-reconcile-get-buffer: Buffer not set"))) (defun ledger-reconcile-toggle () "Toggle the current transaction, and mark the recon window." @@ -273,7 +273,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (goto-char (point-min)) (unless (eobp) (unless (looking-at "(") - (error (buffer-string))) + (error (concat "ledger-do-reconcile: " (buffer-string))) (read (current-buffer)))))) ;current-buffer is the *temp* created above (if (> (length xacts) 0) (progn -- cgit v1.2.3 From 8116ef478160364cde1b33429ae03c81a536ccbf Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 15 Feb 2013 08:07:41 -0700 Subject: Oops. This adds missing parenthesis to the last commit. --- lisp/ldg-mode.el | 2 +- lisp/ldg-reconcile.el | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 6499d803..01a1b615 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -229,7 +229,7 @@ correct chronological place in the buffer." (mapcar 'eval args))) (goto-char (point-min)) (if (looking-at "Error: ") - (error (concat "Error in ledger-add-transaction: " (buffer-string)) + (error (concat "Error in ledger-add-transaction: " (buffer-string))) (buffer-string))) "\n")) (progn diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index bb4bec5e..373b3de9 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -273,7 +273,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (goto-char (point-min)) (unless (eobp) (unless (looking-at "(") - (error (concat "ledger-do-reconcile: " (buffer-string))) + (error (concat "ledger-do-reconcile: " (buffer-string)))) (read (current-buffer)))))) ;current-buffer is the *temp* created above (if (> (length xacts) 0) (progn -- cgit v1.2.3 From 9d2b2e3cebacb40abadfe6820a0064bbff088d39 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 15 Feb 2013 08:54:04 -0700 Subject: Fixes Bug 897. toggle now works correctly if there are comment lines in the xact --- lisp/ldg-state.el | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index 3e349e4e..6c66ab24 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -73,6 +73,8 @@ 'pending) ((eql state-char ?\*) 'cleared) + ((eql state-char ?\;) + 'comment) (t nil))) @@ -92,7 +94,8 @@ dropped." new-status cur-status) ;; Uncompact the entry, to make it easier to toggle the ;; transaction - (save-excursion ;; this excursion unclears the posting + (save-excursion ;; this excursion checks state of entire + ;; transaction and unclears if marked (goto-char (car bounds)) ;; beginning of xact (skip-chars-forward "0-9./= \t") ;; skip the date (setq cur-status (and (member (char-after) '(?\* ?\!)) @@ -107,15 +110,17 @@ dropped." (if (search-forward " " (line-end-position) t) (insert (make-string width ? )))))) (forward-line) + ;; Shift the cleared/pending status to the postings (while (looking-at "[ \t]") (skip-chars-forward " \t") - (insert (ledger-char-from-state cur-status) " ") - (if (search-forward " " (line-end-position) t) - (delete-char 2)) - (forward-line)) + (when (not (eq (ledger-state-from-char (char-after)) 'comment)) + (insert (ledger-char-from-state cur-status) " ") + (if (search-forward " " (line-end-position) t) + (delete-char 2))) + (forward-line)) (setq new-status nil))) - ;;this excursion marks the posting pending or cleared + ;;this excursion toggles the posting status (save-excursion (goto-char (line-beginning-position)) (when (looking-at "[ \t]") @@ -154,7 +159,9 @@ dropped." (delete-char 1)))) (setq new-status inserted))))) - ;; This excursion cleans up the entry so that it displays minimally + ;; This excursion cleans up the entry so that it displays + ;; minimally. This means that if all posts are cleared, remove + ;; the marks and clear the entire transaction. (save-excursion (goto-char (car bounds)) (forward-line) @@ -164,11 +171,12 @@ dropped." (while (and (not hetero) (looking-at "[ \t]")) (skip-chars-forward " \t") (let ((cur-status (ledger-state-from-char (char-after)))) - (if first - (setq state cur-status - first nil) - (if (not (eq state cur-status)) - (setq hetero t)))) + (if (not (eq cur-status 'comment)) + (if first + (setq state cur-status + first nil) + (if (not (eq state cur-status)) + (setq hetero t))))) (forward-line)) (when (and (not hetero) (not (eq state nil))) (goto-char (car bounds)) -- cgit v1.2.3 From 2a7d1c83dd94b7d3af7e25c9e0ae40349f7c8dcd Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 15 Feb 2013 09:04:34 -0700 Subject: Corrects problem clearing a transaction toggle-current in the payee line will override all posting statuses and clear or unclear the entire transaction. --- lisp/ldg-state.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index 6c66ab24..beecb591 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -220,7 +220,7 @@ dropped." (save-excursion (not (eq 'transaction (ledger-thing-at-point))))) (if (looking-at "\\s-+[*!]") - (ledger-toggle-current-transaction style)) + (ledger-toggle-current-posting style)) (forward-line) (goto-char (line-beginning-position)))) (ledger-toggle-current-transaction style)) -- cgit v1.2.3 From adfb03cac0d07ede80ad8603eaa15b145ac4f1ef Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 15 Feb 2013 12:11:50 -0700 Subject: Fixed overrun when ledger report would expand argument and cmd would get short --- lisp/ldg-report.el | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 40e54935..370117fc 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -31,7 +31,7 @@ (defcustom ledger-reports '(("bal" "ledger -f %(ledger-file) bal") ("reg" "ledger -f %(ledger-file) reg") - ("payee" "ledger -f %(ledger-file) reg -- %(payee)") + ("payee" "ledger -f %(ledger-file) reg @%(payee)") ("account" "ledger -f %(ledger-file) reg %(account)")) "Definition of reports to run. @@ -79,12 +79,22 @@ text that should replace the format specifier." (defvar ledger-report-mode-abbrev-table) +(defun ledger-report-reverse-lines () + (interactive) + (goto-char (point-min)) + (forward-paragraph) + (next-line) + (save-excursion + (setq inhibit-read-only t) + (reverse-region (point) (point-max)))) + (define-derived-mode ledger-report-mode text-mode "Ledger-Report" "A mode for viewing ledger reports." (let ((map (make-sparse-keymap))) (define-key map [? ] 'scroll-up) (define-key map [backspace] 'scroll-down) (define-key map [?r] 'ledger-report-redo) + (define-key map [?R] 'ledger-report-reverse-lines) (define-key map [?s] 'ledger-report-save) (define-key map [?k] 'ledger-report-kill) (define-key map [?e] 'ledger-report-edit) @@ -109,6 +119,8 @@ text that should replace the format specifier." (define-key map [menu-bar ldg-rep vis] '("Visit Source" . ledger-report-visit-source)) (define-key map [menu-bar ldg-rep lru] '("Scroll Up" . scroll-up)) (define-key map [menu-bar ldg-rep s1] '("--")) + (define-key map [menu-bar ldg-rep rev] '("Reverse report order" . ledger-report-reverse-lines)) + (define-key map [menu-bar ldg-rep s0] '("--")) (define-key map [menu-bar ldg-rep lrk] '("Kill Report" . ledger-report-kill)) (define-key map [menu-bar ldg-rep lrr] '("Re-run Report" . ledger-report-redo)) (define-key map [menu-bar ldg-rep lre] '("Edit Report" . ledger-report-edit)) @@ -255,7 +267,9 @@ used to generate the buffer, navigating the buffer, etc." (save-match-data (let ((expanded-cmd report-cmd)) (set-match-data (list 0 0)) - (while (string-match "%(\\([^)]*\\))" expanded-cmd (match-end 0)) + (while (string-match "%(\\([^)]*\\))" expanded-cmd (if (> (length expanded-cmd) (match-end 0)) + (match-end 0) + (1- (length expanded-cmd)))) (let* ((specifier (match-string 1 expanded-cmd)) (f (cdr (assoc specifier ledger-report-format-specifiers)))) (if f @@ -294,7 +308,7 @@ Optional EDIT the command." (register-report (string-match " reg\\(ister\\)? " cmd)) files-in-report) (shell-command - ;; subtotal doe not produce identifiable transactions, so don't + ;; --subtotal does not produce identifiable transactions, so don't ;; prepend location information for them (if (and register-report (not (string-match "--subtotal" cmd))) -- cgit v1.2.3 From d37a369c12f0f29bc00d87bb7ef75347c6c5dffe Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Fri, 15 Feb 2013 12:43:56 -0700 Subject: Changed prompt for reconciliation target. --- lisp/ldg-commodities.el | 7 +++---- lisp/ldg-reconcile.el | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index ab5c8898..cf2ee128 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -69,12 +69,11 @@ longer one are after the value." (concat val " " commodity) (concat commodity " " val)))) -(defun ledger-read-commodity-string (comm) +(defun ledger-read-commodity-string (prompt) "Return a commoditizd value (val 'comm') from COMM. Assumes a space between the value and the commodity." - (interactive (list (read-from-minibuffer - (concat "Enter commoditized amount (" ledger-reconcile-default-commodity "): ")))) - (let ((parts (split-string comm))) + (let ((parts (split-string (read-from-minibuffer + (concat prompt " (" ledger-reconcile-default-commodity "): "))))) (if parts (if (/= (length parts) 2) ;;assume a number was entered and use default commodity (list (string-to-number (car parts)) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 373b3de9..58cb6626 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -360,7 +360,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (ledger-occur-change-regex account ledger-buf)) (set-buffer (get-buffer ledger-recon-buffer-name)) (setq ledger-target - (call-interactively #'ledger-read-commodity-string)) + (ledger-read-commodity-string "Set reconciliation target")) (unless (get-buffer-window rbuf) (ledger-reconcile-open-windows buf rbuf)) (ledger-reconcile-refresh) @@ -377,7 +377,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (set (make-local-variable 'ledger-buf) buf) (set (make-local-variable 'ledger-acct) account) (set (make-local-variable 'ledger-target) - (call-interactively #'ledger-read-commodity-string)) + (ledger-read-commodity-string "Set reconciliation target")) (ledger-do-reconcile)))))) (defvar ledger-reconcile-mode-abbrev-table) @@ -385,7 +385,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (defun ledger-reconcile-change-target () "Change the traget amount for the reconciliation process." (interactive) - (setq ledger-target (call-interactively #'ledger-read-commodity-string))) + (setq ledger-target (ledger-read-commodity-string "Set reconciliation target"))) (define-derived-mode ledger-reconcile-mode text-mode "Reconcile" "A mode for reconciling ledger entries." -- cgit v1.2.3 From 0357f92f810ad4843ba11e321ad63e804ad0354e Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sat, 16 Feb 2013 08:56:25 -0700 Subject: Make sure ledger-fully-complete-entry copies the rest of the payee line --- lisp/ldg-complete.el | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index 1836eb2c..3fd1b319 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -146,13 +146,17 @@ Return tree structure" Does not use ledger xact" (interactive) (let ((name (caar (ledger-parse-arguments))) + rest-of-name xacts) (save-excursion (when (eq 'transaction (ledger-thing-at-point)) + ;; Search backward for a matching payee (when (re-search-backward (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" (regexp-quote name) ) nil t) ;; "\\(\t\\|\n\\| [ \t]\\)" - (forward-line) + (setq rest-of-name (buffer-substring-no-properties (match-end 0) (line-end-position))) + ;; Start copying the postings + (forward-line) (while (looking-at "^\\s-+") (setq xacts (cons (buffer-substring-no-properties (line-beginning-position) @@ -162,6 +166,7 @@ Does not use ledger xact" (setq xacts (nreverse xacts))))) (when xacts (save-excursion + (insert rest-of-name) (insert ?\n) (while xacts (insert (car xacts) ?\n) -- cgit v1.2.3 From 2b8743d5026c0cb801cb2e3d8c8fb6d342db4990 Mon Sep 17 00:00:00 2001 From: Ryan Nowakowski Date: Sun, 17 Feb 2013 15:43:48 -0600 Subject: Small corrections in the Embedded Python section --- doc/ledger3.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 55732ceb..92cb07fb 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -7656,11 +7656,11 @@ for loop), then the data reverts back to its raw state. @node Embedded Python, Amounts, Queries, Extending with Python @section Embedded Python -Can you embed Python into your data files using the 'python' directive: +You can embed Python into your data files using the 'python' directive: @smallexample python - import so + import os def check_path(path_value): print "%s => %s" % (str(path_value), os.path.isfile(str(path_value))) return os.path.isfile(str(path_value)) -- cgit v1.2.3 From 2c69aa1ff5759a38f458dda69a7b1f6e49294cd0 Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Sun, 17 Feb 2013 19:47:16 -0700 Subject: A better try to deal with decimal-comma from ledger --- lisp/ldg-commodities.el | 46 ++++++++++++++++++++++++++++++++++++++-------- lisp/ldg-complete.el | 4 ++-- lisp/ldg-post.el | 8 +------- lisp/ldg-reconcile.el | 2 +- lisp/ldg-report.el | 20 +++++++++----------- 5 files changed, 51 insertions(+), 29 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index cf2ee128..04dc23de 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -31,6 +31,12 @@ :type 'string :group 'ledger) +(defcustom ledger-use-decimal-comma nil + "If non-nil the use commas as decimal separator. +This only has effect interfacing to calc mode in edit amount" + :type 'boolean + :group 'ledger) + (defun ledger-string-balance-to-commoditized-amount (str) "Return a commoditized amount (val, 'comm') from STR." (let ((fields (split-string str "[\n\r]"))) ; break any balances @@ -40,10 +46,11 @@ (let* ((parts (split-string str)) ;break into number and commodity string (first (car parts)) (second (cadr parts))) - ;"^-*[1-9][0-9]*[.,][0-9]*" (if (string-match "^-*[1-9]+" first) - (list (string-to-number first) second) - (list (string-to-number second) first)))) + (list (string-to-number + (ledger-commodity-string-number-decimalize first :from-user)) second) + (list (string-to-number + (ledger-commodity-string-number-decimalize second :from-user)) first)))) fields))) @@ -59,15 +66,38 @@ (list (+ (car c1) (car c2)) (cadr c1)) (error "Can't add different commodities, %S to %S" c1 c2))) +(defun ledger-commodity-string-number-decimalize (number-string direction) + "Take NUMBER-STRING and ensure proper decimalization for use by string-to-number and number-to-string. + +DIRECTION can be :to-user or :from-user. All math calculations +are done with decimal-period, some users may prefer decimal-comma +which must be translated both directions." + (let ((val number-string)) + (if ledger-use-decimal-comma + (cond ((eq direction :from-user) + ;; change string to decimal-period + (while (string-match "," val) + (setq val (replace-match "." nil nil val)))) ;; switch to period separator + ((eq direction :to-user) + ;; change to decimal-comma + (while (string-match "\\." val) + (setq val (replace-match "," nil nil val)))) ;; gets rid of periods + (t + (error "ledger-commodity-string-number-decimalize: direction not properly specified %S" direction)))) + val)) + + + (defun ledger-commodity-to-string (c1) "Return string representing C1. Single character commodities are placed ahead of the value, longer one are after the value." -(let ((val (number-to-string (car c1))) - (commodity (cadr c1))) - (if (> (length commodity) 1) - (concat val " " commodity) - (concat commodity " " val)))) +(let ((val (ledger-commodity-string-number-decimalize + (number-to-string (car c1)) :to-user)) + (commodity (cadr c1))) + (if (> (length commodity) 1) + (concat val " " commodity) + (concat commodity " " val)))) (defun ledger-read-commodity-string (prompt) "Return a commoditizd value (val 'comm') from COMM. diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index 3fd1b319..3686d0fd 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -164,10 +164,10 @@ Does not use ledger xact" xacts)) (forward-line)) (setq xacts (nreverse xacts))))) + ;; Insert rest-of-name and the postings (when xacts (save-excursion - (insert rest-of-name) - (insert ?\n) + (insert rest-of-name ?\n) (while xacts (insert (car xacts) ?\n) (setq xacts (cdr xacts)))) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index bdbb4386..14c3c55f 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -51,12 +51,6 @@ :type 'boolean :group 'ledger-post) -(defcustom ledger-post-use-decimal-comma nil - "If non-nil the use commas as decimal separator. -This only has effect interfacing to calc mode in edit amount" - :type 'boolean - :group 'ledger-post) - (defun ledger-post-all-accounts () "Return a list of all accounts in the buffer." (let ((origin (point)) @@ -185,7 +179,7 @@ BEG, END, and LEN control how far it can align." (goto-char (match-beginning 0)) (delete-region (match-beginning 0) (match-end 0)) (calc) - (if ledger-post-use-decimal-comma + (if ledger-use-decimal-comma (progn (while (string-match "\\." val) (setq val (replace-match "" nil nil val))) ;; gets rid of periods diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 58cb6626..20857127 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -81,7 +81,7 @@ numbers" "Calculate the cleared balance of the account being reconciled." (interactive) (let* ((pending (car (ledger-string-balance-to-commoditized-amount - (car (ledger-reconcile-get-balances))))) + (car (ledger-reconcile-get-balances))))) (target-delta (if ledger-target (-commodity ledger-target pending) nil))) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 370117fc..944ae2e6 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -21,7 +21,7 @@ ;;; Commentary: -;; +;; Provide facilities for running and saving reports in emacs ;;; Code: @@ -51,7 +51,8 @@ specifier." (defcustom ledger-report-format-specifiers '(("ledger-file" . ledger-report-ledger-file-format-specifier) ("payee" . ledger-report-payee-format-specifier) - ("account" . ledger-report-account-format-specifier)) + ("account" . ledger-report-account-format-specifier) + ("value" . ledger-report-value-format-specifier)) "An alist mapping ledger report format specifiers to implementing functions. The function is called with no parameters and expected to return the @@ -59,15 +60,6 @@ text that should replace the format specifier." :type 'alist :group 'ledger) -;;(define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report) -;;(define-key map [(control ?c) (control ?o) (control ?g)] 'ledger-report-goto) -;;(define-key map [(control ?c) (control ?o) (control ?a)] 'ledger-report-redo) -;;(define-key map [(control ?c) (control ?o) (control ?s)] 'ledger-report-save) -;;(define-key map [(control ?c) (control ?o) (control ?e)] 'ledger-report-edit) -;;(define-key map [(control ?c) (control ?o) (control ?k)] 'ledger-report-kill) - -;; Ledger report mode - (defvar ledger-report-buffer-name "*Ledger Report*") (defvar ledger-report-name nil) @@ -128,6 +120,12 @@ text that should replace the format specifier." (use-local-map map))) +(defun ledger-report-value-format-specifier () + "Return a valid meta-data tag name" + ;; It is intended completion should be available on existing account + ;; names, but it remains to be implemented. + (ledger-read-string-with-default "Value: " nil)) + (defun ledger-report-read-name () "Read the name of a ledger report to use, with completion. -- cgit v1.2.3 From 0951bcebef04a2933a7b6e3d93d5c23bea7c4dc9 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 18 Feb 2013 06:51:12 -0600 Subject: Bump copyright information to 2013 --- src/account.cc | 2 +- src/account.h | 2 +- src/amount.cc | 2 +- src/amount.h | 2 +- src/annotate.cc | 2 +- src/annotate.h | 2 +- src/archive.cc | 2 +- src/archive.h | 2 +- src/balance.cc | 2 +- src/balance.h | 2 +- src/chain.cc | 2 +- src/chain.h | 2 +- src/commodity.cc | 2 +- src/commodity.h | 2 +- src/compare.cc | 2 +- src/compare.h | 2 +- src/context.h | 2 +- src/convert.cc | 2 +- src/convert.h | 2 +- src/csv.cc | 2 +- src/csv.h | 2 +- src/draft.cc | 2 +- src/draft.h | 2 +- src/emacs.cc | 2 +- src/emacs.h | 2 +- src/error.cc | 2 +- src/error.h | 2 +- src/expr.cc | 2 +- src/expr.h | 2 +- src/exprbase.h | 2 +- src/filters.cc | 2 +- src/filters.h | 2 +- src/flags.h | 2 +- src/format.cc | 2 +- src/format.h | 2 +- src/generate.cc | 2 +- src/generate.h | 2 +- src/global.cc | 2 +- src/global.h | 4 ++-- src/history.cc | 2 +- src/history.h | 2 +- src/item.cc | 2 +- src/item.h | 2 +- src/iterators.cc | 2 +- src/iterators.h | 2 +- src/journal.cc | 2 +- src/journal.h | 2 +- src/lookup.cc | 2 +- src/lookup.h | 2 +- src/main.cc | 2 +- src/mask.cc | 2 +- src/mask.h | 2 +- src/op.cc | 2 +- src/op.h | 2 +- src/option.cc | 2 +- src/option.h | 2 +- src/org.cc | 2 +- src/org.h | 2 +- src/output.cc | 2 +- src/output.h | 2 +- src/parser.cc | 2 +- src/parser.h | 2 +- src/pool.cc | 2 +- src/pool.h | 2 +- src/post.cc | 2 +- src/post.h | 2 +- src/precmd.cc | 2 +- src/precmd.h | 2 +- src/predicate.h | 2 +- src/print.cc | 2 +- src/print.h | 2 +- src/pstream.h | 2 +- src/ptree.cc | 2 +- src/ptree.h | 2 +- src/py_account.cc | 2 +- src/py_amount.cc | 2 +- src/py_balance.cc | 2 +- src/py_commodity.cc | 2 +- src/py_expr.cc | 2 +- src/py_format.cc | 2 +- src/py_item.cc | 2 +- src/py_journal.cc | 2 +- src/py_post.cc | 2 +- src/py_session.cc | 2 +- src/py_times.cc | 2 +- src/py_utils.cc | 2 +- src/py_value.cc | 2 +- src/py_xact.cc | 2 +- src/pyfstream.h | 2 +- src/pyinterp.cc | 2 +- src/pyinterp.h | 2 +- src/pyledger.cc | 2 +- src/pyutils.h | 2 +- src/query.cc | 2 +- src/query.h | 2 +- src/quotes.cc | 2 +- src/quotes.h | 2 +- src/report.cc | 2 +- src/report.h | 2 +- src/scope.cc | 2 +- src/scope.h | 2 +- src/select.cc | 2 +- src/select.h | 2 +- src/session.cc | 2 +- src/session.h | 2 +- src/stats.cc | 2 +- src/stats.h | 2 +- src/stream.cc | 2 +- src/stream.h | 2 +- src/system.hh.in | 2 +- src/temps.cc | 2 +- src/temps.h | 2 +- src/textual.cc | 2 +- src/timelog.cc | 2 +- src/timelog.h | 2 +- src/times.cc | 2 +- src/times.h | 2 +- src/token.cc | 2 +- src/token.h | 2 +- src/unistring.h | 2 +- src/utils.cc | 2 +- src/utils.h | 2 +- src/value.cc | 2 +- src/value.h | 2 +- src/views.cc | 2 +- src/views.h | 2 +- src/xact.cc | 2 +- src/xact.h | 2 +- 128 files changed, 129 insertions(+), 129 deletions(-) diff --git a/src/account.cc b/src/account.cc index 8a5cdffa..7dcd5faa 100644 --- a/src/account.cc +++ b/src/account.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/account.h b/src/account.h index 3642ada0..7b53de15 100644 --- a/src/account.h +++ b/src/account.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/amount.cc b/src/amount.cc index 51e69290..88f2d124 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/amount.h b/src/amount.h index 5fc2ad2e..b70058ff 100644 --- a/src/amount.h +++ b/src/amount.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, John Wiegley. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/src/annotate.cc b/src/annotate.cc index b7b6b5cb..12016868 100644 --- a/src/annotate.cc +++ b/src/annotate.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/annotate.h b/src/annotate.h index 27deaad3..998f7c83 100644 --- a/src/annotate.h +++ b/src/annotate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/archive.cc b/src/archive.cc index caeaf965..6ac1c580 100644 --- a/src/archive.cc +++ b/src/archive.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/archive.h b/src/archive.h index ee4e9ccb..5c15a9fb 100644 --- a/src/archive.h +++ b/src/archive.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/balance.cc b/src/balance.cc index d9551670..f86d6561 100644 --- a/src/balance.cc +++ b/src/balance.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/balance.h b/src/balance.h index f822e353..a1ae51ef 100644 --- a/src/balance.h +++ b/src/balance.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/chain.cc b/src/chain.cc index 52d52f14..b2f6f203 100644 --- a/src/chain.cc +++ b/src/chain.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/chain.h b/src/chain.h index 15ae12ba..de7f68c7 100644 --- a/src/chain.h +++ b/src/chain.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/commodity.cc b/src/commodity.cc index ffeac10d..c7a893f1 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/commodity.h b/src/commodity.h index 82efac6a..a1988a3b 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/compare.cc b/src/compare.cc index e2a298c2..946cd835 100644 --- a/src/compare.cc +++ b/src/compare.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/compare.h b/src/compare.h index e1abbca1..4a91f49f 100644 --- a/src/compare.h +++ b/src/compare.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/context.h b/src/context.h index fd3575ab..e5457641 100644 --- a/src/context.h +++ b/src/context.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/convert.cc b/src/convert.cc index f0d8db06..38ef2c22 100644 --- a/src/convert.cc +++ b/src/convert.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/convert.h b/src/convert.h index de958108..17fb4505 100644 --- a/src/convert.h +++ b/src/convert.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/csv.cc b/src/csv.cc index c7b75712..2a3eb080 100644 --- a/src/csv.cc +++ b/src/csv.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/csv.h b/src/csv.h index 7d5098d2..94f7a328 100644 --- a/src/csv.h +++ b/src/csv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/draft.cc b/src/draft.cc index a6f60520..6aef2f12 100644 --- a/src/draft.cc +++ b/src/draft.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/draft.h b/src/draft.h index 9023e6da..1cc362ba 100644 --- a/src/draft.h +++ b/src/draft.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/emacs.cc b/src/emacs.cc index 41c67cc6..9bfd1e4b 100644 --- a/src/emacs.cc +++ b/src/emacs.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/emacs.h b/src/emacs.h index a018ce68..368c4c4d 100644 --- a/src/emacs.h +++ b/src/emacs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/error.cc b/src/error.cc index 8aa1d3d6..acee85c9 100644 --- a/src/error.cc +++ b/src/error.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/error.h b/src/error.h index 9837fa4d..93d92109 100644 --- a/src/error.h +++ b/src/error.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/expr.cc b/src/expr.cc index dbe860bf..aa1e07d2 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/expr.h b/src/expr.h index 798e5bec..a5119c0b 100644 --- a/src/expr.h +++ b/src/expr.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/exprbase.h b/src/exprbase.h index 4edf2a7a..88d6f118 100644 --- a/src/exprbase.h +++ b/src/exprbase.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/filters.cc b/src/filters.cc index 7570809a..9b8e4fc6 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/filters.h b/src/filters.h index b765f630..42ff2e5c 100644 --- a/src/filters.h +++ b/src/filters.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/flags.h b/src/flags.h index 77a2c4dd..d584e2d0 100644 --- a/src/flags.h +++ b/src/flags.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/format.cc b/src/format.cc index 14bb2430..e0f74616 100644 --- a/src/format.cc +++ b/src/format.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/format.h b/src/format.h index cc48bdda..38f567bd 100644 --- a/src/format.h +++ b/src/format.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/generate.cc b/src/generate.cc index bcbde9f1..2b471c87 100644 --- a/src/generate.cc +++ b/src/generate.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/generate.h b/src/generate.h index 1b22004b..f171605b 100644 --- a/src/generate.h +++ b/src/generate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/global.cc b/src/global.cc index 5fc10f02..a4da6ead 100644 --- a/src/global.cc +++ b/src/global.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/global.h b/src/global.h index 11459529..c024dce2 100644 --- a/src/global.h +++ b/src/global.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, John Wiegley. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -127,7 +127,7 @@ public: out << '-' << Ledger_VERSION_DATE; out << _(", the command-line accounting tool"); out << - _("\n\nCopyright (c) 2003-2012, John Wiegley. All rights reserved.\n\n\ + _("\n\nCopyright (c) 2003-2013, John Wiegley. All rights reserved.\n\n\ This program is made available under the terms of the BSD Public License.\n\ See LICENSE file included with the distribution for details and disclaimer."); out << std::endl; diff --git a/src/history.cc b/src/history.cc index 414fc15d..dde8c441 100644 --- a/src/history.cc +++ b/src/history.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/history.h b/src/history.h index b763cb0b..baefb333 100644 --- a/src/history.h +++ b/src/history.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/item.cc b/src/item.cc index 4e2a487c..896589e9 100644 --- a/src/item.cc +++ b/src/item.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/item.h b/src/item.h index 8b0a5225..b0670ac5 100644 --- a/src/item.h +++ b/src/item.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/iterators.cc b/src/iterators.cc index 0a053031..738f33be 100644 --- a/src/iterators.cc +++ b/src/iterators.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/iterators.h b/src/iterators.h index 53814666..3ece313c 100644 --- a/src/iterators.h +++ b/src/iterators.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/journal.cc b/src/journal.cc index 68939be6..c4c8fd98 100644 --- a/src/journal.cc +++ b/src/journal.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/journal.h b/src/journal.h index 5e0fa0e3..716e2910 100644 --- a/src/journal.h +++ b/src/journal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/lookup.cc b/src/lookup.cc index 9edc3bbc..2a602569 100644 --- a/src/lookup.cc +++ b/src/lookup.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/lookup.h b/src/lookup.h index ba64b0b5..ee80faac 100644 --- a/src/lookup.h +++ b/src/lookup.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/main.cc b/src/main.cc index a44506c9..accae197 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/mask.cc b/src/mask.cc index 18d482ed..56ef02d1 100644 --- a/src/mask.cc +++ b/src/mask.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/mask.h b/src/mask.h index 06bd0141..d46b3349 100644 --- a/src/mask.h +++ b/src/mask.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/op.cc b/src/op.cc index 87857049..15306f02 100644 --- a/src/op.cc +++ b/src/op.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/op.h b/src/op.h index 2a705ca0..bebfcbbd 100644 --- a/src/op.h +++ b/src/op.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/option.cc b/src/option.cc index 7fcc9e4d..256ee45b 100644 --- a/src/option.cc +++ b/src/option.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/option.h b/src/option.h index 642142aa..fe3e257b 100644 --- a/src/option.h +++ b/src/option.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/org.cc b/src/org.cc index 70427321..736260e6 100644 --- a/src/org.cc +++ b/src/org.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/org.h b/src/org.h index 0b34b610..8f9dcf81 100644 --- a/src/org.h +++ b/src/org.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/output.cc b/src/output.cc index 6ed7f861..77d28eed 100644 --- a/src/output.cc +++ b/src/output.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/output.h b/src/output.h index 44eca2d2..31afbd13 100644 --- a/src/output.h +++ b/src/output.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/parser.cc b/src/parser.cc index a17ad271..bcb23f48 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/parser.h b/src/parser.h index 9e6a59f4..8cc8027f 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/pool.cc b/src/pool.cc index 9f1aea9f..b9e64c4b 100644 --- a/src/pool.cc +++ b/src/pool.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/pool.h b/src/pool.h index 849b7a22..1bcb8b65 100644 --- a/src/pool.h +++ b/src/pool.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/post.cc b/src/post.cc index f23b81cb..c7435aec 100644 --- a/src/post.cc +++ b/src/post.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/post.h b/src/post.h index c9aec6b2..3206afdd 100644 --- a/src/post.h +++ b/src/post.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/precmd.cc b/src/precmd.cc index fe0836bc..e9c966e9 100644 --- a/src/precmd.cc +++ b/src/precmd.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/precmd.h b/src/precmd.h index 1c52d8a7..27925f42 100644 --- a/src/precmd.h +++ b/src/precmd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/predicate.h b/src/predicate.h index c670d6a4..6a1cc01c 100644 --- a/src/predicate.h +++ b/src/predicate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/print.cc b/src/print.cc index a4a0bc6f..f04f59d5 100644 --- a/src/print.cc +++ b/src/print.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/print.h b/src/print.h index 42bfc8b6..8d78e8cc 100644 --- a/src/print.h +++ b/src/print.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/pstream.h b/src/pstream.h index e9cddb4c..4886dc0b 100644 --- a/src/pstream.h +++ b/src/pstream.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, John Wiegley. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/src/ptree.cc b/src/ptree.cc index 6fb840e0..1e271465 100644 --- a/src/ptree.cc +++ b/src/ptree.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/ptree.h b/src/ptree.h index b28f97d5..ac9e1060 100644 --- a/src/ptree.h +++ b/src/ptree.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/py_account.cc b/src/py_account.cc index 64a7ae54..fbd68140 100644 --- a/src/py_account.cc +++ b/src/py_account.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/py_amount.cc b/src/py_amount.cc index 0aa8fee8..50e16a70 100644 --- a/src/py_amount.cc +++ b/src/py_amount.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/py_balance.cc b/src/py_balance.cc index 2ae546f1..65e3c401 100644 --- a/src/py_balance.cc +++ b/src/py_balance.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/py_commodity.cc b/src/py_commodity.cc index b283efcc..44a45e33 100644 --- a/src/py_commodity.cc +++ b/src/py_commodity.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/py_expr.cc b/src/py_expr.cc index dd9df1f5..c680bab4 100644 --- a/src/py_expr.cc +++ b/src/py_expr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/py_format.cc b/src/py_format.cc index 482eaf5b..43266b29 100644 --- a/src/py_format.cc +++ b/src/py_format.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/py_item.cc b/src/py_item.cc index 893ddcfa..02b978c5 100644 --- a/src/py_item.cc +++ b/src/py_item.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/py_journal.cc b/src/py_journal.cc index 50a52be9..7cce6b11 100644 --- a/src/py_journal.cc +++ b/src/py_journal.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/py_post.cc b/src/py_post.cc index 692542a0..6061d6ee 100644 --- a/src/py_post.cc +++ b/src/py_post.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/py_session.cc b/src/py_session.cc index f411d5e1..7e2f9e8a 100644 --- a/src/py_session.cc +++ b/src/py_session.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/py_times.cc b/src/py_times.cc index 17f9ec7e..599aa60c 100644 --- a/src/py_times.cc +++ b/src/py_times.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/py_utils.cc b/src/py_utils.cc index 45ffe545..dc572621 100644 --- a/src/py_utils.cc +++ b/src/py_utils.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/py_value.cc b/src/py_value.cc index b931f008..8b565661 100644 --- a/src/py_value.cc +++ b/src/py_value.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/py_xact.cc b/src/py_xact.cc index 96674207..0b07f582 100644 --- a/src/py_xact.cc +++ b/src/py_xact.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/pyfstream.h b/src/pyfstream.h index 18f28bc4..12bbecfd 100644 --- a/src/pyfstream.h +++ b/src/pyfstream.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/pyinterp.cc b/src/pyinterp.cc index 135a088b..3354d3e9 100644 --- a/src/pyinterp.cc +++ b/src/pyinterp.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/pyinterp.h b/src/pyinterp.h index 56f808c8..e961f4c0 100644 --- a/src/pyinterp.h +++ b/src/pyinterp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/pyledger.cc b/src/pyledger.cc index cf5e362e..ee7b99c9 100644 --- a/src/pyledger.cc +++ b/src/pyledger.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/pyutils.h b/src/pyutils.h index 406ca1ee..6bb9d0bd 100644 --- a/src/pyutils.h +++ b/src/pyutils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/query.cc b/src/query.cc index 07f724fd..209205ae 100644 --- a/src/query.cc +++ b/src/query.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/query.h b/src/query.h index fe52eb35..10820a59 100644 --- a/src/query.h +++ b/src/query.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/quotes.cc b/src/quotes.cc index e92af236..2df51ec1 100644 --- a/src/quotes.cc +++ b/src/quotes.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/quotes.h b/src/quotes.h index 56740e47..813bdfa3 100644 --- a/src/quotes.h +++ b/src/quotes.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/report.cc b/src/report.cc index d0b64650..8bb38fb6 100644 --- a/src/report.cc +++ b/src/report.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/report.h b/src/report.h index 6533d2f1..5897e8f6 100644 --- a/src/report.h +++ b/src/report.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/scope.cc b/src/scope.cc index 9112040c..10ae45a9 100644 --- a/src/scope.cc +++ b/src/scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/scope.h b/src/scope.h index 4190f5bb..d6291439 100644 --- a/src/scope.h +++ b/src/scope.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/select.cc b/src/select.cc index afcfb351..b7e4c920 100644 --- a/src/select.cc +++ b/src/select.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/select.h b/src/select.h index 54883d22..346067a2 100644 --- a/src/select.h +++ b/src/select.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/session.cc b/src/session.cc index 0f9cca22..e5425a50 100644 --- a/src/session.cc +++ b/src/session.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/session.h b/src/session.h index 74aeab5f..21be3cc7 100644 --- a/src/session.h +++ b/src/session.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/stats.cc b/src/stats.cc index a12420b6..81d71a46 100644 --- a/src/stats.cc +++ b/src/stats.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/stats.h b/src/stats.h index 7b00fec8..5583e704 100644 --- a/src/stats.h +++ b/src/stats.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/stream.cc b/src/stream.cc index ce40bfcc..ad03ab77 100644 --- a/src/stream.cc +++ b/src/stream.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/stream.h b/src/stream.h index c317ebdf..bb63873a 100644 --- a/src/stream.h +++ b/src/stream.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/system.hh.in b/src/system.hh.in index e7411a5e..08a45a15 100644 --- a/src/system.hh.in +++ b/src/system.hh.in @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/temps.cc b/src/temps.cc index 881077f6..b4778b49 100644 --- a/src/temps.cc +++ b/src/temps.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/temps.h b/src/temps.h index daa1493b..99110496 100644 --- a/src/temps.h +++ b/src/temps.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/textual.cc b/src/textual.cc index b19ce79a..932bde84 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/timelog.cc b/src/timelog.cc index acd8a4fa..64017d50 100644 --- a/src/timelog.cc +++ b/src/timelog.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/timelog.h b/src/timelog.h index a902c084..1ce0be28 100644 --- a/src/timelog.h +++ b/src/timelog.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/times.cc b/src/times.cc index 167aac73..f9a6c279 100644 --- a/src/times.cc +++ b/src/times.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/times.h b/src/times.h index 9a0f21ff..ae4e4c75 100644 --- a/src/times.h +++ b/src/times.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/token.cc b/src/token.cc index 1c43af32..d0ec185b 100644 --- a/src/token.cc +++ b/src/token.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/token.h b/src/token.h index 01ff7ee9..51fa1d78 100644 --- a/src/token.h +++ b/src/token.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/unistring.h b/src/unistring.h index b2278796..eb38f8b1 100644 --- a/src/unistring.h +++ b/src/unistring.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/utils.cc b/src/utils.cc index e5faf184..2f592325 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/utils.h b/src/utils.h index 1b356e7c..c4d11636 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/value.cc b/src/value.cc index 902987a7..e8afac50 100644 --- a/src/value.cc +++ b/src/value.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/value.h b/src/value.h index 49d64ab6..93760234 100644 --- a/src/value.h +++ b/src/value.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/views.cc b/src/views.cc index 76d06370..2646e84b 100644 --- a/src/views.cc +++ b/src/views.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/views.h b/src/views.h index 7f769250..94bedda5 100644 --- a/src/views.h +++ b/src/views.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/xact.cc b/src/xact.cc index 7ac7a9e9..d33520b4 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 diff --git a/src/xact.h b/src/xact.h index c5ad3ad6..e59ead75 100644 --- a/src/xact.h +++ b/src/xact.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * Copyright (c) 2003-2013, 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 -- cgit v1.2.3 From 21cdc04ab3eaea54c90bf93bd33aedb44cab29fb Mon Sep 17 00:00:00 2001 From: Craig Earls Date: Mon, 18 Feb 2013 08:45:24 -0700 Subject: Fixes Bug 900 If the buffer being reconciles was killed with the *Reconcile* buffer still around their were dirty hooks left around that caused bug problems. This fix adds a local kill-buffer hook that calls the ledger-quit routines --- lisp/ldg-reconcile.el | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 20857127..ebaf7949 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -228,23 +228,23 @@ and exit reconcile mode" (defun ledger-reconcile-quit () - "Quite the reconcile window without saving ledger buffer." + "Quit the reconcile window without saving ledger buffer." (interactive) - (ledger-reconcile-quit-cleanup) - (let ((buf ledger-buf) - (recon-buf (get-buffer ledger-recon-buffer-name))) - ;; Make sure you delete the window before you delete the buffer, - ;; otherwise, madness ensues + (let ((recon-buf (get-buffer ledger-recon-buffer-name)) + buf) (with-current-buffer recon-buf + (ledger-reconcile-quit-cleanup) + (set 'buf ledger-buf) + ;; Make sure you delete the window before you delete the buffer, + ;; otherwise, madness ensues (delete-window (get-buffer-window recon-buf)) - (kill-buffer recon-buf)) - (set-window-buffer (selected-window) buf))) + (kill-buffer recon-buf) + (set-window-buffer (selected-window) buf)))) (defun ledger-reconcile-quit-cleanup () "Cleanup all hooks established by reconcile mode." (interactive) - (let ((buf ledger-buf) - (reconcile-buf (get-buffer ledger-recon-buffer-name))) + (let ((buf ledger-buf)) (with-current-buffer buf (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t) (if ledger-fold-on-reconcile @@ -315,6 +315,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (when recon-window (fit-window-to-buffer recon-window) (with-current-buffer buf + (add-hook 'kill-buffer-hook 'ledger-reconcile-quit nil t) (select-window (get-buffer-window buf)) (goto-char (point-max)) (recenter -1)) @@ -426,9 +427,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (define-key map [menu-bar ldg-recon-menu ref] '("Refresh" . ledger-reconcile-refresh)) (define-key map [menu-bar ldg-recon-menu sav] '("Save" . ledger-reconcile-save)) - (use-local-map map) - - (add-hook 'kill-buffer-hook 'ledger-reconcile-quit-cleanup nil t))) + (use-local-map map))) (provide 'ldg-reconcile) (provide 'ldg-reconcile) -- cgit v1.2.3 From 34a6279baa3c836c1850f335c1c7ec3089fb2532 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Mon, 7 Jan 2013 16:38:53 -0500 Subject: Add --single-file-directory option: create single directory with all linked files. This new option copies all files to the directory specified as an argument to the --single-file-directory option, and also creates dummy shorter filenames for the files. This feature was implemented to get around a problem found when zip'ing the spreadsheet up with the supporting files for users on Windows. The Windows users encounter the error 0x80010135 related to some of the ZIP files going beyond the maximum path name length on windows. Apparently, opening ZIP files with long path names just doesn't work on Microsoft systems. I've suggested our accountants switch to a Free Software operating system, but they declined. --- contrib/non-profit-audit-reports/csv2ods.py | 51 ++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/contrib/non-profit-audit-reports/csv2ods.py b/contrib/non-profit-audit-reports/csv2ods.py index 8b880648..3a3411ba 100755 --- a/contrib/non-profit-audit-reports/csv2ods.py +++ b/contrib/non-profit-audit-reports/csv2ods.py @@ -23,16 +23,23 @@ import sys, os, os.path, optparse import csv import ooolib2 +import shutil +import string def err(msg): print 'error: %s' % msg sys.exit(1) -def csv2ods(csvname, odsname, encoding='', verbose = False): +def csv2ods(csvname, odsname, encoding='', singleFileDirectory=None, verbose = False): filesSavedinManifest = {} if verbose: print 'converting from %s to %s' % (csvname, odsname) + + if singleFileDirectory: + if not os.path.isdir(os.path.join(os.getcwd(),singleFileDirectory)): + os.mkdir(singleFileDirectory) + doc = ooolib2.Calc() # add a pagebreak style style = 'pagebreak' @@ -55,20 +62,51 @@ def csv2ods(csvname, odsname, encoding='', verbose = False): if len(fields) > 0: for col in range(len(fields)): val = fields[col] - if encoding != '': + if encoding != '' and val[0:5] != "link:": # Only utf8 encode if it's not a filename val = unicode(val, 'utf8') if len(val) > 0 and val[0] == '$': doc.set_cell_value(col + 1, row, 'currency', val[1:]) else: if (len(val) > 0 and val[0:5] == "link:"): val = val[5:] - linkrel = '../' + val # ../ means remove the name of the *.ods linkname = os.path.basename(val) # name is just the last component + if not singleFileDirectory: + newFile = val + else: + relativeFileWithPath = os.path.basename(val) + fileName, fileExtension = os.path.splitext(relativeFileWithPath) + newFile = fileName[:15] # 15 is an arbitrary choice. + newFile = newFile + fileExtension + # We'll now test to see if we made this file + # before, and if it matched the same file we + # now want. If it doesn't, try to make a + # short file name for it. + if filesSavedinManifest.has_key(newFile) and filesSavedinManifest[newFile] != val: + testFile = None + for cc in list(string.letters) + list(string.digits): + testFile = cc + newFile + if not filesSavedinManifest.has_key(testFile): + break + testFile = None + if not testFile: + raise Exception("too many similar file names for linkage; giving up") + else: + newFile = testFile + if not os.path.exists(csvdir + '/' + val): + raise Exception("File" + csvdir + '/' + val + " does not exist in single file directory mode; giving up") + src = os.path.join(csvdir, val) + dest = os.path.join(csvdir, singleFileDirectory, newFile) + shutil.copyfile(src, dest) + shutil.copystat(src, dest) + shutil.copymode(src, dest) + newFile = os.path.join(singleFileDirectory, newFile) + + linkrel = '../' + newFile # ../ means remove the name of the *.ods doc.set_cell_value(col + 1, row, 'link', (linkrel, linkname)) linkpath = csvdir + '/' + val if not val in filesSavedinManifest: - filesSavedinManifest[val] = col + filesSavedinManifest[newFile] = val if not os.path.exists(linkpath): print "WARNING: link %s DOES NOT EXIST at %s" % (val, linkpath) @@ -109,7 +147,10 @@ def main(): help='ods output filename') parser.add_option('-e', '--encoding', action='store', help='unicode character encoding type') + parser.add_option('-d', '--single-file-directory', action='store', + help='directory name to move all files into') (options, args) = parser.parse_args() + if len(args) != 0: parser.error("not expecting extra args") if not os.path.exists(options.csv): @@ -122,7 +163,7 @@ def main(): print 'csv:', options.csv print 'ods:', options.ods print 'ods:', options.encoding - csv2ods(options.csv, options.ods, options.encoding, options.verbose) + csv2ods(options.csv, options.ods, options.encoding, options.single_file_directory, options.verbose) if __name__ == '__main__': main() -- cgit v1.2.3 From b214a2db5b64b52938aecc60711a0237fc95b575 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 8 Jan 2013 14:01:58 -0500 Subject: Began work on script to reconcile bank accounts. The goal here is to take as input an account, a monthly balance amount that appears on a bank statement, and the date of that bank statement and output the list of transactions that likely weren't cleared properly as of that date that caused the balance in the accounts to fail to match the balance that appeared on the statement. Note that determining this answer requires solving the known NP-Complete problem called the subset sum problem. There is a known pseudo-polynomial dynamic programming solution to this problem, but it's still exponential in the size of the numbers you have to balance. So, if you have *big* account balances, this will make take quite a while to run. For smaller accounts, the pseudo-polynomial solution might be helpful. (BTW, the wikipedia entry on the subset sum problem isn't, at the time of this commit, particularly good, but it's "good enough" to give you a sense of what the subset sum problem is: http://en.wikipedia.org/wiki/Subset_sum_problem ) I originally wrote the subset sum problem solution implementation here: https://gitorious.org/bkuhn/small-hacks/commit/2dca069d810b61cdfad46e00abcb1a3edaf56d1b The code is just cut and pasted in here with some minor modifications. This rest of this first commit just has that aforementioned paste, plus the beginnings of the CLI and query to run to get the proper entries. --- .../bank-reconcilation.plx | 122 +++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100755 contrib/non-profit-audit-reports/bank-reconcilation.plx diff --git a/contrib/non-profit-audit-reports/bank-reconcilation.plx b/contrib/non-profit-audit-reports/bank-reconcilation.plx new file mode 100755 index 00000000..7201ef1f --- /dev/null +++ b/contrib/non-profit-audit-reports/bank-reconcilation.plx @@ -0,0 +1,122 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Math::BigFloat; +use Date::Manip; + +Math::BigFloat->precision(-2); +my $ZERO = Math::BigFloat->new("0.00"); + +my $VERBOSE = 0; +my $DEBUG = 0; + +my $LEDGER_BIN = "/usr/local/bin/ledger"; + +###################################################################### +sub SubSetSumSolver ($$$) { + my($numberList, $totalSought, $extractNumber) = @_; + + my($P, $N) = (0, 0); + foreach my $ii (@{$numberList}) { + if ($ii < $ZERO) { + $N += $ii; + } else { + $P += $ii; + } + } + my $size = scalar(@{$numberList}); + my %Q; + my(@L) = + map { { val => &$extractNumber($_), obj => $_ } } @{$numberList}; + + for (my $ii = 0 ; $ii <= $size ; $ii++ ) { + $Q{$ii}{0}{value} = 1; + $Q{$ii}{0}{list} = []; + } + for (my $jj = $N; $jj <= $P ; $jj++) { + $Q{0}{$jj}{value} = ($L[0]{val} == $jj); + $Q{0}{$jj}{list} = $Q{0}{$jj}{value} ? [ $L[0]{obj} ] : []; + } + for (my $ii = 1; $ii <= $size ; $ii++ ) { + for (my $jj = $N; $jj <= $P ; $jj++) { + if ($Q{$ii-1}{$jj}{value}) { + $Q{$ii}{$jj}{value} = 1; + + $Q{$ii}{$jj}{list} = [] unless defined $Q{$ii}{$jj}{list}; + push(@{$Q{$ii}{$jj}{list}}, @{$Q{$ii-1}{$jj}{list}}); + + } elsif ($L[$ii]{val} == $jj) { + $Q{$ii}{$jj}{value} = 1; + + $Q{$ii}{$jj}{list} = [] unless defined $Q{$ii}{$jj}{list}; + push(@{$Q{$ii}{$jj}{list}}, $jj); + } elsif ($Q{$ii-1}{$jj - $L[$ii]{val}}{value}) { + $Q{$ii}{$jj}{value} = 1; + $Q{$ii}{$jj}{list} = [] unless defined $Q{$ii}{$jj}{list}; + push(@{$Q{$ii}{$jj}{list}}, $L[$ii]{obj}, @{$Q{$ii-1}{$jj - $L[$ii]{val}}{list}}); + } else { + $Q{$ii}{$jj}{value} = 0; + $Q{$ii}{$jj}{list} = []; + } + } + } + foreach (my $ii = 0; $ii <= $size; $ii++) { + foreach (my $jj = $N; $jj <= $P; $jj++) { + print "Q($ii, $jj) == $Q{$ii}{$jj}{value} with List of ", join(", ", @{$Q{$ii}{$jj}{list}}), "\n"; + } + } + return [ $Q{$size}{$totalSought}{value}, \@{$Q{$size}{$totalSought}{list}}]; +} +###################################################################### +sub Commify ($) { + my $text = reverse $_[0]; + $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g; + return scalar reverse $text; +} +###################################################################### +sub ParseNumber($) { + $_[0] =~ s/,//g; + return Math::BigFloat->new($_[0]); +} +if (@ARGV < 4) { + print STDERR "usage: $0 \n"; + exit 1; +} +###################################################################### +my($account, $endDate, $balanceSought, @mainLedgerOptions) = @ARGV; + +$balanceSought = ParseNumber($balanceSought); + +my $err; +my $startDate = UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 month"), \$err), "%Y/%m/%d"); +die "Date calculation error on $endDate" if ($err); + +my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', + '-b', $startDate, '-e', $endDate, + '-F', '"%(date)","%C","%P","%t"\n', + 'reg', "/$account/"); + + open(FILE, "-|", @fullCommand) + or die "unable to run command ledger command: @fullCommand: $!"; + +my @entries; + +foreach my $line () { + die "Unable to parse output line from: $line" + unless $line =~ /^\s*"([^"]*)","([^"]*)","([^"]*)","([^"]*)"\s*$/; + my($date, $checkNum, $payee, $amount) = ($1, $2, $3, $4); + die "$amount is not a valid amount" + unless $amount =~ s/\s*\$\s*([\-\d\.\,]+)\s*$/$1/; + $amount = ParseNumber($amount); + + print "$date, $checkNum, $payee, $amount\n"; + push(@entries, { date => $date, checkNum => $checkNum, amount => $amount }); +} + +############################################################################### +# +# Local variables: +# compile-command: "perl -c bank-reconcilation.plx" +# End: -- cgit v1.2.3 From 6962fc4c57c5709cb106bd544df3cdb338c7495a Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 8 Jan 2013 14:26:04 -0500 Subject: Basic implementation probably correct, but needs much RAM. This is the basic implementation but for large numbers, it needs a *LOT* of RAM. --- .../bank-reconcilation.plx | 45 +++++++++++++++++----- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/contrib/non-profit-audit-reports/bank-reconcilation.plx b/contrib/non-profit-audit-reports/bank-reconcilation.plx index 7201ef1f..b09519a3 100755 --- a/contrib/non-profit-audit-reports/bank-reconcilation.plx +++ b/contrib/non-profit-audit-reports/bank-reconcilation.plx @@ -8,8 +8,9 @@ use Date::Manip; Math::BigFloat->precision(-2); my $ZERO = Math::BigFloat->new("0.00"); +my $ONE_HUNDRED = Math::BigFloat->new("100.00"); -my $VERBOSE = 0; +my $VERBOSE = 1; my $DEBUG = 0; my $LEDGER_BIN = "/usr/local/bin/ledger"; @@ -19,18 +20,27 @@ sub SubSetSumSolver ($$$) { my($numberList, $totalSought, $extractNumber) = @_; my($P, $N) = (0, 0); - foreach my $ii (@{$numberList}) { - if ($ii < $ZERO) { - $N += $ii; - } else { - $P += $ii; - } - } my $size = scalar(@{$numberList}); my %Q; my(@L) = map { { val => &$extractNumber($_), obj => $_ } } @{$numberList}; + + if ($VERBOSE) { + } + } + print STDERR " L in this iteration:\n [" if $VERBOSE; + + foreach my $ee (@L) { + if ($ee->{val} < 0) { + $N += $ee->{val} + } else { + $P += $ee->{val}; + } + print STDERR $ee->{val}, ", " if $VERBOSE; + } + print STDERR "]\n P = $P, N = $N\n" if ($VERBOSE); + for (my $ii = 0 ; $ii <= $size ; $ii++ ) { $Q{$ii}{0}{value} = 1; $Q{$ii}{0}{list} = []; @@ -85,6 +95,14 @@ if (@ARGV < 4) { exit 1; } ###################################################################### +sub ConvertTwoDigitPrecisionToInteger ($) { + return sprintf("%d", $_[0] * $ONE_HUNDRED); +} +###################################################################### +sub ConvertTwoDigitPrecisionToIntegerInEntry ($) { + return ConvertTwoDigitPrecisionToInteger($_[0]->{amount}); +} +###################################################################### my($account, $endDate, $balanceSought, @mainLedgerOptions) = @ARGV; $balanceSought = ParseNumber($balanceSought); @@ -111,9 +129,18 @@ foreach my $line () { unless $amount =~ s/\s*\$\s*([\-\d\.\,]+)\s*$/$1/; $amount = ParseNumber($amount); - print "$date, $checkNum, $payee, $amount\n"; push(@entries, { date => $date, checkNum => $checkNum, amount => $amount }); } +close FILE; +die "unable to properly run ledger command: @fullCommand: $!" unless ($? == 0); + +my(@solution) = SubSetSumSolver(\@entries, ConvertTwoDigitPrecisionToInteger($balanceSought), + \&ConvertTwoDigitPrecisionToIntegerInEntry); + +if ($VERBOSE) { + use Data::Dumper; + print Data::Dumper->Dump(\@solution); +} ############################################################################### # -- cgit v1.2.3 From b1b807fcfab49b9682db79b6b2fed000fc230f90 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 8 Jan 2013 16:37:41 -0500 Subject: Loop through to build smaller sets when testing. Usually, transactions that didn't appear are nearby in date to the statement date. This loop cycles through. Overall, this would take longer to find a solution, but since most solutions are in the early dates "back" from the statement date, this will probably be faster in typical cases. --- .../bank-reconcilation.plx | 81 ++++++++++++++-------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/contrib/non-profit-audit-reports/bank-reconcilation.plx b/contrib/non-profit-audit-reports/bank-reconcilation.plx index b09519a3..f18f43dc 100755 --- a/contrib/non-profit-audit-reports/bank-reconcilation.plx +++ b/contrib/non-profit-audit-reports/bank-reconcilation.plx @@ -25,11 +25,8 @@ sub SubSetSumSolver ($$$) { my(@L) = map { { val => &$extractNumber($_), obj => $_ } } @{$numberList}; - - if ($VERBOSE) { - } - } - print STDERR " L in this iteration:\n [" if $VERBOSE; + print STDERR " TotalSought:", $totalSought if $VERBOSE; + print STDERR " L in this iteration:\n [" if $VERBOSE; foreach my $ee (@L) { if ($ee->{val} < 0) { @@ -108,40 +105,66 @@ my($account, $endDate, $balanceSought, @mainLedgerOptions) = @ARGV; $balanceSought = ParseNumber($balanceSought); my $err; -my $startDate = UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 month"), \$err), "%Y/%m/%d"); +my $earliestStartDate = DateCalc(ParseDate($endDate), ParseDateDelta("- 1 month"), \$err); + die "Date calculation error on $endDate" if ($err); -my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', - '-b', $startDate, '-e', $endDate, - '-F', '"%(date)","%C","%P","%t"\n', - 'reg', "/$account/"); +my $startDate = ParseDate($endDate); + +my @solution; +while ($startDate ge $earliestStartDate) { + print "START LOOP ITR: $startDate $earliestStartDate\n"; + $startDate = DateCalc(ParseDate($startDate), ParseDateDelta("- 1 day"), \$err); + die "Date calculation error on $endDate" if ($err); + + my $formattedStartDate = UnixDate($startDate, "%Y/%m/%d"); + + print STDERR "Testing $formattedStartDate through $endDate: \n" if $VERBOSE; + + my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', + '-b', $formattedStartDate, '-e', $endDate, + '-F', '"%(date)","%C","%P","%t"\n', + 'reg', "/$account/"); open(FILE, "-|", @fullCommand) or die "unable to run command ledger command: @fullCommand: $!"; -my @entries; + my @entries; -foreach my $line () { - die "Unable to parse output line from: $line" - unless $line =~ /^\s*"([^"]*)","([^"]*)","([^"]*)","([^"]*)"\s*$/; - my($date, $checkNum, $payee, $amount) = ($1, $2, $3, $4); - die "$amount is not a valid amount" - unless $amount =~ s/\s*\$\s*([\-\d\.\,]+)\s*$/$1/; - $amount = ParseNumber($amount); + foreach my $line () { + die "Unable to parse output line from: $line" + unless $line =~ /^\s*"([^"]*)","([^"]*)","([^"]*)","([^"]*)"\s*$/; + my($date, $checkNum, $payee, $amount) = ($1, $2, $3, $4); + die "$amount is not a valid amount" + unless $amount =~ s/\s*\$\s*([\-\d\.\,]+)\s*$/$1/; + $amount = ParseNumber($amount); - push(@entries, { date => $date, checkNum => $checkNum, amount => $amount }); -} -close FILE; -die "unable to properly run ledger command: @fullCommand: $!" unless ($? == 0); - -my(@solution) = SubSetSumSolver(\@entries, ConvertTwoDigitPrecisionToInteger($balanceSought), + push(@entries, { date => $date, checkNum => $checkNum, amount => $amount }); + } + close FILE; + die "unable to properly run ledger command: @fullCommand: $!" unless ($? == 0); + + @solution = (); + if (@entries == 1) { + @solution = ( (abs($entries[0]->{amount}) == abs($balanceSought)), \@entries); + } else { + @solution = SubSetSumSolver(\@entries, ConvertTwoDigitPrecisionToInteger($balanceSought), \&ConvertTwoDigitPrecisionToIntegerInEntry); - -if ($VERBOSE) { - use Data::Dumper; - print Data::Dumper->Dump(\@solution); + } + if ($VERBOSE) { + use Data::Dumper; + print STDERR "Solution for $formattedStartDate, $balanceSought: \n", Data::Dumper->Dump(\@solution); + } + print STDERR "Solution Found: Dying" if ($solution[0]) and $VERBOSE; +# last if ($solution[0]); +} +print "DONE LOOP: $startDate $earliestStartDate\n"; +if ($solution[0]) { + print "FINAL SOLUTION: "; + foreach my $ee (@{$solution[1]}) { + print "$ee->date, $ee->payee, $ee->amount\n"; + } } - ############################################################################### # # Local variables: -- cgit v1.2.3 From 18d2867a6315562b4f4588ebf4fc58adf1fb9acf Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 8 Jan 2013 16:38:24 -0500 Subject: Rename the function to note it's the dynamic programming one. --- contrib/non-profit-audit-reports/bank-reconcilation.plx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/non-profit-audit-reports/bank-reconcilation.plx b/contrib/non-profit-audit-reports/bank-reconcilation.plx index f18f43dc..669a25b0 100755 --- a/contrib/non-profit-audit-reports/bank-reconcilation.plx +++ b/contrib/non-profit-audit-reports/bank-reconcilation.plx @@ -16,7 +16,7 @@ my $DEBUG = 0; my $LEDGER_BIN = "/usr/local/bin/ledger"; ###################################################################### -sub SubSetSumSolver ($$$) { +sub DynamicProgrammingSubSetSumSolver ($$$) { my($numberList, $totalSought, $extractNumber) = @_; my($P, $N) = (0, 0); @@ -148,7 +148,7 @@ while ($startDate ge $earliestStartDate) { if (@entries == 1) { @solution = ( (abs($entries[0]->{amount}) == abs($balanceSought)), \@entries); } else { - @solution = SubSetSumSolver(\@entries, ConvertTwoDigitPrecisionToInteger($balanceSought), + @solution = DynamicProgrammingSubSetSumSolver(\@entries, ConvertTwoDigitPrecisionToInteger($balanceSought), \&ConvertTwoDigitPrecisionToIntegerInEntry); } if ($VERBOSE) { -- cgit v1.2.3 From d13ab6a4026cfeec18fdd989862aecbe83caa20f Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Wed, 9 Jan 2013 14:51:33 -0500 Subject: Support for a list of known checksums of files already copied over. For the times when we want to make shorter names of files by doing copies of the documentation files for hyperlink usage, allow input of a new command line option which is a list in the form of: PATH_TO_FILE : sha25sum so that those files can be used rather than new copies made. --- contrib/non-profit-audit-reports/csv2ods.py | 79 +++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 9 deletions(-) diff --git a/contrib/non-profit-audit-reports/csv2ods.py b/contrib/non-profit-audit-reports/csv2ods.py index 3a3411ba..7dd840c8 100755 --- a/contrib/non-profit-audit-reports/csv2ods.py +++ b/contrib/non-profit-audit-reports/csv2ods.py @@ -25,14 +25,46 @@ import csv import ooolib2 import shutil import string +from Crypto.Hash import SHA256 def err(msg): print 'error: %s' % msg sys.exit(1) -def csv2ods(csvname, odsname, encoding='', singleFileDirectory=None, verbose = False): +def ReadChecksums(inputFile): + checksums = {} + with open(inputFile, "r") as inputFH: + entries = inputFH.readlines() + for ee in entries: + fileName, checksum = ee.split(":") + fileName = fileName.replace(' ', "") + checksum = checksum.replace(' ', "") + checksum = checksum.replace("\n", "") + checksums[checksum] = fileName + return checksums + +def ChecksumFile(filename): + sha256 = SHA256.new() + chunk_size = 8192 + with open(filename, 'rb') as myFile: + while True: + chunk = myFile.read(chunk_size) + if len(chunk) == 0: + break + sha256.update(chunk) + return sha256.hexdigest() + +def main(): + program = os.path.basename(sys.argv[0]) + + print get_file_checksum(sys.argv[1]) + +def csv2ods(csvname, odsname, encoding='', singleFileDirectory=None, knownChecksums={}, verbose = False): filesSavedinManifest = {} + if knownChecksums: + checksumCache = {} + if verbose: print 'converting from %s to %s' % (csvname, odsname) @@ -70,10 +102,25 @@ def csv2ods(csvname, odsname, encoding='', singleFileDirectory=None, verbose = F if (len(val) > 0 and val[0:5] == "link:"): val = val[5:] linkname = os.path.basename(val) # name is just the last component + newFile = None + if not singleFileDirectory: newFile = val - else: + + if knownChecksums: + if not checksumCache.has_key(val): + checksum = ChecksumFile(val) + checksumCache[val] = checksum + else: + checksum = checksumCache[val] + + if knownChecksums.has_key(checksum): + newFile = knownChecksums[checksum] + print "FOUND new file in known: " + newFile + + if not newFile: relativeFileWithPath = os.path.basename(val) + fileName, fileExtension = os.path.splitext(relativeFileWithPath) newFile = fileName[:15] # 15 is an arbitrary choice. newFile = newFile + fileExtension @@ -88,19 +135,24 @@ def csv2ods(csvname, odsname, encoding='', singleFileDirectory=None, verbose = F if not filesSavedinManifest.has_key(testFile): break testFile = None - if not testFile: - raise Exception("too many similar file names for linkage; giving up") - else: - newFile = testFile - if not os.path.exists(csvdir + '/' + val): - raise Exception("File" + csvdir + '/' + val + " does not exist in single file directory mode; giving up") + if not testFile: + raise Exception("too many similar file names for linkage; giving up") + else: + newFile = testFile + if not os.path.exists(csvdir + '/' + val): + raise Exception("File" + csvdir + '/' + val + " does not exist in single file directory mode; giving up") src = os.path.join(csvdir, val) dest = os.path.join(csvdir, singleFileDirectory, newFile) shutil.copyfile(src, dest) shutil.copystat(src, dest) shutil.copymode(src, dest) + newFile = os.path.join(singleFileDirectory, newFile) + if knownChecksums: + checksumCache[checksum] = newFile + knownChecksums[checksum] = newFile + linkrel = '../' + newFile # ../ means remove the name of the *.ods doc.set_cell_value(col + 1, row, 'link', (linkrel, linkname)) linkpath = csvdir + '/' + val @@ -149,6 +201,8 @@ def main(): help='unicode character encoding type') parser.add_option('-d', '--single-file-directory', action='store', help='directory name to move all files into') + parser.add_option('-s', '--known-checksum-list', action='store', + help='directory name to move all files into') (options, args) = parser.parse_args() if len(args) != 0: @@ -163,7 +217,14 @@ def main(): print 'csv:', options.csv print 'ods:', options.ods print 'ods:', options.encoding - csv2ods(options.csv, options.ods, options.encoding, options.single_file_directory, options.verbose) + if options.known_checksum_list and not options.single_file_directory: + err(program + ": --known-checksum-list option is completely useless without --single-file-directory") + knownChecksums = {} + if options.known_checksum_list: + if not os.access(options.known_checksum_list, os.R_OK): + err(program + ": unable to read file: " + options.known_checksum_list) + knownChecksums = ReadChecksums(options.known_checksum_list) + csv2ods(options.csv, options.ods, options.encoding, options.single_file_directory, knownChecksums, options.verbose) if __name__ == '__main__': main() -- cgit v1.2.3 From 0530b729e2b38931f653e226bc3c1cfc47d55d24 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Wed, 9 Jan 2013 15:20:50 -0500 Subject: Default to brute-force subset sum solution. The dynamic programming version of the subset sum problem required far too much RAM for larger bank balances. Meanwhile, the brute-force is not to bad now that the loop tries the closer dates *first*. --- .../bank-reconcilation.plx | 52 ++++++++++++++++++---- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/contrib/non-profit-audit-reports/bank-reconcilation.plx b/contrib/non-profit-audit-reports/bank-reconcilation.plx index 669a25b0..18d74067 100755 --- a/contrib/non-profit-audit-reports/bank-reconcilation.plx +++ b/contrib/non-profit-audit-reports/bank-reconcilation.plx @@ -5,6 +5,7 @@ use warnings; use Math::BigFloat; use Date::Manip; +use Data::PowerSet; Math::BigFloat->precision(-2); my $ZERO = Math::BigFloat->new("0.00"); @@ -15,6 +16,30 @@ my $DEBUG = 0; my $LEDGER_BIN = "/usr/local/bin/ledger"; +###################################################################### +sub BruteForceSubSetSumSolver ($$$) { + my($numberList, $totalSought, $extractNumber) = @_; + + my($P, $N) = (0, 0); + my $size = scalar(@{$numberList}); + my %Q; + my(@L) = + map { { val => &$extractNumber($_), obj => $_ } } @{$numberList}; + + my $powerset = Data::PowerSet->new(@L); + + while (my $set = $powerset->next) { + my $total = $ZERO; + foreach my $ee (@{$set}) { + $total += $ee->{val}; + } + if ($totalSought == $total) { + my(@list) = map { $_->{obj} } @{$set}; + return (1, \@list); + } + } + return (0, []); +} ###################################################################### sub DynamicProgrammingSubSetSumSolver ($$$) { my($numberList, $totalSought, $extractNumber) = @_; @@ -88,7 +113,7 @@ sub ParseNumber($) { return Math::BigFloat->new($_[0]); } if (@ARGV < 4) { - print STDERR "usage: $0 \n"; + print STDERR "usage: $0 [-d] \n"; exit 1; } ###################################################################### @@ -100,8 +125,18 @@ sub ConvertTwoDigitPrecisionToIntegerInEntry ($) { return ConvertTwoDigitPrecisionToInteger($_[0]->{amount}); } ###################################################################### +my $firstArg = shift @ARGV; + +my $solver = \&BruteForceSubSetSumSolver; + +if ($firstArg eq '-d') { + $solver = \&DynamicProgrammingSubSetSumSolver; +} else { + unshift(@ARGV, $firstArg); +} my($account, $endDate, $balanceSought, @mainLedgerOptions) = @ARGV; + $balanceSought = ParseNumber($balanceSought); my $err; @@ -139,7 +174,8 @@ while ($startDate ge $earliestStartDate) { unless $amount =~ s/\s*\$\s*([\-\d\.\,]+)\s*$/$1/; $amount = ParseNumber($amount); - push(@entries, { date => $date, checkNum => $checkNum, amount => $amount }); + push(@entries, { date => $date, checkNum => $checkNum, + payee => $payee, amount => $amount }); } close FILE; die "unable to properly run ledger command: @fullCommand: $!" unless ($? == 0); @@ -148,21 +184,21 @@ while ($startDate ge $earliestStartDate) { if (@entries == 1) { @solution = ( (abs($entries[0]->{amount}) == abs($balanceSought)), \@entries); } else { - @solution = DynamicProgrammingSubSetSumSolver(\@entries, ConvertTwoDigitPrecisionToInteger($balanceSought), - \&ConvertTwoDigitPrecisionToIntegerInEntry); + @solution = $solver->(\@entries, + ConvertTwoDigitPrecisionToInteger($balanceSought), + \&ConvertTwoDigitPrecisionToIntegerInEntry); } if ($VERBOSE) { use Data::Dumper; print STDERR "Solution for $formattedStartDate, $balanceSought: \n", Data::Dumper->Dump(\@solution); } - print STDERR "Solution Found: Dying" if ($solution[0]) and $VERBOSE; -# last if ($solution[0]); + last if ($solution[0]); } -print "DONE LOOP: $startDate $earliestStartDate\n"; if ($solution[0]) { print "FINAL SOLUTION: "; foreach my $ee (@{$solution[1]}) { - print "$ee->date, $ee->payee, $ee->amount\n"; + print Data::Dumper->Dump($solution[1]); + print "$ee->{date}, $ee->{payee}, $ee->{amount}\n"; } } ############################################################################### -- cgit v1.2.3 From 94094ce3650e26e584b68f3c0d94d593732dc3bc Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Wed, 9 Jan 2013 16:44:54 -0500 Subject: Finish reporting details for STDOUT; change command line arg to bank balance. Report in CSV now goes to STDOUT. The command line argument that was the difference to seek is now the bank balance. --- .../bank-reconcilation.plx | 60 ++++++++++++++-------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/contrib/non-profit-audit-reports/bank-reconcilation.plx b/contrib/non-profit-audit-reports/bank-reconcilation.plx index 18d74067..ada923f3 100755 --- a/contrib/non-profit-audit-reports/bank-reconcilation.plx +++ b/contrib/non-profit-audit-reports/bank-reconcilation.plx @@ -112,10 +112,6 @@ sub ParseNumber($) { $_[0] =~ s/,//g; return Math::BigFloat->new($_[0]); } -if (@ARGV < 4) { - print STDERR "usage: $0 [-d] \n"; - exit 1; -} ###################################################################### sub ConvertTwoDigitPrecisionToInteger ($) { return sprintf("%d", $_[0] * $ONE_HUNDRED); @@ -129,17 +125,43 @@ my $firstArg = shift @ARGV; my $solver = \&BruteForceSubSetSumSolver; +if (@ARGV < 5) { + print STDERR "usage: $0 [-d] <ACCOUNT_REGEX> <END_DATE> <BANK_STATEMENT_BALANCE> <LEDGER_OPTIONS>\n"; + exit 1; +} if ($firstArg eq '-d') { $solver = \&DynamicProgrammingSubSetSumSolver; } else { unshift(@ARGV, $firstArg); } -my($account, $endDate, $balanceSought, @mainLedgerOptions) = @ARGV; +my($title, $account, $endDate, $bankBalance, @mainLedgerOptions) = @ARGV; + +$bankBalance = ParseNumber($bankBalance); +my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', + '-e', $endDate, '-F', '%t\n', 'bal', "/$account/"); -$balanceSought = ParseNumber($balanceSought); +open(FILE, "-|", @fullCommand) or die "unable to run command ledger command: @fullCommand: $!"; + +my $total; +foreach my $line (<FILE>) { + chomp $line; + die "Unable to parse output line from: \"$line\"" + unless $line =~ /^\s*\$\s*([\-\d\.\,]+)\s*$/ and not defined $total; + $total = $1; + $total = ParseNumber($total); +} +close FILE; +if (not defined $total or $? != 0) { + die "unable to run ledger @fullCommand: $!"; +} +my $differenceSought = $total - $bankBalance; my $err; +my $formattedEndDate = UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 day"), \$err), + "%Y-%m-%d"); +die "Date calculation error on $endDate" if ($err); + my $earliestStartDate = DateCalc(ParseDate($endDate), ParseDateDelta("- 1 month"), \$err); die "Date calculation error on $endDate" if ($err); @@ -148,11 +170,11 @@ my $startDate = ParseDate($endDate); my @solution; while ($startDate ge $earliestStartDate) { - print "START LOOP ITR: $startDate $earliestStartDate\n"; + print STDERR "START LOOP ITR: $startDate $earliestStartDate\n" if ($VERBOSE); $startDate = DateCalc(ParseDate($startDate), ParseDateDelta("- 1 day"), \$err); die "Date calculation error on $endDate" if ($err); - my $formattedStartDate = UnixDate($startDate, "%Y/%m/%d"); + my $formattedStartDate = UnixDate($startDate, "%Y-%m-%d"); print STDERR "Testing $formattedStartDate through $endDate: \n" if $VERBOSE; @@ -180,26 +202,24 @@ while ($startDate ge $earliestStartDate) { close FILE; die "unable to properly run ledger command: @fullCommand: $!" unless ($? == 0); - @solution = (); - if (@entries == 1) { - @solution = ( (abs($entries[0]->{amount}) == abs($balanceSought)), \@entries); - } else { - @solution = $solver->(\@entries, - ConvertTwoDigitPrecisionToInteger($balanceSought), - \&ConvertTwoDigitPrecisionToIntegerInEntry); - } + @solution = $solver->(\@entries, + ConvertTwoDigitPrecisionToInteger($differenceSought), + \&ConvertTwoDigitPrecisionToIntegerInEntry); if ($VERBOSE) { use Data::Dumper; - print STDERR "Solution for $formattedStartDate, $balanceSought: \n", Data::Dumper->Dump(\@solution); + print STDERR "Solution for $formattedStartDate to $formattedEndDate, $differenceSought: \n", + Data::Dumper->Dump(\@solution); } last if ($solution[0]); } if ($solution[0]) { - print "FINAL SOLUTION: "; + print "\"title:$formattedEndDate: $title\"\n\"BANK RECONCILATION: $account\",\"ENDING\",\"$formattedEndDate\"\n"; + print "\n\n\"DATE\",\"CHECK NUM\",\"PAYEE\",\"AMOUNT\"\n\n"; + print "\"$formattedEndDate\",\"\",\"BANK ACCOUNT BALANCE\",\"$bankBalance\"\n\n"; foreach my $ee (@{$solution[1]}) { - print Data::Dumper->Dump($solution[1]); - print "$ee->{date}, $ee->{payee}, $ee->{amount}\n"; + print "\"$ee->{date}\",\"$ee->{checkNum}\",\"$ee->{payee}\",\"$ee->{amount}\"\n"; } + print "\n\"$formattedEndDate\",\"\",\"OUR ACCOUNT BALANCE\",\"$total\"\n\n"; } ############################################################################### # -- cgit v1.2.3 From 8ebb54638ca8a57b15126cb11fd6329faf639be5 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Thu, 10 Jan 2013 11:25:19 -0500 Subject: Start search from date: easy way to resume searches. Instead of always starting a search from the end date, allow a CLI option that is the data to use for the start of searching (back from the end date). This is useful when resuming a search (since they take a long time). --- contrib/non-profit-audit-reports/bank-reconcilation.plx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contrib/non-profit-audit-reports/bank-reconcilation.plx b/contrib/non-profit-audit-reports/bank-reconcilation.plx index ada923f3..701f053e 100755 --- a/contrib/non-profit-audit-reports/bank-reconcilation.plx +++ b/contrib/non-profit-audit-reports/bank-reconcilation.plx @@ -125,8 +125,8 @@ my $firstArg = shift @ARGV; my $solver = \&BruteForceSubSetSumSolver; -if (@ARGV < 5) { - print STDERR "usage: $0 [-d] <TITLE> <ACCOUNT_REGEX> <END_DATE> <BANK_STATEMENT_BALANCE> <LEDGER_OPTIONS>\n"; +if (@ARGV < 6) { + print STDERR "usage: $0 [-d] <TITLE> <ACCOUNT_REGEX> <END_DATE> <START_SEARCH_FROM_DATE> <BANK_STATEMENT_BALANCE> <LEDGER_OPTIONS>\n"; exit 1; } if ($firstArg eq '-d') { @@ -134,7 +134,7 @@ if ($firstArg eq '-d') { } else { unshift(@ARGV, $firstArg); } -my($title, $account, $endDate, $bankBalance, @mainLedgerOptions) = @ARGV; +my($title, $account, $endDate, $startSearchFromDate, $bankBalance, @mainLedgerOptions) = @ARGV; $bankBalance = ParseNumber($bankBalance); @@ -166,7 +166,7 @@ my $earliestStartDate = DateCalc(ParseDate($endDate), ParseDateDelta("- 1 month" die "Date calculation error on $endDate" if ($err); -my $startDate = ParseDate($endDate); +my $startDate = ParseDate($startSearchFromDate); my @solution; while ($startDate ge $earliestStartDate) { @@ -179,7 +179,7 @@ while ($startDate ge $earliestStartDate) { print STDERR "Testing $formattedStartDate through $endDate: \n" if $VERBOSE; my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', - '-b', $formattedStartDate, '-e', $endDate, + '-b', $formattedStartDate, '-e', $startSearchFromDate, '-F', '"%(date)","%C","%P","%t"\n', 'reg', "/$account/"); -- cgit v1.2.3 From 9fcdfc893c41447099169bf4ad51f5856db399a1 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Thu, 10 Jan 2013 11:26:14 -0500 Subject: Support for title: field, to name sheets in the ODS file. If "title:SOMETHING" occurs in the CSV file, use SOMETHING as the title of the sheet. --- contrib/non-profit-audit-reports/csv2ods.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/csv2ods.py b/contrib/non-profit-audit-reports/csv2ods.py index 7dd840c8..6aabcb59 100755 --- a/contrib/non-profit-audit-reports/csv2ods.py +++ b/contrib/non-profit-audit-reports/csv2ods.py @@ -169,7 +169,10 @@ def csv2ods(csvname, odsname, encoding='', singleFileDirectory=None, knownChecks if val == "pagebreak": doc.sheets[doc.sheet_index].set_sheet_config(('row', row), style_pagebreak) else: - doc.set_cell_value(col + 1, row, 'string', val) + if val[0:6] == "title:": + doc.sheets[doc.sheet_index].set_name(val[6:]) + else: + doc.set_cell_value(col + 1, row, 'string', val) else: # enter an empty string for blank lines doc.set_cell_value(1, row, 'string', '') -- cgit v1.2.3 From c0206418f730b0df45898dcf4280d9d96e801bb1 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Fri, 18 Jan 2013 17:04:08 -0500 Subject: Correct regular expression for account queries to avoid inclusion of sub-accounts. The previous queries had a bug whereby an account in the form "A:B" would include all transactions for sub accounts such as "A:B:C". That's not the intended effect. Entries should appear in the lowest level account, and not in their parent. The regular expression now is anchored at start and finish in both queries to ensure this works correctly. --- contrib/non-profit-audit-reports/general-ledger-report.plx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 1fd0e7ce..1e6d9caf 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -166,7 +166,7 @@ foreach my $acct (@sortedAccounts) { print GL_TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; my @acctLedgerOpts = ('-V', '-F', "%(date) %-.10C %-.80P %-.80N %18t %18T\n", '-w', '--sort', 'd', - '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); + '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', '/^' . $acct . '$/'); open(GL_TEXT_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!"; @@ -190,7 +190,7 @@ foreach my $acct (@sortedAccounts) { print GL_CSV_OUT "\"$formattedBeginDate\"", ',"","BALANCE","","$', "$balanceData{totalBegin}{$acct}\"\n"; } - @acctLedgerOpts = ('-V', '-F', $formatString, '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); + @acctLedgerOpts = ('-V', '-F', $formatString, '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', '/^' . $acct . '$/'); open(GL_CSV_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!"; -- cgit v1.2.3 From 86b20430423428f4ad371d98071679c9429f861b Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Mon, 21 Jan 2013 16:28:14 -0500 Subject: Remove output of TXT files. CSV output is adequate. --- .../cash-receipts-and-disbursments-journals.plx | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx index 2ad18a44..b620a75e 100755 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -85,10 +85,8 @@ foreach my $acct (@accounts) { { name => 'receipts', query => 'a>0' }) { my $fileNameBase = $acctFilename . '-' . $typeData->{name}; - open(TEXT_OUT, ">", "$fileNameBase.txt") or die "unable to open $fileNameBase.txt: $!"; open(CSV_OUT, ">", "$fileNameBase.csv") or die "unable to open $fileNameBase.csv: $!"; - print TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; print CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; print CSV_OUT '"DATE","CHECK NUM","NAME","ACCOUNT","AMOUNT"'; @@ -106,10 +104,6 @@ foreach my $acct (@accounts) { goto SKIP_REGISTER_COMMANDS if (-z $tempFile); - my @txtRegLedgerOpts = ('-f', $tempFile, '-V', '-F', - "%(date) %-.70P %-.10C %-.80A %18t\n", '-w', '--sort', 'd', - '-b', $beginDate, '-e', $endDate, 'reg'); - my $formatString = '\n"%(date)","%C","%P","%A","%t"\n%/"","","","%A","%t"'; foreach my $tagField (qw/Receipt Invoice Statement Contract PurchaseOrder Approval Check IncomeDistributionAnalysis CurrencyRate/) { print CSV_OUT ',"', $tagField, '"'; @@ -121,12 +115,6 @@ foreach my $acct (@accounts) { '-b', $beginDate, '-e', $endDate, 'reg'); - open(TXT_DATA, "-|", $LEDGER_CMD, @txtRegLedgerOpts) - or die "unable to run ledger command for $fileNameBase.txt: $!"; - - while (my $line = <TXT_DATA>) { print TEXT_OUT $line; } - close(TEXT_OUT); die "Error read write text out to $fileNameBase.txt: $!" unless $? == 0; - open(CSV_DATA, "-|", $LEDGER_CMD, @csvRegLedgerOpts) or die "unable to run ledger command for $fileNameBase.csv: $!"; @@ -134,7 +122,6 @@ foreach my $acct (@accounts) { close(CSV_DATA); die "Error read from csv ledger command $!" unless $? == 0; SKIP_REGISTER_COMMANDS: - close(TXT_DATA); die "Error read from txt ledger command $!" unless $? == 0; close(CSV_OUT); die "Error read write csv out to $fileNameBase.csv: $!" unless $? == 0; unlink($tempFile); } -- cgit v1.2.3 From ccd0685b6d779c520c0792e2fe6c632a60bb0362 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Sun, 27 Jan 2013 15:22:05 -0500 Subject: Correct account names due to renaming of Conference accounts in chart of accounts. --- contrib/non-profit-audit-reports/summary-reports.plx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index e9e1a3b8..5e6c447b 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -104,9 +104,9 @@ my %reportFields = 'Liabilities, Other' => {args => [ '-e', $endDate, 'bal', '/^Liabilities/', 'and', 'not', '/^Liabilities:Credit Card/']}, 'Unearned Income, Conference Registration' => {args => [ '-e', $endDate, 'bal', - '/^Unearned Income.*Conf.*Reg/' ]}, + '/^Unearned Income.*Reg/' ]}, 'Unearned Income, Other' => {args => [ '-e', $endDate, 'bal', '/^Unearned Income/', 'and', 'not', - '/^Unearned Income.*Conf.*Reg/' ]}, + '/^Unearned Income.*Reg/' ]}, 'Unrestricted Net Assets' => {args => [ '-e', $endDate, 'bal', '/^(Income|Expenses):Conservancy/' ]}, 'Temporarily Restricted Net Assets' => {args => [ '-e', $endDate, 'bal', '/^(Income|Expenses)/', 'and', 'not', '/^(Unearned Income|(Income|Expenses):Conservancy)/' ]}, @@ -213,8 +213,8 @@ my %incomeGroups = ('INTEREST INCOME' => { args => ['/^Income.*Interest/' ] }, 'DONATIONS' => { args => [ '/^Income.*Donation/' ] }, 'BOOK ROYALTIES & AFFILIATE PROGRAMS' => { args => [ '/^Income.*(Royalt|Affilate)/' ] }, - 'CONFERENCES, REGISTRATION' => {args => [ '/^Income.*Conf.*Reg/' ] }, - 'CONFERENCES, RELATED BUSINESS INCOME' => { args => [ '/^Income.*(Booth|RBI)/'] }, + 'CONFERENCES, REGISTRATION' => {args => [ '/^Income.*Reg/' ] }, + 'CONFERENCES, RELATED BUSINESS INCOME' => { args => [ '/^Income.*(Conference:.*Sponsor|Booth|RBI)/'] }, 'LICENSE ENFORCEMENT' => { args => [ '/^Income.*Enforce/' ]}, 'TRADEMARKS' => {args => [ '/^Income.*Trademark/' ]}, 'ADVERSITING' => {args => [ '/^Income.*Advertising/' ]}); -- cgit v1.2.3 From 7d04b92ad1445c60e0b61ab298f7384f0afbaa03 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Sun, 27 Jan 2013 15:22:13 -0500 Subject: This could be for any period, not just the FY. --- contrib/non-profit-audit-reports/summary-reports.plx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 5e6c447b..2860c9b4 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -386,7 +386,7 @@ print STDERR "\n"; open(TRIAL, ">", "trial-balance.csv") or die "unable to open accrued.txt for writing: $!"; print TRIAL "\"TRIAL BALANCE REPORT\",\"ENDING: $formattedEndDate\"\n\n", - "\"ACCOUNT\",\"BALANCE AT $formattedStartDate\",\"CHANGE DURING FY\",\"BALANCE AT $formattedEndDate\"\n\n"; + "\"ACCOUNT\",\"BALANCE AT $formattedStartDate\",\"CHANGE DURING PERIOD\",\"BALANCE AT $formattedEndDate\"\n\n"; my %commands = ( 'totalEndFY' => [ $LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', -- cgit v1.2.3 From 11639785bba1b97600e9b06a85be248e8d2d7688 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Sun, 27 Jan 2013 20:24:07 -0500 Subject: Improve spreadsheet and debugging output. --- contrib/non-profit-audit-reports/bank-reconcilation.plx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/contrib/non-profit-audit-reports/bank-reconcilation.plx b/contrib/non-profit-audit-reports/bank-reconcilation.plx index 701f053e..5b8d3d6f 100755 --- a/contrib/non-profit-audit-reports/bank-reconcilation.plx +++ b/contrib/non-profit-audit-reports/bank-reconcilation.plx @@ -206,20 +206,24 @@ while ($startDate ge $earliestStartDate) { ConvertTwoDigitPrecisionToInteger($differenceSought), \&ConvertTwoDigitPrecisionToIntegerInEntry); if ($VERBOSE) { - use Data::Dumper; - print STDERR "Solution for $formattedStartDate to $formattedEndDate, $differenceSought: \n", - Data::Dumper->Dump(\@solution); + if ($solution[0]) { + use Data::Dumper; + print STDERR "Solution for $formattedStartDate to $formattedEndDate, $differenceSought: \n", + Data::Dumper->Dump(\@solution); + } else { + print STDERR "No Solution Found. :(\n"; + } } last if ($solution[0]); } if ($solution[0]) { print "\"title:$formattedEndDate: $title\"\n\"BANK RECONCILATION: $account\",\"ENDING\",\"$formattedEndDate\"\n"; print "\n\n\"DATE\",\"CHECK NUM\",\"PAYEE\",\"AMOUNT\"\n\n"; - print "\"$formattedEndDate\",\"\",\"BANK ACCOUNT BALANCE\",\"$bankBalance\"\n\n"; + print "\"$formattedEndDate\",\"\",\"BANK ACCOUNT BALANCE\",\"\$$bankBalance\"\n\n"; foreach my $ee (@{$solution[1]}) { - print "\"$ee->{date}\",\"$ee->{checkNum}\",\"$ee->{payee}\",\"$ee->{amount}\"\n"; + print "\"$ee->{date}\",\"$ee->{checkNum}\",\"$ee->{payee}\",\"\$$ee->{amount}\"\n"; } - print "\n\"$formattedEndDate\",\"\",\"OUR ACCOUNT BALANCE\",\"$total\"\n\n"; + print "\n\"$formattedEndDate\",\"\",\"OUR ACCOUNT BALANCE\",\"\$$total\"\n\n"; } ############################################################################### # -- cgit v1.2.3 From afe912f163da2259f29bfd3ac3f5bfbc50190156 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Sun, 27 Jan 2013 20:24:34 -0500 Subject: Searching is better when you can set the begin date, end date and then go back from begin date. --- contrib/non-profit-audit-reports/bank-reconcilation.plx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/non-profit-audit-reports/bank-reconcilation.plx b/contrib/non-profit-audit-reports/bank-reconcilation.plx index 5b8d3d6f..2a3d0d38 100755 --- a/contrib/non-profit-audit-reports/bank-reconcilation.plx +++ b/contrib/non-profit-audit-reports/bank-reconcilation.plx @@ -125,8 +125,8 @@ my $firstArg = shift @ARGV; my $solver = \&BruteForceSubSetSumSolver; -if (@ARGV < 6) { - print STDERR "usage: $0 [-d] <TITLE> <ACCOUNT_REGEX> <END_DATE> <START_SEARCH_FROM_DATE> <BANK_STATEMENT_BALANCE> <LEDGER_OPTIONS>\n"; +if (@ARGV < 7) { + print STDERR "usage: $0 [-d] <TITLE> <ACCOUNT_REGEX> <END_DATE> <START_SEARCH_FROM_DATE> <END_SEARCH_TO_DATE> <BANK_STATEMENT_BALANCE> <LEDGER_OPTIONS>\n"; exit 1; } if ($firstArg eq '-d') { @@ -134,7 +134,7 @@ if ($firstArg eq '-d') { } else { unshift(@ARGV, $firstArg); } -my($title, $account, $endDate, $startSearchFromDate, $bankBalance, @mainLedgerOptions) = @ARGV; +my($title, $account, $endDate, $startSearchFromDate, $endSearchToDate, $bankBalance, @mainLedgerOptions) = @ARGV; $bankBalance = ParseNumber($bankBalance); @@ -170,16 +170,16 @@ my $startDate = ParseDate($startSearchFromDate); my @solution; while ($startDate ge $earliestStartDate) { - print STDERR "START LOOP ITR: $startDate $earliestStartDate\n" if ($VERBOSE); $startDate = DateCalc(ParseDate($startDate), ParseDateDelta("- 1 day"), \$err); die "Date calculation error on $endDate" if ($err); my $formattedStartDate = UnixDate($startDate, "%Y-%m-%d"); - print STDERR "Testing $formattedStartDate through $endDate: \n" if $VERBOSE; + print STDERR "Testing $formattedStartDate through $endSearchToDate for a total of ", Commify($differenceSought), ": \n" + if $VERBOSE; my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', - '-b', $formattedStartDate, '-e', $startSearchFromDate, + '-b', $formattedStartDate, '-e', $endSearchToDate, '-F', '"%(date)","%C","%P","%t"\n', 'reg', "/$account/"); -- cgit v1.2.3 From e87b6abb7f1c7bfd7a626ba5d27dc03fd48f701b Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Sat, 16 Feb 2013 21:28:27 -0500 Subject: Sort solution by date in output. --- contrib/non-profit-audit-reports/bank-reconcilation.plx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/bank-reconcilation.plx b/contrib/non-profit-audit-reports/bank-reconcilation.plx index 2a3d0d38..7a8da911 100755 --- a/contrib/non-profit-audit-reports/bank-reconcilation.plx +++ b/contrib/non-profit-audit-reports/bank-reconcilation.plx @@ -220,7 +220,7 @@ if ($solution[0]) { print "\"title:$formattedEndDate: $title\"\n\"BANK RECONCILATION: $account\",\"ENDING\",\"$formattedEndDate\"\n"; print "\n\n\"DATE\",\"CHECK NUM\",\"PAYEE\",\"AMOUNT\"\n\n"; print "\"$formattedEndDate\",\"\",\"BANK ACCOUNT BALANCE\",\"\$$bankBalance\"\n\n"; - foreach my $ee (@{$solution[1]}) { + foreach my $ee (sort { $a->{date} cmp $b->{date} } @{$solution[1]}) { print "\"$ee->{date}\",\"$ee->{checkNum}\",\"$ee->{payee}\",\"\$$ee->{amount}\"\n"; } print "\n\"$formattedEndDate\",\"\",\"OUR ACCOUNT BALANCE\",\"\$$total\"\n\n"; -- cgit v1.2.3 From aea1445b042d3e5fac02da00775299bfa0807c64 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Sat, 16 Feb 2013 22:15:15 -0500 Subject: Rework report to be just two files (disbursements and receipts). Ensure that tagged linked files appear for all lines. --- .../cash-receipts-and-disbursments-journals.plx | 37 +++++++++++----------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx index b620a75e..65f0bda0 100755 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -4,7 +4,7 @@ # Script to generate a General Ledger report that accountants like # using Ledger. # -# Copyright (C) 2011, 2012 Bradley M. Kuhn +# Copyright (C) 2011, 2012, 2013 Bradley M. Kuhn # # This program gives you software freedom; you can copy, modify, convey, # and/or redistribute it under the terms of the GNU General Public License @@ -21,6 +21,7 @@ # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor # Boston, MA 02110-1301, USA. + use strict; use warnings; @@ -76,19 +77,14 @@ die "bad one day less" if $oneDayLess->parse("- 1 day"); $formattedEndDate = $formattedEndDate->calc($oneDayLess); $formattedEndDate = $formattedEndDate->printf("%Y/%m/%d"); -foreach my $acct (@accounts) { - next unless ($acct =~ /^(?:Assets|Liabilities)/); - - my $acctFilename = LedgerAcctToFilename($acct); - - foreach my $typeData ({ name => 'disbursements', query => 'a<=0' }, - { name => 'receipts', query => 'a>0' }) { - my $fileNameBase = $acctFilename . '-' . $typeData->{name}; +foreach my $typeData ({ name => 'disbursements', query => 'a<=0' }, + { name => 'receipts', query => 'a>0' }) { + my $fileNameBase = $typeData->{name}; - open(CSV_OUT, ">", "$fileNameBase.csv") or die "unable to open $fileNameBase.csv: $!"; + open(CSV_OUT, ">", "$fileNameBase.csv") or die "unable to open $fileNameBase.csv: $!"; - print CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; - print CSV_OUT '"DATE","CHECK NUM","NAME","ACCOUNT","AMOUNT"'; + foreach my $acct (sort { $a cmp $b } @accounts) { + next unless ($acct =~ /^(?:Assets|Liabilities)/); my @entryLedgerOpts = ('-l', $typeData->{query}, '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'print', $acct); @@ -104,27 +100,30 @@ foreach my $acct (@accounts) { goto SKIP_REGISTER_COMMANDS if (-z $tempFile); - my $formatString = '\n"%(date)","%C","%P","%A","%t"\n%/"","","","%A","%t"'; + print CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; + print CSV_OUT '"DATE","CHECK NUM","NAME","ACCOUNT","AMOUNT"'; + + my $formatString = '\n"%(date)","%C","%P","%A","%t"'; + my $tagStrings = ""; foreach my $tagField (qw/Receipt Invoice Statement Contract PurchaseOrder Approval Check IncomeDistributionAnalysis CurrencyRate/) { print CSV_OUT ',"', $tagField, '"'; - $formatString .= ',"link:%(tag(\'' . $tagField . '\'))"'; + $tagStrings .= ',"link:%(tag(\'' . $tagField . '\'))"'; } - $formatString .= "\n"; - print CSV_OUT "\n"; + $formatString .= $tagStrings . '\n%/"","","","%A","%t"' . $tagStrings . '\n'; + my @csvRegLedgerOpts = ('-f', $tempFile, '-V', '-F', $formatString, '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, 'reg'); - open(CSV_DATA, "-|", $LEDGER_CMD, @csvRegLedgerOpts) or die "unable to run ledger command for $fileNameBase.csv: $!"; while (my $line = <CSV_DATA>) { $line =~ s/"link:"/""/g; print CSV_OUT $line; } close(CSV_DATA); die "Error read from csv ledger command $!" unless $? == 0; - + print CSV_OUT "\npagebreak\n"; SKIP_REGISTER_COMMANDS: - close(CSV_OUT); die "Error read write csv out to $fileNameBase.csv: $!" unless $? == 0; unlink($tempFile); } + close(CSV_OUT); die "Error read write csv out to $fileNameBase.csv: $!" unless $? == 0; } ############################################################################### # -- cgit v1.2.3 From a08dd787deb89446bc516612a1ea01937cd2e963 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Mon, 18 Feb 2013 14:05:15 -0500 Subject: Remove extra newline --- .../cash-receipts-and-disbursments-journals.plx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx index 65f0bda0..61b45b3c 100755 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -100,7 +100,7 @@ foreach my $typeData ({ name => 'disbursements', query => 'a<=0' }, goto SKIP_REGISTER_COMMANDS if (-z $tempFile); - print CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; + print CSV_OUT "\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; print CSV_OUT '"DATE","CHECK NUM","NAME","ACCOUNT","AMOUNT"'; my $formatString = '\n"%(date)","%C","%P","%A","%t"'; -- cgit v1.2.3 From 77827f9c80eac22834d17c4985778b70145e3243 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Mon, 18 Feb 2013 14:07:27 -0500 Subject: Subtotaling of BRANCH DEPOSITs. The auditors seem to like to see the check deposits made to be subtotaled, so that's done here. I attempted to aid this by using a --sort and/or --sort-xacts option (or combo thereof) on the ledger command line, but this didn't work as expected. I opened a bug in ledger about this: http://bugs.ledger-cli.org/show_bug.cgi?id=901 --- .../cash-receipts-and-disbursments-journals.plx | 45 +++++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx index 61b45b3c..58974a85 100755 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -111,15 +111,56 @@ foreach my $typeData ({ name => 'disbursements', query => 'a<=0' }, } $formatString .= $tagStrings . '\n%/"","","","%A","%t"' . $tagStrings . '\n'; + # I thought '--sort', 'd', '--sort-xact', 'a', should + # have worked below for a good sort. Then I tried + # rather than '--sort', "d,n,a", which didn't work either. + # I opened a bug: http://bugs.ledger-cli.org/show_bug.cgi?id=901 + my @csvRegLedgerOpts = ('-f', $tempFile, '-V', '-F', $formatString, '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, 'reg'); open(CSV_DATA, "-|", $LEDGER_CMD, @csvRegLedgerOpts) or die "unable to run ledger command for $fileNameBase.csv: $!"; - while (my $line = <CSV_DATA>) { $line =~ s/"link:"/""/g; print CSV_OUT $line; } + my($curDepositDate, $curDepositTotal); + + while (my $line = <CSV_DATA>) { + $line =~ s/"link:"/""/g; + + my $date = $line; chomp $date; + $date =~ s/^\s*"([^"]*)"\s*,.*$/$1/; + if (defined $date and $date !~ /^\s*$/ and + defined $curDepositDate and ($date ne $curDepositDate or + ($date eq $curDepositDate and $line !~ /DEPOSIT[\s\-]+BRANCH/))) { + print CSV_OUT "\"$curDepositDate\",\"SUBTOTAL\",\"BRANCH DEPOSIT TOTAL:\",\"\",\"\$$curDepositTotal\"\n\n"; + $curDepositTotal = $curDepositDate = undef; + } + if ($line =~ /DEPOSIT[\s\-]+BRANCH/) { + if (not defined $curDepositDate) { + $curDepositDate = $line; chomp $curDepositDate; + $curDepositDate =~ s/^\s*"([^"]+)"\s*,.*$/$1/; + } + } + # This is a bit of a hack because I can't ssume that the line with the + # description on it has the account name in it. + if (defined $curDepositDate and $line =~ /$acct/) { + my $amt = $line; + chomp $amt; + $amt =~ s/^\s*"[^"]*","[^"]*","[^"]*","[^"]*","\$\s*([^"]*)".*$/$1/; + $amt =~ s/,//g; + + $curDepositTotal = 0.0 unless defined $curDepositTotal; + $curDepositTotal += $amt; + print "$amt and $curDepositTotal for deposit on $curDepositDate\n"; + } + print CSV_OUT $line; + } + # Catch potential last Deposit subtotal + print CSV_OUT "\n\"$curDepositDate\",\"SUBTOTAL\",\"BRANCH DEPOSIT TOTAL:\",\"\",\"\$$curDepositTotal\"\n\n" + if (defined $curDepositDate); + close(CSV_DATA); die "Error read from csv ledger command $!" unless $? == 0; - print CSV_OUT "\npagebreak\n"; + print CSV_OUT "pagebreak\n"; SKIP_REGISTER_COMMANDS: unlink($tempFile); } -- cgit v1.2.3 From 8fa91dcb31bc176634fbc8503035a1cc52256de8 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Mon, 18 Feb 2013 14:20:15 -0500 Subject: Remove spurious print statement. --- .../non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx index 58974a85..cb19a19e 100755 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -151,7 +151,6 @@ foreach my $typeData ({ name => 'disbursements', query => 'a<=0' }, $curDepositTotal = 0.0 unless defined $curDepositTotal; $curDepositTotal += $amt; - print "$amt and $curDepositTotal for deposit on $curDepositDate\n"; } print CSV_OUT $line; } -- cgit v1.2.3 From cbdffb9a41b445dec9a9a99addf41112bac4f128 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Mon, 18 Feb 2013 14:36:39 -0500 Subject: Catch a few additional accounts under Conference RBI category. --- contrib/non-profit-audit-reports/summary-reports.plx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 2860c9b4..78848dc5 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -214,7 +214,7 @@ my %incomeGroups = ('INTEREST INCOME' => { args => ['/^Income.*Interest/' ] }, 'BOOK ROYALTIES & AFFILIATE PROGRAMS' => { args => [ '/^Income.*(Royalt|Affilate)/' ] }, 'CONFERENCES, REGISTRATION' => {args => [ '/^Income.*Reg/' ] }, - 'CONFERENCES, RELATED BUSINESS INCOME' => { args => [ '/^Income.*(Conference:.*Sponsor|Booth|RBI)/'] }, + 'CONFERENCES, RELATED BUSINESS INCOME' => { args => [ '/^Income.*(Conferences?:.*Sponsor|Booth|RBI)/'] }, 'LICENSE ENFORCEMENT' => { args => [ '/^Income.*Enforce/' ]}, 'TRADEMARKS' => {args => [ '/^Income.*Trademark/' ]}, 'ADVERSITING' => {args => [ '/^Income.*Advertising/' ]}); -- cgit v1.2.3 From 3d90bfc4add2a85b80c2a90b7c0df9b95d77579d Mon Sep 17 00:00:00 2001 From: John Wiegley <johnw@newartisans.com> Date: Mon, 18 Feb 2013 20:54:10 -0600 Subject: Fix formatting and typos --- doc/ledger3.texi | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 92cb07fb..44f305f2 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -1971,7 +1971,7 @@ account. For example: capture Expenses:Deductible:Medical Medical @end smallexample -Would cause any posting with @code{Medical} in it's name to be replaced with +Would cause any posting with @code{Medical} in its name to be replaced with @code{Expenses:Deductible:Medical}. @@ -2889,9 +2889,9 @@ cannot appear in the Key: @node Typed metadata, , Metadata values, Metadata @subsection Typed metadata -If a metadata tag ends in ::, it's value will be parsed as a value expression -and stored internally as a value rather than as a string. For example, -although I can specify a date textually like so: +If a metadata tag ends in ::, its value will be parsed as a value +expression and stored internally as a value rather than as a string. +For example, although I can specify a date textually like so: @smallexample 2012-03-10 * KFC @@ -2900,10 +2900,10 @@ although I can specify a date textually like so: ; AuxDate: 2012/02/30 @end smallexample -@noindent This date is just a string, and won't be parsed as a date unless its value is -used in a date-context (at which time the string is parsed into a date -automatically every time it is needed as a date). If on the other hand I -write this: +@noindent This date is just a string, and won't be parsed as a date +unless its value is used in a date-context (at which time the string +is parsed into a date automatically every time it is needed as a +date). If on the other hand I write this: @smallexample 2012-03-10 * KFC @@ -2912,8 +2912,9 @@ write this: ; AuxDate:: [2012/02/30] @end smallexample -@noindent Then it is parsed as a date only once, and during parsing of the journal file, -which would let me know right away that it is an invalid date. +@noindent Then it is parsed as a date only once, and during parsing +of the journal file, which would let me know right away that it is an +invalid date. @node Virtual postings, Expression amounts, Metadata, Transactions @section Virtual postings -- cgit v1.2.3 From c2bc7b6b9ed28d2069ca80175a56ff9dcc849951 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Tue, 19 Feb 2013 09:11:08 -0500 Subject: Equity and Adjustment accounts should not appear in these reports at all. There were a few spots where they were still sneaking in. --- .../cash-receipts-and-disbursments-journals.plx | 6 ++++++ contrib/non-profit-audit-reports/general-ledger-report.plx | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx index cb19a19e..58cc75a9 100755 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -64,6 +64,8 @@ open(CHART_DATA, "-|", $LEDGER_CMD, @chartOfAccountsOpts) my @accounts; while (my $line = <CHART_DATA>) { chomp $line; + next if $line =~ /^\s*\<\s*Adjustment\s*\>\s*$/; + next if $line =~ /^Equity:/; # Stupid auto-account made by ledger. $line =~ s/^\s*//; $line =~ s/\s*$//; push(@accounts, $line); @@ -127,6 +129,10 @@ foreach my $typeData ({ name => 'disbursements', query => 'a<=0' }, while (my $line = <CSV_DATA>) { $line =~ s/"link:"/""/g; + # Skip lines that have Adjustment or Equity: in them. + next if $line =~ + /^\s*"[^"]*","[^"]*","[^"]*","(\s*\<\s*Adjustment\s*\>\s*|Equity:)/; + my $date = $line; chomp $date; $date =~ s/^\s*"([^"]*)"\s*,.*$/$1/; if (defined $date and $date !~ /^\s*$/ and diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 1e6d9caf..dce855b4 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -72,6 +72,7 @@ my @accounts; while (my $line = <CHART_DATA>) { chomp $line; next if $line =~ /^\s*\<\s*Adjustment\s*\>\s*$/; + next if $line =~ /^\s*Equity:/; # Stupid auto-account made by ledger. $line =~ s/^\s*//; $line =~ s/\s*$//; push(@accounts, $line); @@ -119,7 +120,6 @@ sub preferredAccountSorting ($$) { } } - my @sortedAccounts; foreach my $acct ( sort preferredAccountSorting @accounts) { print CHART_OUTPUT "\"$acct\"\n"; -- cgit v1.2.3 From cf39acfd8ba0ebb542cf32f86944b2b6361cc6db Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 19 Feb 2013 09:30:20 -0700 Subject: Fix another null buffer problem when closing ledger buffers --- lisp/ldg-new.el | 1 + lisp/ldg-reconcile.el | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index ab267747..1e70c432 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -47,6 +47,7 @@ (require 'ldg-fonts) (require 'ldg-occur) (require 'ldg-commodities) +(require 'esh-arg) ;;; Code: diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index ebaf7949..6d7226de 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -232,23 +232,25 @@ and exit reconcile mode" (interactive) (let ((recon-buf (get-buffer ledger-recon-buffer-name)) buf) - (with-current-buffer recon-buf - (ledger-reconcile-quit-cleanup) - (set 'buf ledger-buf) - ;; Make sure you delete the window before you delete the buffer, - ;; otherwise, madness ensues - (delete-window (get-buffer-window recon-buf)) - (kill-buffer recon-buf) - (set-window-buffer (selected-window) buf)))) + (if recon-buf + (with-current-buffer recon-buf + (ledger-reconcile-quit-cleanup) + (set 'buf ledger-buf) + ;; Make sure you delete the window before you delete the buffer, + ;; otherwise, madness ensues + (delete-window (get-buffer-window recon-buf)) + (kill-buffer recon-buf) + (set-window-buffer (selected-window) buf))))) (defun ledger-reconcile-quit-cleanup () "Cleanup all hooks established by reconcile mode." (interactive) (let ((buf ledger-buf)) - (with-current-buffer buf - (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t) - (if ledger-fold-on-reconcile - (ledger-occur-quit-buffer buf))))) + (if buf + (with-current-buffer buf + (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t) + (if ledger-fold-on-reconcile + (ledger-occur-quit-buffer buf)))))) (defun ledger-marker-where-xact-is (emacs-xact posting) "Find the position of the EMACS-XACT in the `ledger-buf'. -- cgit v1.2.3 From 4ebd17efb391b5236c69f5d7eb3b5852a962fe58 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 19 Feb 2013 16:44:53 -0700 Subject: Better way of splitting the commodity from the value. Should allow no spaces between commodities and values. --- lisp/ldg-commodities.el | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 04dc23de..1b6b332a 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -37,20 +37,30 @@ This only has effect interfacing to calc mode in edit amount" :type 'boolean :group 'ledger) +(defun ledger-split-commodity-string (str) + "Split a commoditized amount into two parts" + (let (val + comm) + (with-temp-buffer + (insert str) + (goto-char (point-min)) + (re-search-forward "-?[1-9][0-9]*[.,][0-9]*") + (setq val + (string-to-number + (ledger-commodity-string-number-decimalize + (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user))) + (delete-trailing-whitespace) + (setq comm (buffer-substring (point-min) (point-max))) + (list val comm)))) + + (defun ledger-string-balance-to-commoditized-amount (str) "Return a commoditized amount (val, 'comm') from STR." (let ((fields (split-string str "[\n\r]"))) ; break any balances ; with multi commodities ; into a list (mapcar '(lambda (str) - (let* ((parts (split-string str)) ;break into number and commodity string - (first (car parts)) - (second (cadr parts))) - (if (string-match "^-*[1-9]+" first) - (list (string-to-number - (ledger-commodity-string-number-decimalize first :from-user)) second) - (list (string-to-number - (ledger-commodity-string-number-decimalize second :from-user)) first)))) + (ledger-split-commodity-string str)) fields))) -- cgit v1.2.3 From b378359f5f4fbfad3475f362699e3d353c1f7e80 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Wed, 20 Feb 2013 07:47:33 -0500 Subject: Use a Math::BigFloat() rather than a regular float for Adjustment comparison. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on patch review by Loïc Dachary <loic@dachary.org>, we discovered that this script inconsistently used 0.02 as a float when comparing against numbers from the Math::BigFloat() package. While there were no known bugs related to this (presumably the 0.02 got coerced into a BigFloat (or vice-versa) and compared properly), this change nevertheless normalizes to use of a BigFloat for comparison. --- contrib/non-profit-audit-reports/summary-reports.plx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 78848dc5..f710d765 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -80,6 +80,7 @@ sub ParseNumber($) { Math::BigFloat->precision(-2); my $ZERO = Math::BigFloat->new("0.00"); my $ONE_PENNY = Math::BigFloat->new("0.01"); +my $TWO_CENTS = Math::BigFloat->new("0.02"); if (@ARGV < 2) { print STDERR "usage: $0 <START_DATE> <END_DATE> <LEDGER_OPTIONS>\n"; @@ -249,7 +250,7 @@ foreach my $type (keys %incomeGroups) { my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); $account =~ s/\s+$//; - next if $account =~ /\<Adjustment\>/ and (abs($amount) <= 0.02); + next if $account =~ /\<Adjustment\>/ and (abs($amount) <= $TWO_CENTS); die "Weird account found, $account with amount of $amount in income command\n" unless $account =~ /^\s*Income:/; @@ -321,7 +322,7 @@ foreach my $line (<FILE>) { my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); $account =~ s/\s+$//; - next if $account =~ /\<Adjustment\>/ and (abs($amount) <= 0.02); + next if $account =~ /\<Adjustment\>/ and (abs($amount) <= $TWO_CENTS); die "Weird account found, $account, with amount of $amount in expenses command\n" unless $account =~ /^\s*Expenses:/; @@ -416,7 +417,7 @@ foreach my $id (keys %commands) { my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); $account =~ s/\s+$//; - next if $account =~ /\<Adjustment\>/ and (abs($amount) <= 0.02); + next if $account =~ /\<Adjustment\>/ and (abs($amount) <= $TWO_CENTS); next if $account =~ /^Equity:/; # Stupid auto-account made by ledger. $trialBalanceData{$id}{$account} = $amount; $fullAccountList{$account} = $id; -- cgit v1.2.3 From e606dfd72f7b19b8733e7dc22cd82d8a36006298 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Wed, 20 Feb 2013 07:48:30 -0500 Subject: Fix typo in error output. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HT Loïc Dachary <loic@dachary.org>, who noticed this. --- contrib/non-profit-audit-reports/summary-reports.plx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index f710d765..5caef4f0 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -379,7 +379,7 @@ close EXPENSE; die "unable to write to expense.csv: $!" unless ($? == 0); die "GROUPS NOT INCLUDED : ", join(keys(%verifyAllGroups), ", "), "\n" unless (keys %verifyAllGroups == 0); -die "calculated total of $overallTotal does equal $firstTotal" +die "calculated total of $overallTotal does *not* equal $firstTotal" if (abs($overallTotal) - abs($firstTotal) > $ONE_PENNY); print STDERR "\n"; -- cgit v1.2.3 From a8403eac53c069ec7db434f41df0505543985086 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Wed, 20 Feb 2013 07:59:11 -0500 Subject: Include better explanation of what this report is for in the comments. --- .../cash-receipts-and-disbursments-journals.plx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx index 58cc75a9..2ca9e3b8 100755 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -1,9 +1,21 @@ #!/usr/bin/perl # cash-receipts-and-disbursments-journals -*- Perl -*- # -# Script to generate a General Ledger report that accountants like +# Script to generate a cash receipts and disbursement joural reports # using Ledger. # +# Accountants sometimes ask for a report called the "cash receipts and +# disbursements journals". From a programmer's perspective, these are two +# reports that have the following properties: +# +# * Receipts: "a list of all transactions in the period where funds +# enter a cash account (i.e., the amount reconciled +# against the cash account is > 0" +# +# * Disbursements: "a list of all transactions in the period where +# funds leave a cash account (i.e., the amount +# reconciled against the cash account is < 0) +# # Copyright (C) 2011, 2012, 2013 Bradley M. Kuhn # # This program gives you software freedom; you can copy, modify, convey, -- cgit v1.2.3 From 88667ca0c5c8ca467153d163961865a572050516 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" <bkuhn@ebb.org> Date: Wed, 20 Feb 2013 08:10:27 -0500 Subject: Comment to expound more on what it means for <Adjustment> entries to be ignored by these reports. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Loïc Dachary <loic@dachary.org>, during patch review, pondered whether the ignoring of <Adjustment> by these scripts could ever be used to hide funds, ala the movies Superman III and Office Space. After discussion, we both concluded that it would not be possible to hide funds merely with this report. Such hiding would have to also dig into the main Ledger codebase and muck with how it handles auto-generated <Adjustment> entries. --- .../cash-receipts-and-disbursments-journals.plx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx index 2ca9e3b8..6234542c 100755 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -145,6 +145,19 @@ foreach my $typeData ({ name => 'disbursements', query => 'a<=0' }, next if $line =~ /^\s*"[^"]*","[^"]*","[^"]*","(\s*\<\s*Adjustment\s*\>\s*|Equity:)/; + # Note that we don't do our usual "$TWO_CENTS" check on Adjustment + # here. That's by design: if we consistently ignore Adjustements in + # the same way, it might have the appearance that a Superman + # III/Office Space -style movement of funds is going on. By just + # straight "ignoring" them here, and not doing the TWO_CENTS test, it + # helps to assure that. + + # However, it's worth noting that the ignoring of "Adjustment" in these + # scripts is not that meaningful and doesn't indicate as Superman + # III/Office Space -style scheme, because such a scheme would also have + # to be implemented in the main Ledger codebase. + + my $date = $line; chomp $date; $date =~ s/^\s*"([^"]*)"\s*,.*$/$1/; if (defined $date and $date !~ /^\s*$/ and -- cgit v1.2.3 From 988a41c3a4e9dbc131bb3e0d2fca18f796468777 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 20 Feb 2013 14:00:46 -0700 Subject: Make ledger-reconcile a little cleaner. The recon buffer is filled before asking for target, so there isn't a blank window showing while asking for target. --- lisp/ldg-reconcile.el | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 6d7226de..602d918e 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -362,12 +362,12 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (if ledger-fold-on-reconcile (ledger-occur-change-regex account ledger-buf)) (set-buffer (get-buffer ledger-recon-buffer-name)) - (setq ledger-target - (ledger-read-commodity-string "Set reconciliation target")) (unless (get-buffer-window rbuf) (ledger-reconcile-open-windows buf rbuf)) (ledger-reconcile-refresh) - (goto-char (point-min))) + (goto-char (point-min)) + (setq ledger-target + (ledger-read-commodity-string "Set reconciliation target"))) (progn ;; no recon-buffer, starting from scratch. (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save nil t) @@ -379,9 +379,9 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (ledger-reconcile-mode) (set (make-local-variable 'ledger-buf) buf) (set (make-local-variable 'ledger-acct) account) + (ledger-do-reconcile) (set (make-local-variable 'ledger-target) - (ledger-read-commodity-string "Set reconciliation target")) - (ledger-do-reconcile)))))) + (ledger-read-commodity-string "Set reconciliation target"))))))) (defvar ledger-reconcile-mode-abbrev-table) -- cgit v1.2.3 From f54c15bdf575377383923d368f5de2b5e56a7669 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 20 Feb 2013 16:13:27 -0700 Subject: Bug 884. Highlight first line of file --- lisp/ldg-xact.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index 94a58542..f5a38ef6 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -42,7 +42,8 @@ within the transaction." (let ((end-pos pos) (beg-pos pos)) (backward-paragraph) - (forward-line) + (if (/= (point) (point-min)) + (forward-line)) (beginning-of-line) (setq beg-pos (point)) (forward-paragraph) -- cgit v1.2.3 From 8029fd1149a607ee2eed7712194904b6c711d4b4 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 20 Feb 2013 20:46:38 -0700 Subject: Run ledger-highlight-xact-under-point when reconcile quits, so only one xact is highlighted --- lisp/ldg-reconcile.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 602d918e..9ac89915 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -250,7 +250,9 @@ and exit reconcile mode" (with-current-buffer buf (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t) (if ledger-fold-on-reconcile - (ledger-occur-quit-buffer buf)))))) + (progn + (ledger-occur-quit-buffer buf) + (ledger-highlight-xact-under-point))))))) (defun ledger-marker-where-xact-is (emacs-xact posting) "Find the position of the EMACS-XACT in the `ledger-buf'. -- cgit v1.2.3 From a4e76727be273185c7eee5758262d58c5aa4ccdd Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 20 Feb 2013 21:16:05 -0700 Subject: Put in more nil window protection. --- lisp/ldg-occur.el | 3 ++- lisp/ldg-reconcile.el | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index 417a3d2a..c3f04c5d 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -82,7 +82,8 @@ When REGEX is nil, unhide everything, and remove higlight" (append ledger-occur-overlay-list (ledger-occur-create-folded-overlays buffer-matches))) (setq ledger-occur-last-match regex) - (select-window (get-buffer-window buffer)))) + (if (get-buffer-window buffer) + (select-window (get-buffer-window buffer))))) (recenter))) (defun ledger-occur (regex) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 9ac89915..623d7230 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -320,10 +320,10 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (fit-window-to-buffer recon-window) (with-current-buffer buf (add-hook 'kill-buffer-hook 'ledger-reconcile-quit nil t) - (select-window (get-buffer-window buf)) + (if (get-window-for-other-buffer buf) + (select-window (get-buffer-window buf))) (goto-char (point-max)) (recenter -1)) - (select-window recon-window) (ledger-reconcile-visit t)) (add-hook 'post-command-hook 'ledger-reconcile-track-xact nil t)))) -- cgit v1.2.3 From 2fd1574cf2e969c7da7bf346837d859ac6ae90c9 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 21 Feb 2013 06:43:00 -0700 Subject: Prevent point from being at the end of line when ledger-reconcile-toggle is called --- lisp/ldg-reconcile.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 623d7230..e040359d 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -112,6 +112,7 @@ numbers" (defun ledger-reconcile-toggle () "Toggle the current transaction, and mark the recon window." (interactive) + (beginning-of-line) (let ((where (get-text-property (point) 'where)) (inhibit-read-only t) status) -- cgit v1.2.3 From 023e245e9b942968a5c61e494c28de2823b2a222 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 21 Feb 2013 14:35:29 -0700 Subject: Another attempt to deal with decimal-comma --- lisp/ldg-commodities.el | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 1b6b332a..c832f375 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -44,13 +44,14 @@ This only has effect interfacing to calc mode in edit amount" (with-temp-buffer (insert str) (goto-char (point-min)) - (re-search-forward "-?[1-9][0-9]*[.,][0-9]*") + (re-search-forward "-?[1-9][0-9]*[.,][0-9]*" nil t) (setq val (string-to-number (ledger-commodity-string-number-decimalize (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user))) - (delete-trailing-whitespace) - (setq comm (buffer-substring (point-min) (point-max))) + (re-search-forward "[^[:space:]]" nil t) + (setq comm + (delete-and-extract-region (match-beginning 0) (match-end 0))) (list val comm)))) -- cgit v1.2.3 From d638f8300f01600554017c5c5cad674873af9bc8 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 21 Feb 2013 14:59:32 -0700 Subject: bug-905, inadvertently used an aquamacs function. --- lisp/ldg-reconcile.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index e040359d..58f179f4 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -321,7 +321,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (fit-window-to-buffer recon-window) (with-current-buffer buf (add-hook 'kill-buffer-hook 'ledger-reconcile-quit nil t) - (if (get-window-for-other-buffer buf) + (if (get-buffer-window buf) (select-window (get-buffer-window buf))) (goto-char (point-max)) (recenter -1)) -- cgit v1.2.3 From 510a7c4e6c58d296d93941b193729b1d91dbb927 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 21 Feb 2013 15:31:58 -0700 Subject: Position point at beginning of line on posting being reconciled. --- lisp/ldg-reconcile.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 58f179f4..6a9d05fd 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -198,6 +198,7 @@ numbers" (forward-char) (recenter) (ledger-highlight-xact-under-point) + (forward-char -1) (if come-back (switch-to-buffer-other-window cur-buf)))))) -- cgit v1.2.3 From c68bdde19fe13d85b606c6f8e5f24608c0d4810c Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 21 Feb 2013 21:39:30 -0700 Subject: Another buglet in the commodity handler. --- lisp/ldg-commodities.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index c832f375..14cc168f 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -49,6 +49,7 @@ This only has effect interfacing to calc mode in edit amount" (string-to-number (ledger-commodity-string-number-decimalize (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user))) + (goto-char (point-min)) (re-search-forward "[^[:space:]]" nil t) (setq comm (delete-and-extract-region (match-beginning 0) (match-end 0))) -- cgit v1.2.3 From fd2c6d87a2353b5cc116bcb886a6c18abb308438 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 21 Feb 2013 22:21:13 -0700 Subject: Added ledger-mode-dump-variables to give me some instrumentation on users installs --- lisp/ldg-new.el | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index 1e70c432..64945dfa 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -89,6 +89,57 @@ (delete-char 3) (forward-line 1)))))) +(defun ledger-dump-variable (var) + + (insert (format "%s: %S\n" (symbol-name var) (eval var)))) + +(defun ledger-mode-dump-variables () + (interactive) + (find-file "ledger-mode-dump") + (delete-region (point-min) (point-max)) + (insert "Ledger Mode Configuration Dump\n") + (insert "Date: " (current-time-string) "\n") + (insert "Emacs: " (version) "\n") + (insert "System Configuration: "system-configuration "\n") + (insert "ldg-commodities:\n") + (ledger-dump-variable 'ledger-use-decimal-comma) + (ledger-dump-variable 'ledger-reconcile-default-commodity) + (insert "ldg-exec:\n") + (ledger-dump-variable 'ledger-works) + (ledger-dump-variable 'ledger-binary-path) + (insert "ldg-occur:\n") + (ledger-dump-variable 'ledger-occur-use-face-unfolded) + (ledger-dump-variable 'ledger-occur-mode) + (ledger-dump-variable 'ledger-occur-history) + (ledger-dump-variable 'ledger-occur-last-match) + (insert "ldg-post:\n") + (ledger-dump-variable 'ledger-post-auto-adjust-amounts) + (ledger-dump-variable 'ledger-post-amount-alignment-column) + (ledger-dump-variable 'ledger-post-use-iswitchb) + (ledger-dump-variable 'ledger-post-use-ido) + (insert "ldg-reconcile:\n") + (ledger-dump-variable 'ledger-recon-buffer-name) + (ledger-dump-variable 'ledger-fold-on-reconcile) + (ledger-dump-variable 'ledger-buffer-tracks-reconcile-buffer) + (ledger-dump-variable 'ledger-reconcile-force-window-bottom) + (ledger-dump-variable 'ledger-reconcile-toggle-to-pending) + (insert "ldg-register:\n") + (ledger-dump-variable 'ledger-register-date-format) + (ledger-dump-variable 'ledger-register-line-format) + (insert "ldg-reports:\n") + (ledger-dump-variable 'ledger-reports) +(ledger-dump-variable 'ledger-report-format-specifiers) +(ledger-dump-variable 'ledger-report-buffer-name) +(insert "ldg-state:") +(ledger-dump-variable 'ledger-clear-whole-transactions) +(insert "ldg-xact:\n") +(ledger-dump-variable 'ledger-highlight-xact-under-point) + + +) + + (provide 'ledger) ;;; ldg-new.el ends here + -- cgit v1.2.3 From aa10b6ea5d986a521478a595949afc3838855c63 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Fri, 22 Feb 2013 21:00:41 -0700 Subject: Cleanup dump variables --- lisp/ldg-new.el | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index 64945dfa..d3a4bd02 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -90,7 +90,6 @@ (forward-line 1)))))) (defun ledger-dump-variable (var) - (insert (format "%s: %S\n" (symbol-name var) (eval var)))) (defun ledger-mode-dump-variables () @@ -128,15 +127,12 @@ (ledger-dump-variable 'ledger-register-line-format) (insert "ldg-reports:\n") (ledger-dump-variable 'ledger-reports) -(ledger-dump-variable 'ledger-report-format-specifiers) -(ledger-dump-variable 'ledger-report-buffer-name) -(insert "ldg-state:") -(ledger-dump-variable 'ledger-clear-whole-transactions) -(insert "ldg-xact:\n") -(ledger-dump-variable 'ledger-highlight-xact-under-point) - - -) + (ledger-dump-variable 'ledger-report-format-specifiers) + (ledger-dump-variable 'ledger-report-buffer-name) + (insert "ldg-state:") + (ledger-dump-variable 'ledger-clear-whole-transactions) + (insert "ldg-xact:\n") + (ledger-dump-variable 'ledger-highlight-xact-under-point)) (provide 'ledger) -- cgit v1.2.3 From 929175216dc55544c8c5911902014c7727a95fd7 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Fri, 22 Feb 2013 21:07:11 -0700 Subject: Initial commit of ldg-auto. --- lisp/ldg-auto.el | 187 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 lisp/ldg-auto.el diff --git a/lisp/ldg-auto.el b/lisp/ldg-auto.el new file mode 100644 index 00000000..a582b914 --- /dev/null +++ b/lisp/ldg-auto.el @@ -0,0 +1,187 @@ +;;; ldg-auto.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2013 Craig Earls (enderw88 at gmail dot com) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: +;; +;; This module provides or automatically adding transactions to a +;; ledger buffer on a periodic basis. h Recurrence expressions are +;; inspired by Martin Fowler's "Recurring Events for Calendars", +;; martinfowler.com/apsupp/recurring.pdf + +;; use (fset 'VARNAME (macro args)) to put the macro definition in the +;; function slot of the symbol VARNAME. Then use VARNAME as the +;; function without have to use funcall. + +(defsubst between (val low high) + (and (>= val low) (<= val high))) + +(defun ledger-auto-days-in-month (month year) + "Return number of days in the MONTH, MONTH is form 1 to 12" + (if (between month 1 12) + (if (and (date-leap-year-p year) (= 2 month)) + 29 + (nth (1- month) '(31 28 31 30 31 30 31 31 30 31 30 31))) + (error "Month out of range, MONTH=%S" month))) + +;; Macros to handle date expressions + +(defmacro ledger-auto-day-in-month-macro (count day-of-week) + "Return a form that evaluates DATE that returns true for the COUNT DAY-OF-WEEK. +For example, return true if date is the 3rd Thursday of the +month. Negative COUNT starts from the end of the month. (EQ +COUNT 0) means EVERY day-of-week (eg. every Saturday)" + (if (and (between count -6 6) (between day-of-week 0 6)) + (cond ((zerop count) ;; Return true if day-of-week matches + `(eq (nth 6 (decode-time date)) ,day-of-week)) + ((> count 0) ;; Positive count + (let ((decoded (gensym))) + `(let ((,decoded (decode-time date))) + (if (and (eq (nth 6 ,decoded) ,day-of-week) + (between (nth 3 ,decoded) + ,(* (1- count) 7) + ,(* count 7))) + t + nil)))) + ((< count 0) + (let ((days-in-month (gensym)) + (decoded (gensym))) + `(let* ((,decoded (decode-time date)) + (,days-in-month (ledger-auto-days-in-month + (nth 4 ,decoded) + (nth 5 ,decoded)))) + (if (and (eq (nth 6 ,decoded) ,day-of-week) + (between (nth 3 ,decoded) + (+ ,days-in-month ,(* count 7)) + (+ ,days-in-month ,(* (1+ count) 7)))) + t + nil)))) + (t + (error "COUNT out of range, COUNT=%S" count))) + (error "Invalid argument to ledger-auto-day-in-month-macro %S %S" + count + day-of-week))) + +(defmacro ledger-auto-day-of-month-macro (day) + "Return a form of date that returns true for the DAY of the month. +For example, return true if date is the 23rd of the month." + `(if (eq (nth 3 (decode-time date)) ,day) + t)) + +(defmacro ledger-auto-month-of-year-macro (month) + "Return a form of date that returns true for the MONTH of the year. +For example, return true if date is the 4th month of the year." + `(if (eq (nth 4 (decode-time date)) ,month) + t)) + +(defmacro ledger-auto-every-count-day-macro (day-of-week skip start-date) + "Return a form that is true for every DAY skipping SKIP, starting on START. +For example every second Friday, regardless of month." + (let ((start-day (nth 6 (decode-time (eval start-date))))) + (if (eq start-day day-of-week) ;; good, can proceed + `(if (zerop (mod (- (time-to-days date) ,(time-to-days (eval start-date))) ,(* skip 7))) + t + nil) + (error "START-DATE day of week doesn't match DAY-OF-WEEK")))) + +(defmacro ledger-auto-date-range-macro (month1 day1 month2 day2) + "Return a form of DATE that is true if DATE falls between MONTH1 DAY1 and MONTH2 DAY2." + (let ((decoded (gensym)) + (target-month (gensym)) + (target-day (gensym))) + `(let* ((,decoded (decode-time date)) + (,target-month (nth 4 decoded)) + (,target-day (nth 3 decoded))) + (and (and (> ,target-month ,month1) + (< ,target-month ,month2)) + (and (> ,target-day ,day1) + (< ,target-day ,day2)))))) + +(defun ledger-auto-is-holiday (date) + "Return true if DATE is a holiday.") + +(defun ledger-auto-scan-transactions (auto-file) + (let ((xact-list (list))) + (save-excursion + (find-file auto-file) + (goto-char (point-min)) + (while (re-search-forward "^\\[\\(.*\\)\\] " nil t) + (let ((date-descriptor "") + (transaction nil) + (xact-start (match-end 0))) + (setq date-descriptors + (ledger-auto-read-descriptor-tree + (buffer-substring-no-properties + (match-beginning 0) + (match-end 0)))) + (forward-paragraph) + (setq transaction (list date-descriptors + (buffer-substring-no-properties + xact-start + (point)))) + (setq xact-list (cons transaction xact-list)))) + xact-list))) + +(defun ledger-auto-read-descriptor-tree (descriptor-string) + "Take a date descriptor string and return a function that +returns true if the date meets the requirements" + (with-temp-buffer + (let (pos) + (insert descriptor-string) + (goto-char (point-min)) + (replace-string "[" "(") + (goto-char (point-min)) + (replace-string "]" ")") + (goto-char (point-max)) + (while (re-search-backward + (concat "\\([0-9]+\\|[\*]\\)/" ;; Year slot + "\\([\*EO]\\|[0-9]+\\)/" ;; Month slot + "\\([\*]\\|\\([0-9][0-9]\\)\\|" + "\\([0-5]" + "\\(\\(Su\\)\\|" + "\\(Mo\\)\\|" + "\\(Tu\\)\\|" + "\\(We\\)\\|" + "\\(Th\\)\\|" + "\\(Fr\\)\\|" + "\\(Sa\\)\\)\\)\\)") nil t) ;; Day slot + (goto-char + (match-end 0)) + (insert ?\") + (goto-char (match-beginning 0)) + (insert "\"" ))) + (ledger-auto-traverse-descriptor-tree + (read (buffer-substring (point-min) (point-max))) 0))) + +(defun ledger-auto-traverse-descriptor-tree (tree depth) + (dolist (node tree) + (cond ((eq (type-of node) 'string) + (ledger-auto-parse-date-descriptor node)) + ((eq (type-of node) 'cons) + (ledger-auto-traverse-descriptor-tree node (1+ depth)))))) + + +(defun ledger-auto-parse-date-descriptor (descriptor) + "Parse the date descriptor, return the evaluator" + descriptor) + +(provide 'ldg-auto) + +;;; ldg-auto.el ends here -- cgit v1.2.3 From 47ae01357b8702df78a4dc15280d78302135b13e Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 23 Feb 2013 09:15:16 -0700 Subject: Initial commit of environment handling Reads and parses .ledgerc to an alist --- lisp/ldg-init.el | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 lisp/ldg-init.el diff --git a/lisp/ldg-init.el b/lisp/ldg-init.el new file mode 100644 index 00000000..646d91b2 --- /dev/null +++ b/lisp/ldg-init.el @@ -0,0 +1,62 @@ +;;; ldg-init.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + +;;; Commentary: +;; Determine the ledger environment + +(defvar init-file-name "~/.ledgerrc") +(defvar ledger-environment-alist nil) + +(defun ledger-init-parse-initialization (file) + (with-current-buffer file + (setq ledger-environment-alist nil) + (goto-char (point-min)) + (while (re-search-forward "^--.+?\\($\\|[ ]\\)" nil t ) + (let ((matchb (match-beginning 0)) ;; save the match data, string-match stomp on it + (matche (match-end 0))) + (end-of-line) + (setq ledger-environment-alist + (append ledger-environment-alist + (list (cons (let ((flag (buffer-substring (+ 2 matchb) matche))) + (if (string-match "[ \t\n\r]+\\'" flag) + (replace-match "" t t flag) + flag)) + (let ((value (buffer-substring matche (point) ))) + (if (> (length value) 0) + value + t)))))))) + ledger-environment-alist)) + +(defun ledger-init-load-init-file () + (interactive) + (save-excursion + (if (and (file-exists-p init-file-name) + (file-readable-p init-file-name)) + (progn + (find-file init-file-name) + (ledger-init-parse-initialization (file-name-nondirectory init-file-name)) + (kill-buffer (file-name-nondirectory init-file-name)))))) + + + +(provide 'ldg-init) + +;;; ldg-init.el ends here -- cgit v1.2.3 From 4cb2779464073aa8f1ba9d25121e3496fa71168f Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 23 Feb 2013 17:53:55 -0700 Subject: ledger-mode now automatically loads and parses the init file. Currently only pays attention to decimal-comma --- lisp/ldg-commodities.el | 3 +-- lisp/ldg-init.el | 29 ++++++++++++++++++----------- lisp/ldg-mode.el | 2 ++ lisp/ldg-new.el | 11 ++++++----- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 14cc168f..7f15ab81 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -36,7 +36,6 @@ This only has effect interfacing to calc mode in edit amount" :type 'boolean :group 'ledger) - (defun ledger-split-commodity-string (str) "Split a commoditized amount into two parts" (let (val @@ -85,7 +84,7 @@ DIRECTION can be :to-user or :from-user. All math calculations are done with decimal-period, some users may prefer decimal-comma which must be translated both directions." (let ((val number-string)) - (if ledger-use-decimal-comma + (if (assoc "decimal-comma" ledger-environment-alist) (cond ((eq direction :from-user) ;; change string to decimal-period (while (string-match "," val) diff --git a/lisp/ldg-init.el b/lisp/ldg-init.el index 646d91b2..ef69de3d 100644 --- a/lisp/ldg-init.el +++ b/lisp/ldg-init.el @@ -22,14 +22,17 @@ ;;; Commentary: ;; Determine the ledger environment -(defvar init-file-name "~/.ledgerrc") +(defcustom init-file-name "~/.ledgerrc" + "Location of the ledger initialization file. nil if you don't have one" + :group 'ledger) + (defvar ledger-environment-alist nil) (defun ledger-init-parse-initialization (file) - (with-current-buffer file - (setq ledger-environment-alist nil) - (goto-char (point-min)) - (while (re-search-forward "^--.+?\\($\\|[ ]\\)" nil t ) + (with-current-buffer file + (setq ledger-environment-alist nil) + (goto-char (point-min)) + (while (re-search-forward "^--.+?\\($\\|[ ]\\)" nil t ) (let ((matchb (match-beginning 0)) ;; save the match data, string-match stomp on it (matche (match-end 0))) (end-of-line) @@ -43,17 +46,21 @@ (if (> (length value) 0) value t)))))))) - ledger-environment-alist)) + ledger-environment-alist)) (defun ledger-init-load-init-file () (interactive) (save-excursion - (if (and (file-exists-p init-file-name) + (if (get-buffer (file-name-nondirectory init-file-name)) + (ledger-init-parse-initialization (file-name-nondirectory init-file-name)) + (if (and + init-file-name + (file-exists-p init-file-name) (file-readable-p init-file-name)) - (progn - (find-file init-file-name) - (ledger-init-parse-initialization (file-name-nondirectory init-file-name)) - (kill-buffer (file-name-nondirectory init-file-name)))))) + (let + (find-file-noselect init-file-name) + (ledger-init-parse-initialization (file-name-nondirectory init-file-name)) + (kill-buffer (file-name-nondirectory init-file-name))))))) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 01a1b615..96ce576b 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -76,6 +76,8 @@ (add-hook 'before-revert-hook 'ledger-remove-overlays nil t) (make-variable-buffer-local 'highlight-overlay) + (ledger-init-load-init-file) + (let ((map (current-local-map))) (define-key map [(control ?c) (control ?a)] 'ledger-add-transaction) (define-key map [(control ?c) (control ?b)] 'ledger-post-edit-amount) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index d3a4bd02..7a2961f7 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -32,22 +32,23 @@ ;;; Commentary: ;; Load up the ledger mode +(require 'esh-arg) +(require 'ldg-commodities) (require 'ldg-complete) (require 'ldg-exec) +(require 'ldg-fonts) +(require 'ldg-init) (require 'ldg-mode) +(require 'ldg-occur) (require 'ldg-post) (require 'ldg-reconcile) (require 'ldg-register) (require 'ldg-report) +(require 'ldg-sort) (require 'ldg-state) (require 'ldg-test) (require 'ldg-texi) (require 'ldg-xact) -(require 'ldg-sort) -(require 'ldg-fonts) -(require 'ldg-occur) -(require 'ldg-commodities) -(require 'esh-arg) ;;; Code: -- cgit v1.2.3 From 172a3076bc6d48d0739ddb362f31464eb1fdd931 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 23 Feb 2013 18:07:23 -0700 Subject: Updated README files --- README-1ST | 10 ++++++---- README.md | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README-1ST b/README-1ST index 87e41257..14b9fc6b 100644 --- a/README-1ST +++ b/README-1ST @@ -117,16 +117,18 @@ it's usually fairly obvious where things have gone astray. - Q: Something else fails, or Ledger crashes on startup - A: This, I am most interested in hearing about. Please e-mail me a copy of - config.log and your build log to <johnw@newartisans.com>. Also, if - Ledger is crashing, try running it under gdb like so: + A: This, I am most interested in hearing about. Please file a bug + at the Ledger Bugzilla, http://bugs.ledger-cli.org/. The more + details you can provide, the better. Also, if Ledger is crashing, + try running it under gdb like so: $ gdb ledger (gdb) run <ARGS TO LEDGER> ... runs till crash ... (gdb) bt - Send me that backtrace output, and the output from "ledger --version". + Put that backtrace output, and the output from "ledger + --version" in the bug report. ---------------------------------------------------------------------- diff --git a/README.md b/README.md index 5ab146e2..b81c81e7 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ few alternatives. I know, you just want to build and play. If you have all the dependencies installed (see below), then simply do this: - git clone git://github.com/jwiegley/ledger.git + git clone git://github.com/ledger/ledger.git cd ledger && ./acprep update # Update to the latest, configure, make Now try your first ledger command: -- cgit v1.2.3 From 7a561f6b2eca69eaf3f0a430a3af9788d299da1e Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 24 Feb 2013 08:20:28 -0700 Subject: Bug 907. --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index b81c81e7..45f9de90 100644 --- a/README.md +++ b/README.md @@ -153,8 +153,7 @@ Now that you're up and running, here are a few resources to keep in mind: - [Home page](http://ledger-cli.org) - [IRC channel](irc://irc.freenode.net/ledger) - [Mailing List / Forum](http://groups.google.com/group/ledger-cli) - - [GitHub project page](http://github.com/jwiegley/ledger) - - [Buildbot status](http://www.newartisans.com:9090) + - [GitHub project page](http://github.com/ledger/ledger) - [Ohloh code analysis](http://www.ohloh.net/projects/ledger) If you have ideas you'd like to share, the best way is either to e-mail me a -- cgit v1.2.3 From 94ce2f0fdb4a8ffe576cce0c8bdb2bc96e921cc9 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 25 Feb 2013 12:38:53 -0700 Subject: Fixed typo in doc/CMakeLists.txt line 58 "mesage" ==> "message" --- doc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 8ca83783..c2b1d96a 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -55,7 +55,7 @@ foreach(file ${info_files}) endif(BUILD_WEB_DOCS) if(NOT TEXI2PDF) - mesage(WARNING "Could not find texi2pdf. PDF version of documentation will not be built.") + message(WARNING "Could not find texi2pdf. PDF version of documentation will not be built.") else() add_custom_command(OUTPUT ${file_base}.pdf COMMAND texi2pdf -b -q -o ${file_base}.pdf ${CMAKE_CURRENT_SOURCE_DIR}/${file} -- cgit v1.2.3 From 260d05c8aeb43e73397fee83312c31e800206263 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 25 Feb 2013 13:19:51 -0700 Subject: Ledger-mode now automatically configures itself for --decimal-comma if that option is set in ~/.ledgerrc --- lisp/ldg-init.el | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lisp/ldg-init.el b/lisp/ldg-init.el index ef69de3d..fbb4b838 100644 --- a/lisp/ldg-init.el +++ b/lisp/ldg-init.el @@ -22,7 +22,7 @@ ;;; Commentary: ;; Determine the ledger environment -(defcustom init-file-name "~/.ledgerrc" +(defcustom ledger-init-file-name "~/.ledgerrc" "Location of the ledger initialization file. nil if you don't have one" :group 'ledger) @@ -50,17 +50,17 @@ (defun ledger-init-load-init-file () (interactive) - (save-excursion - (if (get-buffer (file-name-nondirectory init-file-name)) - (ledger-init-parse-initialization (file-name-nondirectory init-file-name)) - (if (and - init-file-name - (file-exists-p init-file-name) - (file-readable-p init-file-name)) - (let - (find-file-noselect init-file-name) - (ledger-init-parse-initialization (file-name-nondirectory init-file-name)) - (kill-buffer (file-name-nondirectory init-file-name))))))) + (let ((init-base-name (file-name-nondirectory ledger-init-file-name))) + (if (get-buffer init-base-name) ;; init file already loaded, parse it and leave it + (ledger-init-parse-initialization init-base-name) + (if (and ;; init file not loaded, load, parse and kill + ledger-init-file-name + (file-exists-p ledger-init-file-name) + (file-readable-p ledger-init-file-name)) + (progn + (find-file-noselect ledger-init-file-name) + (ledger-init-parse-initialization init-base-name) + (kill-buffer init-base-name)))))) -- cgit v1.2.3 From fe9153496a8cf494bc1962de1c43c43ed109d304 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 26 Feb 2013 08:11:36 -0700 Subject: Added a note to the introduction about paying attention to shell expansions --- doc/ledger3.texi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 44f305f2..ae67df19 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -304,6 +304,16 @@ If you would rather start with your own journal right away please see @ref{Keepi * Using the Windows command line:: @end menu +Please note that as a command line program, Ledger is controlled from +your shell. There are several different command shells that all behave +slightly differently with repsect to some special characters. In +particular, the BaSH shell will interpret \$ signs differently than +ledger and they must be escaped to reach the actual program. Another +example is zsh, which will interpret \^ differently than ledger expects. +In all cases that follow you should take that into account when entering +the commandline arguments given. There are too many variations between +shells to give concrete examples for each. + @node Balance Report, Register Report, Run Some Reports, Run Some Reports @subsection Balance Report @cindex balance report -- cgit v1.2.3 From 09f5e41d96949927c20d9ced2c9d37fa5a9e785a Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 26 Feb 2013 08:13:51 -0700 Subject: unescaped a few symbols --- doc/ledger3.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index ae67df19..dbc25d8f 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -307,9 +307,9 @@ If you would rather start with your own journal right away please see @ref{Keepi Please note that as a command line program, Ledger is controlled from your shell. There are several different command shells that all behave slightly differently with repsect to some special characters. In -particular, the BaSH shell will interpret \$ signs differently than +particular, the BaSH shell will interpret $ signs differently than ledger and they must be escaped to reach the actual program. Another -example is zsh, which will interpret \^ differently than ledger expects. +example is zsh, which will interpret ^ differently than ledger expects. In all cases that follow you should take that into account when entering the commandline arguments given. There are too many variations between shells to give concrete examples for each. -- cgit v1.2.3 From 821847b0185f3d69bfbe3af3867556335111b9a2 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 26 Feb 2013 10:42:30 -0700 Subject: Ensure that commodities using decimal period, have comma separators removed for string-to-number. --- lisp/ldg-commodities.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 7f15ab81..612350b3 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -94,7 +94,9 @@ which must be translated both directions." (while (string-match "\\." val) (setq val (replace-match "," nil nil val)))) ;; gets rid of periods (t - (error "ledger-commodity-string-number-decimalize: direction not properly specified %S" direction)))) + (error "ledger-commodity-string-number-decimalize: direction not properly specified %S" direction))) + (while (string-match "," val) + (setq val (replace-match "" nil nil val)))) val)) -- cgit v1.2.3 From 5e0e7e0a973f8a323decbf818e66a6af3ba218fd Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 26 Feb 2013 15:08:52 -0700 Subject: Add reconcile menu entry and correct bug in report that failed on automatically generated xacts --- lisp/ldg-mode.el | 2 ++ lisp/ldg-report.el | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 96ce576b..37c0f69e 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -128,6 +128,8 @@ (define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current)) (define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-entry)) (define-key map [sep4] '(menu-item "--")) + (define-key map [edit-amount] '(menu-item "Reconcile Account" ledger-reconcile)) + (define-key map [sep6] '(menu-item "--")) (define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount)) (define-key map [sep] '(menu-item "--")) (define-key map [delete-xact] '(menu-item "Delete Entry" ledger-delete-current-transaction)) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 944ae2e6..4db58494 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -319,16 +319,18 @@ Optional EDIT the command." (let ((file (match-string 1)) (line (string-to-number (match-string 2)))) (delete-region (match-beginning 0) (match-end 0)) - (set-text-properties (line-beginning-position) (line-end-position) - (list 'ledger-source (cons file (save-window-excursion - (save-excursion - (find-file file) - (widen) - (ledger-goto-line line) - (point-marker)))))) - (add-text-properties (line-beginning-position) (line-end-position) + (if file + (progn + (set-text-properties (line-beginning-position) (line-end-position) + (list 'ledger-source (cons file (save-window-excursion + (save-excursion + (find-file file) + (widen) + (ledger-goto-line line) + (point-marker)))))) + (add-text-properties (line-beginning-position) (line-end-position) (list 'face 'ledger-font-report-clickable-face)) - (end-of-line)))) + (end-of-line)))))) (goto-char data-pos))) -- cgit v1.2.3 From e5dd5344efca4851412eb21076b5715ffe99f212 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 26 Feb 2013 15:36:54 -0700 Subject: Initial commit of ledger-mode documentation and demo file --- doc/ledger-mode.texi | 587 +++++++++++++++++++++++++++++++++++++++++++++++++ test/input/demo.ledger | 63 ++++++ 2 files changed, 650 insertions(+) create mode 100644 doc/ledger-mode.texi create mode 100644 test/input/demo.ledger diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi new file mode 100644 index 00000000..0dc487a2 --- /dev/null +++ b/doc/ledger-mode.texi @@ -0,0 +1,587 @@ +\input texinfo @c -*-texinfo-*- +@setfilename ledger3.info +@settitle Ledger: Command-Line Accounting + +@dircategory Major Modes +@copying +Copyright (c) 2013, Craig Earls. 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 Mode +@subtitle Emacs Support For Version 3.0 of Ledger +@author Craig Earls +@end titlepage + +@direntry +* Ledger Mode: (ledger-mode). Command-Line Accounting +@end direntry + +@contents + +@ifnottex +@node Top, Copying, (dir), (dir) +@top Overview +Ledger is a command line accounting tool that provides double-entry +accounting based on a text journal. It provides no bells or whistles, +and returns the user to the days before user interfaces were even a +1twinkling in their father's CRT. + +Ledger Mode assists you in maintaining input files for Ledger, running +reports and much more... +@c @insertcopying +@end ifnottex + +@menu +* Copying:: +* Introduction to Ledger Mode:: +* The Ledger Buffer:: +* The Reconcile Buffer:: +* The Report Buffer:: +* Installing and Customizing Ledger-mode:: +* Hacking Ledger-mode:: +@end menu + +@node Copying, Introduction to Ledger Mode, Top, Top +@chapter Copying +@insertcopying + +@node Introduction to Ledger Mode, The Ledger Buffer, Copying, Top +@chapter Introduction to Ledger Mode +@menu +* Quick installation:: +* Menus:: +* Quick Demo:: +@end menu + +@node Quick installation, Menus, Introduction to Ledger Mode, Introduction to Ledger Mode +@section Quick Installation + +The emacs lisp source for Ledger-mode is included with the source +distribution of Ledger. It is entirely included in the @file{lisp} +subdirectory. To use ledger mode include the following in your emacs +initialization file (@file{~/.emacs}, @file{~/.emacs.d/init.el}, +@file{~/.Aquamacs/Preferences.el} + +@smallexample +(add-to-list 'load-path (expand-file-name "/path/to/ledger/source/lisp/")) +(load "ldg-new") +(add-to-list 'auto-mode-alist '("\\.ledger$" . ledger-mode)) +@end smallexample + +This sets up Emacs to automatically recognize files that end with +@file{.ledger} and start Ledger mode. Nothing else should be required +as long as the ledger command line utility is properly installed. + +@node Menus, Quick Demo, Quick installation, Introduction to Ledger Mode +@section Menus + +The vast majority of Ledger-mode functionality is available from the +Emacs menu system. The keystrokes are shown in the menu to help you +learn the faster keyboard methods. + +@node Quick Demo, , Menus, Introduction to Ledger Mode +@section Quick Demo + +Load the demo file @file{demo.ledger} from the Ledger source +@file{test/input} directory. The ledger will be loaded and font +highlighted. At this point you could manually edit transactions and run +Ledger from a convenient command line. + +@menu +* Quick Add:: +* Reconciliation:: +* Reports:: +* Folding:: +@end menu + +@node Quick Add, Reconciliation, Quick Demo, Quick Demo +@subsection Quick Add + +As simple as the ledger transaction format is, it can still be daunting +to add many transactions manually. Ledger provides two way to add +transactions with minimal typing. Both are based on the idea that most +tranactions are repretitions of earlier transactions. + +In the @file{demo.ledger} buffer enter a date using the correct +format. The tpye the first few characters of another payee in the +@file{demo.ledger} buffer. Type @code{C-c TAB}. Ledger-mode will +search for a Payee that has the same beginning and copy the rest of the +transaction to you new entry. + +Additionally you can ust the ledger xact command, by typing @code{C-c +C-a} then typing a close match to the payee. Ledger mode will call +@code{ledger xact} with the data you enter and place the transaction in +the proper chronological place in the ledger. + +@node Reconciliation, Reports, Quick Add, Quick Demo +@subsection Reconciliation + +The biggest task of maintaining a ledger is ensuring the it matches the +outside world. This process is called reconciliation (@xref{Basics of +Reconciliation}) and can be quite onerous. Ledger mode attempts to make +it as painless as possible. + +In the @file{demo.ledger} buffer type @code{C-c C-r}. Emacs will prompt +for an account to reconcile in the mini-buffer. Enter @code{Checking}. +Emacs will then prompt for a target value. The target value is the +amount you want the cleared transactions in the buffer to total. +Normally this would be the ending value from your bank statement, or the +latest value in your on-line transaction summary. Enter @code{1710}. +Note that Ledger-mode assumes your are using $ (USD) as your default +commodity, this can be easily changed in the customization +variables. @xref{Ledger-mode Customization} + +You now see a list of uncleared transactions in a buffer below the +@file{demo.ledger} buffer. Touching the space bar will mark a +transaction as pending and display the current cleared (and pending) +balance, along with the difference remaining to meet your target. Clear +the first three transactions, and you will see the difference to target +reach $0. End the reconcilitation by typing @code{C-c C-c}. This saves +the demo.ledger buffer and marks the transactions and finally cleared. +Type @code{q} to close out the reconciliation buffer. + +@node Reports, Folding, Reconciliation, Quick Demo +@subsection Reports + +The real power of Ledger is in it reporting capabilities. Reports can +be run and displayed in a spearate Emacs buffer. In the +@file{demo.ledger} buffer, type @code{C-c C-o C-r}. In the mini-buffer +Emacs will prompt for a report name. There are a few built-in reports, +and you can add any report you need @xref{Adding New Reports}. + +In the mini-buffer type @code{account}. When prompted for an account +type @code{checking}. In another buffer you will see a Ledger register +report. You can move around the buffer, with the point on a transaction, +type @code{C-c C-c}. Ledger mode will take you directly to that +transaction in the @file{demo.ledger} buffer. + +Another built-in report is the balance report. In the +@file{demo.ledger} buffer, type @code{C-c C-o C-r}. When prompted for a +report to run, type @code{bal}, and a balance report of all accounts +will be shown. + +@node Folding, , Reports, Quick Demo +@subsection Folding + +A ledger file can get very large. It can be helpful to collapse the buffer +to display only the transactions you are interested in. Ledger-mode +copies the @code{occur} mode functionality. Typing @code{C-c C-f} and +entering any regex in the mini-buffer will show only transactions that +match the regex. The regex can be on any field, or amount. + +@node The Ledger Buffer, The Reconcile Buffer, Introduction to Ledger Mode, Top +@chapter The Ledger Buffer +@menu +* Adding Transactions:: +* Editing Amounts:: +* Marking Transactions:: +* Deleting Transactions:: +* Sorting Transactions:: +* Hiding Transactions:: +@end menu + +@node Adding Transactions, Editing Amounts, The Ledger Buffer, The Ledger Buffer +@section Adding Transactions + +Beyond the two ways of quickly adding transactions (@pxref{Quick Add}) +Ledger-mode assists you by providing robust @code{TAB} completion for +payees and accounts. Ledger-mode will scan the existing buffer for +payees and accounts. Included files are not currently included in the +completion scan. Repeatedly hitting @code{TAB} will cycle through the +possible completions. + +@node Editing Amounts, Marking Transactions, Adding Transactions, The Ledger Buffer +@section Editing Amounts +GNU Calc is a very powerful Reverse Polish Notation calculator built +into all recent version of Emacs. Ledger-mode makes it easy to +calculate values for amount by integrating GNU Calc. With the point +anywhere in the same line as a posting, typing @code{C-c C-b} will +bring up the Calc buffer, and push the current amount for the posting +onto the top of the Calc stack. Perform any calculations you ened to +arrive at the final vlaue, then type @code{y} to ynk the value at the +top of stack back into the ledger buffer. Note: GNU Calc does not +directly support commas as decimal separators. Ledger mode will +translate values from decimal-comma format to decimal-period format for +use in Calc, but it cannot intercept the value being yanked form the +Calc stack, so decimal-comma users will have to manually replace the +period with a comma. + + +@node Marking Transactions, Deleting Transactions, Editing Amounts, The Ledger Buffer +@section Marking Transactions +Ledger considers transaction or posting to be in one of three states: +uncleared, cleared, and pending. For calculation Ledger ignores these +states unless specifically instructed to use them. Ledger-mode assigns +some additional meaning to the states: +@itemize +@item Uncleared. +No state. This is equivalent to sticking a check in the mail. It has +been obligated, but not been cashed by the recipient. It could also +apply to credit/debit card transactions that have not been cleared into +your account balance. You bank may call these transactions 'pending', +but Ledger-mode usues a slightly different meaning. +@item Pending. +Ledger-mode's reconciliation function see pending transactions as an +intermediate step in reconciling an account. When doing a +reconciliation (@pxref{Reconciliation}), marking a transaction as +pending means that you have seen the transaction finally recorded by the +recipient, but you have not completely reconciled the account. +@item Cleared. +The transaction has been completely recognized by all parties to the transaction. +@end itemize + +Clearing complete transactions is done by typing @code{C-c C-e} with +point in a transaction. This places an asterisk (@code{*}) after the +date. Clearing individual postings is done by typing @code{C-c C-c} +while in a posting. This places an asterisk prior to the posting. + +@node Deleting Transactions, Sorting Transactions, Marking Transactions, The Ledger Buffer +@section Deleting Transactions +Along with normal buffer editing methods to delete text, Ledger mode +provides an easy way to delete the transaction under point: @code{C-c +C-d}. The advantage to using this method is that the complete +transaction operation is in the undo buffer. + +@node Sorting Transactions, Hiding Transactions, Deleting Transactions, The Ledger Buffer +@section Sorting Transactions + +As you operating on the Ledger files, they may become disorganized. For +the most part, Ledger doesn't care, but our human brains prefer a bit of +order. Sorting the transactions in a buffer into chronological order +can help bring order to chaos. Ledger sort (@code C-c C-s) will sort +all of the transactions in a region by date. Ledger-mode isn't +particularly smart about handling dates and it simply sorts the +transactions using the string at the beginning of the transaction. So, +you should use the preferred ISO 8601 standard date format @code{YYYY/MM/DD} +which easily sorts. + +Note, there is a menu entry to sort the entire buffer. Special +transactions like automated transactsion, will be moved in the sorting +process and may not fucntion correctly afterwards. For this reason +there is no key sequence. + +@node Hiding Transactions, , Sorting Transactions, The Ledger Buffer +@section Hiding Transactions + +Ofen times you will want to run Ledger register reports just to look at +a specific set of transactions. If you don't need the running total +calculation hadnled by Ledger, Ledger-mode provides a rapid way of +narrowing what is displayed in the buffer in a way that is sipler than +the Ledger register command. + +Based on the Emacs Occur mode by Alexey Veretennikov, Ledger-occur hides +all transactions that do NOT meet a specific regular expression. The +regular expression can match on any part of the transaction. If you +want to find all transactions whose amount ends in .37, you can do that +( I don't know why, but hey, whatever ever flaots you aerostat). + +Using @code(C-c C-f) or the @code{Hide Xacts} menu entry, enter a +regualr expression in the minbuffer. Ledger-mode will hide all oter +transactions. For details of the regualr expression syntax, see the +Emacs Manual or the Emac Elisp Reference Manual. A few examples using +the @file{demo.ledger} are given here: + +@table @samp +@item Groceries +Show only transactions that have a posting to the `Groceries' account. +@item ^2011/01 +Show only transactions occuring in January of 2011. +@item ^2011/.*/25 +Show only transactions occuring on the 25th of the month in 2011 +@item .*ore +Show only transaction with payeees or accounts ending in `ore' +@end table + +To show all transactions simply invoke @code{Hide Xacts} or @code{C-c +C-f} again. + +@node The Reconcile Buffer, The Report Buffer, The Ledger Buffer, Top +@chapter The Reconcile Buffer +@menu +* Basics of Reconciliation:: +* Starting a Reconciliation:: +* Mark Transactions Pending:: +* Edit Transactions During Reconciliation:: +* Finialize Reconciliation:: +* Adding and Deleting Transactions during Reconciliation:: +* Changing Reconciliation Account:: +* Changing Reconciliation Target:: +@end menu + +@node Basics of Reconciliation, Starting a Reconciliation, The Reconcile Buffer, The Reconcile Buffer +@section Basics of Reconciliation + +Even in this relativley modern era, financial transactions do not happen +instantaneously, unless you are paying cash. When you swipe your debit +card the money may take several days to actually come out of your +account, or a check may take several days to ``clear''. That is the +root of the difference between ``obligating'' funds and ``expending'' +funds. Obligation says you have agreed to pay it, the expnediture +doesn't happen until the money actually leaves your account. Or in the +case of receiving payment, you have an account receivable until the +money has actually made it to you. + +After an account has been reconciled you have verified that all the +transactions in that account have been correctly recorded and all +parties agree. + +@node Starting a Reconciliation, Mark Transactions Pending, Basics of Reconciliation, The Reconcile Buffer +@section Starting a Reconciliation + +To start reconciling an account you must have a target, both the +transactions that you know about and the transactions the bank knows +about. You can get this from a monthly statement, or from checking your +online transaction history. It also helps immensely to know the final +cleared balance you are aiming for. + +Use menu @code{Reconcile Account} or @code{C-c C-r} and enter the +account you wish to reconcile in the mini-buffer. Ledger-mode is not +particular about what you enter for the account. You can leave it blank +and Reconcile Mode will show you ALL uncleared transactions. After you +enter the account enter the target amount. Ledger expects you to enter +an amount with a commodity. It assumes initially that you are using $ +(USD) as your default commodity. If you are working in a difference +currency you can change the default in variable +@code(ledger-reconcile-default-commodity) to whatever you need. If you +work in multiple commodities simply enter the commoditized amount (for +example @code{340 VSDX}, for 340 shares of VSDX). + +Ledger-mode reconcile cannot currently reconcile accounts the have +multiple commodities, such as brokerage accounts. You may use +reconciliation mode to clear transactions, but balance calculations will +not display the complete list of commodities. + +@node Mark Transactions Pending, Edit Transactions During Reconciliation, Starting a Reconciliation, The Reconcile Buffer +@section Mark Transactions Pending + +The @file{*Reconcile*} buffer will show all the uncleared transactions +that meeting the criteria set in the regex. By default uncleared +transactions are shown in red. When you have verified that a +transaction ahs been correctly and compeltely recorded by the opposing +party, mark the transaction as pending using the space bar. Continue +this process until you agree with the opposing party and the difference +from your target is zero. + +@node Edit Transactions During Reconciliation, Finialize Reconciliation, Mark Transactions Pending, The Reconcile Buffer +@section Edit Transactions during Reconciliation + +If you find errors during reconciliation. You can visit the transaction +under point in the @file{*Reconcile*} buffer by hitting the @code{enter} +key. This will take you to the transaction in the Ledger buffer. When +you have finished editing the transaction saving the buffer will +automatically return you to the @file{*Reconcile*} buffer and you can +mark the transaction if appropriate. + +@node Finialize Reconciliation, Adding and Deleting Transactions during Reconciliation, Edit Transactions During Reconciliation, The Reconcile Buffer +@section Finalize Reconciliation + +Once you have marked all transactions as pending and the cleared balance +is correct. Finish the reconciliation by typing @code{C-c C-c}. This +marks all pending transaction as cleared and saves the ledger buffer. + +@node Adding and Deleting Transactions during Reconciliation, Changing Reconciliation Account, Finialize Reconciliation, The Reconcile Buffer +@section Adding and Deleting Transactions during Reconciliation + +While reconciling, you may find new transactions that need to be entered +into your ledger. Simply type @code{a} to bring up the quick add for +the ledger buffer. + +Typing @code{d} will delete the transaction under point in the +@file{*Reconcile*} buffer form the ledger buffer. + +@node Changing Reconciliation Account, Changing Reconciliation Target, Adding and Deleting Transactions during Reconciliation, The Reconcile Buffer +@section Changing Reconciliation Account + +You can conveniently switch the account being reconciled by typing +@code{g}, and entering a new account to reconcile. This simply restarts +teh reconcile process. Any transactions that were marked `pending' in +the ledger buffer are left in that state when the account is switched. + +@node Changing Reconciliation Target, , Changing Reconciliation Account, The Reconcile Buffer +@section Changing Reconciliation Target + +If for some reason during reconciliation your target amount changes, +type @code{t} and enter the new target value. + + +@node The Report Buffer, Installing and Customizing Ledger-mode, The Reconcile Buffer, Top +@chapter The Report Buffer +@menu +* Running Basic Reports:: +* Adding and Editing Reports:: +* Reversing Report Order:: +@end menu + +@node Running Basic Reports, Adding and Editing Reports, The Report Buffer, The Report Buffer +@section Running Reports +The real popwer behing Ledger is in its amazing reporting capability. +Ledger-mode provides easy facility to run reports directly from emacs. +It has four reports built-in and facilities for adding custom reports. + +Typeing @code{C-c C-o C-r} or using menu @code{Ledger Run Report} prompt +for the name of a saved report. The built-in reports are: +@table @samp +@item bal +Produce a balance reports of all accounts. +@item reg +Produce a register report of all transactions. +@item payee +Prompt for a payee, the produce a register report of all transaction +involving that payee. +@item account +Prompt for an account, the produce a register report of all transaction +involving that account. +@end table + + +@node Adding and Editing Reports, Reversing Report Order, Running Basic Reports, The Report Buffer +@section Adding and Editing Reports +@menu +* Expansion Formats:: +* Make Report Transactions Active:: +@end menu + +If you type a report name that Ledger-mode doesn't recognize it will +prompt you for a ledger command line to run. That command is +automatically saved with the name given and you can re-run it at any +time. + +There are two ways to edit the command line for a report. The first is +to privide a prefix argument to the run-report command. For example, +type @code{M-1 C-c C-o C-r}. This will prompt you for the report name, +then present the report command line to be edited. When you hit enter, +the report will be run, but it will not be permanently saved. If you +want to save it, type @code{S} in the the @file{*Ledger Report*} buffer you +will have the option to give it a new name, or overwrite the old report. + +Deleting reports is accomplished by type @code{C-c C-o C-e} Edit Reports +in the ledger buffer, or typing @code{E} in the @file{*Ledger Report*} +buffer. This takes you to the emacs customization window for the +@code{ledger-reports} variable. Use the widgets to delete the report +you want removed. + +@node Expansion Formats, Make Report Transactions Active, Adding and Editing Reports, Adding and Editing Reports +@subsection Expansion Formats + +It is sometime convenient to leave room to customize a report without +saving the command line every time. For example running a register +report for a specific account, enter at runtime by the user. The +built-in report @file{account} does exactly that, using a variable +expansion to prompt the user for the account to use. There are four +variable that can be expanded to run a report: + +@table @samp +@item ledger-file +Returns the file to be operated on. +@item payee +Prompts for a payee. +@item account +Prompt for an account. +@item value +Prompt for a tag value. +@end table + +You can use these expansion values in your ledger report commands. For +example, if you wanted to specify a register report the displayed +trnasactions from a user-determined account with a particular meta-data +tag value, you specify the following command line: +@smallexample +ledger -f %(ledger-file) reg %(account) --limit \"tag('my-tag') =~ +/%(value)/\" +@end smallexample + +@noindent Note how the double-quotes are escaped with back-slashes. + +@node Make Report Transactions Active, , Expansion Formats, Adding and Editing Reports +@subsection Make Report Transactions Active + +In a large register report it is convenient to be anle to jump to the +source transaction. Ledger-mode will automatically include source +information in every register file that doesn't contain a +@code{--subtotal} option. It does this by adding a +@code{--prepend-format='%(filename):%(beg_line):'} to the register +report command-line you specify. You should never have to see this, but +if there is an error in your ledger output this additional information +may not get stripped out of the visible report. + +@node Reversing Report Order, , Adding and Editing Reports, The Report Buffer +@section Reversing Report Order + +Often, banks show their online transaction historyies with the most recent +transaction at the top. Ledger itself cannot do a sensible ledger +report in reverse chronoligcal order, if you sort on reverse date the +calculation will also run in the opposite direction. If you want to +compare a ledger register report to a bank report with the most recent +transactions at the top, type R in the @file{*Ledger Report*} buffer and +it will reverse the order of the transactions and maintain the proper +mathematical sense. + + +@node Installing and Customizing Ledger-mode, Hacking Ledger-mode, The Report Buffer, Top +@chapter Installing and Customizing Ledger-mode +@menu +* Emacs Initialization File:: +* Ledger-mode Customization:: +* Customization Variables:: +* Ledger-mode Faces:: +@end menu + +@node Emacs Initialization File, Ledger-mode Customization, Installing and Customizing Ledger-mode, Installing and Customizing Ledger-mode +@section Emacs Initialization File + +@node Ledger-mode Customization, Ledger-mode Faces, Emacs Initialization File, Installing and Customizing Ledger-mode +@section Ledger-mode Customization +@node Customization Variables, , Ledger-mode Customization, Installing and Customizing Ledger-mode +@section Customization Variables +@node Ledger-mode Faces, , Customization Variables, Installing and Customizing Ledger-mode +@section Ledger-mode Faces +@menu +* Using EMACS customization menus:: +* Complete list of customization variables:: +@end menu + +@node Using EMACS customization menus, Complete list of customization variables, Ledger-mode Faces, Ledger-mode Faces +@subsection Using EMACS customization menus + +@node Complete list of customization variables, , Using EMACS customization menus, Ledger-mode Faces +@subsection Complete list of customization variables + +@node Hacking Ledger-mode, , Installing and Customizing Ledger-mode, Top +@chapter Hacking Ledger-mode + +@bye diff --git a/test/input/demo.ledger b/test/input/demo.ledger new file mode 100644 index 00000000..dbf47c2a --- /dev/null +++ b/test/input/demo.ledger @@ -0,0 +1,63 @@ +2010/12/01 * Checking balance + Assets:Checking $1,000.00 + Equity:Opening Balances + +2010/12/20 * Organic Co-op + Expenses:Food:Groceries $ 37.50 ; [=2011/01/01] + Expenses:Food:Groceries $ 37.50 ; [=2011/02/01] + Expenses:Food:Groceries $ 37.50 ; [=2011/03/01] + Expenses:Food:Groceries $ 37.50 ; [=2011/04/01] + Expenses:Food:Groceries $ 37.50 ; [=2011/05/01] + Expenses:Food:Groceries $ 37.50 ; [=2011/06/01] + Assets:Checking $ -225.00 + +2010/12/28 Acme Mortgage + Liabilities:Mortgage:Principal $ 200.00 + Expenses:Interest:Mortgage $ 500.00 + Expenses:Escrow $ 300.00 + * Assets:Checking $ -1000.00 + +2011/01/02 Grocery Store + Expenses:Food:Groceries $ 65.00 + * Assets:Checking + +2011/01/05 Employer + * Assets:Checking $ 2000.00 + Income:Salary + +2011/01/14 Bank + ; Regular monthly savings transfer + Assets:Savings $ 300.00 + Assets:Checking + +2011/01/19 Grocery Store + Expenses:Food:Groceries $ 44.00 ; hastag: not block + Assets:Checking + +2011/01/25 Bank + ; Transfer to cover car purchase + Assets:Checking $ 5,500.00 + Assets:Savings + ; :nobudget: + +2011/01/25 Tom's Used Cars + Expenses:Auto $ 5,500.00 + ; :nobudget: + Assets:Checking + +2011/01/27 Book Store + Expenses:Books $20.00 + Liabilities:MasterCard + +2011/04/25 Tom's Used Cars + Expenses:Auto $ 5,500.00 + ; :nobudget: + Assets:Checking + +2011/04/27 Bookstore + Expenses:Books $20.00 + Assets:Checking + +2011/12/01 Sale + Assets:Checking $ 30.00 + Income:Sales -- cgit v1.2.3 From 54f50a7690368aaa6d3fd2bd685484b1552aefcd Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 27 Feb 2013 10:06:22 -0700 Subject: Fix typo in ledger3.texi --- doc/ledger3.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index dbc25d8f..8a78b2f0 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -1559,7 +1559,7 @@ whose market value disregards any future changes in the price of gasoline. If you do not want price fixing, you can specify this same transaction -in one of two ways, both equivalent (note the lack of the equal sing +in one of two ways, both equivalent (note the lack of the equal sign from the transaction above): @smallexample -- cgit v1.2.3 From 1e3c795935dc5c938b78fc367ee19e1a259b0fb3 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 27 Feb 2013 10:07:03 -0700 Subject: Update date regex to handles dashes and slashes --- lisp/ldg-commodities.el | 1 + lisp/ldg-regex.el | 2 ++ lisp/ldg-xact.el | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 612350b3..6f835221 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -36,6 +36,7 @@ This only has effect interfacing to calc mode in edit amount" :type 'boolean :group 'ledger) + (defun ledger-split-commodity-string (str) "Split a commoditized amount into two parts" (let (val diff --git a/lisp/ldg-regex.el b/lisp/ldg-regex.el index 680063f7..e81394ef 100644 --- a/lisp/ldg-regex.el +++ b/lisp/ldg-regex.el @@ -24,6 +24,8 @@ (eval-when-compile (require 'cl)) +(defvar ledger-date-regex "\\([0-9]+\\)[/-]\\([0-9]+\\)[/-]\\([0-9]+\\)") + (defmacro ledger-define-regexp (name regex docs &rest args) "Simplify the creation of a Ledger regex and helper functions." (let ((defs diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index f5a38ef6..8db50df2 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -106,7 +106,7 @@ within the transaction." (extents (ledger-find-xact-extents (point))) (transaction (buffer-substring (car extents) (cadr extents))) encoded-date) - (if (string-match "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)" date) + (if (string-match ledger-date-regex date) (setq encoded-date (encode-time 0 0 0 (string-to-number (match-string 3 date)) (string-to-number (match-string 2 date)) @@ -114,7 +114,7 @@ within the transaction." (ledger-find-slot encoded-date) (insert transaction "\n") (backward-paragraph) - (re-search-forward "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)") + (re-search-forward ledger-date-regex) (replace-match date) (re-search-forward "[1-9][0-9]+\.[0-9]+"))) -- cgit v1.2.3 From 42911df9f5f25914d2be7f48f294ab2fccc06248 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 27 Feb 2013 17:27:52 -0700 Subject: Restructured customization groups. Completed initial draft of ledger-mode documentation --- doc/ledger-mode.texi | 195 ++++++++++++++++++++++++++++++++++++++++++------ lisp/ldg-commodities.el | 8 +- lisp/ldg-exec.el | 2 +- lisp/ldg-init.el | 2 +- lisp/ldg-occur.el | 2 +- lisp/ldg-post.el | 26 +++---- lisp/ldg-reconcile.el | 16 ++-- lisp/ldg-report.el | 9 ++- lisp/ldg-test.el | 14 ++-- lisp/ldg-texi.el | 26 +++++-- 10 files changed, 232 insertions(+), 68 deletions(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index 0dc487a2..9b2c1262 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -72,7 +72,9 @@ reports and much more... * The Ledger Buffer:: * The Reconcile Buffer:: * The Report Buffer:: -* Installing and Customizing Ledger-mode:: +* Customizing Ledger-mode:: +* Generating Ledger Regression Tests:: +* Embedding Example results in Ledger Documentation:: * Hacking Ledger-mode:: @end menu @@ -83,12 +85,12 @@ reports and much more... @node Introduction to Ledger Mode, The Ledger Buffer, Copying, Top @chapter Introduction to Ledger Mode @menu -* Quick installation:: +* Quick Installation:: * Menus:: * Quick Demo:: @end menu -@node Quick installation, Menus, Introduction to Ledger Mode, Introduction to Ledger Mode +@node Quick Installation, Menus, Introduction to Ledger Mode, Introduction to Ledger Mode @section Quick Installation The emacs lisp source for Ledger-mode is included with the source @@ -107,7 +109,7 @@ This sets up Emacs to automatically recognize files that end with @file{.ledger} and start Ledger mode. Nothing else should be required as long as the ledger command line utility is properly installed. -@node Menus, Quick Demo, Quick installation, Introduction to Ledger Mode +@node Menus, Quick Demo, Quick Installation, Introduction to Ledger Mode @section Menus The vast majority of Ledger-mode functionality is available from the @@ -225,6 +227,12 @@ payees and accounts. Included files are not currently included in the completion scan. Repeatedly hitting @code{TAB} will cycle through the possible completions. +Ledger mode can also help you keep your amounts in alignment. Setting +@code{ledger-post-auto-adjust-amounts} to true tells Ledger-mode to +automatically place any amounts such that their last digit is aligned to +the column specified by @code{ledger-post-amount-alignment-column}, +which defautls to 52. @xref{Ledger Post Customization Group} + @node Editing Amounts, Marking Transactions, Adding Transactions, The Ledger Buffer @section Editing Amounts GNU Calc is a very powerful Reverse Polish Notation calculator built @@ -439,7 +447,7 @@ If for some reason during reconciliation your target amount changes, type @code{t} and enter the new target value. -@node The Report Buffer, Installing and Customizing Ledger-mode, The Reconcile Buffer, Top +@node The Report Buffer, Customizing Ledger-mode, The Reconcile Buffer, Top @chapter The Report Buffer @menu * Running Basic Reports:: @@ -552,36 +560,177 @@ it will reverse the order of the transactions and maintain the proper mathematical sense. -@node Installing and Customizing Ledger-mode, Hacking Ledger-mode, The Report Buffer, Top -@chapter Installing and Customizing Ledger-mode +@node Customizing Ledger-mode, Generating Ledger Regression Tests, The Report Buffer, Top +@chapter Customizing Ledger-mode @menu -* Emacs Initialization File:: * Ledger-mode Customization:: * Customization Variables:: -* Ledger-mode Faces:: @end menu -@node Emacs Initialization File, Ledger-mode Customization, Installing and Customizing Ledger-mode, Installing and Customizing Ledger-mode -@section Emacs Initialization File - -@node Ledger-mode Customization, Ledger-mode Faces, Emacs Initialization File, Installing and Customizing Ledger-mode +@node Ledger-mode Customization, Customization Variables, Customizing Ledger-mode, Customizing Ledger-mode @section Ledger-mode Customization -@node Customization Variables, , Ledger-mode Customization, Installing and Customizing Ledger-mode + +Ledger-mode has several options available for configuration. All +options can be configure through the Emacs customization menus, or +specified in your Emacs initialization file. The complete list of +options is show below. To change the option using the Emacs +customization menu, simply choe customize in the Options menu and look +for Ledger under the data options. Alternately you can choose +``Customize Specific Group'' and enger ``Ledger'' as the group. + +@node Customization Variables, , Ledger-mode Customization, Customizing Ledger-mode @section Customization Variables -@node Ledger-mode Faces, , Customization Variables, Installing and Customizing Ledger-mode -@section Ledger-mode Faces + @menu -* Using EMACS customization menus:: -* Complete list of customization variables:: +* Ledger Customization Group:: +* Ledger Reconcile Customization Group:: +* Ledger Report Customization Group:: +* Ledger Faces Customization Group:: +* Ledger Post Customization Group:: +* Ledger Exec Customization Group:: +* Ledger Test Customization Group:: +* Ledger Texi Customization Group:: @end menu -@node Using EMACS customization menus, Complete list of customization variables, Ledger-mode Faces, Ledger-mode Faces -@subsection Using EMACS customization menus +@node Ledger Customization Group, Ledger Reconcile Customization Group, Customization Variables, Customization Variables +@subsection Ledger Customization Group +@table @code +@item ledger-default-acct-transaction-indent + Default indentation for account transactions in an entry. +@item ledger-occur-use-face-unfolded + If non-nil use a custom face for xacts shown in `ledger-occur' mode using @code{ledger-occur-xact-face}. +@item ledger-clear-whole-transactions + If non-nil, clear whole transactions, not individual postings. +@item ledger-highlight-xact-under-point + If non-nil highlight xact under point using @code{ledger-font-highlight-face}. +@end table + +@node Ledger Reconcile Customization Group, Ledger Report Customization Group, Ledger Customization Group, Customization Variables +@subsection Ledger Reconcile Customization Group + +@table @code +@item ledger-reconcile-default-commodity +The default commodity for use in target calculations in ledger +reconcile. Defaults to $ (USD) +@item ledger-recon-buffer-name + Name to use for reconciliation window. +@item ledger-fold-on-reconcile + If non-nil, limit transactions shown in main buffer to those matching the + reconcile regex. +@item ledger-buffer-tracks-reconcile-buffer + If non-nil, then when the cursor is moved to a new xact in the recon + window. +@item ledger-reconcile-force-window-bottom + If non-nil, make the reconcile window appear along the bottom of the + register window and resize. +@item ledger-reconcile-toggle-to-pending + If non-nil, then toggle between uncleared and pending (@code{!}). If false + toggle between unlceared and cleared (@code{*}) +@end table + +@node Ledger Report Customization Group, Ledger Faces Customization Group, Ledger Reconcile Customization Group, Customization Variables +@subsection Ledger Report Customization Group + +@table @code +@item ledger-reports + Definition of reports to run. +@item ledger-report-format-specifiers + An alist mapping ledger report format specifiers to implementing functions. +@end table + + +@node Ledger Faces Customization Group, Ledger Post Customization Group, Ledger Report Customization Group, Customization Variables +@subsection Ledger Faces Customization Group +Ledger Faces : Ledger mode highlighting +@table @code +@item ledger-font-uncleared-face +Default face for Ledger +@item ledger-font-cleared-face +Default face for cleared (*) transactions +@item ledger-font-highlight-face +Default face for transaction under point +@item ledger-font-pending-face +Default face for pending (!) transactions +@item ledger-font-other-face +Default face for other transactions +@item ledger-font-posting-account-face +Face for Ledger accounts +@item ledger-font-posting-amount-face +Face for Ledger amounts +@item ledger-occur-folded-face +Default face for Ledger occur mode hidden transactions +@item ledger-occur-xact-face +Default face for Ledger occur mode shown transactions +@item ledger-font-comment-face +Face for Ledger comments +@item ledger-font-reconciler-uncleared-face +Default face for uncleared transactions in the reconcile window +@item ledger-font-reconciler-cleared-face +Default face for cleared (*) transactions in the reconcile window +@item ledger-font-reconciler-pending-face +Default face for pending (!) transactions in the reconcile window +@item ledger-font-report-clickable-face +Default face for pending (!) transactions in the reconcile window +@end table + +@node Ledger Post Customization Group, Ledger Exec Customization Group, Ledger Faces Customization Group, Customization Variables +@subsection Ledger Post Customization Group +Ledger Post : +@table @code +@item ledger-post-auto-adjust-amounts +If non-nil, then automatically align amounts to column specified in +@code{ledger-post-amount-alignment-column} +@item ledger-post-amount-alignment-column +The column Ledger-mode uses to align amounts +@item ledger-post-use-completion-engine +Which completion engine to use, iswitchb, ido, or built-in +@item ledger-post-use-ido +@end table + +@node Ledger Exec Customization Group, Ledger Test Customization Group, Ledger Post Customization Group, Customization Variables +@subsection Ledger Exec Customization Group + +Ledger Exec : Interface to the Ledger command-line accounting program. + +@table @code +@item ledger-binary-path +Path to the ledger executable. +@item ledger-init-file-name +Location of the ledger initialization file. nil if you don't have one +@end table + + +@node Ledger Test Customization Group, Ledger Texi Customization Group, Ledger Exec Customization Group, Customization Variables +@subsection Ledger Test Customization Group +@table @code +@item ledger-source-directory + Directory where the Ledger sources are located. +@item ledger-test-binary + Directory where the debug binary. +@end table + +@node Ledger Texi Customization Group, , Ledger Test Customization Group, Customization Variables +@subsection Ledger Texi Customization Group + +@table @code +@item ledger-texi-sample-doc-path +Location for sample data to be used in texi tests, defaults to @file{~/ledger/doc/sample.dat} +@item ledger-texi-normalization-args +texi normalization for producing ledger output, defaults to ``@code{--args-only --columns 80}'' +@end table + +@node Generating Ledger Regression Tests, Embedding Example results in Ledger Documentation, Customizing Ledger-mode, Top +@chapter Generating Ledger Regression Tests + +Work in Progress. + +@node Embedding Example results in Ledger Documentation, Hacking Ledger-mode, Generating Ledger Regression Tests, Top +@chapter Embedding Example results in Ledger Documentation -@node Complete list of customization variables, , Using EMACS customization menus, Ledger-mode Faces -@subsection Complete list of customization variables +Work in Progress. -@node Hacking Ledger-mode, , Installing and Customizing Ledger-mode, Top +@node Hacking Ledger-mode, , Embedding Example results in Ledger Documentation, Top @chapter Hacking Ledger-mode +Work in Progress. @bye diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 6f835221..c5500785 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -29,13 +29,7 @@ (defcustom ledger-reconcile-default-commodity "$" "The default commodity for use in target calculations in ledger reconcile." :type 'string - :group 'ledger) - -(defcustom ledger-use-decimal-comma nil - "If non-nil the use commas as decimal separator. -This only has effect interfacing to calc mode in edit amount" - :type 'boolean - :group 'ledger) + :group 'ledger-reconcile) (defun ledger-split-commodity-string (str) "Split a commoditized amount into two parts" diff --git a/lisp/ldg-exec.el b/lisp/ldg-exec.el index af5dd3a8..d62fd419 100644 --- a/lisp/ldg-exec.el +++ b/lisp/ldg-exec.el @@ -38,7 +38,7 @@ (defcustom ledger-binary-path "ledger" "Path to the ledger executable." :type 'file - :group 'ledger) + :group 'ledger-exec) (defun ledger-exec-ledger (input-buffer &optional output-buffer &rest args) "Run Ledger using INPUT-BUFFER and optionally capturing output in OUTPUT-BUFFER with ARGS." diff --git a/lisp/ldg-init.el b/lisp/ldg-init.el index fbb4b838..72317088 100644 --- a/lisp/ldg-init.el +++ b/lisp/ldg-init.el @@ -24,7 +24,7 @@ (defcustom ledger-init-file-name "~/.ledgerrc" "Location of the ledger initialization file. nil if you don't have one" - :group 'ledger) + :group 'ledger-exec) (defvar ledger-environment-alist nil) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index c3f04c5d..1561d6f8 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -35,7 +35,7 @@ (defconst ledger-occur-overlay-property-name 'ledger-occur-custom-buffer-grep) (defcustom ledger-occur-use-face-unfolded t - "If non-nil use a custom face for xacts shown in `ledger-occur' mode." + "If non-nil, use a custom face for xacts shown in `ledger-occur' mode using ledger-occur-xact-face." :type 'boolean :group 'ledger) (make-variable-buffer-local 'ledger-occur-use-face-unfolded) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 14c3c55f..de28a8a9 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -28,7 +28,7 @@ ;;; Code: (defgroup ledger-post nil - "" + "Options for controlling how Ledger-mode deals with postings and completion" :group 'ledger) (defcustom ledger-post-auto-adjust-amounts nil @@ -37,19 +37,17 @@ :group 'ledger-post) (defcustom ledger-post-amount-alignment-column 52 - "If non-nil, ." + "The column Ledger-mode attempts to align amounts to." :type 'integer :group 'ledger-post) -(defcustom ledger-post-use-iswitchb nil - "If non-nil, ." - :type 'boolean - :group 'ledger-post) - -(defcustom ledger-post-use-ido nil - "If non-nil, ." - :type 'boolean - :group 'ledger-post) +(defcustom ledger-post-use-completion-engine :built-in + "Which completion engine to use, :iswitchb or :ido chose those engines, +:built-in uses built-in Ledger-mode completion" + :type '(radio (const :tag "built in completion" :built-in) + (const :tag "ido completion" :ido) + (const :tag "iswitchb completion" :iswitchb) ) + :group 'ledger-post) (defun ledger-post-all-accounts () "Return a list of all accounts in the buffer." @@ -73,13 +71,13 @@ PROMPT is a string to prompt with. CHOICES is a list of strings to choose from." (cond - (ledger-post-use-iswitchb + ((eq ledger-post-use-completion-engine :iswitchb) (let* ((iswitchb-use-virtual-buffers nil) (iswitchb-make-buflist-hook (lambda () (setq iswitchb-temp-buflist choices)))) (iswitchb-read-buffer prompt))) - (ledger-post-use-ido + ((eq ledger-post-use-completion-engine :ido) (ido-completing-read prompt choices)) (t (completing-read prompt choices)))) @@ -114,7 +112,7 @@ PROMPT is a string to prompt with. CHOICES is a list of (defun ledger-next-amount (&optional end) "Move point to the next amount, as long as it is not past END." - (when (re-search-forward "\\( \\|\t\\| \t\\)[ \t]*-?\\([A-Z$€£]+ *\\)?\\(-?[0-9,]+?\\)\\(.[0-9]+\\)?\\( *[A-Z$€£]+\\)?\\([ \t]*@@?[^\n;]+?\\)?\\([ \t]+;.+?\\)?$" (marker-position end) t) + (when (re-search-forward "\\( \\|\t\\| \t\\)[ \t]*-?\\([A-Z$€£]+ *\\)?\\(-?[0-9,]+?\\)\\(.[0-9]+\\)?\\( *[A-Z$€£]+\\)?\\([ \t]*@@?[^\n;]+?\\)?\\([ \t]+;.+?\\|[ \t]*\\)?$" (marker-position end) t) (goto-char (match-beginning 0)) (skip-syntax-forward " ") (- (or (match-end 4) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 6a9d05fd..6093f9df 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -23,7 +23,7 @@ ;;; Commentary: -;; +;; Code to handle reconciling Ledger files wiht outside sources ;;; Code: @@ -32,31 +32,35 @@ (defvar ledger-acct nil) (defvar ledger-target nil) +(defgroup ledger-reconcile nil + "Options for Ledger-mode reconciliation" + :group 'ledger) + (defcustom ledger-recon-buffer-name "*Reconcile*" "Name to use for reconciliation window." - :group 'ledger) + :group 'ledger-reconcile) (defcustom ledger-fold-on-reconcile t "If t, limit transactions shown in main buffer to those matching the reconcile regex." :type 'boolean - :group 'ledger) + :group 'ledger-reconcile) (defcustom ledger-buffer-tracks-reconcile-buffer t "If t, then when the cursor is moved to a new xact in the recon window. Then that transaction will be shown in its source buffer." :type 'boolean - :group 'ledger) + :group 'ledger-reconcile) (defcustom ledger-reconcile-force-window-bottom nil "If t make the reconcile window appear along the bottom of the register window and resize." :type 'boolean - :group 'ledger) + :group 'ledger-reconcile) (defcustom ledger-reconcile-toggle-to-pending t "If true then toggle between uncleared and pending. reconcile-finish will mark all pending posting cleared." :type 'boolean - :group 'ledger) + :group 'ledger-reconcile) (defun ledger-reconcile-get-balances () diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 4db58494..0aa91ac0 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -28,6 +28,11 @@ (eval-when-compile (require 'cl)) +(defgroup ledger-report nil + "Customization option for the Report buffer" + :group 'ledger +) + (defcustom ledger-reports '(("bal" "ledger -f %(ledger-file) bal") ("reg" "ledger -f %(ledger-file) reg") @@ -46,7 +51,7 @@ in that variable for more information on the behavior of each specifier." :type '(repeat (list (string :tag "Report Name") (string :tag "Command Line"))) - :group 'ledger) + :group 'ledger-report) (defcustom ledger-report-format-specifiers '(("ledger-file" . ledger-report-ledger-file-format-specifier) @@ -58,7 +63,7 @@ specifier." The function is called with no parameters and expected to return the text that should replace the format specifier." :type 'alist - :group 'ledger) + :group 'ledger-report) (defvar ledger-report-buffer-name "*Ledger Report*") diff --git a/lisp/ldg-test.el b/lisp/ldg-test.el index 7667a05e..dbba9546 100644 --- a/lisp/ldg-test.el +++ b/lisp/ldg-test.el @@ -19,15 +19,19 @@ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. -(defcustom ledger-source-directory "~/src/ledger" - "Directory where the Ledger sources are located." - :type 'directory +(defgroup ledger-test nil + "Definitions for the Ledger testing framework" :group 'ledger) -(defcustom ledger-test-binary "~/Products/ledger/debug/ledger" +(defcustom ledger-source-directory "~/ledger/" "Directory where the Ledger sources are located." + :type 'directory + :group 'ledger-test) + +(defcustom ledger-test-binary "/Products/ledger/debug/ledger" + "Directory where the Ledger debug binary is located." :type 'file - :group 'ledger) + :group 'ledger-test) (defun ledger-test-org-narrow-to-entry () (outline-back-to-heading) diff --git a/lisp/ldg-texi.el b/lisp/ldg-texi.el index 53e050ce..84ba34c2 100644 --- a/lisp/ldg-texi.el +++ b/lisp/ldg-texi.el @@ -19,9 +19,19 @@ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. -(defvar ledger-path "/Users/johnw/bin/ledger") -(defvar ledger-sample-doc-path "/Users/johnw/src/ledger/doc/sample.dat") -(defvar ledger-normalization-args "--args-only --columns 80") +(defgroup ledger-texi nil +"Options for working on Ledger texi documentation" +:group 'ledger) + +(defcustom ledger-texi-sample-doc-path "~/ledger/doc/sample.dat" +"Location for sample data to be used in texi tests" +:type 'file +:group 'ledger-texi) + +(defcustom ledger-texi-normalization-args "--args-only --columns 80" +"texi normalization for producing ledger output" +:type 'string +:group 'ledger-texi) (defun ledger-update-test () (interactive) @@ -92,10 +102,10 @@ (defun ledger-texi-expand-command (command data-file) (if (string-match "\\$LEDGER" command) - (replace-match (format "%s -f \"%s\" %s" ledger-path - data-file ledger-normalization-args) t t command) - (concat (format "%s -f \"%s\" %s " ledger-path - data-file ledger-normalization-args) command))) + (replace-match (format "%s -f \"%s\" %s" ledger-binary-path + data-file ledger-texi-normalization-args) t t command) + (concat (format "%s -f \"%s\" %s " ledger-binary-path + data-file ledger-texi-normalization-args) command))) (defun ledger-texi-invoke-command (command) (with-temp-buffer (shell-command command t (current-buffer)) @@ -122,7 +132,7 @@ (let ((section (match-string 1)) (example-name (match-string 2)) (command (match-string 3)) expanded-command - (data-file ledger-sample-doc-path) + (data-file ledger-texi-sample-doc-path) input output) (goto-char (match-end 0)) (forward-line) -- cgit v1.2.3 From 69dd94b6cce86739b9a6fc6890434cb5b47ea6d9 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 27 Feb 2013 17:29:41 -0700 Subject: Removed use-decimal-comma custom, since we are now reading the .ledgerrc file --- lisp/ldg-commodities.el | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 6f835221..004d4f56 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -31,12 +31,6 @@ :type 'string :group 'ledger) -(defcustom ledger-use-decimal-comma nil - "If non-nil the use commas as decimal separator. -This only has effect interfacing to calc mode in edit amount" - :type 'boolean - :group 'ledger) - (defun ledger-split-commodity-string (str) "Split a commoditized amount into two parts" (let (val -- cgit v1.2.3 From b5548661dcb69ed6c1e1723e52284978835fa1a1 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 27 Feb 2013 17:51:03 -0700 Subject: Fixed data regexs so that dashes are properly handled in dates --- lisp/ldg-state.el | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index beecb591..b2247afe 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -44,7 +44,7 @@ (save-excursion (when (or (looking-at "^[0-9]") (re-search-backward "^[0-9]" nil t)) - (skip-chars-forward "0-9./=") + (skip-chars-forward "0-9./=\\-") (skip-syntax-forward " ") (cond ((looking-at "!\\s-*") 'pending) ((looking-at "\\*\\s-*") 'cleared) @@ -97,7 +97,7 @@ dropped." (save-excursion ;; this excursion checks state of entire ;; transaction and unclears if marked (goto-char (car bounds)) ;; beginning of xact - (skip-chars-forward "0-9./= \t") ;; skip the date + (skip-chars-forward "0-9./=\\- \t") ;; skip the date (setq cur-status (and (member (char-after) '(?\* ?\!)) (ledger-state-from-char (char-after)))) ;;if cur-status if !, or * then delete the marker @@ -193,7 +193,7 @@ dropped." (insert (make-string width ? )))))) (forward-line)) (goto-char (car bounds)) - (skip-chars-forward "0-9./= \t") + (skip-chars-forward "0-9./=\\- \t") (insert (ledger-char-from-state state) " ") (setq new-status state) (if (re-search-forward "\\(\t\\| [ \t]\\)" @@ -233,7 +233,7 @@ dropped." (save-excursion (when (or (looking-at "^[0-9]") (re-search-backward "^[0-9]" nil t)) - (skip-chars-forward "0-9./=") + (skip-chars-forward "0-9./=\\-") (delete-horizontal-space) (if (or (eq (ledger-state-from-char (char-after)) 'pending) (eq (ledger-state-from-char (char-after)) 'cleared)) -- cgit v1.2.3 From d8acba2c3f340f643619e9087141748e28e345b1 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 27 Feb 2013 19:21:19 -0700 Subject: Add ledger-mode.texi to the build list --- doc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index c2b1d96a..12f96444 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -32,7 +32,7 @@ if(NOT BUILD_DOCS) return() endif() -set(info_files ledger.texi ledger3.texi) +set(info_files ledger.texi ledger3.texi ledger-mode.texi) find_program(MAKEINFO makeinfo) find_program(TEXI2PDF texi2pdf) -- cgit v1.2.3 From 20c00bc3af7148f088d1c6d1222c5ce559877bf5 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 27 Feb 2013 21:17:47 -0700 Subject: Removed EMACS section from Ledger3 --- doc/ledger3.texi | 311 +------------------------------------------------------ 1 file changed, 1 insertion(+), 310 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 8a78b2f0..0939918c 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -1252,7 +1252,6 @@ posting. * Journal Format:: * Converting from other formats:: * Archiving Previous Years :: -* Using EMACS:: @end menu @node Most Basic Entry, Starting up, Keeping a Journal, Keeping a Journal @@ -2260,7 +2259,7 @@ easily be parsed into Ledger format using one of those tools. Some of the more function. -@node Archiving Previous Years , Using EMACS, Converting from other formats, Keeping a Journal +@node Archiving Previous Years , , Converting from other formats, Keeping a Journal @section Archiving Previous Years @@ -2319,314 +2318,6 @@ any electronic statements received during the year. In the arena of organization, just keep in mind this maxim: Do whatever keeps you doing it. -@node Using EMACS, , Archiving Previous Years , Keeping a Journal -@section Using EMACS to Maintain Your Journal -@cindex EMACS - -@menu -* Running ledger-mode:: -* Working with entries:: -* Reconciling accounts:: -* Generating Reports:: -@end menu - -@node Running ledger-mode, Working with entries, Using EMACS, Using EMACS -@subsection Running ledger-mode in EMACS - -Journal files are simple free text files easily modified by any text -editor. A special mode for EMACS is included with the source -distribution. This mode provides syntax highlighting, a reconcile mode -and a report mode. This makes it quote possible to use ledger without -ever leaving EMACS. - -@cindex EMACS .emacs file - -Add the following line to your @file{.emacs} (or equivalent, -@file{~/Aquamacs/Preferences.el} for Aquamacs on Mac OS X) -@smallexample -(load "ldg-new") -@end smallexample - -Copy the several lisp files (@file{ldg-*.el}) from the source lisp directory your your -@file{site-lisp} directory, or add the ledger lisp source directory to -your EMACS load path by adding: -@smallexample -(add-to-list 'load-path "~/ledger/lisp") -@end smallexample -@noindent to your @file{.emacs} file. - -To trigger ledger mode when you visit a journal file, the first line of -each of your journal files should be: -@smallexample -; -*-ledger-*- -@end smallexample -To enter ledger-mode on a new file, type @command{M-x ledger-mode}. - -Once you have loaded a Journal file into EMACS, you have several -commands available to make entering, clearing and reconciling -transactions and producing reports (these are also available from the -menu if you can't remember the key combinations): - -@cindex EMACS commands -@table @code -@item C-i or <TAB> -auto complete entry -@item C-c C-a -add a new entry, based on previous entries -@item C-c C-e -toggle cleared status of an entire entry -@item C-c C-c -toggle cleared status of an individual posting -@item C-c C-f -toggle folding mode. When on shows only transactions that meet a given REGEX -@item C-c C-y -set default year for entry mode -@item C-c C-m -set default month for entry mode -@item C-c C-r -reconcile uncleared entries related to an account -@item C-c C-d -delete the current entry -@item C-c C-s -sort all entries in the region. -@item C-c C-o C-r -run a ledger report -@item C-C C-o C-g -go to the ledger report buffer -@item C-c C-o C-e -edit the defined ledger reports -@item C-c C-o C-s -save a report definition based on the current report -@item C-c C-o C-a -rerun a ledger report -@item C-c C-o C-k -kill the ledger report buffer -@end table - -@menu -* Working with entries:: -* Reconciling accounts:: -* Generating Reports:: -@end menu - -@node Working with entries, Reconciling accounts, Running ledger-mode, Using EMACS -@subsection Working with entries -@menu -* Manual Entry Support:: -* Hiding Transactions:: -* Automagically Adding new entries:: -* Clearing Transactions:: -* Calculating Values with EMACS Calc:: -@end menu - -@node Manual Entry Support, Hiding Transactions, Working with entries, Working with entries -@subsubsection Manual Entry Support - -@cindex <TAB> completion -@cindex auto-completion -@cindex misspelled accounts treated as new - -In most financial programs, some sort of auto-completion is available to -save typing and improve accuracy. Ledger doesn't leave you hanging, -@code{ledger-mode} provides tab completion on all portions of an entry. -Type a portion of the payee and hit @code{<TAB>}, and @code{ledger-mode} will -suggest a completion. When filling in the account type the first few -letters followed by a @code{<TAB>} and the account will be filled in. For -example typing @code{Ex<TAB>Au<TAB>F<TAB>} would yield -@code{Expenses:Auto:Fuel} if you had previously used that account in -this journal. If there are more than one account with similar starting, -hitting @code{<TAB>} multiple times will iterate through them. This is a good -habit to get in to prevent misspellings of accounts. Remember Ledger -does not validate the names of payees or account so a misspelled account -will be interpreted as a new account by ledger. - -@node Hiding Transactions, Automagically Adding new entries, Manual Entry Support, Working with entries -@subsubsection Hiding Transactions - -There are several ways to organize Ledger data files. You can use a -master file and @code{include} one file for each real bank or brokerage -account, separate files for major expense categories, a mix of those -ideas, or throw every transaction in to one giant file. The biggest -drawback to uing one file is that it can get confusing finding specific -transactions in the file. - -Ledger mode has a special transaction hiding mode that you can use to -hide all transactions except those that meet a regular expression you -provide. By default this command is bound to @code{C-c C-f}. EMACS -will ask for a regular expression, which at its simplest is just text -you want to match. For example, lets say you want to review the -transactions in your checking account named @code{"Assets:Checking"}. -Type @code{C-c C-f}, then type @code{Checking} in the minibuffer. EMACS -will hide all other transactions and highlight the remaining -transactions. You can edit them without fear that your other -transaction have had anything done, they are only hidden from view. - -The color used to highlight the xaction can be customized in the EMACS -customization menu. It is called @code{ledger-occur-xact-face}, and can -be changed to alter any charactistic of a font that you want. If you -don't want any highlighting, simply set -@code{ledger-occur-use-face-unfolded} to @code{nil} in the customization -menu. - -To clear the highlighting and show all transactions, type @code{C-c C-f} -again. - -@node Automagically Adding new entries, Clearing Transactions, Hiding Transactions, Working with entries -@subsubsection Automagically Adding new entries -@cindex new transactions in EMACS -@cindex EMACS, adding new transactions -@code{C-c C-a} will run the @code{ledger entry} command (@pxref{entry -and xact}) from within EMACS. When typed, the mini-buffer will appear -with the current year and month, waiting for you to enter the day and -the payee, and optionally, a commoditized amount. Ledger will generate -a new entry based on the most recent entry for that payee, using the -amount and accounts from that transaction. If you have a new amount -simply type the amount after the payee. For example, if your journal -contains an entry -@smallexample -2011/11/25 Viva Italiano - Expenses:Food $12.45 - Expenses:Tips $2.55 - Liabilities:MasterCard $-15.00 -@end smallexample -@noindent and you type @code{C-c C-a}, the mini-buffer will appear showing the -current year and month. If you complete the mini-buffer entry by typing -@smallexample -Entry: 2011/11/28 viva food 34 tip 7 <enter> -@end smallexample -@noindent EMACS will add the following entry to your journal: -@smallexample -2011/11/30 Viva Italiano - Expenses:Food $34.00 - Expenses:Tips $7.00 - Liabilities:MasterCard -@end smallexample -@noindent Notice that the entry will appear at the correct place in the journal -ordered by date, not at the bottom of the file. If you need to include -spaces in the payee name, then surrond the name of the payee with double -quotes, otherwise ledger will interpret the second part of the name as -an account. -@node Clearing Transactions, Calculating Values with EMACS Calc, Automagically Adding new entries, Working with entries -@subsubsection Clearing Transactions and Postings -@cindex clearing transactions in EMACS -@cindex EMACS, clear transaction -@code{C-c C-e} will place an asterisk after the date in the current -transaction. The tells ledger the transaction has been cleared through -your bank (or whatever else you want the concept to mean) -@smallexample -2011/11/25 Viva Italiano - Expenses:Food $12.45 - Expenses:Tips $2.55 - Liabilities:MasterCard $-15.00 -@end smallexample -@noindent becomes -@smallexample -2011/11/25 * Viva Italiano - Expenses:Food $12.45 - Expenses:Tips $2.55 - Liabilities:MasterCard $-15.00 -@end smallexample - -If, for some reason you need to clear a specific posting in the -transaction you can type @code{C-c C-c} and the posting at point will be -toggled. - -@node Calculating Values with EMACS Calc, , Clearing Transactions, Working with entries -@subsubsection Calculating Values with EMACS Calc - -EMACS come with a very powerful calculator built in. You can use it to -easily insert calculated amounts directly into your ledger buffer. From -the menu, select @code{Calc on Amount}. Calc will pull the current -amount to the top of the calc stack. Calulate the value as you normally -would with an RPN calculator. When you have the desired value on thetop -of the calc stack, press @code{y}, and calc will insert the value -in place of the previous amount. - - -@node Reconciling accounts, Generating Reports, Working with entries, Using EMACS -@subsection Reconciling accounts - -Enter the reconcile mode using the menu entry, or @code{C-c C-r}. Emacs -will prompt you for an account name, then display a second buffer with -all of the uncleared transactions. The reconcile buffer has several functions: - -@table @code - @item SPACE - toggles the cleared status of a transaction, and shows pending balance in the mini-buffer - @item RETURN - moves the cursor to that transaction in the ledger. - @item C-x C-s - to save changes (to the ledger file as well). - @item q - quit the reconcile mode - @item n p - next line or previous line - @item A - add entry - @item D - delete entry - @item t - change target reconciliation amount - @item g - reconcile new account - @item b - show cleared balance in mini-buffer - @item C-l - refresh display -@end table - -By default the reconcile mode uses transaction hiding to show only -transaction eligible for your reconcile. The reconcile widow itself will -only show a summary of uncleared transaction while the main buffer will -show all transaction meeting the regex, cleared or not. This behavior -can be disabled by setting @code{ledger-fold-on-reconcile} to nil in the -emacs customization menus. - -When you reconcile an account you nromally know the final balance you -are aiming at. When you enter the reconciliation mode ledger will ask -for a target balance. Enter the amount you are aiming for (the default -commodity can be chaged in the customization window). Each time you -toggle a posting to pending, ledger will calculate the new balance of -the account and display the new balance and the difference to make the -target. - -@node Generating Reports, , Reconciling accounts, Using EMACS -@subsection Generating Reports - -The ledger reports command asks the user to select a report to run then -creates a report buffer containing the results of running the associated -command line. This allows you to run frequently used reports without -retyping the command line, or writing shell scripts for simple one line -commands. - -To generate a report, select the @code{Run Reports} menu, or type -@code{C-c C-o C-r}. EMACS will prompt for a report name. If it -recognizes the name it will run the report again. If it is a new name, -or blank it will respond by giving you an example command line to edit. -Hitting return willrun the report and present it in a new buffer. - -If you have given it a new name, then @code{s} will save the report for -future use. - - -In a report buffer, the following keys are available: -@table @code -@item (space) -scroll up -@item e -edit the defined ledger reports -@item s -save a report definition based on the current report -@item q -quit the report (return to ledger buffer) -@item r -redo the report -@item k -kill the report buffer -@end table - - - @node Transactions , Building Reports, Keeping a Journal, Top @chapter Transactions -- cgit v1.2.3 From 917c11021390d2b53e8bf8ed1bb4f0d24abdcdda Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 27 Feb 2013 21:21:39 -0700 Subject: Removed EMACS section from Ledger3.texi --- doc/ledger3.texi | 312 +------------------------------------------------------ 1 file changed, 1 insertion(+), 311 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 8a78b2f0..3382ab33 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -1252,7 +1252,6 @@ posting. * Journal Format:: * Converting from other formats:: * Archiving Previous Years :: -* Using EMACS:: @end menu @node Most Basic Entry, Starting up, Keeping a Journal, Keeping a Journal @@ -2260,7 +2259,7 @@ easily be parsed into Ledger format using one of those tools. Some of the more function. -@node Archiving Previous Years , Using EMACS, Converting from other formats, Keeping a Journal +@node Archiving Previous Years , , Converting from other formats, Keeping a Journal @section Archiving Previous Years @@ -2319,315 +2318,6 @@ any electronic statements received during the year. In the arena of organization, just keep in mind this maxim: Do whatever keeps you doing it. -@node Using EMACS, , Archiving Previous Years , Keeping a Journal -@section Using EMACS to Maintain Your Journal -@cindex EMACS - -@menu -* Running ledger-mode:: -* Working with entries:: -* Reconciling accounts:: -* Generating Reports:: -@end menu - -@node Running ledger-mode, Working with entries, Using EMACS, Using EMACS -@subsection Running ledger-mode in EMACS - -Journal files are simple free text files easily modified by any text -editor. A special mode for EMACS is included with the source -distribution. This mode provides syntax highlighting, a reconcile mode -and a report mode. This makes it quote possible to use ledger without -ever leaving EMACS. - -@cindex EMACS .emacs file - -Add the following line to your @file{.emacs} (or equivalent, -@file{~/Aquamacs/Preferences.el} for Aquamacs on Mac OS X) -@smallexample -(load "ldg-new") -@end smallexample - -Copy the several lisp files (@file{ldg-*.el}) from the source lisp directory your your -@file{site-lisp} directory, or add the ledger lisp source directory to -your EMACS load path by adding: -@smallexample -(add-to-list 'load-path "~/ledger/lisp") -@end smallexample -@noindent to your @file{.emacs} file. - -To trigger ledger mode when you visit a journal file, the first line of -each of your journal files should be: -@smallexample -; -*-ledger-*- -@end smallexample -To enter ledger-mode on a new file, type @command{M-x ledger-mode}. - -Once you have loaded a Journal file into EMACS, you have several -commands available to make entering, clearing and reconciling -transactions and producing reports (these are also available from the -menu if you can't remember the key combinations): - -@cindex EMACS commands -@table @code -@item C-i or <TAB> -auto complete entry -@item C-c C-a -add a new entry, based on previous entries -@item C-c C-e -toggle cleared status of an entire entry -@item C-c C-c -toggle cleared status of an individual posting -@item C-c C-f -toggle folding mode. When on shows only transactions that meet a given REGEX -@item C-c C-y -set default year for entry mode -@item C-c C-m -set default month for entry mode -@item C-c C-r -reconcile uncleared entries related to an account -@item C-c C-d -delete the current entry -@item C-c C-s -sort all entries in the region. -@item C-c C-o C-r -run a ledger report -@item C-C C-o C-g -go to the ledger report buffer -@item C-c C-o C-e -edit the defined ledger reports -@item C-c C-o C-s -save a report definition based on the current report -@item C-c C-o C-a -rerun a ledger report -@item C-c C-o C-k -kill the ledger report buffer -@end table - -@menu -* Working with entries:: -* Reconciling accounts:: -* Generating Reports:: -@end menu - -@node Working with entries, Reconciling accounts, Running ledger-mode, Using EMACS -@subsection Working with entries -@menu -* Manual Entry Support:: -* Hiding Transactions:: -* Automagically Adding new entries:: -* Clearing Transactions:: -* Calculating Values with EMACS Calc:: -@end menu - -@node Manual Entry Support, Hiding Transactions, Working with entries, Working with entries -@subsubsection Manual Entry Support - -@cindex <TAB> completion -@cindex auto-completion -@cindex misspelled accounts treated as new - -In most financial programs, some sort of auto-completion is available to -save typing and improve accuracy. Ledger doesn't leave you hanging, -@code{ledger-mode} provides tab completion on all portions of an entry. -Type a portion of the payee and hit @code{<TAB>}, and @code{ledger-mode} will -suggest a completion. When filling in the account type the first few -letters followed by a @code{<TAB>} and the account will be filled in. For -example typing @code{Ex<TAB>Au<TAB>F<TAB>} would yield -@code{Expenses:Auto:Fuel} if you had previously used that account in -this journal. If there are more than one account with similar starting, -hitting @code{<TAB>} multiple times will iterate through them. This is a good -habit to get in to prevent misspellings of accounts. Remember Ledger -does not validate the names of payees or account so a misspelled account -will be interpreted as a new account by ledger. - -@node Hiding Transactions, Automagically Adding new entries, Manual Entry Support, Working with entries -@subsubsection Hiding Transactions - -There are several ways to organize Ledger data files. You can use a -master file and @code{include} one file for each real bank or brokerage -account, separate files for major expense categories, a mix of those -ideas, or throw every transaction in to one giant file. The biggest -drawback to uing one file is that it can get confusing finding specific -transactions in the file. - -Ledger mode has a special transaction hiding mode that you can use to -hide all transactions except those that meet a regular expression you -provide. By default this command is bound to @code{C-c C-f}. EMACS -will ask for a regular expression, which at its simplest is just text -you want to match. For example, lets say you want to review the -transactions in your checking account named @code{"Assets:Checking"}. -Type @code{C-c C-f}, then type @code{Checking} in the minibuffer. EMACS -will hide all other transactions and highlight the remaining -transactions. You can edit them without fear that your other -transaction have had anything done, they are only hidden from view. - -The color used to highlight the xaction can be customized in the EMACS -customization menu. It is called @code{ledger-occur-xact-face}, and can -be changed to alter any charactistic of a font that you want. If you -don't want any highlighting, simply set -@code{ledger-occur-use-face-unfolded} to @code{nil} in the customization -menu. - -To clear the highlighting and show all transactions, type @code{C-c C-f} -again. - -@node Automagically Adding new entries, Clearing Transactions, Hiding Transactions, Working with entries -@subsubsection Automagically Adding new entries -@cindex new transactions in EMACS -@cindex EMACS, adding new transactions -@code{C-c C-a} will run the @code{ledger entry} command (@pxref{entry -and xact}) from within EMACS. When typed, the mini-buffer will appear -with the current year and month, waiting for you to enter the day and -the payee, and optionally, a commoditized amount. Ledger will generate -a new entry based on the most recent entry for that payee, using the -amount and accounts from that transaction. If you have a new amount -simply type the amount after the payee. For example, if your journal -contains an entry -@smallexample -2011/11/25 Viva Italiano - Expenses:Food $12.45 - Expenses:Tips $2.55 - Liabilities:MasterCard $-15.00 -@end smallexample -@noindent and you type @code{C-c C-a}, the mini-buffer will appear showing the -current year and month. If you complete the mini-buffer entry by typing -@smallexample -Entry: 2011/11/28 viva food 34 tip 7 <enter> -@end smallexample -@noindent EMACS will add the following entry to your journal: -@smallexample -2011/11/30 Viva Italiano - Expenses:Food $34.00 - Expenses:Tips $7.00 - Liabilities:MasterCard -@end smallexample -@noindent Notice that the entry will appear at the correct place in the journal -ordered by date, not at the bottom of the file. If you need to include -spaces in the payee name, then surrond the name of the payee with double -quotes, otherwise ledger will interpret the second part of the name as -an account. -@node Clearing Transactions, Calculating Values with EMACS Calc, Automagically Adding new entries, Working with entries -@subsubsection Clearing Transactions and Postings -@cindex clearing transactions in EMACS -@cindex EMACS, clear transaction -@code{C-c C-e} will place an asterisk after the date in the current -transaction. The tells ledger the transaction has been cleared through -your bank (or whatever else you want the concept to mean) -@smallexample -2011/11/25 Viva Italiano - Expenses:Food $12.45 - Expenses:Tips $2.55 - Liabilities:MasterCard $-15.00 -@end smallexample -@noindent becomes -@smallexample -2011/11/25 * Viva Italiano - Expenses:Food $12.45 - Expenses:Tips $2.55 - Liabilities:MasterCard $-15.00 -@end smallexample - -If, for some reason you need to clear a specific posting in the -transaction you can type @code{C-c C-c} and the posting at point will be -toggled. - -@node Calculating Values with EMACS Calc, , Clearing Transactions, Working with entries -@subsubsection Calculating Values with EMACS Calc - -EMACS come with a very powerful calculator built in. You can use it to -easily insert calculated amounts directly into your ledger buffer. From -the menu, select @code{Calc on Amount}. Calc will pull the current -amount to the top of the calc stack. Calulate the value as you normally -would with an RPN calculator. When you have the desired value on thetop -of the calc stack, press @code{y}, and calc will insert the value -in place of the previous amount. - - -@node Reconciling accounts, Generating Reports, Working with entries, Using EMACS -@subsection Reconciling accounts - -Enter the reconcile mode using the menu entry, or @code{C-c C-r}. Emacs -will prompt you for an account name, then display a second buffer with -all of the uncleared transactions. The reconcile buffer has several functions: - -@table @code - @item SPACE - toggles the cleared status of a transaction, and shows pending balance in the mini-buffer - @item RETURN - moves the cursor to that transaction in the ledger. - @item C-x C-s - to save changes (to the ledger file as well). - @item q - quit the reconcile mode - @item n p - next line or previous line - @item A - add entry - @item D - delete entry - @item t - change target reconciliation amount - @item g - reconcile new account - @item b - show cleared balance in mini-buffer - @item C-l - refresh display -@end table - -By default the reconcile mode uses transaction hiding to show only -transaction eligible for your reconcile. The reconcile widow itself will -only show a summary of uncleared transaction while the main buffer will -show all transaction meeting the regex, cleared or not. This behavior -can be disabled by setting @code{ledger-fold-on-reconcile} to nil in the -emacs customization menus. - -When you reconcile an account you nromally know the final balance you -are aiming at. When you enter the reconciliation mode ledger will ask -for a target balance. Enter the amount you are aiming for (the default -commodity can be chaged in the customization window). Each time you -toggle a posting to pending, ledger will calculate the new balance of -the account and display the new balance and the difference to make the -target. - -@node Generating Reports, , Reconciling accounts, Using EMACS -@subsection Generating Reports - -The ledger reports command asks the user to select a report to run then -creates a report buffer containing the results of running the associated -command line. This allows you to run frequently used reports without -retyping the command line, or writing shell scripts for simple one line -commands. - -To generate a report, select the @code{Run Reports} menu, or type -@code{C-c C-o C-r}. EMACS will prompt for a report name. If it -recognizes the name it will run the report again. If it is a new name, -or blank it will respond by giving you an example command line to edit. -Hitting return willrun the report and present it in a new buffer. - -If you have given it a new name, then @code{s} will save the report for -future use. - - -In a report buffer, the following keys are available: -@table @code -@item (space) -scroll up -@item e -edit the defined ledger reports -@item s -save a report definition based on the current report -@item q -quit the report (return to ledger buffer) -@item r -redo the report -@item k -kill the report buffer -@end table - - - - @node Transactions , Building Reports, Keeping a Journal, Top @chapter Transactions @menu -- cgit v1.2.3 From 71d5d6078f0c7237461209fd7ab2ef6f9bf38882 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 28 Feb 2013 11:57:51 -0700 Subject: Make reverse-report SHIFT-R --- lisp/ldg-report.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 0aa91ac0..0728495e 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -91,7 +91,7 @@ text that should replace the format specifier." (define-key map [? ] 'scroll-up) (define-key map [backspace] 'scroll-down) (define-key map [?r] 'ledger-report-redo) - (define-key map [?R] 'ledger-report-reverse-lines) + (define-key map [(shift ?r)] 'ledger-report-reverse-lines) (define-key map [?s] 'ledger-report-save) (define-key map [?k] 'ledger-report-kill) (define-key map [?e] 'ledger-report-edit) -- cgit v1.2.3 From ebea838d4c116de77ed5b5e2d620ed8cd70d3cce Mon Sep 17 00:00:00 2001 From: Rémi Vanicat <vanicat@debian.org> Date: Fri, 1 Mar 2013 10:10:34 +0100 Subject: The .info for ledger-mode should not be the same than for ledger3 --- doc/ledger-mode.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index 9b2c1262..68273440 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -1,5 +1,5 @@ \input texinfo @c -*-texinfo-*- -@setfilename ledger3.info +@setfilename ledger-mode.info @settitle Ledger: Command-Line Accounting @dircategory Major Modes -- cgit v1.2.3 From 7d7b011ed15f481752ae8f259ddd52188d84583f Mon Sep 17 00:00:00 2001 From: Rémi Vanicat <vanicat@debian.org> Date: Fri, 1 Mar 2013 10:13:35 +0100 Subject: Added forgotten {} for @code in ledger-mode.texi --- doc/ledger-mode.texi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index 68273440..1600bdd8 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -291,7 +291,7 @@ transaction operation is in the undo buffer. As you operating on the Ledger files, they may become disorganized. For the most part, Ledger doesn't care, but our human brains prefer a bit of order. Sorting the transactions in a buffer into chronological order -can help bring order to chaos. Ledger sort (@code C-c C-s) will sort +can help bring order to chaos. Ledger sort (@code{C-c C-s}) will sort all of the transactions in a region by date. Ledger-mode isn't particularly smart about handling dates and it simply sorts the transactions using the string at the beginning of the transaction. So, @@ -318,7 +318,7 @@ regular expression can match on any part of the transaction. If you want to find all transactions whose amount ends in .37, you can do that ( I don't know why, but hey, whatever ever flaots you aerostat). -Using @code(C-c C-f) or the @code{Hide Xacts} menu entry, enter a +Using @code{C-c C-f} or the @code{Hide Xacts} menu entry, enter a regualr expression in the minbuffer. Ledger-mode will hide all oter transactions. For details of the regualr expression syntax, see the Emacs Manual or the Emac Elisp Reference Manual. A few examples using @@ -385,7 +385,7 @@ enter the account enter the target amount. Ledger expects you to enter an amount with a commodity. It assumes initially that you are using $ (USD) as your default commodity. If you are working in a difference currency you can change the default in variable -@code(ledger-reconcile-default-commodity) to whatever you need. If you +@code{ledger-reconcile-default-commodity} to whatever you need. If you work in multiple commodities simply enter the commoditized amount (for example @code{340 VSDX}, for 340 shares of VSDX). -- cgit v1.2.3 From 6d7b00cff5899546028ad326d5289a04f019316c Mon Sep 17 00:00:00 2001 From: Rémi Vanicat <vanicat@debian.org> Date: Fri, 1 Mar 2013 10:14:13 +0100 Subject: Corrected one @xref --- doc/ledger-mode.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index 1600bdd8..d9400d99 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -184,7 +184,7 @@ The real power of Ledger is in it reporting capabilities. Reports can be run and displayed in a spearate Emacs buffer. In the @file{demo.ledger} buffer, type @code{C-c C-o C-r}. In the mini-buffer Emacs will prompt for a report name. There are a few built-in reports, -and you can add any report you need @xref{Adding New Reports}. +and you can add any report you need @xref{Adding and Editing Reports}. In the mini-buffer type @code{account}. When prompted for an account type @code{checking}. In another buffer you will see a Ledger register -- cgit v1.2.3 From 3771c1abf0b50ac59ee7349a535f73480cbee6b8 Mon Sep 17 00:00:00 2001 From: Rémi Vanicat <vanicat@debian.org> Date: Fri, 1 Mar 2013 10:15:05 +0100 Subject: Removing several warning by makeinfo in ledger-mode.texi --- doc/ledger-mode.texi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index d9400d99..04275054 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -154,7 +154,7 @@ the proper chronological place in the ledger. @subsection Reconciliation The biggest task of maintaining a ledger is ensuring the it matches the -outside world. This process is called reconciliation (@xref{Basics of +outside world. This process is called reconciliation (@pxref{Basics of Reconciliation}) and can be quite onerous. Ledger mode attempts to make it as painless as possible. @@ -166,7 +166,7 @@ Normally this would be the ending value from your bank statement, or the latest value in your on-line transaction summary. Enter @code{1710}. Note that Ledger-mode assumes your are using $ (USD) as your default commodity, this can be easily changed in the customization -variables. @xref{Ledger-mode Customization} +variables. @xref{Ledger-mode Customization}. You now see a list of uncleared transactions in a buffer below the @file{demo.ledger} buffer. Touching the space bar will mark a @@ -231,7 +231,7 @@ Ledger mode can also help you keep your amounts in alignment. Setting @code{ledger-post-auto-adjust-amounts} to true tells Ledger-mode to automatically place any amounts such that their last digit is aligned to the column specified by @code{ledger-post-amount-alignment-column}, -which defautls to 52. @xref{Ledger Post Customization Group} +which defautls to 52. @xref{Ledger Post Customization Group}. @node Editing Amounts, Marking Transactions, Adding Transactions, The Ledger Buffer @section Editing Amounts -- cgit v1.2.3 From dbc1334a94e38e5f5756a50bec5d7d81f3b0d6c6 Mon Sep 17 00:00:00 2001 From: Rémi Vanicat <vanicat@debian.org> Date: Fri, 1 Mar 2013 10:59:58 +0100 Subject: Some spelling correction. --- doc/ledger-mode.texi | 95 ++++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index 04275054..336f5ba8 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -93,9 +93,9 @@ reports and much more... @node Quick Installation, Menus, Introduction to Ledger Mode, Introduction to Ledger Mode @section Quick Installation -The emacs lisp source for Ledger-mode is included with the source +The Emacs lisp source for Ledger-mode is included with the source distribution of Ledger. It is entirely included in the @file{lisp} -subdirectory. To use ledger mode include the following in your emacs +subdirectory. To use ledger mode include the following in your Emacs initialization file (@file{~/.emacs}, @file{~/.emacs.d/init.el}, @file{~/.Aquamacs/Preferences.el} @@ -137,15 +137,15 @@ Ledger from a convenient command line. As simple as the ledger transaction format is, it can still be daunting to add many transactions manually. Ledger provides two way to add transactions with minimal typing. Both are based on the idea that most -tranactions are repretitions of earlier transactions. +transactions are repetitions of earlier transactions. In the @file{demo.ledger} buffer enter a date using the correct -format. The tpye the first few characters of another payee in the +format. Then type the first few characters of another payee in the @file{demo.ledger} buffer. Type @code{C-c TAB}. Ledger-mode will search for a Payee that has the same beginning and copy the rest of the transaction to you new entry. -Additionally you can ust the ledger xact command, by typing @code{C-c +Additionally you can use the ledger xact command, by typing @code{C-c C-a} then typing a close match to the payee. Ledger mode will call @code{ledger xact} with the data you enter and place the transaction in the proper chronological place in the ledger. @@ -173,7 +173,7 @@ You now see a list of uncleared transactions in a buffer below the transaction as pending and display the current cleared (and pending) balance, along with the difference remaining to meet your target. Clear the first three transactions, and you will see the difference to target -reach $0. End the reconcilitation by typing @code{C-c C-c}. This saves +reach $0. End the reconciliation by typing @code{C-c C-c}. This saves the demo.ledger buffer and marks the transactions and finally cleared. Type @code{q} to close out the reconciliation buffer. @@ -181,7 +181,7 @@ Type @code{q} to close out the reconciliation buffer. @subsection Reports The real power of Ledger is in it reporting capabilities. Reports can -be run and displayed in a spearate Emacs buffer. In the +be run and displayed in a separate Emacs buffer. In the @file{demo.ledger} buffer, type @code{C-c C-o C-r}. In the mini-buffer Emacs will prompt for a report name. There are a few built-in reports, and you can add any report you need @xref{Adding and Editing Reports}. @@ -190,7 +190,7 @@ In the mini-buffer type @code{account}. When prompted for an account type @code{checking}. In another buffer you will see a Ledger register report. You can move around the buffer, with the point on a transaction, type @code{C-c C-c}. Ledger mode will take you directly to that -transaction in the @file{demo.ledger} buffer. +transaction in the @file{demo.ledger} buffer. Another built-in report is the balance report. In the @file{demo.ledger} buffer, type @code{C-c C-o C-r}. When prompted for a @@ -231,7 +231,7 @@ Ledger mode can also help you keep your amounts in alignment. Setting @code{ledger-post-auto-adjust-amounts} to true tells Ledger-mode to automatically place any amounts such that their last digit is aligned to the column specified by @code{ledger-post-amount-alignment-column}, -which defautls to 52. @xref{Ledger Post Customization Group}. +which defaults to 52. @xref{Ledger Post Customization Group}. @node Editing Amounts, Marking Transactions, Adding Transactions, The Ledger Buffer @section Editing Amounts @@ -240,8 +240,8 @@ into all recent version of Emacs. Ledger-mode makes it easy to calculate values for amount by integrating GNU Calc. With the point anywhere in the same line as a posting, typing @code{C-c C-b} will bring up the Calc buffer, and push the current amount for the posting -onto the top of the Calc stack. Perform any calculations you ened to -arrive at the final vlaue, then type @code{y} to ynk the value at the +onto the top of the Calc stack. Perform any calculations you need to +arrive at the final value, then type @code{y} to yank the value at the top of stack back into the ledger buffer. Note: GNU Calc does not directly support commas as decimal separators. Ledger mode will translate values from decimal-comma format to decimal-period format for @@ -262,7 +262,7 @@ No state. This is equivalent to sticking a check in the mail. It has been obligated, but not been cashed by the recipient. It could also apply to credit/debit card transactions that have not been cleared into your account balance. You bank may call these transactions 'pending', -but Ledger-mode usues a slightly different meaning. +but Ledger-mode uses a slightly different meaning. @item Pending. Ledger-mode's reconciliation function see pending transactions as an intermediate step in reconciling an account. When doing a @@ -299,40 +299,41 @@ you should use the preferred ISO 8601 standard date format @code{YYYY/MM/DD} which easily sorts. Note, there is a menu entry to sort the entire buffer. Special -transactions like automated transactsion, will be moved in the sorting -process and may not fucntion correctly afterwards. For this reason +transactions like automated transaction, will be moved in the sorting +process and may not function correctly afterwards. For this reason there is no key sequence. @node Hiding Transactions, , Sorting Transactions, The Ledger Buffer @section Hiding Transactions -Ofen times you will want to run Ledger register reports just to look at -a specific set of transactions. If you don't need the running total -calculation hadnled by Ledger, Ledger-mode provides a rapid way of -narrowing what is displayed in the buffer in a way that is sipler than -the Ledger register command. +Often you will want to run Ledger register reports just to look at a +specific set of transactions. If you don't need the running total +calculation handled by Ledger, Ledger-mode provides a rapid way of +narrowing what is displayed in the buffer in a way that is simpler than +the Ledger register command. Based on the Emacs Occur mode by Alexey Veretennikov, Ledger-occur hides all transactions that do NOT meet a specific regular expression. The regular expression can match on any part of the transaction. If you want to find all transactions whose amount ends in .37, you can do that -( I don't know why, but hey, whatever ever flaots you aerostat). +( I don't know why, but hey, whatever ever floats you aerostat). Using @code{C-c C-f} or the @code{Hide Xacts} menu entry, enter a -regualr expression in the minbuffer. Ledger-mode will hide all oter -transactions. For details of the regualr expression syntax, see the -Emacs Manual or the Emac Elisp Reference Manual. A few examples using -the @file{demo.ledger} are given here: +regular expression in the minibuffer. Ledger-mode will hide all other +transactions. For details of the regular expression syntax, see +@ref{(emacs)Regexps, Syntax of Regular Expressions} or +@ref{(elisp)Regular Expressions, Regular Expressions}. A few examples +using the @file{demo.ledger} are given here: @table @samp @item Groceries Show only transactions that have a posting to the `Groceries' account. @item ^2011/01 -Show only transactions occuring in January of 2011. +Show only transactions occurring in January of 2011. @item ^2011/.*/25 -Show only transactions occuring on the 25th of the month in 2011 +Show only transactions occurring on the 25th of the month in 2011 @item .*ore -Show only transaction with payeees or accounts ending in `ore' +Show only transaction with payees or accounts ending in `ore' @end table To show all transactions simply invoke @code{Hide Xacts} or @code{C-c @@ -345,7 +346,7 @@ C-f} again. * Starting a Reconciliation:: * Mark Transactions Pending:: * Edit Transactions During Reconciliation:: -* Finialize Reconciliation:: +* Finalize Reconciliation:: * Adding and Deleting Transactions during Reconciliation:: * Changing Reconciliation Account:: * Changing Reconciliation Target:: @@ -354,12 +355,12 @@ C-f} again. @node Basics of Reconciliation, Starting a Reconciliation, The Reconcile Buffer, The Reconcile Buffer @section Basics of Reconciliation -Even in this relativley modern era, financial transactions do not happen +Even in this relatively modern era, financial transactions do not happen instantaneously, unless you are paying cash. When you swipe your debit card the money may take several days to actually come out of your account, or a check may take several days to ``clear''. That is the root of the difference between ``obligating'' funds and ``expending'' -funds. Obligation says you have agreed to pay it, the expnediture +funds. Obligation says you have agreed to pay it, the expenditure doesn't happen until the money actually leaves your account. Or in the case of receiving payment, you have an account receivable until the money has actually made it to you. @@ -400,12 +401,12 @@ not display the complete list of commodities. The @file{*Reconcile*} buffer will show all the uncleared transactions that meeting the criteria set in the regex. By default uncleared transactions are shown in red. When you have verified that a -transaction ahs been correctly and compeltely recorded by the opposing +transaction has been correctly and completely recorded by the opposing party, mark the transaction as pending using the space bar. Continue this process until you agree with the opposing party and the difference from your target is zero. -@node Edit Transactions During Reconciliation, Finialize Reconciliation, Mark Transactions Pending, The Reconcile Buffer +@node Edit Transactions During Reconciliation, Finalize Reconciliation, Mark Transactions Pending, The Reconcile Buffer @section Edit Transactions during Reconciliation If you find errors during reconciliation. You can visit the transaction @@ -415,14 +416,14 @@ you have finished editing the transaction saving the buffer will automatically return you to the @file{*Reconcile*} buffer and you can mark the transaction if appropriate. -@node Finialize Reconciliation, Adding and Deleting Transactions during Reconciliation, Edit Transactions During Reconciliation, The Reconcile Buffer +@node Finalize Reconciliation, Adding and Deleting Transactions during Reconciliation, Edit Transactions During Reconciliation, The Reconcile Buffer @section Finalize Reconciliation Once you have marked all transactions as pending and the cleared balance is correct. Finish the reconciliation by typing @code{C-c C-c}. This marks all pending transaction as cleared and saves the ledger buffer. -@node Adding and Deleting Transactions during Reconciliation, Changing Reconciliation Account, Finialize Reconciliation, The Reconcile Buffer +@node Adding and Deleting Transactions during Reconciliation, Changing Reconciliation Account, Finalize Reconciliation, The Reconcile Buffer @section Adding and Deleting Transactions during Reconciliation While reconciling, you may find new transactions that need to be entered @@ -437,7 +438,7 @@ Typing @code{d} will delete the transaction under point in the You can conveniently switch the account being reconciled by typing @code{g}, and entering a new account to reconcile. This simply restarts -teh reconcile process. Any transactions that were marked `pending' in +the reconcile process. Any transactions that were marked `pending' in the ledger buffer are left in that state when the account is switched. @node Changing Reconciliation Target, , Changing Reconciliation Account, The Reconcile Buffer @@ -457,11 +458,11 @@ type @code{t} and enter the new target value. @node Running Basic Reports, Adding and Editing Reports, The Report Buffer, The Report Buffer @section Running Reports -The real popwer behing Ledger is in its amazing reporting capability. -Ledger-mode provides easy facility to run reports directly from emacs. +The real power behind Ledger is in its amazing reporting capability. +Ledger-mode provides easy facility to run reports directly from Emacs. It has four reports built-in and facilities for adding custom reports. -Typeing @code{C-c C-o C-r} or using menu @code{Ledger Run Report} prompt +Typing @code{C-c C-o C-r} or using menu @code{Ledger Run Report} prompt for the name of a saved report. The built-in reports are: @table @samp @item bal @@ -490,7 +491,7 @@ automatically saved with the name given and you can re-run it at any time. There are two ways to edit the command line for a report. The first is -to privide a prefix argument to the run-report command. For example, +to provide a prefix argument to the run-report command. For example, type @code{M-1 C-c C-o C-r}. This will prompt you for the report name, then present the report command line to be edited. When you hit enter, the report will be run, but it will not be permanently saved. If you @@ -499,7 +500,7 @@ will have the option to give it a new name, or overwrite the old report. Deleting reports is accomplished by type @code{C-c C-o C-e} Edit Reports in the ledger buffer, or typing @code{E} in the @file{*Ledger Report*} -buffer. This takes you to the emacs customization window for the +buffer. This takes you to the Emacs customization window for the @code{ledger-reports} variable. Use the widgets to delete the report you want removed. @@ -526,7 +527,7 @@ Prompt for a tag value. You can use these expansion values in your ledger report commands. For example, if you wanted to specify a register report the displayed -trnasactions from a user-determined account with a particular meta-data +transactions from a user-determined account with a particular meta-data tag value, you specify the following command line: @smallexample ledger -f %(ledger-file) reg %(account) --limit \"tag('my-tag') =~ @@ -538,7 +539,7 @@ ledger -f %(ledger-file) reg %(account) --limit \"tag('my-tag') =~ @node Make Report Transactions Active, , Expansion Formats, Adding and Editing Reports @subsection Make Report Transactions Active -In a large register report it is convenient to be anle to jump to the +In a large register report it is convenient to be able to jump to the source transaction. Ledger-mode will automatically include source information in every register file that doesn't contain a @code{--subtotal} option. It does this by adding a @@ -550,9 +551,9 @@ may not get stripped out of the visible report. @node Reversing Report Order, , Adding and Editing Reports, The Report Buffer @section Reversing Report Order -Often, banks show their online transaction historyies with the most recent +Often, banks show their online transaction histories with the most recent transaction at the top. Ledger itself cannot do a sensible ledger -report in reverse chronoligcal order, if you sort on reverse date the +report in reverse chronological order, if you sort on reverse date the calculation will also run in the opposite direction. If you want to compare a ledger register report to a bank report with the most recent transactions at the top, type R in the @file{*Ledger Report*} buffer and @@ -574,9 +575,9 @@ Ledger-mode has several options available for configuration. All options can be configure through the Emacs customization menus, or specified in your Emacs initialization file. The complete list of options is show below. To change the option using the Emacs -customization menu, simply choe customize in the Options menu and look +customization menu, simply chose customize in the Options menu and look for Ledger under the data options. Alternately you can choose -``Customize Specific Group'' and enger ``Ledger'' as the group. +``Customize Specific Group'' and enter ``Ledger'' as the group. @node Customization Variables, , Ledger-mode Customization, Customizing Ledger-mode @section Customization Variables @@ -625,7 +626,7 @@ reconcile. Defaults to $ (USD) register window and resize. @item ledger-reconcile-toggle-to-pending If non-nil, then toggle between uncleared and pending (@code{!}). If false - toggle between unlceared and cleared (@code{*}) + toggle between uncleared and cleared (@code{*}) @end table @node Ledger Report Customization Group, Ledger Faces Customization Group, Ledger Reconcile Customization Group, Customization Variables -- cgit v1.2.3 From 3a0182d8d7a20ac33f78ab7e614881c6fe87a129 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Fri, 1 Mar 2013 09:37:33 -0700 Subject: Ensure reconcile balance display can handle empty accounts. Also force balance display at the beginning of reconciliation. --- lisp/ldg-commodities.el | 27 +++++++++++++++++---------- lisp/ldg-reconcile.el | 29 ++++++++++++++++------------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index c5500785..a3cc8951 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -38,16 +38,23 @@ (with-temp-buffer (insert str) (goto-char (point-min)) - (re-search-forward "-?[1-9][0-9]*[.,][0-9]*" nil t) - (setq val - (string-to-number - (ledger-commodity-string-number-decimalize - (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user))) - (goto-char (point-min)) - (re-search-forward "[^[:space:]]" nil t) - (setq comm - (delete-and-extract-region (match-beginning 0) (match-end 0))) - (list val comm)))) + (cond ((re-search-forward "-?[1-9][0-9]*[.,][0-9]*" nil t) + ;; found a decimal number + (setq val + (string-to-number + (ledger-commodity-string-number-decimalize + (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user))) + (goto-char (point-min)) + (re-search-forward "[^[:space:]]" nil t) + (setq comm + (delete-and-extract-region (match-beginning 0) (match-end 0))) + (list val comm)) + ((re-search-forward "0" nil t) + ;; couldn't find a decimal number, look for a single 0, + ;; indicating account with zero balance + (list 0 ledger-reconcile-default-commodity)) + (t + (error "split-commodity-string: cannot parse commodity string: %S" str)))))) (defun ledger-string-balance-to-commoditized-amount (str) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 6093f9df..f64f1bca 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -63,10 +63,8 @@ reconcile-finish will mark all pending posting cleared." :group 'ledger-reconcile) -(defun ledger-reconcile-get-balances () - "Calculate the cleared and uncleared balance of the account. -Return a list with the account, uncleared and cleared balances as -numbers" +(defun ledger-reconcile-get-cleared-or-pending-balance () + "Calculate the cleared or pending balance of the account." (interactive) (let ((buffer ledger-buf) (account ledger-acct) @@ -77,15 +75,17 @@ numbers" ; separated from the actual format string. emacs does not ; split arguments like the shell does, so you need to ; specify the individual fields in the command line. - "balance" "--limit" "cleared or pending" - "--format" "(\"%(display_total)\")" account) - (setq val (read (buffer-substring-no-properties (point-min) (point-max))))))) + "balance" "--limit" "cleared or pending" "--empty" + "--format" "%(display_total)" account) + (setq val + (ledger-split-commodity-string + (buffer-substring-no-properties (point-min) (point-max))))))) (defun ledger-display-balance () - "Calculate the cleared balance of the account being reconciled." + "Display the cleared-or-pending balnce and calculate the +target-delta of the account being reconciled." (interactive) - (let* ((pending (car (ledger-string-balance-to-commoditized-amount - (car (ledger-reconcile-get-balances))))) + (let* ((pending (ledger-reconcile-get-cleared-or-pending-balance)) (target-delta (if ledger-target (-commodity ledger-target pending) nil))) @@ -156,7 +156,8 @@ numbers" (ledger-do-reconcile) (set-buffer-modified-p t) (goto-char (point-min)) - (forward-line line))) + (forward-line line) + (ledger-display-balance))) (defun ledger-reconcile-refresh-after-save () "Refresh the recon-window after the ledger buffer is saved." @@ -375,7 +376,8 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (ledger-reconcile-refresh) (goto-char (point-min)) (setq ledger-target - (ledger-read-commodity-string "Set reconciliation target"))) + (ledger-read-commodity-string "Set reconciliation target")) + (ledger-display-balance)) (progn ;; no recon-buffer, starting from scratch. (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save nil t) @@ -389,7 +391,8 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (set (make-local-variable 'ledger-acct) account) (ledger-do-reconcile) (set (make-local-variable 'ledger-target) - (ledger-read-commodity-string "Set reconciliation target"))))))) + (ledger-read-commodity-string "Set reconciliation target")) + (ledger-display-balance)))))) (defvar ledger-reconcile-mode-abbrev-table) -- cgit v1.2.3 From 90d67876fc09ceea33798324ac410a8077e62f18 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Fri, 1 Mar 2013 23:28:35 -0700 Subject: Have a working tree parser and numerical date constraint --- lisp/ldg-auto.el | 123 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 90 insertions(+), 33 deletions(-) diff --git a/lisp/ldg-auto.el b/lisp/ldg-auto.el index a582b914..12832a4e 100644 --- a/lisp/ldg-auto.el +++ b/lisp/ldg-auto.el @@ -34,16 +34,17 @@ (and (>= val low) (<= val high))) (defun ledger-auto-days-in-month (month year) - "Return number of days in the MONTH, MONTH is form 1 to 12" + "Return number of days in the MONTH, MONTH is from 1 to 12. +If year is nil, assume it is not a leap year" (if (between month 1 12) - (if (and (date-leap-year-p year) (= 2 month)) + (if (and year (date-leap-year-p year) (= 2 month)) 29 (nth (1- month) '(31 28 31 30 31 30 31 31 30 31 30 31))) (error "Month out of range, MONTH=%S" month))) ;; Macros to handle date expressions -(defmacro ledger-auto-day-in-month-macro (count day-of-week) +(defmacro ledger-auto-constrain-day-in-month-macro (count day-of-week) "Return a form that evaluates DATE that returns true for the COUNT DAY-OF-WEEK. For example, return true if date is the 3rd Thursday of the month. Negative COUNT starts from the end of the month. (EQ @@ -78,20 +79,33 @@ COUNT 0) means EVERY day-of-week (eg. every Saturday)" (error "Invalid argument to ledger-auto-day-in-month-macro %S %S" count day-of-week))) - -(defmacro ledger-auto-day-of-month-macro (day) - "Return a form of date that returns true for the DAY of the month. -For example, return true if date is the 23rd of the month." - `(if (eq (nth 3 (decode-time date)) ,day) - t)) - -(defmacro ledger-auto-month-of-year-macro (month) - "Return a form of date that returns true for the MONTH of the year. -For example, return true if date is the 4th month of the year." - `(if (eq (nth 4 (decode-time date)) ,month) - t)) - -(defmacro ledger-auto-every-count-day-macro (day-of-week skip start-date) + +(defmacro ledger-auto-constrain-numerical-date-macro (year month day) + "Return a function of date that is only true if all constraints are met. +A nil constraint matches any input, a numerical entry must match that field +of date." + ;; Do bounds checking to make sure the incoming date constraint is sane + (if + (if (eval month) ;; if we have a month + (and (between (eval month) 1 12) ;; make sure it is between 1 + ;; and twelve and the number + ;; of days are ok + (between (eval day) 1 (ledger-auto-days-in-month (eval month) (eval year)))) + (between (eval day) 1 31)) ;; no month specified, assume 31 days. + `#'(lambda (date) + (and ,(if (eval year) + `(if (eq (nth 5 (decode-time date)) ,(eval year)) t) + `t) + ,(if (eval month) + `(if (eq (nth 4 (decode-time date)) ,(eval month)) t) + `t) + ,(if (eval day) + `(if (eq (nth 3 (decode-time date)) ,(eval day)) t)))) + (error "ledger-auto-constraint-numerical-date-macro: date out of range %S %S %S" (eval year) (eval month) (eval day)))) + + + +(defmacro ledger-auto-constrain-every-count-day-macro (day-of-week skip start-date) "Return a form that is true for every DAY skipping SKIP, starting on START. For example every second Friday, regardless of month." (let ((start-day (nth 6 (decode-time (eval start-date))))) @@ -101,7 +115,7 @@ For example every second Friday, regardless of month." nil) (error "START-DATE day of week doesn't match DAY-OF-WEEK")))) -(defmacro ledger-auto-date-range-macro (month1 day1 month2 day2) +(defmacro ledger-auto-constrain-date-range-macro (month1 day1 month2 day2) "Return a form of DATE that is true if DATE falls between MONTH1 DAY1 and MONTH2 DAY2." (let ((decoded (gensym)) (target-month (gensym)) @@ -114,13 +128,15 @@ For example every second Friday, regardless of month." (and (> ,target-day ,day1) (< ,target-day ,day2)))))) + (defun ledger-auto-is-holiday (date) "Return true if DATE is a holiday.") (defun ledger-auto-scan-transactions (auto-file) + (interactive "fFile name: ") (let ((xact-list (list))) - (save-excursion - (find-file auto-file) + (with-current-buffer + (find-file-noselect auto-file) (goto-char (point-min)) (while (re-search-forward "^\\[\\(.*\\)\\] " nil t) (let ((date-descriptor "") @@ -143,16 +159,19 @@ For example every second Friday, regardless of month." "Take a date descriptor string and return a function that returns true if the date meets the requirements" (with-temp-buffer + ;; copy the descriptor string into a temp buffer for manipulation (let (pos) + ;; Replace brackets with parens (insert descriptor-string) (goto-char (point-min)) (replace-string "[" "(") (goto-char (point-min)) (replace-string "]" ")") (goto-char (point-max)) + ;; double quote all the descriptors for string processing later (while (re-search-backward - (concat "\\([0-9]+\\|[\*]\\)/" ;; Year slot - "\\([\*EO]\\|[0-9]+\\)/" ;; Month slot + (concat "\\(20[0-9][0-9]\\|[\*]\\)[/\\-]" ;; Year slot + "\\([\*EO]\\|[0-9]+\\)[/\\-]" ;; Month slot "\\([\*]\\|\\([0-9][0-9]\\)\\|" "\\([0-5]" "\\(\\(Su\\)\\|" @@ -167,20 +186,58 @@ returns true if the date meets the requirements" (insert ?\") (goto-char (match-beginning 0)) (insert "\"" ))) - (ledger-auto-traverse-descriptor-tree - (read (buffer-substring (point-min) (point-max))) 0))) - -(defun ledger-auto-traverse-descriptor-tree (tree depth) - (dolist (node tree) - (cond ((eq (type-of node) 'string) - (ledger-auto-parse-date-descriptor node)) - ((eq (type-of node) 'cons) - (ledger-auto-traverse-descriptor-tree node (1+ depth)))))) - + + ;; read the descriptor string into a lisp object the transform the + ;; string descriptor into useable things + (ledger-transform-auto-tree + (read (buffer-substring (point-min) (point-max)))))) + +(defun ledger-transform-auto-tree (tree) + (if (consp tree) + (let (result) + (while (consp tree) + (let ((newcar (car tree))) + (if (consp (car tree)) + (setq newcar (ledger-transform-auto-tree (car tree)))) + (if (consp newcar) + (push newcar result) + (push (ledger-auto-parse-date-descriptor newcar) result)) ) + (setq tree (cdr tree))) + (nconc (nreverse result) tree)))) + +(defun ledger-auto-split-constraints (descriptor-string) + "Return a list with the year, month and day fields split" + (let ((fields (split-string descriptor-string "[/\\-]" t)) + constrain-year constrain-month constrain-day) + (if (string= (car fields) "*") + (setq constrain-year nil) + (setq constrain-year (car fields))) + (if (string= (cadr fields) "*") + (setq constrain-month nil) + (setq constrain-month (cadr fields))) + (if (string= (nth 2 fields) "*") + (setq constrain-day nil) + (setq constrain-day (nth 2 fields))) + (list constrain-year constrain-month constrain-day))) + +(defun ledger-string-to-number-or-nil (str) + (if str + (string-to-number str) + nil)) + +(defun ledger-auto-compile-constraints (constraint-list) + (let ((year-constraint (ledger-string-to-number-or-nil (nth 0 constraint-list))) + (month-constraint (ledger-string-to-number-or-nil (nth 1 constraint-list))) + (day-constraint (ledger-string-to-number-or-nil (nth 2 constraint-list)))) + (ledger-auto-constrain-numerical-date-macro + year-constraint + month-constraint + day-constraint))) (defun ledger-auto-parse-date-descriptor (descriptor) "Parse the date descriptor, return the evaluator" - descriptor) + (ledger-auto-compile-constraints + (ledger-auto-split-constraints descriptor))) (provide 'ldg-auto) -- cgit v1.2.3 From 497d668778e17e08ac91695ba1cb5da50612cd0a Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Fri, 1 Mar 2013 23:29:31 -0700 Subject: Clean up the reconcile balance display code --- lisp/ldg-reconcile.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index f64f1bca..33c9f06f 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -156,8 +156,7 @@ target-delta of the account being reconciled." (ledger-do-reconcile) (set-buffer-modified-p t) (goto-char (point-min)) - (forward-line line) - (ledger-display-balance))) + (forward-line line))) (defun ledger-reconcile-refresh-after-save () "Refresh the recon-window after the ledger buffer is saved." -- cgit v1.2.3 From 9a86fe022cb5ef95c675ebc59269a7c7e63d1077 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 2 Mar 2013 13:33:12 -0700 Subject: Add ability to posting the account in a posting using the iedger-default-acct-transaction-indent --- doc/ledger-mode.texi | 5 +++-- lisp/ldg-mode.el | 5 ----- lisp/ldg-post.el | 21 +++++++++++++++++---- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index 336f5ba8..1d317725 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -596,8 +596,6 @@ for Ledger under the data options. Alternately you can choose @node Ledger Customization Group, Ledger Reconcile Customization Group, Customization Variables, Customization Variables @subsection Ledger Customization Group @table @code -@item ledger-default-acct-transaction-indent - Default indentation for account transactions in an entry. @item ledger-occur-use-face-unfolded If non-nil use a custom face for xacts shown in `ledger-occur' mode using @code{ledger-occur-xact-face}. @item ledger-clear-whole-transactions @@ -678,11 +676,14 @@ Default face for pending (!) transactions in the reconcile window @subsection Ledger Post Customization Group Ledger Post : @table @code + @item ledger-post-auto-adjust-amounts If non-nil, then automatically align amounts to column specified in @code{ledger-post-amount-alignment-column} @item ledger-post-amount-alignment-column The column Ledger-mode uses to align amounts +@item ledger-default-acct-transaction-indent +Default indentation for account transactions in an entry. @item ledger-post-use-completion-engine Which completion engine to use, iswitchb, ido, or built-in @item ledger-post-use-ido diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 37c0f69e..00df0e67 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -39,11 +39,6 @@ (defvar ledger-month (ledger-current-month) "Start a ledger session with the current month, but make it customizable to ease retro-entry.") -(defcustom ledger-default-acct-transaction-indent " " - "Default indentation for account transactions in an entry." - :type 'string - :group 'ledger) - (defun ledger-remove-overlays () "Remove all overlays from the ledger buffer." (interactive) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index de28a8a9..2a736bfc 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -27,6 +27,11 @@ ;;; Code: +(defcustom ledger-default-acct-transaction-indent " " + "Default indentation for account transactions in an entry." + :type 'string + :group 'ledger-post) + (defgroup ledger-post nil "Options for controlling how Ledger-mode deals with postings and completion" :group 'ledger) @@ -119,17 +124,25 @@ PROMPT is a string to prompt with. CHOICES is a list of (match-end 3)) (point)))) (defun ledger-align-amounts (&optional column) - "Align amounts in the current region. + "Align amounts and accounts in the current region. This is done so that the last digit falls in COLUMN, which - defaults to 52." +defaults to 52. ledger-default-acct-transaction-indent positions +the account" (interactive "p") (if (or (null column) (= column 1)) (setq column ledger-post-amount-alignment-column)) (save-excursion + ;; Position the account + (beginning-of-line) + (set-mark (point)) + (delete-horizontal-space) + (insert ledger-default-acct-transaction-indent) + (goto-char (1+ (line-end-position))) (let* ((mark-first (< (mark) (point))) (begin (if mark-first (mark) (point))) (end (if mark-first (point-marker) (mark-marker))) offset) + ;; Position the amount (goto-char begin) (while (setq offset (ledger-next-amount end)) (let ((col (current-column)) @@ -159,10 +172,10 @@ This is done so that the last digit falls in COLUMN, which BEG, END, and LEN control how far it can align." (save-excursion (goto-char beg) - (when (< end (line-end-position)) + (when (<= end (line-end-position)) (goto-char (line-beginning-position)) (if (looking-at ledger-post-line-regexp) - (ledger-post-align-amount))))) + (ledger-align-amounts))))) (defun ledger-post-edit-amount () "Call 'calc-mode' and push the amount in the posting to the top of stack." -- cgit v1.2.3 From c85a91b030f27b8cc22fa71bf0215b846b2be246 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 2 Mar 2013 20:19:43 -0700 Subject: Ad ledger-mode flags to limit sort region for sort buffer --- doc/ledger-mode.texi | 15 +++++++++++++++ lisp/ldg-sort.el | 13 ++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index 1d317725..f530d587 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -303,6 +303,21 @@ transactions like automated transaction, will be moved in the sorting process and may not function correctly afterwards. For this reason there is no key sequence. +You can limit the allowed sort region by using embedded Ledger-mode +markup within your ledger. For exmaple +@smallexample +<<< infomration to not sort >>> + +; Ledger-mode: Start sort + +<<< xacts to sort >>> + +;Ledger-mode: End sort + +<<< information to not sort >>> +@end smallexample + + @node Hiding Transactions, , Sorting Transactions, The Ledger Buffer @section Hiding Transactions diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el index 361eead8..cc036492 100644 --- a/lisp/ldg-sort.el +++ b/lisp/ldg-sort.el @@ -54,8 +54,8 @@ ;; the beginning of next record ;; after the region (setq new-end (point)) - (narrow-to-region beg end) - (goto-char (point-min)) + (narrow-to-region new-beg new-end) + (goto-char new-beg) (let ((inhibit-field-text-motion t)) (sort-subr @@ -66,7 +66,14 @@ (defun ledger-sort-buffer () "Sort the entire buffer." (interactive) - (ledger-sort-region (point-min) (point-max))) + (let ((sort-start (point-min)) + (sort-end (point-max))) + (goto-char (point-min)) + (if (re-search-forward ";.*Ledger-mode:.*Start sort" nil t) + (set 'sort-start (match-end 0))) + (if (re-search-forward ";.*Ledger-mode:.*End sort" nil t) + (set 'sort-end (match-end 0))) + (ledger-sort-region sort-start sort-end))) (provide 'ldg-sort) -- cgit v1.2.3 From 4810da9398809fc090c7f044d3545050a465d2bb Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 2 Mar 2013 20:20:58 -0700 Subject: Remove auto account alignment as it interfered with account completion. --- lisp/ldg-post.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 2a736bfc..7105ef7a 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -133,10 +133,10 @@ the account" (setq column ledger-post-amount-alignment-column)) (save-excursion ;; Position the account - (beginning-of-line) + ;; (beginning-of-line) (set-mark (point)) - (delete-horizontal-space) - (insert ledger-default-acct-transaction-indent) + ;; (delete-horizontal-space) + ;; (insert ledger-default-acct-transaction-indent) (goto-char (1+ (line-end-position))) (let* ((mark-first (< (mark) (point))) (begin (if mark-first (mark) (point))) -- cgit v1.2.3 From efce6c89362abed1276cd060cec8077777a038e4 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 4 Mar 2013 09:36:34 -0700 Subject: Add acct under point to reconcile prompt. Fix reconcile balance display of empty accounts --- lisp/ldg-commodities.el | 46 ++++++++++++++++++++++++---------------------- lisp/ldg-post.el | 12 ++++++++++++ lisp/ldg-reconcile.el | 9 +++++---- lisp/ldg-report.el | 11 +++-------- 4 files changed, 44 insertions(+), 34 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index a3cc8951..9291136f 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -33,28 +33,30 @@ (defun ledger-split-commodity-string (str) "Split a commoditized amount into two parts" - (let (val - comm) - (with-temp-buffer - (insert str) - (goto-char (point-min)) - (cond ((re-search-forward "-?[1-9][0-9]*[.,][0-9]*" nil t) - ;; found a decimal number - (setq val - (string-to-number - (ledger-commodity-string-number-decimalize - (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user))) - (goto-char (point-min)) - (re-search-forward "[^[:space:]]" nil t) - (setq comm - (delete-and-extract-region (match-beginning 0) (match-end 0))) - (list val comm)) - ((re-search-forward "0" nil t) - ;; couldn't find a decimal number, look for a single 0, - ;; indicating account with zero balance - (list 0 ledger-reconcile-default-commodity)) - (t - (error "split-commodity-string: cannot parse commodity string: %S" str)))))) + (if (> (length str) 0) + (let (val + comm) + (with-temp-buffer + (insert str) + (goto-char (point-min)) + (cond ((re-search-forward "-?[1-9][0-9]*[.,][0-9]*" nil t) + ;; found a decimal number + (setq val + (string-to-number + (ledger-commodity-string-number-decimalize + (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user))) + (goto-char (point-min)) + (re-search-forward "[^[:space:]]" nil t) + (setq comm + (delete-and-extract-region (match-beginning 0) (match-end 0))) + (list val comm)) + ((re-search-forward "0" nil t) + ;; couldn't find a decimal number, look for a single 0, + ;; indicating account with zero balance + (list 0 ledger-reconcile-default-commodity)) + (t + (error "split-commodity-string: cannot parse commodity string: %S" str))))) + (list 0 ledger-reconcile-default-commodity))) (defun ledger-string-balance-to-commoditized-amount (str) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 7105ef7a..6cba305b 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -229,6 +229,18 @@ BEG, END, and LEN control how far it can align." (add-hook 'after-change-functions 'ledger-post-maybe-align t t)) (add-hook 'after-save-hook #'(lambda () (setq ledger-post-current-list nil)))) + +(defun ledger-post-read-account-with-prompt (prompt) + (let* ((context (ledger-context-at-point)) + (default + (if (eq (ledger-context-line-type context) 'acct-transaction) + (regexp-quote (ledger-context-field-value context 'account)) + nil))) + (ledger-read-string-with-default prompt default))) + + (provide 'ldg-post) + + ;;; ldg-post.el ends here diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 33c9f06f..e45ab7c3 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -351,10 +351,11 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (set-window-buffer (split-window (get-buffer-window buf) nil nil) rbuf) (pop-to-buffer rbuf))) -(defun ledger-reconcile (account) - "Start reconciling ACCOUNT." - (interactive "sAccount to reconcile: ") - (let ((buf (current-buffer)) +(defun ledger-reconcile () + "Start reconciling, prompt for account." + (interactive) + (let ((account (ledger-post-read-account-with-prompt "Account to reconcile")) + (buf (current-buffer)) (rbuf (get-buffer ledger-recon-buffer-name))) ;; this means ;; only one ;; *Reconcile* diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 0728495e..ef088f17 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -258,12 +258,7 @@ used to generate the buffer, navigating the buffer, etc." the default." ;; It is intended completion should be available on existing account ;; names, but it remains to be implemented. - (let* ((context (ledger-context-at-point)) - (default - (if (eq (ledger-context-line-type context) 'acct-transaction) - (regexp-quote (ledger-context-field-value context 'account)) - nil))) - (ledger-read-string-with-default "Account" default))) + (ledger-post-read-account-with-prompt "Account")) (defun ledger-report-expand-format-specifiers (report-cmd) "Expand %(account) and %(payee) appearing in REPORT-CMD with thing under point." @@ -437,9 +432,9 @@ Optional EDIT the command." ("^\\(\\([0-9][0-9][0-9][0-9]/\\)?[01]?[0-9]/[0123]?[0-9]\\)[ \t]+\\(\\([!*]\\)[ \t]\\)?[ \t]*\\((\\(.*\\))\\)?[ \t]*\\(.*\\)[ \t]*$" (date nil status nil nil code payee)))) (acct-transaction - (("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\([$]\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" + (("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\([$€£]\\s-?\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" (indent account commodity amount nil comment)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\([$]\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*$" + ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\([$€£]\\s-?\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*$" (indent account commodity amount nil)) ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\(-?[0-9]+\\(\\.[0-9]*\\)?\\)[ \t]+\\(.*?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" (indent account amount nil commodity comment)) -- cgit v1.2.3 From 5a48bc39356d98abe1b1afdcdc42f382755f6929 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 5 Mar 2013 21:30:05 -0500 Subject: Removed timeclock.el. This has been parts of the standard Emacs installation for a very long time. No need to repeat it here. --- lisp/timeclock.el | 1362 ----------------------------------------------------- 1 file changed, 1362 deletions(-) delete mode 100644 lisp/timeclock.el diff --git a/lisp/timeclock.el b/lisp/timeclock.el deleted file mode 100644 index 2cafa8eb..00000000 --- a/lisp/timeclock.el +++ /dev/null @@ -1,1362 +0,0 @@ -;;; timeclock.el --- mode for keeping track of how much you work - -;; Copyright (C) 1999, 2000, 2001, 2003, 2004 Free Software Foundation, Inc. - -;; Author: John Wiegley <johnw@gnu.org> -;; Created: 25 Mar 1999 -;; Version: 2.6 -;; Keywords: calendar data - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;;; Commentary: - -;; This mode is for keeping track of time intervals. You can use it -;; for whatever purpose you like, but the typical scenario is to keep -;; track of how much time you spend working on certain projects. -;; -;; Use `timeclock-in' when you start on a project, and `timeclock-out' -;; when you're done. Once you've collected some data, you can use -;; `timeclock-workday-remaining' to see how much time is left to be -;; worked today (where `timeclock-workday' specifies the length of the -;; working day), and `timeclock-when-to-leave' to calculate when you're free. - -;; You'll probably want to bind the timeclock commands to some handy -;; keystrokes. At the moment, C-x t is unused: -;; -;; (require 'timeclock) -;; -;; (define-key ctl-x-map "ti" 'timeclock-in) -;; (define-key ctl-x-map "to" 'timeclock-out) -;; (define-key ctl-x-map "tc" 'timeclock-change) -;; (define-key ctl-x-map "tr" 'timeclock-reread-log) -;; (define-key ctl-x-map "tu" 'timeclock-update-modeline) -;; (define-key ctl-x-map "tw" 'timeclock-when-to-leave-string) - -;; If you want Emacs to display the amount of time "left" to your -;; workday in the modeline, you can either set the value of -;; `timeclock-modeline-display' to t using M-x customize, or you -;; can add this code to your .emacs file: -;; -;; (require 'timeclock) -;; (timeclock-modeline-display) -;; -;; To cancel this modeline display at any time, just call -;; `timeclock-modeline-display' again. - -;; You may also want Emacs to ask you before exiting, if you are -;; currently working on a project. This can be done either by setting -;; `timeclock-ask-before-exiting' to t using M-x customize (this is -;; the default), or by adding the following to your .emacs file: -;; -;; (add-hook 'kill-emacs-query-functions 'timeclock-query-out) - -;; NOTE: If you change your .timelog file without using timeclock's -;; functions, or if you change the value of any of timeclock's -;; customizable variables, you should run the command -;; `timeclock-reread-log'. This will recompute any discrepancies in -;; your average working time, and will make sure that the various -;; display functions return the correct value. - -;;; History: - -;;; Code: - -(defgroup timeclock nil - "Keeping track time of the time that gets spent." - :group 'data) - -;;; User Variables: - -(defcustom timeclock-file (convert-standard-filename "~/.timelog") - "*The file used to store timeclock data in." - :type 'file - :group 'timeclock) - -(defcustom timeclock-workday (* 8 60 60) - "*The length of a work period." - :type 'integer - :group 'timeclock) - -(defcustom timeclock-relative t - "*Whether to maken reported time relative to `timeclock-workday'. -For example, if the length of a normal workday is eight hours, and you -work four hours on Monday, then the amount of time \"remaining\" on -Tuesday is twelve hours -- relative to an averaged work period of -eight hours -- or eight hours, non-relative. So relative time takes -into account any discrepancy of time under-worked or over-worked on -previous days. This only affects the timeclock modeline display." - :type 'boolean - :group 'timeclock) - -(defcustom timeclock-get-project-function 'timeclock-ask-for-project - "*The function used to determine the name of the current project. -When clocking in, and no project is specified, this function will be -called to determine what is the current project to be worked on. -If this variable is nil, no questions will be asked." - :type 'function - :group 'timeclock) - -(defcustom timeclock-get-reason-function 'timeclock-ask-for-reason - "*A function used to determine the reason for clocking out. -When clocking out, and no reason is specified, this function will be -called to determine what is the reason. -If this variable is nil, no questions will be asked." - :type 'function - :group 'timeclock) - -(defcustom timeclock-get-workday-function nil - "*A function used to determine the length of today's workday. -The first time that a user clocks in each day, this function will be -called to determine what is the length of the current workday. If -the return value is nil, or equal to `timeclock-workday', nothing special -will be done. If it is a quantity different from `timeclock-workday', -however, a record will be output to the timelog file to note the fact that -that day has a length that is different from the norm." - :type '(choice (const nil) function) - :group 'timeclock) - -(defcustom timeclock-ask-before-exiting t - "*If non-nil, ask if the user wants to clock out before exiting Emacs. -This variable only has effect if set with \\[customize]." - :set (lambda (symbol value) - (if value - (add-hook 'kill-emacs-query-functions 'timeclock-query-out) - (remove-hook 'kill-emacs-query-functions 'timeclock-query-out)) - (setq timeclock-ask-before-exiting value)) - :type 'boolean - :group 'timeclock) - -(defvar timeclock-update-timer nil - "The timer used to update `timeclock-mode-string'.") - -;; For byte-compiler. -(defvar display-time-hook) -(defvar timeclock-modeline-display) - -(defcustom timeclock-use-display-time t - "*If non-nil, use `display-time-hook' for doing modeline updates. -The advantage of this is that one less timer has to be set running -amok in Emacs' process space. The disadvantage is that it requires -you to have `display-time' running. If you don't want to use -`display-time', but still want the modeline to show how much time is -left, set this variable to nil. Changing the value of this variable -while timeclock information is being displayed in the modeline has no -effect. You should call the function `timeclock-modeline-display' with -a positive argument to force an update." - :set (lambda (symbol value) - (let ((currently-displaying - (and (boundp 'timeclock-modeline-display) - timeclock-modeline-display))) - ;; if we're changing to the state that - ;; `timeclock-modeline-display' is already using, don't - ;; bother toggling it. This happens on the initial loading - ;; of timeclock.el. - (if (and currently-displaying - (or (and value - (boundp 'display-time-hook) - (memq 'timeclock-update-modeline - display-time-hook)) - (and (not value) - timeclock-update-timer))) - (setq currently-displaying nil)) - (and currently-displaying - (set-variable 'timeclock-modeline-display nil)) - (setq timeclock-use-display-time value) - (and currently-displaying - (set-variable 'timeclock-modeline-display t)) - timeclock-use-display-time)) - :type 'boolean - :group 'timeclock - :require 'time) - -(defcustom timeclock-first-in-hook nil - "*A hook run for the first \"in\" event each day. -Note that this hook is run before recording any events. Thus the -value of `timeclock-hours-today', `timeclock-last-event' and the -return value of function `timeclock-last-period' are relative previous -to today." - :type 'hook - :group 'timeclock) - -(defcustom timeclock-load-hook nil - "*Hook that gets run after timeclock has been loaded." - :type 'hook - :group 'timeclock) - -(defcustom timeclock-in-hook nil - "*A hook run every time an \"in\" event is recorded." - :type 'hook - :group 'timeclock) - -(defcustom timeclock-day-over-hook nil - "*A hook that is run when the workday has been completed. -This hook is only run if the current time remaining is being displayed -in the modeline. See the variable `timeclock-modeline-display'." - :type 'hook - :group 'timeclock) - -(defcustom timeclock-out-hook nil - "*A hook run every time an \"out\" event is recorded." - :type 'hook - :group 'timeclock) - -(defcustom timeclock-done-hook nil - "*A hook run every time a project is marked as completed." - :type 'hook - :group 'timeclock) - -(defcustom timeclock-event-hook nil - "*A hook run every time any event is recorded." - :type 'hook - :group 'timeclock) - -(defvar timeclock-last-event nil - "A list containing the last event that was recorded. -The format of this list is (CODE TIME PROJECT).") - -(defvar timeclock-last-event-workday nil - "The number of seconds in the workday of `timeclock-last-event'.") - -;;; Internal Variables: - -(defvar timeclock-discrepancy nil - "A variable containing the time discrepancy before the last event. -Normally, timeclock assumes that you intend to work for -`timeclock-workday' seconds every day. Any days in which you work -more or less than this amount is considered either a positive or -a negative discrepancy. If you work in such a manner that the -discrepancy is always brought back to zero, then you will by -definition have worked an average amount equal to `timeclock-workday' -each day.") - -(defvar timeclock-elapsed nil - "A variable containing the time elapsed for complete periods today. -This value is not accurate enough to be useful by itself. Rather, -call `timeclock-workday-elapsed', to determine how much time has been -worked so far today. Also, if `timeclock-relative' is nil, this value -will be the same as `timeclock-discrepancy'.") ; ? gm - -(defvar timeclock-last-period nil - "Integer representing the number of seconds in the last period. -Note that you shouldn't access this value, but instead should use the -function `timeclock-last-period'.") - -(defvar timeclock-mode-string nil - "The timeclock string (optionally) displayed in the modeline. -The time is bracketed by <> if you are clocked in, otherwise by [].") - -(defvar timeclock-day-over nil - "The date of the last day when notified \"day over\" for.") - -;;; User Functions: - -;;;###autoload -(defun timeclock-modeline-display (&optional arg) - "Toggle display of the amount of time left today in the modeline. -If `timeclock-use-display-time' is non-nil (the default), then -the function `display-time-mode' must be active, and the modeline -will be updated whenever the time display is updated. Otherwise, -the timeclock will use its own sixty second timer to do its -updating. With prefix ARG, turn modeline display on if and only -if ARG is positive. Returns the new status of timeclock modeline -display (non-nil means on)." - (interactive "P") - ;; cf display-time-mode. - (setq timeclock-mode-string "") - (or global-mode-string (setq global-mode-string '(""))) - (let ((on-p (if arg - (> (prefix-numeric-value arg) 0) - (not timeclock-modeline-display)))) - (if on-p - (progn - (or (memq 'timeclock-mode-string global-mode-string) - (setq global-mode-string - (append global-mode-string '(timeclock-mode-string)))) - (unless (memq 'timeclock-update-modeline timeclock-event-hook) - (add-hook 'timeclock-event-hook 'timeclock-update-modeline)) - (when timeclock-update-timer - (cancel-timer timeclock-update-timer) - (setq timeclock-update-timer nil)) - (if (boundp 'display-time-hook) - (remove-hook 'display-time-hook 'timeclock-update-modeline)) - (if timeclock-use-display-time - (progn - ;; Update immediately so there is a visible change - ;; on calling this function. - (if display-time-mode (timeclock-update-modeline) - (message "Activate `display-time-mode' to see \ -timeclock information")) - (add-hook 'display-time-hook 'timeclock-update-modeline)) - (setq timeclock-update-timer - (run-at-time nil 60 'timeclock-update-modeline)))) - (setq global-mode-string - (delq 'timeclock-mode-string global-mode-string)) - (remove-hook 'timeclock-event-hook 'timeclock-update-modeline) - (if (boundp 'display-time-hook) - (remove-hook 'display-time-hook - 'timeclock-update-modeline)) - (when timeclock-update-timer - (cancel-timer timeclock-update-timer) - (setq timeclock-update-timer nil))) - (force-mode-line-update) - (setq timeclock-modeline-display on-p))) - -;; This has to be here so that the function definition of -;; `timeclock-modeline-display' is known to the "set" function. -(defcustom timeclock-modeline-display nil - "Toggle modeline display of time remaining. -You must modify via \\[customize] for this variable to have an effect." - :set (lambda (symbol value) - (setq timeclock-modeline-display - (timeclock-modeline-display (or value 0)))) - :type 'boolean - :group 'timeclock - :require 'timeclock) - -(defsubst timeclock-time-to-date (time) - "Convert the TIME value to a textual date string." - (format-time-string "%Y/%m/%d" time)) - -;;;###autoload -(defun timeclock-in (&optional arg project find-project) - "Clock in, recording the current time moment in the timelog. -With a numeric prefix ARG, record the fact that today has only that -many hours in it to be worked. If arg is a non-numeric prefix arg -\(non-nil, but not a number), 0 is assumed (working on a holiday or -weekend). *If not called interactively, ARG should be the number of -_seconds_ worked today*. This feature only has effect the first time -this function is called within a day. - -PROJECT is the project being clocked into. If PROJECT is nil, and -FIND-PROJECT is non-nil -- or the user calls `timeclock-in' -interactively -- call the function `timeclock-get-project-function' to -discover the name of the project." - (interactive - (list (and current-prefix-arg - (if (numberp current-prefix-arg) - (* current-prefix-arg 60 60) - 0)))) - (if (equal (car timeclock-last-event) "i") - (error "You've already clocked in!") - (unless timeclock-last-event - (timeclock-reread-log)) - ;; Either no log file, or day has rolled over. - (unless (and timeclock-last-event - (equal (timeclock-time-to-date - (cadr timeclock-last-event)) - (timeclock-time-to-date (current-time)))) - (let ((workday (or (and (numberp arg) arg) - (and arg 0) - (and timeclock-get-workday-function - (funcall timeclock-get-workday-function)) - timeclock-workday))) - (run-hooks 'timeclock-first-in-hook) - ;; settle the discrepancy for the new day - (setq timeclock-discrepancy - (- (or timeclock-discrepancy 0) workday)) - (if (not (= workday timeclock-workday)) - (timeclock-log "h" (and (numberp arg) - (number-to-string arg)))))) - (timeclock-log "i" (or project - (and timeclock-get-project-function - (or find-project (interactive-p)) - (funcall timeclock-get-project-function)))) - (run-hooks 'timeclock-in-hook))) - -;;;###autoload -(defun timeclock-out (&optional arg reason find-reason) - "Clock out, recording the current time moment in the timelog. -If a prefix ARG is given, the user has completed the project that was -begun during the last time segment. - -REASON is the user's reason for clocking out. If REASON is nil, and -FIND-REASON is non-nil -- or the user calls `timeclock-out' -interactively -- call the function `timeclock-get-reason-function' to -discover the reason." - (interactive "P") - (or timeclock-last-event - (error "You haven't clocked in!")) - (if (equal (downcase (car timeclock-last-event)) "o") - (error "You've already clocked out!") - (timeclock-log - (if arg "O" "o") - (or reason - (and timeclock-get-reason-function - (or find-reason (interactive-p)) - (funcall timeclock-get-reason-function)))) - (run-hooks 'timeclock-out-hook) - (if arg - (run-hooks 'timeclock-done-hook)))) - -;; Should today-only be removed in favour of timeclock-relative? - gm -(defsubst timeclock-workday-remaining (&optional today-only) - "Return the number of seconds until the workday is complete. -The amount returned is relative to the value of `timeclock-workday'. -If TODAY-ONLY is non-nil, the value returned will be relative only to -the time worked today, and not to past time." - (let ((discrep (timeclock-find-discrep))) - (if discrep - (- (if today-only (cadr discrep) - (car discrep))) - 0.0))) - -;;;###autoload -(defun timeclock-status-string (&optional show-seconds today-only) - "Report the overall timeclock status at the present moment. -If SHOW-SECONDS is non-nil, display second resolution. -If TODAY-ONLY is non-nil, the display will be relative only to time -worked today, ignoring the time worked on previous days." - (interactive "P") - (let ((remainder (timeclock-workday-remaining)) ; today-only? - (last-in (equal (car timeclock-last-event) "i")) - status) - (setq status - (format "Currently %s since %s (%s), %s %s, leave at %s" - (if last-in "IN" "OUT") - (if show-seconds - (format-time-string "%-I:%M:%S %p" - (nth 1 timeclock-last-event)) - (format-time-string "%-I:%M %p" - (nth 1 timeclock-last-event))) - (or (nth 2 timeclock-last-event) - (if last-in "**UNKNOWN**" "workday over")) - (timeclock-seconds-to-string remainder show-seconds t) - (if (> remainder 0) - "remaining" "over") - (timeclock-when-to-leave-string show-seconds today-only))) - (if (interactive-p) - (message status) - status))) - -;;;###autoload -(defun timeclock-change (&optional arg project) - "Change to working on a different project. -This clocks out of the current project, then clocks in on a new one. -With a prefix ARG, consider the previous project as finished at the -time of changeover. PROJECT is the name of the last project you were -working on." - (interactive "P") - (timeclock-out arg) - (timeclock-in nil project (interactive-p))) - -;;;###autoload -(defun timeclock-query-out () - "Ask the user whether to clock out. -This is a useful function for adding to `kill-emacs-query-functions'." - (and (equal (car timeclock-last-event) "i") - (y-or-n-p "You're currently clocking time, clock out? ") - (timeclock-out)) - ;; Unconditionally return t for `kill-emacs-query-functions'. - t) - -;;;###autoload -(defun timeclock-reread-log () - "Re-read the timeclock, to account for external changes. -Returns the new value of `timeclock-discrepancy'." - (interactive) - (setq timeclock-discrepancy nil) - (timeclock-find-discrep) - (if (and timeclock-discrepancy timeclock-modeline-display) - (timeclock-update-modeline)) - timeclock-discrepancy) - -(defun timeclock-seconds-to-string (seconds &optional show-seconds - reverse-leader) - "Convert SECONDS into a compact time string. -If SHOW-SECONDS is non-nil, make the resolution of the return string -include the second count. If REVERSE-LEADER is non-nil, it means to -output a \"+\" if the time value is negative, rather than a \"-\". -This is used when negative time values have an inverted meaning (such -as with time remaining, where negative time really means overtime)." - (if show-seconds - (format "%s%d:%02d:%02d" - (if (< seconds 0) (if reverse-leader "+" "-") "") - (truncate (/ (abs seconds) 60 60)) - (% (truncate (/ (abs seconds) 60)) 60) - (% (truncate (abs seconds)) 60)) - (format "%s%d:%02d" - (if (< seconds 0) (if reverse-leader "+" "-") "") - (truncate (/ (abs seconds) 60 60)) - (% (truncate (/ (abs seconds) 60)) 60)))) - -(defsubst timeclock-currently-in-p () - "Return non-nil if the user is currently clocked in." - (equal (car timeclock-last-event) "i")) - -;;;###autoload -(defun timeclock-workday-remaining-string (&optional show-seconds - today-only) - "Return a string representing the amount of time left today. -Display second resolution if SHOW-SECONDS is non-nil. If TODAY-ONLY -is non-nil, the display will be relative only to time worked today. -See `timeclock-relative' for more information about the meaning of -\"relative to today\"." - (interactive) - (let ((string (timeclock-seconds-to-string - (timeclock-workday-remaining today-only) - show-seconds t))) - (if (interactive-p) - (message string) - string))) - -(defsubst timeclock-workday-elapsed () - "Return the number of seconds worked so far today. -If RELATIVE is non-nil, the amount returned will be relative to past -time worked. The default is to return only the time that has elapsed -so far today." - (let ((discrep (timeclock-find-discrep))) - (if discrep - (nth 2 discrep) - 0.0))) - -;;;###autoload -(defun timeclock-workday-elapsed-string (&optional show-seconds) - "Return a string representing the amount of time worked today. -Display seconds resolution if SHOW-SECONDS is non-nil. If RELATIVE is -non-nil, the amount returned will be relative to past time worked." - (interactive) - (let ((string (timeclock-seconds-to-string (timeclock-workday-elapsed) - show-seconds))) - (if (interactive-p) - (message string) - string))) - -(defsubst timeclock-time-to-seconds (time) - "Convert TIME to a floating point number." - (+ (* (car time) 65536.0) - (cadr time) - (/ (or (car (cdr (cdr time))) 0) 1000000.0))) - -(defsubst timeclock-seconds-to-time (seconds) - "Convert SECONDS (a floating point number) to an Emacs time structure." - (list (floor seconds 65536) - (floor (mod seconds 65536)) - (floor (* (- seconds (ffloor seconds)) 1000000)))) - -;; Should today-only be removed in favour of timeclock-relative? - gm -(defsubst timeclock-when-to-leave (&optional today-only) - "Return a time value representing the end of today's workday. -If TODAY-ONLY is non-nil, the value returned will be relative only to -the time worked today, and not to past time." - (timeclock-seconds-to-time - (- (timeclock-time-to-seconds (current-time)) - (let ((discrep (timeclock-find-discrep))) - (if discrep - (if today-only - (cadr discrep) - (car discrep)) - 0.0))))) - -;;;###autoload -(defun timeclock-when-to-leave-string (&optional show-seconds - today-only) - "Return a string representing the end of today's workday. -This string is relative to the value of `timeclock-workday'. If -SHOW-SECONDS is non-nil, the value printed/returned will include -seconds. If TODAY-ONLY is non-nil, the value returned will be -relative only to the time worked today, and not to past time." - ;; Should today-only be removed in favour of timeclock-relative? - gm - (interactive) - (let* ((then (timeclock-when-to-leave today-only)) - (string - (if show-seconds - (format-time-string "%-I:%M:%S %p" then) - (format-time-string "%-I:%M %p" then)))) - (if (interactive-p) - (message string) - string))) - -;;; Internal Functions: - -(defvar timeclock-project-list nil) -(defvar timeclock-last-project nil) - -(defun timeclock-completing-read (prompt alist &optional default) - "A version of `completing-read' that works on both Emacs and XEmacs." - (if (featurep 'xemacs) - (let ((str (completing-read prompt alist))) - (if (or (null str) (= (length str) 0)) - default - str)) - (completing-read prompt alist nil nil nil nil default))) - -(defun timeclock-ask-for-project () - "Ask the user for the project they are clocking into." - (timeclock-completing-read - (format "Clock into which project (default \"%s\"): " - (or timeclock-last-project - (car timeclock-project-list))) - (mapcar 'list timeclock-project-list) - (or timeclock-last-project - (car timeclock-project-list)))) - -(defvar timeclock-reason-list nil) - -(defun timeclock-ask-for-reason () - "Ask the user for the reason they are clocking out." - (timeclock-completing-read "Reason for clocking out: " - (mapcar 'list timeclock-reason-list))) - -(defun timeclock-update-modeline () - "Update the `timeclock-mode-string' displayed in the modeline. -The value of `timeclock-relative' affects the display as described in -that variable's documentation." - (interactive) - (let ((remainder (timeclock-workday-remaining (not timeclock-relative))) - (last-in (equal (car timeclock-last-event) "i"))) - (when (and (< remainder 0) - (not (and timeclock-day-over - (equal timeclock-day-over - (timeclock-time-to-date - (current-time)))))) - (setq timeclock-day-over - (timeclock-time-to-date (current-time))) - (run-hooks 'timeclock-day-over-hook)) - (setq timeclock-mode-string - (propertize - (format " %c%s%c " - (if last-in ?< ?[) - (timeclock-seconds-to-string remainder nil t) - (if last-in ?> ?])) - 'help-echo "timeclock: time remaining")))) - -(put 'timeclock-mode-string 'risky-local-variable t) - -(defun timeclock-log (code &optional project) - "Log the event CODE to the timeclock log, at the time of call. -If PROJECT is a string, it represents the project which the event is -being logged for. Normally only \"in\" events specify a project." - (with-current-buffer (find-file-noselect timeclock-file) - (goto-char (point-max)) - (if (not (bolp)) - (insert "\n")) - (let ((now (current-time))) - (insert code " " - (format-time-string "%Y/%m/%d %H:%M:%S" now) - (or (and project - (stringp project) - (> (length project) 0) - (concat " " project)) - "") - "\n") - (if (equal (downcase code) "o") - (setq timeclock-last-period - (- (timeclock-time-to-seconds now) - (timeclock-time-to-seconds - (cadr timeclock-last-event))) - timeclock-discrepancy - (+ timeclock-discrepancy - timeclock-last-period))) - (setq timeclock-last-event (list code now project))) - (save-buffer) - (run-hooks 'timeclock-event-hook) - (kill-buffer (current-buffer)))) - -(defvar timeclock-moment-regexp - (concat "\\([bhioO]\\)\\s-+" - "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)\\s-+" - "\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)[ \t]*" "\\([^\n]*\\)")) - -(defsubst timeclock-read-moment () - "Read the moment under point from the timelog." - (if (looking-at timeclock-moment-regexp) - (let ((code (match-string 1)) - (year (string-to-number (match-string 2))) - (mon (string-to-number (match-string 3))) - (mday (string-to-number (match-string 4))) - (hour (string-to-number (match-string 5))) - (min (string-to-number (match-string 6))) - (sec (string-to-number (match-string 7))) - (project (match-string 8))) - (list code (encode-time sec min hour mday mon year) project)))) - -(defun timeclock-last-period (&optional moment) - "Return the value of the last event period. -If the last event was a clock-in, the period will be open ended, and -growing every second. Otherwise, it is a fixed amount which has been -recorded to disk. If MOMENT is non-nil, use that as the current time. -This is only provided for coherency when used by -`timeclock-discrepancy'." - (if (equal (car timeclock-last-event) "i") - (- (timeclock-time-to-seconds (or moment (current-time))) - (timeclock-time-to-seconds - (cadr timeclock-last-event))) - timeclock-last-period)) - -(defsubst timeclock-entry-length (entry) - (- (timeclock-time-to-seconds (cadr entry)) - (timeclock-time-to-seconds (car entry)))) - -(defsubst timeclock-entry-begin (entry) - (car entry)) - -(defsubst timeclock-entry-end (entry) - (cadr entry)) - -(defsubst timeclock-entry-project (entry) - (nth 2 entry)) - -(defsubst timeclock-entry-comment (entry) - (nth 3 entry)) - - -(defsubst timeclock-entry-list-length (entry-list) - (let ((length 0)) - (while entry-list - (setq length (+ length (timeclock-entry-length (car entry-list)))) - (setq entry-list (cdr entry-list))) - length)) - -(defsubst timeclock-entry-list-begin (entry-list) - (timeclock-entry-begin (car entry-list))) - -(defsubst timeclock-entry-list-end (entry-list) - (timeclock-entry-end (car (last entry-list)))) - -(defsubst timeclock-entry-list-span (entry-list) - (- (timeclock-time-to-seconds (timeclock-entry-list-end entry-list)) - (timeclock-time-to-seconds (timeclock-entry-list-begin entry-list)))) - -(defsubst timeclock-entry-list-break (entry-list) - (- (timeclock-entry-list-span entry-list) - (timeclock-entry-list-length entry-list))) - -(defsubst timeclock-entry-list-projects (entry-list) - (let (projects) - (while entry-list - (let ((project (timeclock-entry-project (car entry-list)))) - (if projects - (add-to-list 'projects project) - (setq projects (list project)))) - (setq entry-list (cdr entry-list))) - projects)) - - -(defsubst timeclock-day-required (day) - (or (car day) timeclock-workday)) - -(defsubst timeclock-day-length (day) - (timeclock-entry-list-length (cdr day))) - -(defsubst timeclock-day-debt (day) - (- (timeclock-day-required day) - (timeclock-day-length day))) - -(defsubst timeclock-day-begin (day) - (timeclock-entry-list-begin (cdr day))) - -(defsubst timeclock-day-end (day) - (timeclock-entry-list-end (cdr day))) - -(defsubst timeclock-day-span (day) - (timeclock-entry-list-span (cdr day))) - -(defsubst timeclock-day-break (day) - (timeclock-entry-list-break (cdr day))) - -(defsubst timeclock-day-projects (day) - (timeclock-entry-list-projects (cdr day))) - -(defmacro timeclock-day-list-template (func) - `(let ((length 0)) - (while day-list - (setq length (+ length (,(eval func) (car day-list)))) - (setq day-list (cdr day-list))) - length)) - -(defun timeclock-day-list-required (day-list) - (timeclock-day-list-template 'timeclock-day-required)) - -(defun timeclock-day-list-length (day-list) - (timeclock-day-list-template 'timeclock-day-length)) - -(defun timeclock-day-list-debt (day-list) - (timeclock-day-list-template 'timeclock-day-debt)) - -(defsubst timeclock-day-list-begin (day-list) - (timeclock-day-begin (car day-list))) - -(defsubst timeclock-day-list-end (day-list) - (timeclock-day-end (car (last day-list)))) - -(defun timeclock-day-list-span (day-list) - (timeclock-day-list-template 'timeclock-day-span)) - -(defun timeclock-day-list-break (day-list) - (timeclock-day-list-template 'timeclock-day-break)) - -(defun timeclock-day-list-projects (day-list) - (let (projects) - (while day-list - (let ((projs (timeclock-day-projects (car day-list)))) - (while projs - (if projects - (add-to-list 'projects (car projs)) - (setq projects (list (car projs)))) - (setq projs (cdr projs)))) - (setq day-list (cdr day-list))) - projects)) - - -(defsubst timeclock-current-debt (&optional log-data) - (nth 0 (or log-data (timeclock-log-data)))) - -(defsubst timeclock-day-alist (&optional log-data) - (nth 1 (or log-data (timeclock-log-data)))) - -(defun timeclock-day-list (&optional log-data) - (let ((alist (timeclock-day-alist log-data)) - day-list) - (while alist - (setq day-list (cons (cdar alist) day-list) - alist (cdr alist))) - day-list)) - -(defsubst timeclock-project-alist (&optional log-data) - (nth 2 (or log-data (timeclock-log-data)))) - - -(defun timeclock-log-data (&optional recent-only filename) - "Return the contents of the timelog file, in a useful format. -If the optional argument RECENT-ONLY is non-nil, only show the contents -from the last point where the time debt (see below) was set. -If the optional argument FILENAME is non-nil, it is used instead of -the file specified by `timeclock-file.' - -A timelog contains data in the form of a single entry per line. -Each entry has the form: - - CODE YYYY/MM/DD HH:MM:SS [COMMENT] - -CODE is one of: b, h, i, o or O. COMMENT is optional when the code is -i, o or O. The meanings of the codes are: - - b Set the current time balance, or \"time debt\". Useful when - archiving old log data, when a debt must be carried forward. - The COMMENT here is the number of seconds of debt. - - h Set the required working time for the given day. This must - be the first entry for that day. The COMMENT in this case is - the number of hours in this workday. Floating point amounts - are allowed. - - i Clock in. The COMMENT in this case should be the name of the - project worked on. - - o Clock out. COMMENT is unnecessary, but can be used to provide - a description of how the period went, for example. - - O Final clock out. Whatever project was being worked on, it is - now finished. Useful for creating summary reports. - -When this function is called, it will return a data structure with the -following format: - - (DEBT ENTRIES-BY-DAY ENTRIES-BY-PROJECT) - -DEBT is a floating point number representing the number of seconds -\"owed\" before any work was done. For a new file (one without a 'b' -entry), this is always zero. - -The two entries lists have similar formats. They are both alists, -where the CAR is the index, and the CDR is a list of time entries. -For ENTRIES-BY-DAY, the CAR is a textual date string, of the form -YYYY/MM/DD. For ENTRIES-BY-PROJECT, it is the name of the project -worked on, or t for the default project. - -The CDR for ENTRIES-BY-DAY is slightly different than for -ENTRIES-BY-PROJECT. It has the following form: - - (DAY-LENGTH TIME-ENTRIES...) - -For ENTRIES-BY-PROJECT, there is no DAY-LENGTH member. It is simply a -list of TIME-ENTRIES. Note that if DAY-LENGTH is nil, it means -whatever is the default should be used. - -A TIME-ENTRY is a recorded time interval. It has the following format -\(although generally one does not have to manipulate these entries -directly; see below): - - (BEGIN-TIME END-TIME PROJECT [COMMENT] [FINAL-P]) - -Anyway, suffice it to say there are a lot of structures. Typically -the user is expected to manipulate to the day(s) or project(s) that he -or she wants, at which point the following helper functions may be -used: - - timeclock-day-required - timeclock-day-length - timeclock-day-debt - timeclock-day-begin - timeclock-day-end - timeclock-day-span - timeclock-day-break - timeclock-day-projects - - timeclock-day-list-required - timeclock-day-list-length - timeclock-day-list-debt - timeclock-day-list-begin - timeclock-day-list-end - timeclock-day-list-span - timeclock-day-list-break - timeclock-day-list-projects - - timeclock-entry-length - timeclock-entry-begin - timeclock-entry-end - timeclock-entry-project - timeclock-entry-comment - - timeclock-entry-list-length - timeclock-entry-list-begin - timeclock-entry-list-end - timeclock-entry-list-span - timeclock-entry-list-break - timeclock-entry-list-projects - -A few comments should make the use of the above functions obvious: - - `required' is the amount of time that must be spent during a day, or - sequence of days, in order to have no debt. - - `length' is the actual amount of time that was spent. - - `debt' is the difference between required time and length. A - negative debt signifies overtime. - - `begin' is the earliest moment at which work began. - - `end' is the final moment work was done. - - `span' is the difference between begin and end. - - `break' is the difference between span and length. - - `project' is the project that was worked on, and `projects' is a - list of all the projects that were worked on during a given period. - - `comment', where it applies, could mean anything. - -There are a few more functions available, for locating day and entry -lists: - - timeclock-day-alist LOG-DATA - timeclock-project-alist LOG-DATA - timeclock-current-debt LOG-DATA - -See the documentation for the given function if more info is needed." - (let* ((log-data (list 0.0 nil nil)) - (now (current-time)) - (todays-date (timeclock-time-to-date now)) - last-date-limited last-date-seconds last-date - (line 0) last beg day entry event) - (with-temp-buffer - (insert-file-contents (or filename timeclock-file)) - (when recent-only - (goto-char (point-max)) - (unless (re-search-backward "^b\\s-+" nil t) - (goto-char (point-min)))) - (while (or (setq event (timeclock-read-moment)) - (and beg (not last) - (setq last t event (list "o" now)))) - (setq line (1+ line)) - (cond ((equal (car event) "b") - (setcar log-data (string-to-number (nth 2 event)))) - ((equal (car event) "h") - (setq last-date-limited (timeclock-time-to-date (cadr event)) - last-date-seconds (* (string-to-number (nth 2 event)) - 3600.0))) - ((equal (car event) "i") - (if beg - (error "Error in format of timelog file, line %d" line) - (setq beg t)) - (setq entry (list (cadr event) nil - (and (> (length (nth 2 event)) 0) - (nth 2 event)))) - (let ((date (timeclock-time-to-date (cadr event)))) - (if (and last-date - (not (equal date last-date))) - (progn - (setcar (cdr log-data) - (cons (cons last-date day) - (cadr log-data))) - (setq day (list (and last-date-limited - last-date-seconds)))) - (unless day - (setq day (list (and last-date-limited - last-date-seconds))))) - (setq last-date date - last-date-limited nil))) - ((equal (downcase (car event)) "o") - (if (not beg) - (error "Error in format of timelog file, line %d" line) - (setq beg nil)) - (setcar (cdr entry) (cadr event)) - (let ((desc (and (> (length (nth 2 event)) 0) - (nth 2 event)))) - (if desc - (nconc entry (list (nth 2 event)))) - (if (equal (car event) "O") - (nconc entry (if desc - (list t) - (list nil t)))) - (nconc day (list entry)) - (setq desc (nth 2 entry)) - (let ((proj (assoc desc (nth 2 log-data)))) - (if (null proj) - (setcar (cddr log-data) - (cons (cons desc (list entry)) - (car (cddr log-data)))) - (nconc (cdr proj) (list entry))))))) - (forward-line)) - (if day - (setcar (cdr log-data) - (cons (cons last-date day) - (cadr log-data)))) - log-data))) - -(defun timeclock-find-discrep () - "Calculate time discrepancies, in seconds. -The result is a three element list, containing the total time -discrepancy, today's discrepancy, and the time worked today." - ;; This is not implemented in terms of the functions above, because - ;; it's a bit wasteful to read all of that data in, just to throw - ;; away more than 90% of the information afterwards. - ;; - ;; If it were implemented using those functions, it would look - ;; something like this: - ;; (let ((days (timeclock-day-alist (timeclock-log-data))) - ;; (total 0.0)) - ;; (while days - ;; (setq total (+ total (- (timeclock-day-length (cdar days)) - ;; (timeclock-day-required (cdar days)))) - ;; days (cdr days))) - ;; total) - (let* ((now (current-time)) - (todays-date (timeclock-time-to-date now)) - (first t) (accum 0) (elapsed 0) - event beg last-date avg - last-date-limited last-date-seconds) - (unless timeclock-discrepancy - (when (file-readable-p timeclock-file) - (setq timeclock-project-list nil - timeclock-last-project nil - timeclock-reason-list nil - timeclock-elapsed 0) - (with-temp-buffer - (insert-file-contents timeclock-file) - (goto-char (point-max)) - (unless (re-search-backward "^b\\s-+" nil t) - (goto-char (point-min))) - (while (setq event (timeclock-read-moment)) - (cond ((equal (car event) "b") - (setq accum (string-to-number (nth 2 event)))) - ((equal (car event) "h") - (setq last-date-limited - (timeclock-time-to-date (cadr event)) - last-date-seconds - (* (string-to-number (nth 2 event)) 3600.0))) - ((equal (car event) "i") - (when (and (nth 2 event) - (> (length (nth 2 event)) 0)) - (add-to-list 'timeclock-project-list (nth 2 event)) - (setq timeclock-last-project (nth 2 event))) - (let ((date (timeclock-time-to-date (cadr event)))) - (if (if last-date - (not (equal date last-date)) - first) - (setq first nil - accum (- accum (if last-date-limited - last-date-seconds - timeclock-workday)))) - (setq last-date date - last-date-limited nil) - (if beg - (error "Error in format of timelog file!") - (setq beg (timeclock-time-to-seconds (cadr event)))))) - ((equal (downcase (car event)) "o") - (if (and (nth 2 event) - (> (length (nth 2 event)) 0)) - (add-to-list 'timeclock-reason-list (nth 2 event))) - (if (not beg) - (error "Error in format of timelog file!") - (setq timeclock-last-period - (- (timeclock-time-to-seconds (cadr event)) beg) - accum (+ timeclock-last-period accum) - beg nil)) - (if (equal last-date todays-date) - (setq timeclock-elapsed - (+ timeclock-last-period timeclock-elapsed))))) - (setq timeclock-last-event event - timeclock-last-event-workday - (if (equal (timeclock-time-to-date now) last-date-limited) - last-date-seconds - timeclock-workday)) - (forward-line)) - (setq timeclock-discrepancy accum)))) - (unless timeclock-last-event-workday - (setq timeclock-last-event-workday timeclock-workday)) - (setq accum (or timeclock-discrepancy 0) - elapsed (or timeclock-elapsed elapsed)) - (if timeclock-last-event - (if (equal (car timeclock-last-event) "i") - (let ((last-period (timeclock-last-period now))) - (setq accum (+ accum last-period) - elapsed (+ elapsed last-period))) - (if (not (equal (timeclock-time-to-date - (cadr timeclock-last-event)) - (timeclock-time-to-date now))) - (setq accum (- accum timeclock-last-event-workday))))) - (list accum (- elapsed timeclock-last-event-workday) - elapsed))) - -;;; A reporting function that uses timeclock-log-data - -(defun timeclock-day-base (&optional time) - "Given a time within a day, return 0:0:0 within that day. -If optional argument TIME is non-nil, use that instead of the current time." - (let ((decoded (decode-time (or time (current-time))))) - (setcar (nthcdr 0 decoded) 0) - (setcar (nthcdr 1 decoded) 0) - (setcar (nthcdr 2 decoded) 0) - (apply 'encode-time decoded))) - -(defun timeclock-geometric-mean (l) - "Compute the geometric mean of the values in the list L." - (let ((total 0) - (count 0)) - (while l - (setq total (+ total (car l)) - count (1+ count) - l (cdr l))) - (if (> count 0) - (/ total count) - 0))) - -(defun timeclock-generate-report (&optional html-p) - "Generate a summary report based on the current timelog file. -By default, the report is in plain text, but if the optional argument -HTML-P is non-nil, HTML markup is added." - (interactive) - (let ((log (timeclock-log-data)) - (today (timeclock-day-base))) - (if html-p (insert "<p>")) - (insert "Currently ") - (let ((project (nth 2 timeclock-last-event)) - (begin (nth 1 timeclock-last-event)) - done) - (if (timeclock-currently-in-p) - (insert "IN") - (if (or (null project) (= (length project) 0)) - (progn (insert "Done Working Today") - (setq done t)) - (insert "OUT"))) - (unless done - (insert " since " (format-time-string "%Y/%m/%d %-I:%M %p" begin)) - (if html-p - (insert "<br>\n<b>") - (insert "\n*")) - (if (timeclock-currently-in-p) - (insert "Working on ")) - (if html-p - (insert project "</b><br>\n") - (insert project "*\n")) - (let ((proj-data (cdr (assoc project (timeclock-project-alist log)))) - (two-weeks-ago (timeclock-seconds-to-time - (- (timeclock-time-to-seconds today) - (* 2 7 24 60 60)))) - two-week-len today-len) - (while proj-data - (if (not (time-less-p - (timeclock-entry-begin (car proj-data)) today)) - (setq today-len (timeclock-entry-list-length proj-data) - proj-data nil) - (if (and (null two-week-len) - (not (time-less-p - (timeclock-entry-begin (car proj-data)) - two-weeks-ago))) - (setq two-week-len (timeclock-entry-list-length proj-data))) - (setq proj-data (cdr proj-data)))) - (if (null two-week-len) - (setq two-week-len today-len)) - (if html-p (insert "<p>")) - (if today-len - (insert "\nTime spent on this task today: " - (timeclock-seconds-to-string today-len) - ". In the last two weeks: " - (timeclock-seconds-to-string two-week-len)) - (if two-week-len - (insert "\nTime spent on this task in the last two weeks: " - (timeclock-seconds-to-string two-week-len)))) - (if html-p (insert "<br>")) - (insert "\n" - (timeclock-seconds-to-string (timeclock-workday-elapsed)) - " worked today, " - (timeclock-seconds-to-string (timeclock-workday-remaining)) - " remaining, done at " - (timeclock-when-to-leave-string) "\n"))) - (if html-p (insert "<p>")) - (insert "\nThere have been " - (number-to-string - (length (timeclock-day-alist log))) - " days of activity, starting " - (caar (last (timeclock-day-alist log)))) - (if html-p (insert "</p>")) - (when html-p - (insert "<p> -<table> -<td width=\"25\"><br></td><td> -<table border=1 cellpadding=3> -<tr><th><i>Statistics</i></th> - <th>Entire</th> - <th>-30 days</th> - <th>-3 mons</th> - <th>-6 mons</th> - <th>-1 year</th> -</tr>") - (let* ((day-list (timeclock-day-list)) - (thirty-days-ago (timeclock-seconds-to-time - (- (timeclock-time-to-seconds today) - (* 30 24 60 60)))) - (three-months-ago (timeclock-seconds-to-time - (- (timeclock-time-to-seconds today) - (* 90 24 60 60)))) - (six-months-ago (timeclock-seconds-to-time - (- (timeclock-time-to-seconds today) - (* 180 24 60 60)))) - (one-year-ago (timeclock-seconds-to-time - (- (timeclock-time-to-seconds today) - (* 365 24 60 60)))) - (time-in (vector (list t) (list t) (list t) (list t) (list t))) - (time-out (vector (list t) (list t) (list t) (list t) (list t))) - (breaks (vector (list t) (list t) (list t) (list t) (list t))) - (workday (vector (list t) (list t) (list t) (list t) (list t))) - (lengths (vector '(0 0) thirty-days-ago three-months-ago - six-months-ago one-year-ago))) - ;; collect statistics from complete timelog - (while day-list - (let ((i 0) (l 5)) - (while (< i l) - (unless (time-less-p - (timeclock-day-begin (car day-list)) - (aref lengths i)) - (let ((base (timeclock-time-to-seconds - (timeclock-day-base - (timeclock-day-begin (car day-list)))))) - (nconc (aref time-in i) - (list (- (timeclock-time-to-seconds - (timeclock-day-begin (car day-list))) - base))) - (let ((span (timeclock-day-span (car day-list))) - (len (timeclock-day-length (car day-list))) - (req (timeclock-day-required (car day-list)))) - ;; If the day's actual work length is less than - ;; 70% of its span, then likely the exit time - ;; and break amount are not worthwhile adding to - ;; the statistic - (when (and (> span 0) - (> (/ (float len) (float span)) 0.70)) - (nconc (aref time-out i) - (list (- (timeclock-time-to-seconds - (timeclock-day-end (car day-list))) - base))) - (nconc (aref breaks i) (list (- span len)))) - (if req - (setq len (+ len (- timeclock-workday req)))) - (nconc (aref workday i) (list len))))) - (setq i (1+ i)))) - (setq day-list (cdr day-list))) - ;; average statistics - (let ((i 0) (l 5)) - (while (< i l) - (aset time-in i (timeclock-geometric-mean - (cdr (aref time-in i)))) - (aset time-out i (timeclock-geometric-mean - (cdr (aref time-out i)))) - (aset breaks i (timeclock-geometric-mean - (cdr (aref breaks i)))) - (aset workday i (timeclock-geometric-mean - (cdr (aref workday i)))) - (setq i (1+ i)))) - ;; Output the HTML table - (insert "<tr>\n") - (insert "<td align=\"center\">Time in</td>\n") - (let ((i 0) (l 5)) - (while (< i l) - (insert "<td align=\"right\">" - (timeclock-seconds-to-string (aref time-in i)) - "</td>\n") - (setq i (1+ i)))) - (insert "</tr>\n") - - (insert "<tr>\n") - (insert "<td align=\"center\">Time out</td>\n") - (let ((i 0) (l 5)) - (while (< i l) - (insert "<td align=\"right\">" - (timeclock-seconds-to-string (aref time-out i)) - "</td>\n") - (setq i (1+ i)))) - (insert "</tr>\n") - - (insert "<tr>\n") - (insert "<td align=\"center\">Break</td>\n") - (let ((i 0) (l 5)) - (while (< i l) - (insert "<td align=\"right\">" - (timeclock-seconds-to-string (aref breaks i)) - "</td>\n") - (setq i (1+ i)))) - (insert "</tr>\n") - - (insert "<tr>\n") - (insert "<td align=\"center\">Workday</td>\n") - (let ((i 0) (l 5)) - (while (< i l) - (insert "<td align=\"right\">" - (timeclock-seconds-to-string (aref workday i)) - "</td>\n") - (setq i (1+ i)))) - (insert "</tr>\n")) - (insert "<tfoot> -<td colspan=\"6\" align=\"center\"> - <i>These are approximate figures</i></td> -</tfoot> -</table> -</td></table>"))))) - -;;; A helpful little function - -(defun timeclock-visit-timelog () - "Open the file named by `timeclock-file' in another window." - (interactive) - (find-file-other-window timeclock-file)) - -(provide 'timeclock) - -(run-hooks 'timeclock-load-hook) - -;; make sure we know the list of reasons, projects, and have computed -;; the last event and current discrepancy. -(if (file-readable-p timeclock-file) - (timeclock-reread-log)) - -;;; arch-tag: a0be3377-deb6-44ec-b9a2-a7be28436a40 -;;; timeclock.el ends here -- cgit v1.2.3 From 0744a0ac8fac128255a0baec0343d1092a998cee Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 6 Mar 2013 14:35:34 -0500 Subject: Added menu entries to help set sort region --- doc/ledger-mode.texi | 4 +++- lisp/ldg-mode.el | 2 ++ lisp/ldg-sort.el | 47 +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index f530d587..e13610bc 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -316,7 +316,9 @@ markup within your ledger. For exmaple <<< information to not sort >>> @end smallexample - +You can use menu entries to insert start and end markers. These +functions will automatically delete old markers and put new new marker +at point. @node Hiding Transactions, , Sorting Transactions, The Ledger Buffer @section Hiding Transactions diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 00df0e67..84ccf62b 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -116,6 +116,8 @@ (interactive) (customize-group 'ledger)))) (define-key map [sep1] '("--")) + (define-key map [sort-end] '(menu-item "Mark Sort End" ledger-sort-insert-end-mark)) + (define-key map [sort-start] '(menu-item "Mark Sort Beginning" ledger-sort-insert-start-mark)) (define-key map [sort-buff] '(menu-item "Sort Buffer" ledger-sort-buffer)) (define-key map [sort-reg] '(menu-item "Sort Region" ledger-sort-region :enable mark-active)) (define-key map [sep2] '(menu-item "--")) diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el index cc036492..33ae2a98 100644 --- a/lisp/ldg-sort.el +++ b/lisp/ldg-sort.el @@ -38,6 +38,36 @@ "Move point to end of transaction." (forward-paragraph)) +(defun ledger-sort-find-start () + (if (re-search-forward ";.*Ledger-mode:.*Start sort" nil t) + (match-end 0))) + +(defun ledger-sort-find-end () + (if (re-search-forward ";.*Ledger-mode:.*End sort" nil t) + (match-end 0))) + +(defun ledger-sort-insert-start-mark () + (interactive) + (let (has-old-marker) + (save-excursion + (goto-char (point-min)) + (setq has-old-marker (ledger-sort-find-start)) + (if has-old-marker + (delete-region (match-beginning 0) (match-end 0)))) + (beginning-of-line) + (insert "\n; Ledger-mode: Start sort\n\n"))) + +(defun ledger-sort-insert-end-mark () + (interactive) + (let (has-old-marker) + (save-excursion + (goto-char (point-min)) + (setq has-old-marker (ledger-sort-find-end)) + (if has-old-marker + (delete-region (match-beginning 0) (match-end 0)))) + (beginning-of-line) + (insert "\n; Ledger-mode: End sort\n\n"))) + (defun ledger-sort-region (beg end) "Sort the region from BEG to END in chronological order." (interactive "r") ;; load beg and end from point and mark @@ -66,14 +96,15 @@ (defun ledger-sort-buffer () "Sort the entire buffer." (interactive) - (let ((sort-start (point-min)) - (sort-end (point-max))) - (goto-char (point-min)) - (if (re-search-forward ";.*Ledger-mode:.*Start sort" nil t) - (set 'sort-start (match-end 0))) - (if (re-search-forward ";.*Ledger-mode:.*End sort" nil t) - (set 'sort-end (match-end 0))) - (ledger-sort-region sort-start sort-end))) + (goto-char (point-min)) + (let ((sort-start (ledger-sort-find-start)) + (sort-end (ledger-sort-find-end))) + (ledger-sort-region (if sort-start + sort-start + (point-min)) + (if sort-end + sort-end + (point-max))))) (provide 'ldg-sort) -- cgit v1.2.3 From 1eba7c6cdf4ac334a5b8580e4f18102db26b8c5f Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 6 Mar 2013 14:36:31 -0500 Subject: Code formatting cleanup. --- lisp/ldg-occur.el | 4 +++- lisp/ldg-reconcile.el | 1 - lisp/ldg-regex.el | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index 1561d6f8..f14aeeda 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -41,7 +41,9 @@ (make-variable-buffer-local 'ledger-occur-use-face-unfolded) -(defvar ledger-occur-mode nil) ;; name of the minor mode, shown in the mode-line +(defvar ledger-occur-mode nil +"name of the minor mode, shown in the mode-line") + (make-variable-buffer-local 'ledger-occur-mode) (or (assq 'ledger-occur-mode minor-mode-alist) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index e45ab7c3..fd452004 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -443,6 +443,5 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (use-local-map map))) (provide 'ldg-reconcile) -(provide 'ldg-reconcile) ;;; ldg-reconcile.el ends here diff --git a/lisp/ldg-regex.el b/lisp/ldg-regex.el index e81394ef..97fd6e2c 100644 --- a/lisp/ldg-regex.el +++ b/lisp/ldg-regex.el @@ -24,7 +24,8 @@ (eval-when-compile (require 'cl)) -(defvar ledger-date-regex "\\([0-9]+\\)[/-]\\([0-9]+\\)[/-]\\([0-9]+\\)") +(defvar ledger-date-regex + "\\([0-9]+\\)[/-]\\([0-9]+\\)[/-]\\([0-9]+\\)") (defmacro ledger-define-regexp (name regex docs &rest args) "Simplify the creation of a Ledger regex and helper functions." -- cgit v1.2.3 From 7579ebb34dbd53309b7069c23fc7812a261aea97 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 6 Mar 2013 14:44:22 -0500 Subject: Added missing lisp files to CMakeList.txt --- lisp/CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lisp/CMakeLists.txt b/lisp/CMakeLists.txt index 949171b3..5341f67a 100644 --- a/lisp/CMakeLists.txt +++ b/lisp/CMakeLists.txt @@ -1,19 +1,21 @@ set(EMACS_LISP_SOURCES + ldg-commodities.el ldg-complete.el ldg-exec.el + ldg-fonts.el ldg-mode.el ldg-new.el + ldg-occur.el ldg-post.el ldg-reconcile.el ldg-regex.el ldg-register.el ldg-report.el + ldg-sort.el ldg-state.el ldg-test.el ldg-texi.el - ldg-xact.el - ledger.el - timeclock.el) + ldg-xact.el) # find emacs and complain if not found find_program(EMACS_EXECUTABLE emacs) -- cgit v1.2.3 From 63653f50d5e05d07a65bb906d0afa77f22a6084e Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 6 Mar 2013 15:23:46 -0500 Subject: Correct bug is edit amount. Edit-amount was still looking for decimal-comma --- doc/ledger-mode.texi | 2 +- lisp/ldg-post.el | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index e13610bc..001eb054 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -323,7 +323,7 @@ at point. @node Hiding Transactions, , Sorting Transactions, The Ledger Buffer @section Hiding Transactions -Often you will want to run Ledger register reports just to look at a +Often you will want to run Ledger register reports just to look at ax specific set of transactions. If you don't need the running total calculation handled by Ledger, Ledger-mode provides a rapid way of narrowing what is displayed in the buffer in a way that is simpler than diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 6cba305b..e794f071 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -186,19 +186,10 @@ BEG, END, and LEN control how far it can align." (let ((end-of-amount (re-search-forward "[-.,0-9]+" (line-end-position) t))) ;; determine if there is an amount to edit (if end-of-amount - (let ((val (match-string 0))) + (let ((val (ledger-commodity-string-number-decimalize (match-string 0) :from-user))) (goto-char (match-beginning 0)) (delete-region (match-beginning 0) (match-end 0)) (calc) - (if ledger-use-decimal-comma - (progn - (while (string-match "\\." val) - (setq val (replace-match "" nil nil val))) ;; gets rid of periods - (while (string-match "," val) - (setq val (replace-match "." nil nil val)))) ;; switch to period separator - (progn - (while (string-match "," val) - (setq val (replace-match "" nil nil val))))) ;; gets rid of commas (calc-eval val 'push)) ;; edit the amount (progn ;;make sure there are two spaces after the account name and go to calc (if (search-backward " " (- (point) 3) t) -- cgit v1.2.3 From 81eeb210e8e2b33077624fd9d0fd3ef63837701a Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 6 Mar 2013 16:57:07 -0500 Subject: Improved context regex to handles @ and @@ pricing --- lisp/ldg-report.el | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index ef088f17..8d91d9d4 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -432,11 +432,13 @@ Optional EDIT the command." ("^\\(\\([0-9][0-9][0-9][0-9]/\\)?[01]?[0-9]/[0123]?[0-9]\\)[ \t]+\\(\\([!*]\\)[ \t]\\)?[ \t]*\\((\\(.*\\))\\)?[ \t]*\\(.*\\)[ \t]*$" (date nil status nil nil code payee)))) (acct-transaction - (("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\([$€£]\\s-?\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" + (("^\\([ \t]+;\\|;\\)\\s-?\\(.*\\)" + (indent comment)) + ("\\(^[ \t]+\\)\\([:A-Za-z0-9]+?\\)\\s-\\s-+\\([$€£]\\s-?\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)$" + (indent account commodity amount)) + ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\([$€£]\\s-?\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" (indent account commodity amount nil comment)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\([$€£]\\s-?\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*$" - (indent account commodity amount nil)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\(-?[0-9]+\\(\\.[0-9]*\\)?\\)[ \t]+\\(.*?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" + ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\(-?[0-9]+\\(\\.[0-9]*\\)?\\)[ \t]+\\(.*?\\)[ \t]*\\(;[ \t]*\\(.*?\\)[ \t]*$\\|@+\\)" (indent account amount nil commodity comment)) ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\(-?[0-9]+\\(\\.[0-9]*\\)?\\)[ \t]+\\(.*?\\)[ \t]*$" (indent account amount nil commodity)) @@ -447,7 +449,13 @@ Optional EDIT the command." ("\\(^[ \t]+\\)\\(.*?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" (indent account comment)) ("\\(^[ \t]+\\)\\(.*?\\)[ \t]*$" - (indent account)))))) + (indent account)) + +;; Bad regexes + ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\([$€£]\\s-?\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*$" + (indent account commodity amount nil)) + + )))) (defun ledger-extract-context-info (line-type pos) "Get context info for current line with LINE-TYPE. -- cgit v1.2.3 From 27d27ecb6c5be3a9523fd4efc895b6d0b2a6cfb4 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 6 Mar 2013 21:13:06 -0500 Subject: Account auto formatting now works with tab completion --- lisp/ldg-complete.el | 11 ++++++----- lisp/ldg-post.el | 13 +++++++++---- lisp/ldg-reconcile.el | 2 +- lisp/ldg-xact.el | 3 --- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index 3686d0fd..6607d372 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -145,16 +145,17 @@ Return tree structure" "Completes a transaction if there is another matching payee in the buffer. Does not use ledger xact" (interactive) - (let ((name (caar (ledger-parse-arguments))) - rest-of-name + (let* ((name (caar (ledger-parse-arguments))) + (rest-of-name name) xacts) (save-excursion (when (eq 'transaction (ledger-thing-at-point)) + (delete-region (point) (+ (length name) (point))) ;; Search backward for a matching payee (when (re-search-backward - (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" - (regexp-quote name) ) nil t) ;; "\\(\t\\|\n\\| [ \t]\\)" - (setq rest-of-name (buffer-substring-no-properties (match-end 0) (line-end-position))) + (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+\\(.*" + (regexp-quote name) ".*\\)" ) nil t) ;; "\\(\t\\|\n\\| [ \t]\\)" + (setq rest-of-name (match-string 3)) ;; Start copying the postings (forward-line) (while (looking-at "^\\s-+") diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index e794f071..d68d7f16 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -133,10 +133,15 @@ the account" (setq column ledger-post-amount-alignment-column)) (save-excursion ;; Position the account - ;; (beginning-of-line) - (set-mark (point)) - ;; (delete-horizontal-space) - ;; (insert ledger-default-acct-transaction-indent) + (if (not + (and (looking-at "[ \t]+\n") + (looking-back "[ \n]" (- (point) 2)))) + (progn + (beginning-of-line) + (set-mark (point)) + (delete-horizontal-space) + (insert ledger-default-acct-transaction-indent)) + (set-mark (point))) (goto-char (1+ (line-end-position))) (let* ((mark-first (< (mark) (point))) (begin (if mark-first (mark) (point))) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index fd452004..7b3df459 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -397,7 +397,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (defvar ledger-reconcile-mode-abbrev-table) (defun ledger-reconcile-change-target () - "Change the traget amount for the reconciliation process." + "Change the target amount for the reconciliation process." (interactive) (setq ledger-target (ledger-read-commodity-string "Set reconciliation target"))) diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index 8db50df2..ecd87127 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -118,9 +118,6 @@ within the transaction." (replace-match date) (re-search-forward "[1-9][0-9]+\.[0-9]+"))) - - -(provide 'ldg-xact) (provide 'ldg-xact) ;;; ldg-xact.el ends here -- cgit v1.2.3 From b475e569c4c4cb97d32e76de4d85d0810c9cc462 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 7 Mar 2013 15:28:09 -0500 Subject: Made account formatting and auto complete compatible. --- lisp/ldg-new.el | 1 + lisp/ldg-post.el | 38 +++++++++++++----------- lisp/ldg-reconcile.el | 16 +++++------ lisp/ldg-state.el | 80 +++++++++++++++++++++++++++------------------------ 4 files changed, 72 insertions(+), 63 deletions(-) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index 7a2961f7..4cebbba7 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -32,6 +32,7 @@ ;;; Commentary: ;; Load up the ledger mode +(require 'esh-util) (require 'esh-arg) (require 'ldg-commodities) (require 'ldg-complete) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index d68d7f16..87922dd1 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -36,11 +36,16 @@ "Options for controlling how Ledger-mode deals with postings and completion" :group 'ledger) -(defcustom ledger-post-auto-adjust-amounts nil - "If non-nil, ." +(defcustom ledger-post-auto-adjust-postings nil + "If non-nil, adjust account and amount to columns set below" :type 'boolean :group 'ledger-post) +(defcustom ledger-post-account-alignment-column 4 + "The column Ledger-mode attempts to align accounts to." + :type 'integer + :group 'ledger-post) + (defcustom ledger-post-amount-alignment-column 52 "The column Ledger-mode attempts to align amounts to." :type 'integer @@ -123,25 +128,25 @@ PROMPT is a string to prompt with. CHOICES is a list of (- (or (match-end 4) (match-end 3)) (point)))) -(defun ledger-align-amounts (&optional column) +(defun ledger-post-align-postings (&optional column) "Align amounts and accounts in the current region. This is done so that the last digit falls in COLUMN, which -defaults to 52. ledger-default-acct-transaction-indent positions +defaults to 52. ledger-post-account-column positions the account" (interactive "p") (if (or (null column) (= column 1)) (setq column ledger-post-amount-alignment-column)) (save-excursion ;; Position the account - (if (not - (and (looking-at "[ \t]+\n") - (looking-back "[ \n]" (- (point) 2)))) - (progn + (if (not (and (looking-at "[ \t]+\n") + (looking-back "[ \n]" (- (point) 2)))) + (save-excursion (beginning-of-line) - (set-mark (point)) - (delete-horizontal-space) - (insert ledger-default-acct-transaction-indent)) + (set-mark (point)) + (delete-horizontal-space) + (insert (make-string ledger-post-account-alignment-column ? ))) (set-mark (point))) + (set-mark (point)) (goto-char (1+ (line-end-position))) (let* ((mark-first (< (mark) (point))) (begin (if mark-first (mark) (point))) @@ -153,7 +158,7 @@ the account" (let ((col (current-column)) (target-col (- column offset)) adjust) - (setq adjust (- target-col col)) + (setq adjust (- target-col col)) (if (< col target-col) (insert (make-string (- target-col col) ? )) (move-to-column target-col) @@ -164,13 +169,13 @@ the account" (insert " "))) (forward-line)))))) -(defun ledger-post-align-amount () +(defun ledger-post-align-posting () "Align the amounts in this posting." (interactive) (save-excursion (set-mark (line-beginning-position)) (goto-char (1+ (line-end-position))) - (ledger-align-amounts))) + (ledger-post-align-postings))) (defun ledger-post-maybe-align (beg end len) "Align amounts only if point is in a posting. @@ -180,7 +185,7 @@ BEG, END, and LEN control how far it can align." (when (<= end (line-end-position)) (goto-char (line-beginning-position)) (if (looking-at ledger-post-line-regexp) - (ledger-align-amounts))))) + (ledger-post-align-postings))))) (defun ledger-post-edit-amount () "Call 'calc-mode' and push the amount in the posting to the top of stack." @@ -221,8 +226,7 @@ BEG, END, and LEN control how far it can align." (defun ledger-post-setup () "Configure `ledger-mode' to auto-align postings." - (if ledger-post-auto-adjust-amounts - (add-hook 'after-change-functions 'ledger-post-maybe-align t t)) + (add-hook 'after-change-functions 'ledger-post-maybe-align t t) (add-hook 'after-save-hook #'(lambda () (setq ledger-post-current-list nil)))) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 7b3df459..6ede6b51 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -70,20 +70,20 @@ reconcile-finish will mark all pending posting cleared." (account ledger-acct) (val nil)) (with-temp-buffer + ;; note that in the line below, the --format option is + ;; separated from the actual format string. emacs does not + ;; split arguments like the shell does, so you need to + ;; specify the individual fields in the command line. (ledger-exec-ledger buffer (current-buffer) - ; note that in the line below, the --format option is - ; separated from the actual format string. emacs does not - ; split arguments like the shell does, so you need to - ; specify the individual fields in the command line. "balance" "--limit" "cleared or pending" "--empty" "--format" "%(display_total)" account) - (setq val + (setq val (ledger-split-commodity-string (buffer-substring-no-properties (point-min) (point-max))))))) (defun ledger-display-balance () - "Display the cleared-or-pending balnce and calculate the -target-delta of the account being reconciled." + "Display the cleared-or-pending balance. +And calculate the target-delta of the account being reconciled." (interactive) (let* ((pending (ledger-reconcile-get-cleared-or-pending-balance)) (target-delta (if ledger-target @@ -111,7 +111,7 @@ target-delta of the account being reconciled." "Return a buffer from WHERE the transaction is." (if (bufferp (car where)) (car where) - (error "ledger-reconcile-get-buffer: Buffer not set"))) + (error "Function ledger-reconcile-get-buffer: Buffer not set"))) (defun ledger-reconcile-toggle () "Toggle the current transaction, and mark the recon window." diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index b2247afe..dd5e42ad 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -122,42 +122,48 @@ dropped." ;;this excursion toggles the posting status (save-excursion - (goto-char (line-beginning-position)) - (when (looking-at "[ \t]") - (skip-chars-forward " \t") - (let ((here (point)) - (cur-status (ledger-state-from-char (char-after)))) - (skip-chars-forward "*! ") - (let ((width (- (point) here))) - (when (> width 0) - (delete-region here (point)) - (save-excursion - (if (search-forward " " (line-end-position) t) - (insert (make-string width ? )))))) - (let (inserted) - (if cur-status - (if (and style (eq style 'cleared)) - (progn - (insert "* ") - (setq inserted 'cleared))) - (if (and style (eq style 'pending)) - (progn - (insert "! ") - (setq inserted 'pending)) - (progn - (insert "* ") - (setq inserted 'cleared)))) - (if (and inserted - (re-search-forward "\\(\t\\| [ \t]\\)" - (line-end-position) t)) - (cond - ((looking-at "\t") - (delete-char 1)) - ((looking-at " [ \t]") - (delete-char 2)) - ((looking-at " ") - (delete-char 1)))) - (setq new-status inserted))))) + (let ((has-align-hook (remove-hook + 'after-change-functions + 'ledger-post-maybe-align t))) + + (goto-char (line-beginning-position)) + (when (looking-at "[ \t]") + (skip-chars-forward " \t") + (let ((here (point)) + (cur-status (ledger-state-from-char (char-after)))) + (skip-chars-forward "*! ") + (let ((width (- (point) here))) + (when (> width 0) + (delete-region here (point)) + (save-excursion + (if (search-forward " " (line-end-position) t) + (insert (make-string width ? )))))) + (let (inserted) + (if cur-status + (if (and style (eq style 'cleared)) + (progn + (insert "* ") + (setq inserted 'cleared))) + (if (and style (eq style 'pending)) + (progn + (insert "! ") + (setq inserted 'pending)) + (progn + (insert "* ") + (setq inserted 'cleared)))) + (if (and inserted + (re-search-forward "\\(\t\\| [ \t]\\)" + (line-end-position) t)) + (cond + ((looking-at "\t") + (delete-char 1)) + ((looking-at " [ \t]") + (delete-char 2)) + ((looking-at " ") + (delete-char 1)))) + (setq new-status inserted)))) + (if has-align-hook + (add-hook 'after-change-functions 'ledger-post-maybe-align t t)))) ;; This excursion cleans up the entry so that it displays ;; minimally. This means that if all posts are cleared, remove @@ -254,6 +260,4 @@ dropped." (provide 'ldg-state) -(provide 'ldg-state) - ;;; ldg-state.el ends here -- cgit v1.2.3 From 7758100df9152bab243d9531518af76acdbc7287 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 7 Mar 2013 16:08:07 -0500 Subject: Caught another omission in the built list --- lisp/CMakeLists.txt | 1 + lisp/ldg-new.el | 1 + 2 files changed, 2 insertions(+) diff --git a/lisp/CMakeLists.txt b/lisp/CMakeLists.txt index 5341f67a..32a31001 100644 --- a/lisp/CMakeLists.txt +++ b/lisp/CMakeLists.txt @@ -3,6 +3,7 @@ set(EMACS_LISP_SOURCES ldg-complete.el ldg-exec.el ldg-fonts.el + ldg-init.el ldg-mode.el ldg-new.el ldg-occur.el diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index 4cebbba7..f888fd6c 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -43,6 +43,7 @@ (require 'ldg-occur) (require 'ldg-post) (require 'ldg-reconcile) +(require 'ldg-regex) (require 'ldg-register) (require 'ldg-report) (require 'ldg-sort) -- cgit v1.2.3 From 37ddc5f5888197782e7e3449b3e29a0285d9ad61 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 7 Mar 2013 16:11:55 -0500 Subject: Deprecated ledger.el --- lisp/ledger.el | 1340 -------------------------------------------------------- 1 file changed, 1340 deletions(-) delete mode 100644 lisp/ledger.el diff --git a/lisp/ledger.el b/lisp/ledger.el deleted file mode 100644 index 4fc21d6a..00000000 --- a/lisp/ledger.el +++ /dev/null @@ -1,1340 +0,0 @@ -;;; ledger.el --- Helper code for use with the "ledger" command-line tool - -;; Copyright (C) 2003-2009 John Wiegley (johnw AT gnu DOT org) - -;; Emacs Lisp Archive Entry -;; Filename: ledger.el -;; Version: 2.6.3 -;; Date: Fri 18-Jul-2008 -;; Keywords: data -;; Author: John Wiegley (johnw AT gnu DOT org) -;; Maintainer: John Wiegley (johnw AT gnu DOT org) -;; Description: Helper code for using my "ledger" command-line tool -;; URL: http://www.newartisans.com/johnw/emacs.html -;; Compatibility: Emacs22 - -;; This file is not part of GNU Emacs. - -;; This is free software; you can redistribute it and/or modify it under -;; the terms of the GNU General Public License as published by the Free -;; Software Foundation; either version 2, or (at your option) any later -;; version. -;; -;; This is distributed in the hope that it will be useful, but WITHOUT -;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -;; for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. - -;;; Commentary: - -;; To use this module: Load this file, open a ledger data file, and -;; type M-x ledger-mode. Once this is done, you can type: -;; -;; C-c C-a add a new entry, based on previous entries -;; C-c C-e toggle cleared status of an entry -;; C-c C-y set default year for entry mode -;; C-c C-m set default month for entry mode -;; C-c C-r reconcile uncleared entries related to an account -;; C-c C-o C-r run a ledger report -;; C-C C-o C-g goto the ledger report buffer -;; C-c C-o C-e edit the defined ledger reports -;; C-c C-o C-s save a report definition based on the current report -;; C-c C-o C-a rerun a ledger report -;; C-c C-o C-k kill the ledger report buffer -;; -;; In the reconcile buffer, use SPACE to toggle the cleared status of -;; a transaction, C-x C-s to save changes (to the ledger file as -;; well). -;; -;; The ledger reports command asks the user to select a report to run -;; then creates a report buffer containing the results of running the -;; associated command line. Its' behavior is modified by a prefix -;; argument which, when given, causes the generated command line that -;; will be used to create the report to be presented for editing -;; before the report is actually run. Arbitrary unnamed command lines -;; can be run by specifying an empty name for the report. The command -;; line used can later be named and saved for future use as a named -;; report from the generated reports buffer. -;; -;; In a report buffer, the following keys are available: -;; (space) scroll up -;; e edit the defined ledger reports -;; s save a report definition based on the current report -;; q quit the report (return to ledger buffer) -;; r redo the report -;; k kill the report buffer - -(require 'esh-util) -(require 'esh-arg) -(require 'pcomplete) - -(defvar ledger-version "1.3" - "The version of ledger.el currently loaded") - -(defgroup ledger nil - "Interface to the Ledger command-line accounting program." - :group 'data) - -(defcustom ledger-binary-path "ledger" - "Path to the ledger executable." - :type 'file - :group 'ledger) - -(defcustom ledger-clear-whole-entries nil - "If non-nil, clear whole entries, not individual transactions." - :type 'boolean - :group 'ledger) - -(defcustom ledger-reports - '(("bal" "ledger -f %(ledger-file) bal") - ("reg" "ledger -f %(ledger-file) reg") - ("payee" "ledger -f %(ledger-file) reg -- %(payee)") - ("account" "ledger -f %(ledger-file) reg %(account)")) - "Definition of reports to run. - -Each element has the form (NAME CMDLINE). The command line can -contain format specifiers that are replaced with context sensitive -information. Format specifiers have the format '%(<name>)' where -<name> is an identifier for the information to be replaced. The -`ledger-report-format-specifiers' alist variable contains a mapping -from format specifier identifier to a lisp function that implements -the substitution. See the documentation of the individual functions -in that variable for more information on the behavior of each -specifier." - :type '(repeat (list (string :tag "Report Name") - (string :tag "Command Line"))) - :group 'ledger) - -(defcustom ledger-report-format-specifiers - '(("ledger-file" . ledger-report-ledger-file-format-specifier) - ("payee" . ledger-report-payee-format-specifier) - ("account" . ledger-report-account-format-specifier)) - "Alist mapping ledger report format specifiers to implementing functions - -The function is called with no parameters and expected to return the -text that should replace the format specifier." - :type 'alist - :group 'ledger) - -(defcustom ledger-default-acct-transaction-indent " " - "Default indentation for account transactions in an entry." - :type 'string - :group 'ledger) - -(defvar bold 'bold) -(defvar ledger-font-lock-keywords - '(("\\( \\| \\|^\\)\\(;.*\\)" 2 font-lock-comment-face) - ("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 bold) - ;;("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" - ;; 2 font-lock-type-face) - ("^\\s-+\\([*]\\s-*\\)?\\(\\([[(]\\)?\\([^*;]\\)+?\\(:\\|\\s-\\)[^]); - ]+?\\([])]\\)?\\)\\( \\| \\|$\\)" - 2 font-lock-keyword-face) - ("^\\([~=].+\\)" 1 font-lock-function-name-face) - ("^\\([A-Za-z]+ .+\\)" 1 font-lock-function-name-face)) - "Expressions to highlight in Ledger mode.") - -(defsubst ledger-current-year () - (format-time-string "%Y")) -(defsubst ledger-current-month () - (format-time-string "%m")) - -(defvar ledger-year (ledger-current-year) - "Start a ledger session with the current year, but make it -customizable to ease retro-entry.") -(defvar ledger-month (ledger-current-month) - "Start a ledger session with the current month, but make it -customizable to ease retro-entry.") - -(defun ledger-iterate-entries (callback) - (goto-char (point-min)) - (let* ((now (current-time)) - (current-year (nth 5 (decode-time now)))) - (while (not (eobp)) - (when (looking-at - (concat "\\(Y\\s-+\\([0-9]+\\)\\|" - "\\([0-9]\\{4\\}+\\)?[./]?" - "\\([0-9]+\\)[./]\\([0-9]+\\)\\s-+" - "\\(\\*\\s-+\\)?\\(.+\\)\\)")) - (let ((found (match-string 2))) - (if found - (setq current-year (string-to-number found)) - (let ((start (match-beginning 0)) - (year (match-string 3)) - (month (string-to-number (match-string 4))) - (day (string-to-number (match-string 5))) - (mark (match-string 6)) - (desc (match-string 7))) - (if (and year (> (length year) 0)) - (setq year (string-to-number year))) - (funcall callback start - (encode-time 0 0 0 day month - (or year current-year)) - mark desc))))) - (forward-line)))) - -(defun ledger-time-less-p (t1 t2) - "Say whether time value T1 is less than time value T2." - (or (< (car t1) (car t2)) - (and (= (car t1) (car t2)) - (< (nth 1 t1) (nth 1 t2))))) - -(defun ledger-time-subtract (t1 t2) - "Subtract two time values. -Return the difference in the format of a time value." - (let ((borrow (< (cadr t1) (cadr t2)))) - (list (- (car t1) (car t2) (if borrow 1 0)) - (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2))))) - -(defun ledger-find-slot (moment) - (catch 'found - (ledger-iterate-entries - (function - (lambda (start date mark desc) - (if (ledger-time-less-p moment date) - (throw 'found t))))))) - -(defun ledger-add-entry (entry-text &optional insert-at-point) - (interactive - (list - (read-string "Entry: " (concat ledger-year "/" ledger-month "/")))) - (let* ((args (with-temp-buffer - (insert entry-text) - (eshell-parse-arguments (point-min) (point-max)))) - (ledger-buf (current-buffer)) - exit-code) - (unless insert-at-point - (let ((date (car args))) - (if (string-match "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)" date) - (setq date - (encode-time 0 0 0 (string-to-number (match-string 3 date)) - (string-to-number (match-string 2 date)) - (string-to-number (match-string 1 date))))) - (ledger-find-slot date))) - (save-excursion - (insert - (with-temp-buffer - (setq exit-code - (apply #'ledger-run-ledger ledger-buf "entry" - (mapcar 'eval args))) - (goto-char (point-min)) - (if (looking-at "Error: ") - (error (buffer-string)) - (buffer-string))) - "\n")))) - -(defun ledger-current-entry-bounds () - (save-excursion - (when (or (looking-at "^[0-9]") - (re-search-backward "^[0-9]" nil t)) - (let ((beg (point))) - (while (not (eolp)) - (forward-line)) - (cons (copy-marker beg) (point-marker)))))) - -(defun ledger-delete-current-entry () - (interactive) - (let ((bounds (ledger-current-entry-bounds))) - (delete-region (car bounds) (cdr bounds)))) - -(defun ledger-toggle-current-entry (&optional style) - (interactive) - (let (clear) - (save-excursion - (when (or (looking-at "^[0-9]") - (re-search-backward "^[0-9]" nil t)) - (skip-chars-forward "0-9./=") - (delete-horizontal-space) - (if (member (char-after) '(?\* ?\!)) - (progn - (delete-char 1) - (if (and style (eq style 'cleared)) - (insert " *"))) - (if (and style (eq style 'pending)) - (insert " ! ") - (insert " * ")) - (setq clear t)))) - clear)) - -(defun ledger-move-to-next-field () - (re-search-forward "\\( \\|\t\\)" (line-end-position) t)) - -(defun ledger-toggle-state (state &optional style) - (if (not (null state)) - (if (and style (eq style 'cleared)) - 'cleared) - (if (and style (eq style 'pending)) - 'pending - 'cleared))) - -(defun ledger-entry-state () - (save-excursion - (when (or (looking-at "^[0-9]") - (re-search-backward "^[0-9]" nil t)) - (skip-chars-forward "0-9./=") - (skip-syntax-forward " ") - (cond ((looking-at "!\\s-*") 'pending) - ((looking-at "\\*\\s-*") 'cleared) - (t nil))))) - -(defun ledger-transaction-state () - (save-excursion - (goto-char (line-beginning-position)) - (skip-syntax-forward " ") - (cond ((looking-at "!\\s-*") 'pending) - ((looking-at "\\*\\s-*") 'cleared) - (t (ledger-entry-state))))) - -(defun ledger-toggle-current-transaction (&optional style) - "Toggle the cleared status of the transaction under point. -Optional argument STYLE may be `pending' or `cleared', depending -on which type of status the caller wishes to indicate (default is -`cleared'). -This function is rather complicated because it must preserve both -the overall formatting of the ledger entry, as well as ensuring -that the most minimal display format is used. This could be -achieved more certainly by passing the entry to ledger for -formatting, but doing so causes inline math expressions to be -dropped." - (interactive) - (let ((bounds (ledger-current-entry-bounds)) - clear cleared) - ;; Uncompact the entry, to make it easier to toggle the - ;; transaction - (save-excursion - (goto-char (car bounds)) - (skip-chars-forward "0-9./= \t") - (setq cleared (and (member (char-after) '(?\* ?\!)) - (char-after))) - (when cleared - (let ((here (point))) - (skip-chars-forward "*! ") - (let ((width (- (point) here))) - (when (> width 0) - (delete-region here (point)) - (if (search-forward " " (line-end-position) t) - (insert (make-string width ? )))))) - (forward-line) - (while (looking-at "[ \t]") - (skip-chars-forward " \t") - (insert cleared " ") - (if (search-forward " " (line-end-position) t) - (delete-char 2)) - (forward-line)))) - ;; Toggle the individual transaction - (save-excursion - (goto-char (line-beginning-position)) - (when (looking-at "[ \t]") - (skip-chars-forward " \t") - (let ((here (point)) - (cleared (member (char-after) '(?\* ?\!)))) - (skip-chars-forward "*! ") - (let ((width (- (point) here))) - (when (> width 0) - (delete-region here (point)) - (save-excursion - (if (search-forward " " (line-end-position) t) - (insert (make-string width ? )))))) - (let (inserted) - (if cleared - (if (and style (eq style 'cleared)) - (progn - (insert "* ") - (setq inserted t))) - (if (and style (eq style 'pending)) - (progn - (insert "! ") - (setq inserted t)) - (progn - (insert "* ") - (setq inserted t)))) - (if (and inserted - (re-search-forward "\\(\t\\| [ \t]\\)" - (line-end-position) t)) - (cond - ((looking-at "\t") - (delete-char 1)) - ((looking-at " [ \t]") - (delete-char 2)) - ((looking-at " ") - (delete-char 1)))) - (setq clear inserted))))) - ;; Clean up the entry so that it displays minimally - (save-excursion - (goto-char (car bounds)) - (forward-line) - (let ((first t) - (state ? ) - (hetero nil)) - (while (and (not hetero) (looking-at "[ \t]")) - (skip-chars-forward " \t") - (let ((cleared (if (member (char-after) '(?\* ?\!)) - (char-after) - ? ))) - (if first - (setq state cleared - first nil) - (if (/= state cleared) - (setq hetero t)))) - (forward-line)) - (when (and (not hetero) (/= state ? )) - (goto-char (car bounds)) - (forward-line) - (while (looking-at "[ \t]") - (skip-chars-forward " \t") - (let ((here (point))) - (skip-chars-forward "*! ") - (let ((width (- (point) here))) - (when (> width 0) - (delete-region here (point)) - (if (re-search-forward "\\(\t\\| [ \t]\\)" - (line-end-position) t) - (insert (make-string width ? )))))) - (forward-line)) - (goto-char (car bounds)) - (skip-chars-forward "0-9./= \t") - (insert state " ") - (if (re-search-forward "\\(\t\\| [ \t]\\)" - (line-end-position) t) - (cond - ((looking-at "\t") - (delete-char 1)) - ((looking-at " [ \t]") - (delete-char 2)) - ((looking-at " ") - (delete-char 1))))))) - clear)) - -(defun ledger-toggle-current (&optional style) - (interactive) - (if (or ledger-clear-whole-entries - (eq 'entry (ledger-thing-at-point))) - (progn - (save-excursion - (forward-line) - (goto-char (line-beginning-position)) - (while (and (not (eolp)) - (save-excursion - (not (eq 'entry (ledger-thing-at-point))))) - (if (looking-at "\\s-+[*!]") - (ledger-toggle-current-transaction nil)) - (forward-line) - (goto-char (line-beginning-position)))) - (ledger-toggle-current-entry style)) - (ledger-toggle-current-transaction style))) - -(defvar ledger-mode-abbrev-table) - -;;;###autoload -(define-derived-mode ledger-mode text-mode "Ledger" - "A mode for editing ledger data files. - -\\{ledger-mode-map}" - (set (make-local-variable 'comment-start) " ; ") - (set (make-local-variable 'comment-end) "") - (set (make-local-variable 'indent-tabs-mode) nil) - - (if (boundp 'font-lock-defaults) - (set (make-local-variable 'font-lock-defaults) - '(ledger-font-lock-keywords nil t))) - - (set (make-local-variable 'pcomplete-parse-arguments-function) - 'ledger-parse-arguments) - (set (make-local-variable 'pcomplete-command-completion-function) - 'ledger-complete-at-point) - (set (make-local-variable 'pcomplete-termination-string) "") - - (let ((map (current-local-map))) - (define-key map [(control ?c) (control ?a)] 'ledger-add-entry) - (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-entry) - (define-key map [(control ?c) (control ?y)] 'ledger-set-year) - (define-key map [(control ?c) (control ?m)] 'ledger-set-month) - (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) - (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-entry) - (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) - (define-key map [(control ?c) (control ?s)] 'ledger-sort) - (define-key map [tab] 'pcomplete) - (define-key map [(control ?i)] 'pcomplete) - (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) - (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry) - (define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report) - (define-key map [(control ?c) (control ?o) (control ?g)] 'ledger-report-goto) - (define-key map [(control ?c) (control ?o) (control ?a)] 'ledger-report-redo) - (define-key map [(control ?c) (control ?o) (control ?s)] 'ledger-report-save) - (define-key map [(control ?c) (control ?o) (control ?e)] 'ledger-report-edit) - (define-key map [(control ?c) (control ?o) (control ?k)] 'ledger-report-kill))) - -;; Reconcile mode - -(defvar ledger-buf nil) -(defvar ledger-acct nil) - -(defun ledger-display-balance () - (let ((buffer ledger-buf) - (account ledger-acct)) - (with-temp-buffer - (let ((exit-code (ledger-run-ledger buffer "-C" "balance" account))) - (if (/= 0 exit-code) - (message "Error determining cleared balance") - (goto-char (1- (point-max))) - (goto-char (line-beginning-position)) - (delete-horizontal-space) - (message "Cleared balance = %s" - (buffer-substring-no-properties (point) - (line-end-position)))))))) - -(defun ledger-reconcile-toggle () - (interactive) - (let ((where (get-text-property (point) 'where)) - (account ledger-acct) - (inhibit-read-only t) - cleared) - (when (or (equal (car where) "<stdin>") (equal (car where) "/dev/stdin")) - (with-current-buffer ledger-buf - (goto-char (cdr where)) - (setq cleared (ledger-toggle-current 'pending))) - (if cleared - (add-text-properties (line-beginning-position) - (line-end-position) - (list 'face 'bold)) - (remove-text-properties (line-beginning-position) - (line-end-position) - (list 'face)))) - (forward-line))) - -(defun ledger-reconcile-refresh () - (interactive) - (let ((inhibit-read-only t) - (line (count-lines (point-min) (point)))) - (erase-buffer) - (ledger-do-reconcile) - (set-buffer-modified-p t) - (goto-char (point-min)) - (forward-line line))) - -(defun ledger-reconcile-refresh-after-save () - (let ((buf (get-buffer "*Reconcile*"))) - (if buf - (with-current-buffer buf - (ledger-reconcile-refresh) - (set-buffer-modified-p nil))))) - -(defun ledger-reconcile-add () - (interactive) - (with-current-buffer ledger-buf - (call-interactively #'ledger-add-entry)) - (ledger-reconcile-refresh)) - -(defun ledger-reconcile-delete () - (interactive) - (let ((where (get-text-property (point) 'where))) - (when (or (equal (car where) "<stdin>") (equal (car where) "/dev/stdin")) - (with-current-buffer ledger-buf - (goto-char (cdr where)) - (ledger-delete-current-entry)) - (let ((inhibit-read-only t)) - (goto-char (line-beginning-position)) - (delete-region (point) (1+ (line-end-position))) - (set-buffer-modified-p t))))) - -(defun ledger-reconcile-visit () - (interactive) - (let ((where (get-text-property (point) 'where))) - (when (markerp (cdr where)) - (switch-to-buffer-other-window ledger-buf) - (goto-char (cdr where))))) - -(defun ledger-reconcile-save () - (interactive) - (with-current-buffer ledger-buf - (save-buffer)) - (set-buffer-modified-p nil) - (ledger-display-balance)) - -(defun ledger-reconcile-quit () - (interactive) - (kill-buffer (current-buffer))) - -(defun ledger-reconcile-finish () - (interactive) - (save-excursion - (goto-char (point-min)) - (while (not (eobp)) - (let ((where (get-text-property (point) 'where)) - (face (get-text-property (point) 'face))) - (if (and (eq face 'bold) - (or (equal (car where) "<stdin>") - (equal (car where) "/dev/stdin"))) - (with-current-buffer ledger-buf - (goto-char (cdr where)) - (ledger-toggle-current 'cleared)))) - (forward-line 1))) - (ledger-reconcile-save)) - -(defun ledger-do-reconcile () - (let* ((buf ledger-buf) - (account ledger-acct) - (items - (with-temp-buffer - (let ((exit-code - (ledger-run-ledger buf "--uncleared" "--real" - "emacs" account))) - (when (= 0 exit-code) - (goto-char (point-min)) - (unless (eobp) - (unless (looking-at "(") - (error (buffer-string))) - (read (current-buffer)))))))) - (dolist (item items) - (let ((index 1)) - (dolist (xact (nthcdr 5 item)) - (let ((beg (point)) - (where - (with-current-buffer buf - (cons - (nth 0 item) - (if ledger-clear-whole-entries - (save-excursion - (goto-line (nth 1 item)) - (point-marker)) - (save-excursion - (goto-line (nth 0 xact)) - (point-marker))))))) - (insert (format "%s %-30s %-25s %15s\n" - (format-time-string "%m/%d" (nth 2 item)) - (nth 4 item) (nth 1 xact) (nth 2 xact))) - (if (nth 3 xact) - (set-text-properties beg (1- (point)) - (list 'face 'bold - 'where where)) - (set-text-properties beg (1- (point)) - (list 'where where)))) - (setq index (1+ index))))) - (goto-char (point-min)) - (set-buffer-modified-p nil) - (toggle-read-only t))) - -(defun ledger-reconcile (account) - (interactive "sAccount to reconcile: ") - (let ((buf (current-buffer)) - (rbuf (get-buffer "*Reconcile*"))) - (if rbuf - (kill-buffer rbuf)) - (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save) - (with-current-buffer - (pop-to-buffer (get-buffer-create "*Reconcile*")) - (ledger-reconcile-mode) - (set (make-local-variable 'ledger-buf) buf) - (set (make-local-variable 'ledger-acct) account) - (ledger-do-reconcile)))) - -(defvar ledger-reconcile-mode-abbrev-table) - -(defvar ledger-reconcile-mode-map - (let ((map (make-sparse-keymap))) - (define-key map [(control ?m)] 'ledger-reconcile-visit) - (define-key map [return] 'ledger-reconcile-visit) - (define-key map [(control ?c) (control ?c)] 'ledger-reconcile-finish) - (define-key map [(control ?x) (control ?s)] 'ledger-reconcile-save) - (define-key map [(control ?l)] 'ledger-reconcile-refresh) - (define-key map [? ] 'ledger-reconcile-toggle) - (define-key map [?a] 'ledger-reconcile-add) - (define-key map [?d] 'ledger-reconcile-delete) - (define-key map [?n] 'next-line) - (define-key map [?p] 'previous-line) - (define-key map [?s] 'ledger-reconcile-save) - (define-key map [?q] 'ledger-reconcile-quit) - map)) - -(define-derived-mode ledger-reconcile-mode text-mode "Reconcile" - "A mode for reconciling ledger entries. - -\\{ledger-reconcile-mode-map}") - -;; Context sensitivity - -(defconst ledger-line-config - '((entry - (("^\\(\\([0-9][0-9][0-9][0-9]/\\)?[01]?[0-9]/[0123]?[0-9]\\)[ \t]+\\(\\([!*]\\)[ \t]\\)?[ \t]*\\((\\(.*\\))\\)?[ \t]*\\(.*?\\)[ \t]*;\\(.*\\)[ \t]*$" - (date nil status nil nil code payee comment)) - ("^\\(\\([0-9][0-9][0-9][0-9]/\\)?[01]?[0-9]/[0123]?[0-9]\\)[ \t]+\\(\\([!*]\\)[ \t]\\)?[ \t]*\\((\\(.*\\))\\)?[ \t]*\\(.*\\)[ \t]*$" - (date nil status nil nil code payee)))) - (acct-transaction - (("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\([$]\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" - (indent account commodity amount nil comment)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\([$]\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*$" - (indent account commodity amount nil)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\(-?[0-9]+\\(\\.[0-9]*\\)?\\)[ \t]+\\(.*?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" - (indent account amount nil commodity comment)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\(-?[0-9]+\\(\\.[0-9]*\\)?\\)[ \t]+\\(.*?\\)[ \t]*$" - (indent account amount nil commodity)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\(-?\\(\\.[0-9]*\\)\\)[ \t]+\\(.*?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" - (indent account amount nil commodity comment)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\(-?\\(\\.[0-9]*\\)\\)[ \t]+\\(.*?\\)[ \t]*$" - (indent account amount nil commodity)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" - (indent account comment)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]*$" - (indent account)))))) - -(defun ledger-extract-context-info (line-type pos) - "Get context info for current line. - -Assumes point is at beginning of line, and the pos argument specifies -where the \"users\" point was." - (let ((linfo (assoc line-type ledger-line-config)) - found field fields) - (dolist (re-info (nth 1 linfo)) - (let ((re (nth 0 re-info)) - (names (nth 1 re-info))) - (unless found - (when (looking-at re) - (setq found t) - (dotimes (i (length names)) - (when (nth i names) - (setq fields (append fields - (list - (list (nth i names) - (match-string-no-properties (1+ i)) - (match-beginning (1+ i)))))))) - (dolist (f fields) - (and (nth 1 f) - (>= pos (nth 2 f)) - (setq field (nth 0 f)))))))) - (list line-type field fields))) - -(defun ledger-context-at-point () - "Return a list describing the context around point. - -The contents of the list are the line type, the name of the field -point containing point, and for selected line types, the content of -the fields in the line in a association list." - (let ((pos (point))) - (save-excursion - (beginning-of-line) - (let ((first-char (char-after))) - (cond ((equal (point) (line-end-position)) - '(empty-line nil nil)) - ((memq first-char '(?\ ?\t)) - (ledger-extract-context-info 'acct-transaction pos)) - ((memq first-char '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9)) - (ledger-extract-context-info 'entry pos)) - ((equal first-char ?\=) - '(automated-entry nil nil)) - ((equal first-char ?\~) - '(period-entry nil nil)) - ((equal first-char ?\!) - '(command-directive)) - ((equal first-char ?\;) - '(comment nil nil)) - ((equal first-char ?Y) - '(default-year nil nil)) - ((equal first-char ?P) - '(commodity-price nil nil)) - ((equal first-char ?N) - '(price-ignored-commodity nil nil)) - ((equal first-char ?D) - '(default-commodity nil nil)) - ((equal first-char ?C) - '(commodity-conversion nil nil)) - ((equal first-char ?i) - '(timeclock-i nil nil)) - ((equal first-char ?o) - '(timeclock-o nil nil)) - ((equal first-char ?b) - '(timeclock-b nil nil)) - ((equal first-char ?h) - '(timeclock-h nil nil)) - (t - '(unknown nil nil))))))) - -(defun ledger-context-other-line (offset) - "Return a list describing context of line offset for existing position. - -Offset can be positive or negative. If run out of buffer before reaching -specified line, returns nil." - (save-excursion - (let ((left (forward-line offset))) - (if (not (equal left 0)) - nil - (ledger-context-at-point))))) - -(defun ledger-context-line-type (context-info) - (nth 0 context-info)) - -(defun ledger-context-current-field (context-info) - (nth 1 context-info)) - -(defun ledger-context-field-info (context-info field-name) - (assoc field-name (nth 2 context-info))) - -(defun ledger-context-field-present-p (context-info field-name) - (not (null (ledger-context-field-info context-info field-name)))) - -(defun ledger-context-field-value (context-info field-name) - (nth 1 (ledger-context-field-info context-info field-name))) - -(defun ledger-context-field-position (context-info field-name) - (nth 2 (ledger-context-field-info context-info field-name))) - -(defun ledger-context-field-end-position (context-info field-name) - (+ (ledger-context-field-position context-info field-name) - (length (ledger-context-field-value context-info field-name)))) - -(defun ledger-context-goto-field-start (context-info field-name) - (goto-char (ledger-context-field-position context-info field-name))) - -(defun ledger-context-goto-field-end (context-info field-name) - (goto-char (ledger-context-field-end-position context-info field-name))) - -(defun ledger-entry-payee () - "Returns the payee of the entry containing point or nil." - (let ((i 0)) - (while (eq (ledger-context-line-type (ledger-context-other-line i)) 'acct-transaction) - (setq i (- i 1))) - (let ((context-info (ledger-context-other-line i))) - (if (eq (ledger-context-line-type context-info) 'entry) - (ledger-context-field-value context-info 'payee) - nil)))) - -;; Ledger report mode - -(defvar ledger-report-buffer-name "*Ledger Report*") - -(defvar ledger-report-name nil) -(defvar ledger-report-cmd nil) -(defvar ledger-report-name-prompt-history nil) -(defvar ledger-report-cmd-prompt-history nil) -(defvar ledger-original-window-cfg nil) - -(defvar ledger-report-mode-abbrev-table) - -(defvar ledger-report-mode-map - (let ((map (make-sparse-keymap))) - (define-key map [? ] 'scroll-up) - (define-key map [backspace] 'scroll-down) - (define-key map [?r] 'ledger-report-redo) - (define-key map [?s] 'ledger-report-save) - (define-key map [?k] 'ledger-report-kill) - (define-key map [?e] 'ledger-report-edit) - (define-key map [?q] 'ledger-report-quit) - (define-key map [(control ?c) (control ?l) (control ?r)] - 'ledger-report-redo) - (define-key map [(control ?c) (control ?l) (control ?S)] - 'ledger-report-save) - (define-key map [(control ?c) (control ?l) (control ?k)] - 'ledger-report-kill) - (define-key map [(control ?c) (control ?l) (control ?e)] - 'ledger-report-edit) - map)) - -(define-derived-mode ledger-report-mode text-mode "Ledger-Report" - "A mode for viewing ledger reports.") - -(defun ledger-report-read-name () - "Read the name of a ledger report to use, with completion. - -The empty string and unknown names are allowed." - (completing-read "Report name: " - ledger-reports nil nil nil - 'ledger-report-name-prompt-history nil)) - -(defun ledger-report (report-name edit) - "Run a user-specified report from `ledger-reports'. - -Prompts the user for the name of the report to run. If no name is -entered, the user will be prompted for a command line to run. The -command line specified or associated with the selected report name -is run and the output is made available in another buffer for viewing. -If a prefix argument is given and the user selects a valid report -name, the user is prompted with the corresponding command line for -editing before the command is run. - -The output buffer will be in `ledger-report-mode', which defines -commands for saving a new named report based on the command line -used to generate the buffer, navigating the buffer, etc." - (interactive - (progn - (when (and (buffer-modified-p) - (y-or-n-p "Buffer modified, save it? ")) - (save-buffer)) - (let ((rname (ledger-report-read-name)) - (edit (not (null current-prefix-arg)))) - (list rname edit)))) - (let ((buf (current-buffer)) - (rbuf (get-buffer ledger-report-buffer-name)) - (wcfg (current-window-configuration))) - (if rbuf - (kill-buffer rbuf)) - (with-current-buffer - (pop-to-buffer (get-buffer-create ledger-report-buffer-name)) - (ledger-report-mode) - (set (make-local-variable 'ledger-buf) buf) - (set (make-local-variable 'ledger-report-name) report-name) - (set (make-local-variable 'ledger-original-window-cfg) wcfg) - (ledger-do-report (ledger-report-cmd report-name edit)) - (shrink-window-if-larger-than-buffer) - (set-buffer-modified-p nil) - (setq buffer-read-only t) - (message "q to quit; r to redo; e to edit; k to kill; s to save; SPC and DEL to scroll")))) - -(defun string-empty-p (s) - "Check for the empty string." - (string-equal "" s)) - -(defun ledger-report-name-exists (name) - "Check to see if the given report name exists. - -If name exists, returns the object naming the report, otherwise returns nil." - (unless (string-empty-p name) - (car (assoc name ledger-reports)))) - -(defun ledger-reports-add (name cmd) - "Add a new report to `ledger-reports'." - (setq ledger-reports (cons (list name cmd) ledger-reports))) - -(defun ledger-reports-custom-save () - "Save the `ledger-reports' variable using the customize framework." - (customize-save-variable 'ledger-reports ledger-reports)) - -(defun ledger-report-read-command (report-cmd) - "Read the command line to create a report." - (read-from-minibuffer "Report command line: " - (if (null report-cmd) "ledger " report-cmd) - nil nil 'ledger-report-cmd-prompt-history)) - -(defun ledger-report-ledger-file-format-specifier () - "Substitute the full path to master or current ledger file - -The master file name is determined by the ledger-master-file buffer-local -variable which can be set using file variables. If it is set, it is used, -otherwise the current buffer file is used." - (ledger-master-file)) - -(defun ledger-read-string-with-default (prompt default) - (let ((default-prompt (concat prompt - (if default - (concat " (" default "): ") - ": ")))) - (read-string default-prompt nil nil default))) - -(defun ledger-report-payee-format-specifier () - "Substitute a payee name - -The user is prompted to enter a payee and that is substitued. If -point is in an entry, the payee for that entry is used as the -default." - ;; It is intended copmletion should be available on existing - ;; payees, but the list of possible completions needs to be - ;; developed to allow this. - (ledger-read-string-with-default "Payee" (regexp-quote (ledger-entry-payee)))) - -(defun ledger-report-account-format-specifier () - "Substitute an account name - -The user is prompted to enter an account name, which can be any -regular expression identifying an account. If point is on an account -transaction line for an entry, the full account name on that line is -the default." - ;; It is intended completion should be available on existing account - ;; names, but it remains to be implemented. - (let* ((context (ledger-context-at-point)) - (default - (if (eq (ledger-context-line-type context) 'acct-transaction) - (regexp-quote (ledger-context-field-value context 'account)) - nil))) - (ledger-read-string-with-default "Account" default))) - -(defun ledger-report-expand-format-specifiers (report-cmd) - (let ((expanded-cmd report-cmd)) - (while (string-match "%(\\([^)]*\\))" expanded-cmd) - (let* ((specifier (match-string 1 expanded-cmd)) - (f (cdr (assoc specifier ledger-report-format-specifiers)))) - (if f - (setq expanded-cmd (replace-match - (save-match-data - (with-current-buffer ledger-buf - (shell-quote-argument (funcall f)))) - t t expanded-cmd)) - (progn - (set-window-configuration ledger-original-window-cfg) - (error "Invalid ledger report format specifier '%s'" specifier))))) - expanded-cmd)) - -(defun ledger-report-cmd (report-name edit) - "Get the command line to run the report." - (let ((report-cmd (car (cdr (assoc report-name ledger-reports))))) - ;; logic for substitution goes here - (when (or (null report-cmd) edit) - (setq report-cmd (ledger-report-read-command report-cmd))) - (setq report-cmd (ledger-report-expand-format-specifiers report-cmd)) - (set (make-local-variable 'ledger-report-cmd) report-cmd) - (or (string-empty-p report-name) - (ledger-report-name-exists report-name) - (ledger-reports-add report-name report-cmd) - (ledger-reports-custom-save)) - report-cmd)) - -(defun ledger-do-report (cmd) - "Run a report command line." - (goto-char (point-min)) - (insert (format "Report: %s\n" ledger-report-name) - (format "Command: %s\n" cmd) - (make-string (- (window-width) 1) ?=) - "\n") - (shell-command cmd t nil)) - -(defun ledger-report-goto () - "Goto the ledger report buffer." - (interactive) - (let ((rbuf (get-buffer ledger-report-buffer-name))) - (if (not rbuf) - (error "There is no ledger report buffer")) - (pop-to-buffer rbuf) - (shrink-window-if-larger-than-buffer))) - -(defun ledger-report-redo () - "Redo the report in the current ledger report buffer." - (interactive) - (ledger-report-goto) - (setq buffer-read-only nil) - (erase-buffer) - (ledger-do-report ledger-report-cmd) - (setq buffer-read-only nil)) - -(defun ledger-report-quit () - "Quit the ledger report buffer by burying it." - (interactive) - (ledger-report-goto) - (set-window-configuration ledger-original-window-cfg) - (bury-buffer (get-buffer ledger-report-buffer-name))) - -(defun ledger-report-kill () - "Kill the ledger report buffer." - (interactive) - (ledger-report-quit) - (kill-buffer (get-buffer ledger-report-buffer-name))) - -(defun ledger-report-edit () - "Edit the defined ledger reports." - (interactive) - (customize-variable 'ledger-reports)) - -(defun ledger-report-read-new-name () - "Read the name for a new report from the minibuffer." - (let ((name "")) - (while (string-empty-p name) - (setq name (read-from-minibuffer "Report name: " nil nil nil - 'ledger-report-name-prompt-history))) - name)) - -(defun ledger-report-save () - "Save the current report command line as a named report." - (interactive) - (ledger-report-goto) - (let (existing-name) - (when (string-empty-p ledger-report-name) - (setq ledger-report-name (ledger-report-read-new-name))) - - (while (setq existing-name (ledger-report-name-exists ledger-report-name)) - (cond ((y-or-n-p (format "Overwrite existing report named '%s' " - ledger-report-name)) - (when (string-equal - ledger-report-cmd - (car (cdr (assq existing-name ledger-reports)))) - (error "Current command is identical to existing saved one")) - (setq ledger-reports - (assq-delete-all existing-name ledger-reports))) - (t - (setq ledger-report-name (ledger-report-read-new-name))))) - - (ledger-reports-add ledger-report-name ledger-report-cmd) - (ledger-reports-custom-save))) - -;; In-place completion support - -(defun ledger-thing-at-point () - (let ((here (point))) - (goto-char (line-beginning-position)) - (cond ((looking-at "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.+?)\\)?\\s-+") - (goto-char (match-end 0)) - 'entry) - ((looking-at "^\\s-+\\([*!]\\s-+\\)?[[(]?\\(.\\)") - (goto-char (match-beginning 2)) - 'transaction) - ((looking-at "^\\(sun\\|mon\\|tue\\|wed\\|thu\\|fri\\|sat\\)\\s-+") - (goto-char (match-end 0)) - 'entry) - (t - (ignore (goto-char here)))))) - -(defun ledger-parse-arguments () - "Parse whitespace separated arguments in the current region." - (let* ((info (save-excursion - (cons (ledger-thing-at-point) (point)))) - (begin (cdr info)) - (end (point)) - begins args) - (save-excursion - (goto-char begin) - (when (< (point) end) - (skip-chars-forward " \t\n") - (setq begins (cons (point) begins)) - (setq args (cons (buffer-substring-no-properties - (car begins) end) - args))) - (cons (reverse args) (reverse begins))))) - -(defun ledger-entries () - (let ((origin (point)) - entries-list) - (save-excursion - (goto-char (point-min)) - (while (re-search-forward - (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" - "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) - (unless (and (>= origin (match-beginning 0)) - (< origin (match-end 0))) - (setq entries-list (cons (match-string-no-properties 3) - entries-list))))) - (pcomplete-uniqify-list (nreverse entries-list)))) - -(defvar ledger-account-tree nil) - -(defun ledger-find-accounts () - (let ((origin (point)) account-path elements) - (save-excursion - (setq ledger-account-tree (list t)) - (goto-char (point-min)) - (while (re-search-forward - "^[ \t]+\\([*!]\\s-+\\)?[[(]?\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)" nil t) - (unless (and (>= origin (match-beginning 0)) - (< origin (match-end 0))) - (setq account-path (match-string-no-properties 2)) - (setq elements (split-string account-path ":")) - (let ((root ledger-account-tree)) - (while elements - (let ((entry (assoc (car elements) root))) - (if entry - (setq root (cdr entry)) - (setq entry (cons (car elements) (list t))) - (nconc root (list entry)) - (setq root (cdr entry)))) - (setq elements (cdr elements))))))))) - -(defun ledger-accounts () - (ledger-find-accounts) - (let* ((current (caar (ledger-parse-arguments))) - (elements (and current (split-string current ":"))) - (root ledger-account-tree) - (prefix nil)) - (while (cdr elements) - (let ((entry (assoc (car elements) root))) - (if entry - (setq prefix (concat prefix (and prefix ":") - (car elements)) - root (cdr entry)) - (setq root nil elements nil))) - (setq elements (cdr elements))) - (and root - (sort - (mapcar (function - (lambda (x) - (let ((term (if prefix - (concat prefix ":" (car x)) - (car x)))) - (if (> (length (cdr x)) 1) - (concat term ":") - term)))) - (cdr root)) - 'string-lessp)))) - -(defun ledger-complete-at-point () - "Do appropriate completion for the thing at point" - (interactive) - (while (pcomplete-here - (if (eq (save-excursion - (ledger-thing-at-point)) 'entry) - (if (null current-prefix-arg) - (ledger-entries) ; this completes against entry names - (progn - (let ((text (buffer-substring (line-beginning-position) - (line-end-position)))) - (delete-region (line-beginning-position) - (line-end-position)) - (condition-case err - (ledger-add-entry text t) - ((error) - (insert text)))) - (forward-line) - (goto-char (line-end-position)) - (search-backward ";" (line-beginning-position) t) - (skip-chars-backward " \t0123456789.,") - (throw 'pcompleted t))) - (ledger-accounts))))) - -(defun ledger-fully-complete-entry () - "Do appropriate completion for the thing at point" - (interactive) - (let ((name (caar (ledger-parse-arguments))) - xacts) - (save-excursion - (when (eq 'entry (ledger-thing-at-point)) - (when (re-search-backward - (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" - (regexp-quote name) "\\(\t\\|\n\\| [ \t]\\)") nil t) - (forward-line) - (while (looking-at "^\\s-+") - (setq xacts (cons (buffer-substring-no-properties - (line-beginning-position) - (line-end-position)) - xacts)) - (forward-line)) - (setq xacts (nreverse xacts))))) - (when xacts - (save-excursion - (insert ?\n) - (while xacts - (insert (car xacts) ?\n) - (setq xacts (cdr xacts)))) - (forward-line) - (goto-char (line-end-position)) - (if (re-search-backward "\\(\t\\| [ \t]\\)" nil t) - (goto-char (match-end 0)))))) - -;; A sample function for $ users - -(defun ledger-next-amount (&optional end) - (when (re-search-forward "\\( \\|\t\\| \t\\)[ \t]*-?\\([A-Z$€£]+ *\\)?\\(-?[0-9,]+?\\)\\(.[0-9]+\\)?\\( *[A-Z$€£]+\\)?\\([ \t]*@@?[^\n;]+?\\)?\\([ \t]+;.+?\\)?$" (marker-position end) t) - (goto-char (match-beginning 0)) - (skip-syntax-forward " ") - (- (or (match-end 4) - (match-end 3)) (point)))) - -(defun ledger-align-amounts (&optional column) - "Align amounts in the current region. -This is done so that the last digit falls in COLUMN, which defaults to 52." - (interactive "p") - (if (or (null column) (= column 1)) - (setq column 52)) - (save-excursion - (let* ((mark-first (< (mark) (point))) - (begin (if mark-first (mark) (point))) - (end (if mark-first (point-marker) (mark-marker))) - offset) - (goto-char begin) - (while (setq offset (ledger-next-amount end)) - (let ((col (current-column)) - (target-col (- column offset)) - adjust) - (setq adjust (- target-col col)) - (if (< col target-col) - (insert (make-string (- target-col col) ? )) - (move-to-column target-col) - (if (looking-back " ") - (delete-char (- col target-col)) - (skip-chars-forward "^ \t") - (delete-horizontal-space) - (insert " "))) - (forward-line)))))) - -(defalias 'ledger-align-dollars 'ledger-align-amounts) - -;; A sample entry sorting function, which works if entry dates are of -;; the form YYYY/mm/dd. - -(defun ledger-sort () - (interactive) - (save-excursion - (goto-char (point-min)) - (sort-subr - nil - (function - (lambda () - (if (re-search-forward - (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" - "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) - (goto-char (match-beginning 0)) - (goto-char (point-max))))) - (function - (lambda () - (forward-paragraph)))))) - -;; General helper functions - -(defvar ledger-delete-after nil) - -(defun ledger-run-ledger (buffer &rest args) - "run ledger with supplied arguments" - ;; Let's try again, just in case they moved it while we were sleeping. - (cond - ((null ledger-binary-path) - (error "The variable `ledger-binary-path' has not been set")) - (t - (let ((buf (current-buffer))) - (with-current-buffer buffer - (let ((coding-system-for-write 'utf-8) - (coding-system-for-read 'utf-8)) - (apply #'call-process-region - (append (list (point-min) (point-max) - ledger-binary-path ledger-delete-after - buf nil "-f" "-") - args)))))))) - -(defun ledger-run-ledger-and-delete (buffer &rest args) - (let ((ledger-delete-after t)) - (apply #'ledger-run-ledger buffer args))) - -(defun ledger-set-year (newyear) - "Set ledger's idea of the current year to the prefix argument." - (interactive "p") - (if (= newyear 1) - (setq ledger-year (read-string "Year: " (ledger-current-year))) - (setq ledger-year (number-to-string newyear)))) - -(defun ledger-set-month (newmonth) - "Set ledger's idea of the current month to the prefix argument." - (interactive "p") - (if (= newmonth 1) - (setq ledger-month (read-string "Month: " (ledger-current-month))) - (setq ledger-month (format "%02d" newmonth)))) - -(defvar ledger-master-file nil) - -(defun ledger-master-file () - "Return the master file for a ledger file. - -The master file is either the file for the current ledger buffer or the -file specified by the buffer-local variable ledger-master-file. Typically -this variable would be set in a file local variable comment block at the -end of a ledger file which is included in some other file." - (if ledger-master-file - (expand-file-name ledger-master-file) - (buffer-file-name))) - -(easy-menu-define ledger-menu ledger-mode-map - "Ledger menu" - '("Ledger" - ["New entry" ledger-add-entry t] - ["Toggle cleared status of current entry" ledger-toggle-current-entry t] - ["Set default year for entry" ledger-set-year t] - ["Set default month for entry" ledger-set-month t] - "--" - ["Reconcile uncleared entries for account" ledger-reconcile t] - "--" - "Reports" - ["Run a report" ledger-report t] - ["Go to report buffer" ledger-report-goto t] - ["Edit defined reports" ledger-report-edit t] - ["Save report definition" ledger-report-save t] - ["Re-run ledger report" ledger-report-redo t] - ["Kill report buffer" ledger-report-kill t])) - -(provide 'ledger) - -;;; ledger.el ends here -- cgit v1.2.3 From cdd7f0675c5906e6a70781a09f87dc4f459a518d Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 7 Mar 2013 16:52:51 -0500 Subject: refactored the auto-adjust to make it default --- lisp/ldg-post.el | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 87922dd1..46acad1a 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -31,12 +31,11 @@ "Default indentation for account transactions in an entry." :type 'string :group 'ledger-post) - (defgroup ledger-post nil "Options for controlling how Ledger-mode deals with postings and completion" :group 'ledger) -(defcustom ledger-post-auto-adjust-postings nil +(defcustom ledger-post-auto-adjust-postings t "If non-nil, adjust account and amount to columns set below" :type 'boolean :group 'ledger-post) @@ -138,8 +137,9 @@ the account" (setq column ledger-post-amount-alignment-column)) (save-excursion ;; Position the account - (if (not (and (looking-at "[ \t]+\n") - (looking-back "[ \n]" (- (point) 2)))) + (if (not (or (looking-at "[ \t]*[1-9]") + (and (looking-at "[ \t]+\n") + (looking-back "[ \n]" (- (point) 2))))) (save-excursion (beginning-of-line) (set-mark (point)) @@ -180,12 +180,13 @@ the account" (defun ledger-post-maybe-align (beg end len) "Align amounts only if point is in a posting. BEG, END, and LEN control how far it can align." - (save-excursion - (goto-char beg) - (when (<= end (line-end-position)) - (goto-char (line-beginning-position)) - (if (looking-at ledger-post-line-regexp) - (ledger-post-align-postings))))) + (if ledger-post-auto-adjust-postings + (save-excursion + (goto-char beg) + (when (<= end (line-end-position)) + (goto-char (line-beginning-position)) + (if (looking-at ledger-post-line-regexp) + (ledger-post-align-postings)))))) (defun ledger-post-edit-amount () "Call 'calc-mode' and push the amount in the posting to the top of stack." -- cgit v1.2.3 From 8f4b0e89627b082f9c5d4bd2b506661aab732b0b Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Fri, 8 Mar 2013 00:08:25 -0500 Subject: Added Ledger error handling. No more lisp backtraces! --- lisp/ldg-exec.el | 83 +++++++++++++++++++++++++++++++-------------------- lisp/ldg-reconcile.el | 53 ++++++++++++++++---------------- 2 files changed, 78 insertions(+), 58 deletions(-) diff --git a/lisp/ldg-exec.el b/lisp/ldg-exec.el index d62fd419..46775914 100644 --- a/lisp/ldg-exec.el +++ b/lisp/ldg-exec.el @@ -40,30 +40,48 @@ :type 'file :group 'ledger-exec) +(defun ledger-exec-handle-error (ledger-output) + "Deal with ledger errors contained in LEDGER-OUTPUT." + (with-current-buffer (get-buffer-create "*Ledger Error*") + (insert-buffer-substring ledger-output) + (make-frame) + (fit-frame) + (view-mode) + (toggle-read-only))) + +(defun ledger-exec-success-p (ledger-output-buffer) + (with-current-buffer ledger-output-buffer + (goto-char (point-min)) + (if (and (> (buffer-size) 1) (looking-at (regexp-quote "While"))) + nil + ledger-output-buffer))) + (defun ledger-exec-ledger (input-buffer &optional output-buffer &rest args) "Run Ledger using INPUT-BUFFER and optionally capturing output in OUTPUT-BUFFER with ARGS." (if (null ledger-binary-path) - (error "The variable `ledger-binary-path' has not been set")) - (let ((buf (or input-buffer (current-buffer))) - (outbuf (or output-buffer - (generate-new-buffer " *ledger-tmp*")))) - (with-current-buffer buf - (let ((coding-system-for-write 'utf-8) - (coding-system-for-read 'utf-8)) - (apply #'call-process-region - (append (list (point-min) (point-max) - ledger-binary-path nil outbuf nil "-f" "-") - args))) - outbuf))) - -(defun ledger-exec-read (&optional input-buffer &rest args) - "Run ledger from option INPUT-BUFFER using ARGS, return a list structure of the ledger Emacs output." - (with-current-buffer - (apply #'ledger-exec-ledger input-buffer nil "emacs" args) - (goto-char (point-min)) - (prog1 - (read (current-buffer)) - (kill-buffer (current-buffer))))) + (error "The variable `ledger-binary-path' has not been set") + (let ((buf (or input-buffer (current-buffer))) + (outbuf (or output-buffer + (generate-new-buffer " *ledger-tmp*")))) + (with-current-buffer buf + (let ((coding-system-for-write 'utf-8) + (coding-system-for-read 'utf-8)) + (apply #'call-process-region + (append (list (point-min) (point-max) + ledger-binary-path nil outbuf nil "-f" "-") + args))) + (if (ledger-exec-success-p outbuf) + outbuf + (ledger-exec-handle-error outbuf)))))) + +;; (defun ledger-exec-read (&optional input-buffer &rest args) +;; "Run ledger from option INPUT-BUFFER using ARGS, return a list structure of the ledger Emacs output." +;; (with-current-buffer +;; (apply #'ledger-exec-ledger input-buffer nil "emacs" args) +;; (goto-char (point-min)) +;; (prog1 +;; (read (current-buffer)) +;; (kill-buffer (current-buffer))))) (defun ledger-version-greater-p (needed) "Verify the ledger binary is usable for `ledger-mode' (version greater than NEEDED)." @@ -71,17 +89,18 @@ (version-strings '()) (version-number)) (with-temp-buffer - (ledger-exec-ledger buffer (current-buffer) "--version") - (goto-char (point-min)) - (delete-horizontal-space) - (setq version-strings (split-string - (buffer-substring-no-properties (point) - (+ (point) 12)))) - (if (and (string-match (regexp-quote "Ledger") (car version-strings)) - (or (string= needed (car (cdr version-strings))) - (string< needed (car (cdr version-strings))))) - t - nil)))) + (if (ledger-exec-ledger (current-buffer) (current-buffer) "--version") + (progn + (goto-char (point-min)) + (delete-horizontal-space) + (setq version-strings (split-string + (buffer-substring-no-properties (point) + (point-max)))) + (if (and (string-match (regexp-quote "Ledger") (car version-strings)) + (or (string= needed (car (cdr version-strings))) + (string< needed (car (cdr version-strings))))) + t + nil)))))) (defun ledger-check-version () "Verify that ledger works and is modern enough." diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 6ede6b51..9f1a220c 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -74,28 +74,25 @@ reconcile-finish will mark all pending posting cleared." ;; separated from the actual format string. emacs does not ;; split arguments like the shell does, so you need to ;; specify the individual fields in the command line. - (ledger-exec-ledger buffer (current-buffer) - "balance" "--limit" "cleared or pending" "--empty" - "--format" "%(display_total)" account) - (setq val - (ledger-split-commodity-string - (buffer-substring-no-properties (point-min) (point-max))))))) + (if (ledger-exec-ledger buffer (current-buffer) + "balance" "--limit" "cleared or pending" "--empty" + "--format" "%(display_total)" account) + (setq val + (ledger-split-commodity-string + (buffer-substring-no-properties (point-min) (point-max)))))))) (defun ledger-display-balance () "Display the cleared-or-pending balance. And calculate the target-delta of the account being reconciled." (interactive) - (let* ((pending (ledger-reconcile-get-cleared-or-pending-balance)) - (target-delta (if ledger-target - (-commodity ledger-target pending) - nil))) - - (if target-delta - (message "Pending balance: %s, Difference from target: %s" - (ledger-commodity-to-string pending) - (ledger-commodity-to-string target-delta)) - (message "Pending balance: %s" - (ledger-commodity-to-string pending))))) + (let* ((pending (ledger-reconcile-get-cleared-or-pending-balance))) + (if pending + (if ledger-target + (message "Pending balance: %s, Difference from target: %s" + (ledger-commodity-to-string pending) + (ledger-commodity-to-string (-commodity ledger-target pending))) + (message "Pending balance: %s" + (ledger-commodity-to-string pending)))))) @@ -276,16 +273,18 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." "Get the uncleared transactions in the account and display them in the *Reconcile* buffer." (let* ((buf ledger-buf) (account ledger-acct) + (ledger-success nil) (xacts (with-temp-buffer - (ledger-exec-ledger buf (current-buffer) - "--uncleared" "--real" "emacs" account) - (goto-char (point-min)) - (unless (eobp) - (unless (looking-at "(") - (error (concat "ledger-do-reconcile: " (buffer-string)))) - (read (current-buffer)))))) ;current-buffer is the *temp* created above - (if (> (length xacts) 0) + (if (ledger-exec-ledger buf (current-buffer) + "--uncleared" "--real" "emacs" account) + (progn + (setq ledger-success t) + (goto-char (point-min)) + (unless (eobp) + (if (looking-at "(") + (read (current-buffer))))))))) ;current-buffer is the *temp* created above + (if (and ledger-success (> (length xacts) 0)) (progn (dolist (xact xacts) (dolist (posting (nthcdr 5 xact)) @@ -310,7 +309,9 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." 'where where)))) )) (goto-char (point-max)) (delete-char -1)) ;gets rid of the extra line feed at the bottom of the list - (insert (concat "There are no uncleared entries for " account))) + (if ledger-success + (insert (concat "There are no uncleared entries for " account)) + (insert "Ledger has reported a problem. Check *Ledger Error* buffer."))) (goto-char (point-min)) (set-buffer-modified-p nil) (toggle-read-only t) -- cgit v1.2.3 From a875940a93848d4b18b5bed45049edc901ad07a2 Mon Sep 17 00:00:00 2001 From: Johann Klähn <kljohann@gmail.com> Date: Fri, 8 Mar 2013 21:45:56 +0100 Subject: fix ledger xml output, remove ledger json command As the format used by property trees to represent valid JSON and that for valid XML is too different and given that there are more requests for valid XML output I decided to pursue a quick fix and remove the json command in favor of a working xml command. See bug #782, #909, recent discussion on mailing list. JSON support is postponed until I or someone else finds time to work on this or the python bindings are more stable. --- src/account.cc | 19 +++++++------------ src/amount.cc | 8 +++----- src/amount.h | 2 +- src/annotate.cc | 16 +++++----------- src/balance.cc | 6 ++---- src/commodity.cc | 6 ++---- src/item.cc | 9 ++++----- src/mask.h | 2 +- src/post.cc | 43 +++++++++++++++---------------------------- src/ptree.cc | 15 +++++++-------- src/ptree.h | 3 +-- src/report.cc | 5 ----- src/system.hh.in | 1 - src/times.h | 16 ++++------------ src/value.cc | 20 ++++++++++---------- src/xact.cc | 18 ++++++------------ 16 files changed, 68 insertions(+), 121 deletions(-) diff --git a/src/account.cc b/src/account.cc index 7dcd5faa..c3fc80f1 100644 --- a/src/account.cc +++ b/src/account.cc @@ -692,12 +692,10 @@ void account_t::xdata_t::details_t::update(post_t& post, } } -void put_account(property_tree::ptree& pt, const account_t& acct, +void put_account(property_tree::ptree& st, const account_t& acct, function<bool(const account_t&)> pred) { if (pred(acct)) { - property_tree::ptree& st(pt.put("account", "")); - std::ostringstream buf; buf.width(sizeof(unsigned long) * 2); buf.fill('0'); @@ -709,18 +707,15 @@ void put_account(property_tree::ptree& pt, const account_t& acct, st.put("fullname", acct.fullname()); value_t total = acct.amount(); - if (! total.is_null()) { - property_tree::ptree& t(st.put("account-amount", "")); - put_value(t, total); - } + if (! total.is_null()) + put_value(st.put("account-amount", ""), total); + total = acct.total(); - if (! total.is_null()) { - property_tree::ptree& t(st.put("account-total", "")); - put_value(t, total); - } + if (! total.is_null()) + put_value(st.put("account-total", ""), total); foreach (const accounts_map::value_type& pair, acct.accounts) - put_account(st, *pair.second, pred); + put_account(st.add("account", ""), *pair.second, pred); } } diff --git a/src/amount.cc b/src/amount.cc index 88f2d124..55cbabeb 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -1320,13 +1320,11 @@ bool amount_t::valid() const return true; } -void put_amount(property_tree::ptree& pt, const amount_t& amt, - bool wrap, bool commodity_details) +void put_amount(property_tree::ptree& st, const amount_t& amt, + bool commodity_details) { - property_tree::ptree& st(wrap ? pt.put("amount", "") : pt); - if (amt.has_commodity()) - put_commodity(st, amt.commodity(), commodity_details); + put_commodity(st.put("commodity", ""), amt.commodity(), commodity_details); st.put("quantity", amt.quantity_string()); } diff --git a/src/amount.h b/src/amount.h index b70058ff..938d4b7b 100644 --- a/src/amount.h +++ b/src/amount.h @@ -793,7 +793,7 @@ inline std::istream& operator>>(std::istream& in, amount_t& amt) { } void put_amount(property_tree::ptree& pt, const amount_t& amt, - bool wrap = true, bool commodity_details = false); + bool commodity_details = false); } // namespace ledger diff --git a/src/annotate.cc b/src/annotate.cc index 12016868..8816a89c 100644 --- a/src/annotate.cc +++ b/src/annotate.cc @@ -216,19 +216,13 @@ void annotation_t::print(std::ostream& out, bool keep_base, out << " ((" << *value_expr << "))"; } -void put_annotation(property_tree::ptree& pt, const annotation_t& details) +void put_annotation(property_tree::ptree& st, const annotation_t& details) { - property_tree::ptree& st(pt.put("annotation", "")); + if (details.price) + put_amount(st.put("price", ""), *details.price); - if (details.price) { - property_tree::ptree& t(st.put("price", "")); - put_amount(t, *details.price, false); - } - - if (details.date) { - property_tree::ptree& t(st.put("date", "")); - put_date(t, *details.date, false); - } + if (details.date) + put_date(st.put("date", ""), *details.date); if (details.tag) st.put("tag", *details.tag); diff --git a/src/balance.cc b/src/balance.cc index f86d6561..b702cb7b 100644 --- a/src/balance.cc +++ b/src/balance.cc @@ -336,12 +336,10 @@ void balance_t::print(std::ostream& out, amount_printer.close(); } -void put_balance(property_tree::ptree& pt, const balance_t& bal) +void put_balance(property_tree::ptree& st, const balance_t& bal) { - property_tree::ptree& st(pt.put("balance", "")); - foreach (const balance_t::amounts_map::value_type& pair, bal.amounts) - put_amount(st, pair.second); + put_amount(st.add("amount", ""), pair.second); } } // namespace ledger diff --git a/src/commodity.cc b/src/commodity.cc index c7a893f1..535b31c9 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -497,11 +497,9 @@ bool commodity_t::compare_by_commodity::operator()(const amount_t * left, } } -void put_commodity(property_tree::ptree& pt, const commodity_t& comm, +void put_commodity(property_tree::ptree& st, const commodity_t& comm, bool commodity_details) { - property_tree::ptree& st(pt.put("commodity", "")); - std::string flags; if (! (comm.has_flags(COMMODITY_STYLE_SUFFIXED))) flags += 'P'; if (comm.has_flags(COMMODITY_STYLE_SEPARATED)) flags += 'S'; @@ -512,7 +510,7 @@ void put_commodity(property_tree::ptree& pt, const commodity_t& comm, st.put("symbol", comm.symbol()); if (commodity_details && comm.has_annotation()) - put_annotation(st, as_annotated_commodity(comm).details); + put_annotation(st.put("annotation", ""), as_annotated_commodity(comm).details); } } // namespace ledger diff --git a/src/item.cc b/src/item.cc index 896589e9..a29a3fd3 100644 --- a/src/item.cc +++ b/src/item.cc @@ -600,16 +600,15 @@ string item_context(const item_t& item, const string& desc) return out.str(); } -void put_metadata(property_tree::ptree& pt, const item_t::string_map& metadata) +void put_metadata(property_tree::ptree& st, const item_t::string_map& metadata) { - property_tree::ptree& st(pt.put("metadata", "")); foreach (const item_t::string_map::value_type& pair, metadata) { if (pair.second.first) { - property_tree::ptree& vt(st.put("pair", "")); - vt.put("key", pair.first); + property_tree::ptree& vt(st.add("value", "")); + vt.put("<xmlattr>.key", pair.first); put_value(vt, *pair.second.first); } else { - st.put("tag", pair.first); + st.add("tag", pair.first); } } } diff --git a/src/mask.h b/src/mask.h index d46b3349..877a0011 100644 --- a/src/mask.h +++ b/src/mask.h @@ -151,7 +151,7 @@ inline std::ostream& operator<<(std::ostream& out, const mask_t& mask) { } inline void put_mask(property_tree::ptree& pt, const mask_t& mask) { - pt.put("mask", mask.str()); + pt.put_value(mask.str()); } } // namespace ledger diff --git a/src/post.cc b/src/post.cc index c7435aec..1a24429b 100644 --- a/src/post.cc +++ b/src/post.cc @@ -696,10 +696,8 @@ void extend_post(post_t& post, journal_t& journal) } } -void put_post(property_tree::ptree& pt, const post_t& post) +void put_post(property_tree::ptree& st, const post_t& post) { - property_tree::ptree& st(pt.put("posting", "")); - if (post.state() == item_t::CLEARED) st.put("<xmlattr>.state", "cleared"); else if (post.state() == item_t::PENDING) @@ -710,14 +708,10 @@ void put_post(property_tree::ptree& pt, const post_t& post) if (post.has_flags(ITEM_GENERATED)) st.put("<xmlattr>.generated", "true"); - if (post._date) { - property_tree::ptree& t(st.put("date", "")); - put_date(t, *post._date, false); - } - if (post._date_aux) { - property_tree::ptree& t(st.put("aux-date", "")); - put_date(t, *post._date_aux, false); - } + if (post._date) + put_date(st.put("date", ""), *post._date); + if (post._date_aux) + put_date(st.put("aux-date", ""), *post._date_aux); if (post.account) { property_tree::ptree& t(st.put("account", "")); @@ -736,34 +730,27 @@ void put_post(property_tree::ptree& pt, const post_t& post) if (post.has_xdata() && post.xdata().has_flags(POST_EXT_COMPOUND)) put_value(t, post.xdata().compound_value); else - put_amount(t, post.amount); + put_amount(t.put("amount", ""), post.amount); } - if (post.cost) { - property_tree::ptree& t(st.put("cost", "")); - put_amount(t, *post.cost, false); - } + if (post.cost) + put_amount(st.put("cost", ""), *post.cost); if (post.assigned_amount) { - if (post.has_flags(POST_CALCULATED)) { - property_tree::ptree& t(st.put("balance-assertion", "")); - put_amount(t, *post.assigned_amount, false); - } else { - property_tree::ptree& t(st.put("balance-assignment", "")); - put_amount(t, *post.assigned_amount, false); - } + if (post.has_flags(POST_CALCULATED)) + put_amount(st.put("balance-assertion", ""), *post.assigned_amount); + else + put_amount(st.put("balance-assignment", ""), *post.assigned_amount); } if (post.note) st.put("note", *post.note); if (post.metadata) - put_metadata(st, *post.metadata); + put_metadata(st.put("metadata", ""), *post.metadata); - if (post.xdata_ && ! post.xdata_->total.is_null()) { - property_tree::ptree& t(st.put("total", "")); - put_value(t, post.xdata_->total); - } + if (post.xdata_ && ! post.xdata_->total.is_null()) + put_value(st.put("total", ""), post.xdata_->total); } } // namespace ledger diff --git a/src/ptree.cc b/src/ptree.cc index 1e271465..1d2d4b26 100644 --- a/src/ptree.cc +++ b/src/ptree.cc @@ -61,28 +61,27 @@ void format_ptree::flush() property_tree::ptree& ct(pt.put("ledger.commodities", "")); foreach (const commodities_pair& pair, commodities) - put_commodity(ct, *pair.second, true); + put_commodity(ct.add("commodity", ""), *pair.second, true); property_tree::ptree& at(pt.put("ledger.accounts", "")); - put_account(at, *report.session.journal->master, account_visited_p); + put_account(at.add("account", ""), *report.session.journal->master, account_visited_p); property_tree::ptree& tt(pt.put("ledger.transactions", "")); foreach (const xact_t * xact, transactions) { - put_xact(tt, *xact); + property_tree::ptree& t(tt.add("transaction", "")); + put_xact(t, *xact); - property_tree::ptree& post_tree(tt.put("postings", "")); + property_tree::ptree& post_tree(t.put("postings", "")); foreach (const post_t * post, xact->posts) if (post->has_xdata() && post->xdata().has_flags(POST_EXT_VISITED)) - put_post(post_tree, *post); + put_post(post_tree.add("posting", ""), *post); } switch (format) { case FORMAT_XML: property_tree::write_xml(out, pt); - break; - case FORMAT_JSON: - property_tree::write_json(out, pt); + out << std::endl; break; } } diff --git a/src/ptree.h b/src/ptree.h index ac9e1060..154c8837 100644 --- a/src/ptree.h +++ b/src/ptree.h @@ -75,8 +75,7 @@ protected: public: enum format_t { - FORMAT_XML, - FORMAT_JSON + FORMAT_XML } format; format_ptree(report_t& _report, format_t _format = FORMAT_XML) diff --git a/src/report.cc b/src/report.cc index 8bb38fb6..29077f10 100644 --- a/src/report.cc +++ b/src/report.cc @@ -1628,11 +1628,6 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, } break; - case 'j': - if (is_eq(p, "json")) - return POSTS_REPORTER(new format_ptree(*this, - format_ptree::FORMAT_JSON)); - break; case 'l': if (is_eq(p, "lisp")) return POSTS_REPORTER(new format_emacs_posts(output_stream)); diff --git a/src/system.hh.in b/src/system.hh.in index 08a45a15..ff7ea75b 100644 --- a/src/system.hh.in +++ b/src/system.hh.in @@ -204,7 +204,6 @@ typedef std::ostream::pos_type ostream_pos_type; #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/xml_parser.hpp> -#include <boost/property_tree/json_parser.hpp> #include <boost/random/mersenne_twister.hpp> #include <boost/random/uniform_int.hpp> diff --git a/src/times.h b/src/times.h index ae4e4c75..4b89cc0c 100644 --- a/src/times.h +++ b/src/times.h @@ -111,20 +111,12 @@ std::string format_date(const date_t& when, void set_date_format(const char * format); void set_input_date_format(const char * format); -inline void put_datetime(property_tree::ptree& pt, const datetime_t& when, - bool wrap = true) { - if (wrap) - pt.put("datetime", format_datetime(when, FMT_WRITTEN)); - else - pt.put_value(format_datetime(when, FMT_WRITTEN)); +inline void put_datetime(property_tree::ptree& pt, const datetime_t& when) { + pt.put_value(format_datetime(when, FMT_WRITTEN)); } -inline void put_date(property_tree::ptree& pt, const date_t& when, - bool wrap = true) { - if (wrap) - pt.put("date", format_date(when, FMT_WRITTEN)); - else - pt.put_value(format_date(when, FMT_WRITTEN)); +inline void put_date(property_tree::ptree& pt, const date_t& when) { + pt.put_value(format_date(when, FMT_WRITTEN)); } struct date_traits_t diff --git a/src/value.cc b/src/value.cc index e8afac50..98e48c2f 100644 --- a/src/value.cc +++ b/src/value.cc @@ -2062,35 +2062,35 @@ void put_value(property_tree::ptree& pt, const value_t& value) { switch (value.type()) { case value_t::VOID: - pt.put("void", ""); + pt.add("void", ""); break; case value_t::BOOLEAN: - pt.put("bool", value.as_boolean() ? "true" : "false"); + pt.add("bool", value.as_boolean() ? "true" : "false"); break; case value_t::INTEGER: - pt.put("int", value.to_string()); + pt.add("int", value.to_string()); break; case value_t::AMOUNT: - put_amount(pt, value.as_amount()); + put_amount(pt.add("amount", ""), value.as_amount()); break; case value_t::BALANCE: - put_balance(pt, value.as_balance()); + put_balance(pt.add("balance", ""), value.as_balance()); break; case value_t::DATETIME: - put_datetime(pt, value.as_datetime()); + put_datetime(pt.add("datetime", ""), value.as_datetime()); break; case value_t::DATE: - put_date(pt, value.as_date()); + put_date(pt.add("date", ""), value.as_date()); break; case value_t::STRING: - pt.put("string", value.as_string()); + pt.add("string", value.as_string()); break; case value_t::MASK: - put_mask(pt, value.as_mask()); + put_mask(pt.add("mask", ""), value.as_mask()); break; case value_t::SEQUENCE: { - property_tree::ptree& st(pt.put("sequence", "")); + property_tree::ptree& st(pt.add("sequence", "")); foreach (const value_t& member, value.as_sequence()) put_value(st, member); break; diff --git a/src/xact.cc b/src/xact.cc index d33520b4..8aecf5d6 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -847,10 +847,8 @@ void auto_xact_t::extend_xact(xact_base_t& xact, parse_context_t& context) } } -void put_xact(property_tree::ptree& pt, const xact_t& xact) +void put_xact(property_tree::ptree& st, const xact_t& xact) { - property_tree::ptree& st(pt.put("transaction", "")); - if (xact.state() == item_t::CLEARED) st.put("<xmlattr>.state", "cleared"); else if (xact.state() == item_t::PENDING) @@ -859,14 +857,10 @@ void put_xact(property_tree::ptree& pt, const xact_t& xact) if (xact.has_flags(ITEM_GENERATED)) st.put("<xmlattr>.generated", "true"); - if (xact._date) { - property_tree::ptree& t(st.put("date", "")); - put_date(t, *xact._date, false); - } - if (xact._date_aux) { - property_tree::ptree& t(st.put("aux-date", "")); - put_date(t, *xact._date_aux, false); - } + if (xact._date) + put_date(st.put("date", ""), *xact._date); + if (xact._date_aux) + put_date(st.put("aux-date", ""), *xact._date_aux); if (xact.code) st.put("code", *xact.code); @@ -877,7 +871,7 @@ void put_xact(property_tree::ptree& pt, const xact_t& xact) st.put("note", *xact.note); if (xact.metadata) - put_metadata(st, *xact.metadata); + put_metadata(st.put("metadata", ""), *xact.metadata); } } // namespace ledger -- cgit v1.2.3 From 44823d241f01c9cb2b891283f9e110f15aeebf9a Mon Sep 17 00:00:00 2001 From: Johann Klähn <kljohann@gmail.com> Date: Fri, 8 Mar 2013 23:16:31 +0100 Subject: indent output of ledger xml --- src/ptree.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ptree.cc b/src/ptree.cc index 1d2d4b26..e7afdcd1 100644 --- a/src/ptree.cc +++ b/src/ptree.cc @@ -80,7 +80,8 @@ void format_ptree::flush() switch (format) { case FORMAT_XML: - property_tree::write_xml(out, pt); + property_tree::xml_writer_settings<char> indented(' ', 2); + property_tree::write_xml(out, pt, indented); out << std::endl; break; } -- cgit v1.2.3 From 404e84cd445d41b3f2fc6cd775babf12864fcefc Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Fri, 8 Mar 2013 18:53:02 -0500 Subject: Removed ldg-register.el functionality all contained in ldg-report --- lisp/CMakeLists.txt | 1 - lisp/ldg-new.el | 4 --- lisp/ldg-register.el | 86 ---------------------------------------------------- 3 files changed, 91 deletions(-) delete mode 100644 lisp/ldg-register.el diff --git a/lisp/CMakeLists.txt b/lisp/CMakeLists.txt index 32a31001..876b3548 100644 --- a/lisp/CMakeLists.txt +++ b/lisp/CMakeLists.txt @@ -10,7 +10,6 @@ set(EMACS_LISP_SOURCES ldg-post.el ldg-reconcile.el ldg-regex.el - ldg-register.el ldg-report.el ldg-sort.el ldg-state.el diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index f888fd6c..a9c70ff4 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -44,7 +44,6 @@ (require 'ldg-post) (require 'ldg-reconcile) (require 'ldg-regex) -(require 'ldg-register) (require 'ldg-report) (require 'ldg-sort) (require 'ldg-state) @@ -125,9 +124,6 @@ (ledger-dump-variable 'ledger-buffer-tracks-reconcile-buffer) (ledger-dump-variable 'ledger-reconcile-force-window-bottom) (ledger-dump-variable 'ledger-reconcile-toggle-to-pending) - (insert "ldg-register:\n") - (ledger-dump-variable 'ledger-register-date-format) - (ledger-dump-variable 'ledger-register-line-format) (insert "ldg-reports:\n") (ledger-dump-variable 'ledger-reports) (ledger-dump-variable 'ledger-report-format-specifiers) diff --git a/lisp/ldg-register.el b/lisp/ldg-register.el deleted file mode 100644 index bfd8d360..00000000 --- a/lisp/ldg-register.el +++ /dev/null @@ -1,86 +0,0 @@ -;;; ldg-register.el --- Helper code for use with the "ledger" command-line tool - -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) - -;; This file is not part of GNU Emacs. - -;; This is free software; you can redistribute it and/or modify it under -;; the terms of the GNU General Public License as published by the Free -;; Software Foundation; either version 2, or (at your option) any later -;; version. -;; -;; This is distributed in the hope that it will be useful, but WITHOUT -;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -;; for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. - -(require 'ldg-post) -(require 'ldg-state) - -(defgroup ledger-register nil - "" - :group 'ledger) - -(defcustom ledger-register-date-format "%m/%d/%y" - "*The date format used for ledger register reports." - :type 'string - :group 'ledger-register) - -(defcustom ledger-register-line-format "%s %-30.30s %-25.25s %15s\n" - "*The date format used for ledger register reports." - :type 'string - :group 'ledger-register) - -(defface ledger-register-pending-face - '((((background light)) (:weight bold)) - (((background dark)) (:weight bold))) - "Face used to highlight pending entries in a register report." - :group 'ledger-register) - -(defun ledger-register-render (data-buffer posts) - (dolist (post posts) - (let ((index 1)) - (dolist (xact (nthcdr 5 post)) - (let ((beg (point)) - (where - (with-current-buffer data-buffer - (cons - (nth 0 post) - (if ledger-clear-whole-transactions - (save-excursion - (goto-line (nth 1 post)) - (point-marker)) - (save-excursion - (goto-line (nth 0 xact)) - (point-marker))))))) - (insert (format ledger-register-line-format - (format-time-string ledger-register-date-format - (nth 2 post)) - (nth 4 post) (nth 1 xact) (nth 2 xact))) - (if (nth 3 xact) - (set-text-properties beg (1- (point)) - (list 'face 'ledger-register-pending-face - 'where where)) - (set-text-properties beg (1- (point)) - (list 'where where)))) - (setq index (1+ index))))) - (goto-char (point-min))) - -(defun ledger-register-generate (&optional data-buffer &rest args) - (let ((buf (or data-buffer (current-buffer)))) - (with-current-buffer (get-buffer-create "*ledger-register*") - (let ((pos (point)) - (inhibit-read-only t)) - (erase-buffer) - (ledger-register-render buf (apply #'ledger-exec-read buf args)) - (goto-char pos)) - (set-buffer-modified-p nil) - (toggle-read-only t) - (display-buffer (current-buffer) t)))) - -(provide 'ldg-register) -- cgit v1.2.3 From bfe360d4c992caf2e7da09ab058599c0404f1348 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Fri, 8 Mar 2013 19:33:16 -0500 Subject: Reconcile date configuration is pulled from ledgerrc --- lisp/ldg-reconcile.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 9f1a220c..802cb3b4 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -285,13 +285,15 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (if (looking-at "(") (read (current-buffer))))))))) ;current-buffer is the *temp* created above (if (and ledger-success (> (length xacts) 0)) - (progn + (let ((date-format (cdr (assoc "date-format" ledger-environment-alist)))) (dolist (xact xacts) (dolist (posting (nthcdr 5 xact)) (let ((beg (point)) (where (ledger-marker-where-xact-is xact posting))) (insert (format "%s %-4s %-30s %-30s %15s\n" - (format-time-string "%Y/%m/%d" (nth 2 xact)) + (format-time-string (if date-format + date-format + "%Y/%m/%d") (nth 2 xact)) (if (nth 3 xact) (nth 3 xact) "") -- cgit v1.2.3 From 13b4c5adc000ca17c03a7d412f6e0a12a0f35e74 Mon Sep 17 00:00:00 2001 From: David Keegan <dksw@eircom.net> Date: Sat, 9 Mar 2013 18:39:30 +0000 Subject: Fixed bug 913 ledger mode C-c C-a and ISO dates. --- lisp/ldg-mode.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 84ccf62b..97662aa3 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -167,8 +167,8 @@ MOMENT is an encoded date" (while (not (eobp)) (when (looking-at (concat "\\(Y\\s-+\\([0-9]+\\)\\|" - "\\([0-9]\\{4\\}+\\)?[./]?" - "\\([0-9]+\\)[./]\\([0-9]+\\)\\s-+" + "\\([0-9]\\{4\\}+\\)?[./-]?" + "\\([0-9]+\\)[./-]\\([0-9]+\\)\\s-+" "\\(\\*\\s-+\\)?\\(.+\\)\\)")) (let ((found (match-string 2))) (if found @@ -215,7 +215,7 @@ correct chronological place in the buffer." exit-code) (unless insert-at-point (let ((date (car args))) - (if (string-match "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)" date) + (if (string-match "\\([0-9]+\\)[-/]\\([0-9]+\\)[-/]\\([0-9]+\\)" date) (setq date (encode-time 0 0 0 (string-to-number (match-string 3 date)) (string-to-number (match-string 2 date)) -- cgit v1.2.3 From 007836dfce1dcba54f6bbb5f0a5c3f9eb12e21da Mon Sep 17 00:00:00 2001 From: David Keegan <dksw@eircom.net> Date: Sat, 9 Mar 2013 19:19:40 +0000 Subject: ledger-sort-region did nothing if point was at end of region. --- lisp/ldg-sort.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el index 33ae2a98..01d8edc9 100644 --- a/lisp/ldg-sort.el +++ b/lisp/ldg-sort.el @@ -76,6 +76,7 @@ (new-end end)) (save-excursion (save-restriction + (goto-char beg) (ledger-next-record-function) ;; make sure point is at the ;; beginning of a xact (setq new-beg (point)) -- cgit v1.2.3 From be4a212ff2839adebd908be42cbf46254bf4f754 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 9 Mar 2013 15:04:07 -0700 Subject: Fixed bug where reconcile bombed if you tried to start from a comment --- lisp/ldg-post.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 46acad1a..e23b3135 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -234,7 +234,8 @@ BEG, END, and LEN control how far it can align." (defun ledger-post-read-account-with-prompt (prompt) (let* ((context (ledger-context-at-point)) (default - (if (eq (ledger-context-line-type context) 'acct-transaction) + (if (and (eq (ledger-context-line-type context) 'acct-transaction) + (eq (ledger-context-current-field context) 'account)) (regexp-quote (ledger-context-field-value context 'account)) nil))) (ledger-read-string-with-default prompt default))) -- cgit v1.2.3 From c85f397edc33f895921b7900f938cd9cbb9f0e16 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 13 Mar 2013 10:20:21 -0700 Subject: Cleaned up ledger-reconcile, easier to read, fewer lines of code. --- lisp/ldg-reconcile.el | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 802cb3b4..9a6c7b67 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -363,6 +363,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." ;; only one ;; *Reconcile* ;; buffer, ever + ;; Set up the reconcile buffer (if rbuf ;; *Reconcile* already exists (with-current-buffer rbuf (set 'ledger-acct account) ;; already buffer local @@ -371,31 +372,31 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (ledger-reconcile-quit-cleanup) (set 'ledger-buf buf))) ;; should already be ;; buffer-local - (if ledger-fold-on-reconcile - (ledger-occur-change-regex account ledger-buf)) - (set-buffer (get-buffer ledger-recon-buffer-name)) + (unless (get-buffer-window rbuf) - (ledger-reconcile-open-windows buf rbuf)) - (ledger-reconcile-refresh) - (goto-char (point-min)) - (setq ledger-target - (ledger-read-commodity-string "Set reconciliation target")) - (ledger-display-balance)) - - (progn ;; no recon-buffer, starting from scratch. - (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save nil t) - (if ledger-fold-on-reconcile - (ledger-occur-mode account buf)) - - (with-current-buffer (get-buffer-create ledger-recon-buffer-name) - (ledger-reconcile-open-windows buf (current-buffer)) - (ledger-reconcile-mode) - (set (make-local-variable 'ledger-buf) buf) - (set (make-local-variable 'ledger-acct) account) - (ledger-do-reconcile) - (set (make-local-variable 'ledger-target) - (ledger-read-commodity-string "Set reconciliation target")) - (ledger-display-balance)))))) + (ledger-reconcile-open-windows buf rbuf))) + + (progn ;; no recon-buffer, starting from scratch. + (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save nil t) + + (with-current-buffer (setq rbuf + (get-buffer-create ledger-recon-buffer-name)) + (ledger-reconcile-open-windows buf rbuf) + (ledger-reconcile-mode) + (make-local-variable 'ledger-target) + (set (make-local-variable 'ledger-buf) buf) + (set (make-local-variable 'ledger-acct) account)))) + + ;; Fold the ledger buffer + (if ledger-fold-on-reconcile + (ledger-occur-mode account buf)) + + ;; Now, actually run the reconciliation + (with-current-buffer rbuf + (ledger-reconcile-refresh) + (goto-char (point-min)) + (ledger-reconcile-change-target) + (ledger-display-balance)))) (defvar ledger-reconcile-mode-abbrev-table) -- cgit v1.2.3 From 3b5316486abcde380ee0f7d31ec56ab1aa736687 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 13 Mar 2013 10:26:07 -0700 Subject: Removed unused function loedger-occur-change-regex --- lisp/ldg-occur.el | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index f14aeeda..8b56d12c 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -19,9 +19,6 @@ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. - - - ;;; Commentary: ;; Provide code folding to ledger mode. Adapted from original loccur ;; mode by Alexey Veretennikov <alexey dot veretennikov at gmail dot @@ -164,15 +161,6 @@ Argument OVL-BOUNDS contains bounds for the transactions to be left visible." (overlay-put ovl 'face 'ledger-occur-xact-face ))) overlays))) -(defun ledger-occur-change-regex (regex buffer) - "Use this function to programatically change the overlays using REGEX in BUFFER, rather than quitting out and restarting." - (progn - (set-buffer buffer) - (setq ledger-occur-mode nil) - (force-mode-line-update) - (ledger-occur-mode regex buffer) - (recenter))) - (defun ledger-occur-quit-buffer (buffer) "Quits hidings transaction in the given BUFFER. Used for coordinating `ledger-occur' with other buffers, like reconcile." -- cgit v1.2.3 From 027c03858d5292a2c66888133a5a464514f5a8ab Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 13 Mar 2013 10:57:43 -0700 Subject: More reconcile restructuring. --- lisp/ldg-reconcile.el | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 9a6c7b67..37d6f32c 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -318,11 +318,13 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (set-buffer-modified-p nil) (toggle-read-only t) - ;; this next piece of code ensures that the last of the visible - ;; transactions in the ledger buffer is at the bottom of the main - ;; window. The key to this is to ensure the window is selected - ;; when the buffer point is moved and recentered. If they aren't - ;; strange things happen. + (ledger-reconcile-ensure-xacts-visible))) + +(defun ledger-reconcile-ensure-xacts-visible () + "Ensures that the last of the visible transactions in the +ledger buffer is at the bottom of the main window. The key to +this is to ensure the window is selected when the buffer point is +moved and recentered. If they aren't strange things happen." (let ((recon-window (get-buffer-window (get-buffer ledger-recon-buffer-name)))) (when recon-window @@ -335,10 +337,10 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (recenter -1)) (select-window recon-window) (ledger-reconcile-visit t)) - (add-hook 'post-command-hook 'ledger-reconcile-track-xact nil t)))) + (add-hook 'post-command-hook 'ledger-reconcile-track-xact nil t))) (defun ledger-reconcile-track-xact () - "Force the ledger buffer to recenter on the transactionat point in the reconcile buffer." + "Force the ledger buffer to recenter on the transaction at point in the reconcile buffer." (if (member this-command (list 'next-line 'previous-line 'mouse-set-point @@ -388,11 +390,12 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (set (make-local-variable 'ledger-acct) account)))) ;; Fold the ledger buffer - (if ledger-fold-on-reconcile - (ledger-occur-mode account buf)) ;; Now, actually run the reconciliation (with-current-buffer rbuf + (save-excursion + (if ledger-fold-on-reconcile + (ledger-occur-mode account ledger-buf))) (ledger-reconcile-refresh) (goto-char (point-min)) (ledger-reconcile-change-target) -- cgit v1.2.3 From b608ed23e413aaec6024c42c453f8cd9854498d7 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 13 Mar 2013 11:27:51 -0700 Subject: Reconcile skips asking for target if there are no uncleared xacts. --- lisp/ldg-reconcile.el | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 37d6f32c..ec4b7f88 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -145,15 +145,16 @@ And calculate the target-delta of the account being reconciled." (ledger-display-balance))) (defun ledger-reconcile-refresh () - "Force the reconciliation window to refresh." + "Force the reconciliation window to refresh. +Return the number of uncleared xacts found." (interactive) (let ((inhibit-read-only t) (line (count-lines (point-min) (point)))) (erase-buffer) - (ledger-do-reconcile) - (set-buffer-modified-p t) - (goto-char (point-min)) - (forward-line line))) + (prog1 (ledger-do-reconcile) + (set-buffer-modified-p t) + (goto-char (point-min)) + (forward-line line)))) (defun ledger-reconcile-refresh-after-save () "Refresh the recon-window after the ledger buffer is saved." @@ -270,7 +271,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (nth 0 posting))))) ;; return line-no of posting (defun ledger-do-reconcile () - "Get the uncleared transactions in the account and display them in the *Reconcile* buffer." + "Return the number of uncleared transactions in the account and display them in the *Reconcile* buffer." (let* ((buf ledger-buf) (account ledger-acct) (ledger-success nil) @@ -318,7 +319,8 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (set-buffer-modified-p nil) (toggle-read-only t) - (ledger-reconcile-ensure-xacts-visible))) + (ledger-reconcile-ensure-xacts-visible) + (length xacts))) (defun ledger-reconcile-ensure-xacts-visible () "Ensures that the last of the visible transactions in the @@ -396,9 +398,8 @@ moved and recentered. If they aren't strange things happen." (save-excursion (if ledger-fold-on-reconcile (ledger-occur-mode account ledger-buf))) - (ledger-reconcile-refresh) - (goto-char (point-min)) - (ledger-reconcile-change-target) + (if (> (ledger-reconcile-refresh) 0) + (ledger-reconcile-change-target)) (ledger-display-balance)))) (defvar ledger-reconcile-mode-abbrev-table) -- cgit v1.2.3 From f89665ba44ae50f056363d7e2c79a508060e2d18 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 14 Mar 2013 11:37:12 -0700 Subject: Reconcile code cleanup --- lisp/ldg-reconcile.el | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index ec4b7f88..c5e20c64 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -148,13 +148,11 @@ And calculate the target-delta of the account being reconciled." "Force the reconciliation window to refresh. Return the number of uncleared xacts found." (interactive) - (let ((inhibit-read-only t) - (line (count-lines (point-min) (point)))) + (let ((inhibit-read-only t)) (erase-buffer) (prog1 (ledger-do-reconcile) (set-buffer-modified-p t) - (goto-char (point-min)) - (forward-line line)))) + (goto-char (point-min))))) (defun ledger-reconcile-refresh-after-save () "Refresh the recon-window after the ledger buffer is saved." -- cgit v1.2.3 From 4c9b8cb9906ed86d3301c2fe1c8dbdf1498cd2cf Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 14 Mar 2013 11:38:32 -0700 Subject: Auto is now correctly scanning a ledger-auto buffer and returning useable functions --- lisp/ldg-auto.el | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/lisp/ldg-auto.el b/lisp/ldg-auto.el index 12832a4e..33a2cdba 100644 --- a/lisp/ldg-auto.el +++ b/lisp/ldg-auto.el @@ -21,8 +21,8 @@ ;;; Commentary: ;; -;; This module provides or automatically adding transactions to a -;; ledger buffer on a periodic basis. h Recurrence expressions are +;; This module provides for automatically adding transactions to a +;; ledger buffer on a periodic basis. Recurrence expressions are ;; inspired by Martin Fowler's "Recurring Events for Calendars", ;; martinfowler.com/apsupp/recurring.pdf @@ -92,15 +92,14 @@ of date." ;; of days are ok (between (eval day) 1 (ledger-auto-days-in-month (eval month) (eval year)))) (between (eval day) 1 31)) ;; no month specified, assume 31 days. - `#'(lambda (date) - (and ,(if (eval year) - `(if (eq (nth 5 (decode-time date)) ,(eval year)) t) - `t) - ,(if (eval month) - `(if (eq (nth 4 (decode-time date)) ,(eval month)) t) - `t) - ,(if (eval day) - `(if (eq (nth 3 (decode-time date)) ,(eval day)) t)))) + `'(and ,(if (eval year) + `(if (eq (nth 5 (decode-time date)) ,(eval year)) t) + `t) + ,(if (eval month) + `(if (eq (nth 4 (decode-time date)) ,(eval month)) t) + `t) + ,(if (eval day) + `(if (eq (nth 3 (decode-time date)) ,(eval day)) t))) (error "ledger-auto-constraint-numerical-date-macro: date out of range %S %S %S" (eval year) (eval month) (eval day)))) @@ -155,6 +154,15 @@ For example every second Friday, regardless of month." (setq xact-list (cons transaction xact-list)))) xact-list))) +(defun ledger-auto-replace-brackets () + "Replace all brackets with parens" + (goto-char (point-min)) + (while (search-forward "]" nil t) + (replace-match ")" nil t)) + (goto-char (point-min)) + (while (search-forward "[" nil t) + (replace-match "(" nil t))) + (defun ledger-auto-read-descriptor-tree (descriptor-string) "Take a date descriptor string and return a function that returns true if the date meets the requirements" @@ -163,16 +171,14 @@ returns true if the date meets the requirements" (let (pos) ;; Replace brackets with parens (insert descriptor-string) - (goto-char (point-min)) - (replace-string "[" "(") - (goto-char (point-min)) - (replace-string "]" ")") + (ledger-auto-replace-brackets) + (goto-char (point-max)) ;; double quote all the descriptors for string processing later (while (re-search-backward (concat "\\(20[0-9][0-9]\\|[\*]\\)[/\\-]" ;; Year slot - "\\([\*EO]\\|[0-9]+\\)[/\\-]" ;; Month slot - "\\([\*]\\|\\([0-9][0-9]\\)\\|" + "\\([\*EO]\\|[01][0-9]\\)[/\\-]" ;; Month slot + "\\([\*]\\|\\([0-3][0-9]\\)\\|" "\\([0-5]" "\\(\\(Su\\)\\|" "\\(Mo\\)\\|" @@ -193,17 +199,20 @@ returns true if the date meets the requirements" (read (buffer-substring (point-min) (point-max)))))) (defun ledger-transform-auto-tree (tree) +"Takes a lisp list of date descriptor strings, TREE, and returns a string with a lambda function of date." +;; use funcall to use the lambda function spit out here (if (consp tree) (let (result) (while (consp tree) (let ((newcar (car tree))) - (if (consp (car tree)) + (if (consp newcar) (setq newcar (ledger-transform-auto-tree (car tree)))) (if (consp newcar) (push newcar result) (push (ledger-auto-parse-date-descriptor newcar) result)) ) (setq tree (cdr tree))) - (nconc (nreverse result) tree)))) + `(lambda (date) + ,(nconc (list 'or) (nreverse result) tree))))) (defun ledger-auto-split-constraints (descriptor-string) "Return a list with the year, month and day fields split" -- cgit v1.2.3 From 720a73dec30fbab08f5233894b879d1fb26083c8 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 16 Mar 2013 21:52:54 -0700 Subject: Finally got rid of ledger-post-deafult-account-indent string. --- lisp/ldg-post.el | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index e23b3135..c871df28 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -27,10 +27,6 @@ ;;; Code: -(defcustom ledger-default-acct-transaction-indent " " - "Default indentation for account transactions in an entry." - :type 'string - :group 'ledger-post) (defgroup ledger-post nil "Options for controlling how Ledger-mode deals with postings and completion" :group 'ledger) -- cgit v1.2.3 From c2999a70f237cbdf8f666d80c4468898d94fd6ec Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 16 Mar 2013 21:55:09 -0700 Subject: Starting on forecast handling for the auto mode --- lisp/ldg-auto.el | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/lisp/ldg-auto.el b/lisp/ldg-auto.el index 33a2cdba..2a1a5b11 100644 --- a/lisp/ldg-auto.el +++ b/lisp/ldg-auto.el @@ -30,6 +30,16 @@ ;; function slot of the symbol VARNAME. Then use VARNAME as the ;; function without have to use funcall. +(defgroup ledger-auto nil + "Support for automatically recommendation transactions." + :group 'ledger) + +(defcustom ledger-auto-look-forward 14 + "Number of days auto look forward to recommend transactions" + :type 'integer + :group 'ledger-auto) + + (defsubst between (val low high) (and (>= val low) (<= val high))) @@ -132,6 +142,9 @@ For example every second Friday, regardless of month." "Return true if DATE is a holiday.") (defun ledger-auto-scan-transactions (auto-file) + "Scans AUTO_FILE and returns a list of transactions with date predicates. +The car of each item is a fuction of date that returns true if +the transaction should be logged for that day." (interactive "fFile name: ") (let ((xact-list (list))) (with-current-buffer @@ -211,6 +224,8 @@ returns true if the date meets the requirements" (push newcar result) (push (ledger-auto-parse-date-descriptor newcar) result)) ) (setq tree (cdr tree))) + + ;; tie up all the clauses in a big or and lambda `(lambda (date) ,(nconc (list 'or) (nreverse result) tree))))) @@ -248,6 +263,26 @@ returns true if the date meets the requirements" (ledger-auto-compile-constraints (ledger-auto-split-constraints descriptor))) + + +;; +;; Test harnesses for use in ielm +;; +(defvar auto-items) + +(defun ledger-auto-test-setup () + (setq auto-items + (ledger-auto-scan-transactions "~/FinanceData/ledger-auto.ledger"))) + + +(defun ledger-auto-test-predict () + (let ((today (current-time)) + test-date) + + (loop for day from 0 to ledger-auto-look-forward by 1 do + (setq test-date (time-add today (days-to-time day))) + (message "date: %S" (decode-time test-date))))) + (provide 'ldg-auto) ;;; ldg-auto.el ends here -- cgit v1.2.3 From b1c2c49709c9f2e9a2c0bb715a2e599094483498 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 17 Mar 2013 19:56:02 -0700 Subject: Fix bug 917 C-Begin C-End don't keep buffer synced --- lisp/ldg-reconcile.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index c5e20c64..a2c13917 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -344,7 +344,9 @@ moved and recentered. If they aren't strange things happen." (if (member this-command (list 'next-line 'previous-line 'mouse-set-point - 'ledger-reconcile-toggle)) + 'ledger-reconcile-toggle + 'end-of-buffer + 'beginning-of-buffer)) (if ledger-buffer-tracks-reconcile-buffer (save-excursion (ledger-reconcile-visit t))))) -- cgit v1.2.3 From 431d7e5b25f7e2997494ace7a0be78492c5d688b Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 17 Mar 2013 20:01:58 -0700 Subject: Fix bug 915 Save in reconcile mode maintains point. --- lisp/ldg-reconcile.el | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index a2c13917..40795ca2 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -205,11 +205,13 @@ Return the number of uncleared xacts found." (defun ledger-reconcile-save () "Save the ledger buffer." (interactive) - (dolist (buf (cons ledger-buf ledger-bufs)) - (with-current-buffer buf - (save-buffer))) - (set-buffer-modified-p nil) - (ledger-display-balance)) + (let ((curpoint (point))) + (dolist (buf (cons ledger-buf ledger-bufs)) + (with-current-buffer buf + (save-buffer))) + (set-buffer-modified-p nil) + (ledger-display-balance) + (goto-char curpoint))) (defun ledger-reconcile-finish () "Mark all pending posting or transactions as cleared. -- cgit v1.2.3 From ea72ac29eadad36d2b9e37a168127cff76f2880a Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 18 Mar 2013 10:50:11 -0700 Subject: Enh918 Have occur mode searches stored in mini buffer history --- lisp/ldg-occur.el | 5 ++--- lisp/ldg-report.el | 4 ++-- lisp/ldg-xact.el | 7 ++++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index 8b56d12c..35ca7f3d 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -49,7 +49,7 @@ (defvar ledger-occur-history nil "History of previously searched expressions for the prompt.") -(make-variable-buffer-local 'ledger-occur-history) +;;(make-variable-buffer-local 'ledger-occur-history) (defvar ledger-occur-last-match nil "Last match found.") @@ -95,8 +95,7 @@ When REGEX is nil, unhide everything, and remove higlight" (if ledger-occur-mode (list nil) (list (read-string (concat "Regexp<" (ledger-occur-prompt) - ">: ") "" 'ledger-occur-history )))) - (if (string-equal "" regex) (setq regex (ledger-occur-prompt))) + ">: ") nil 'ledger-occur-history (ledger-occur-prompt))))) (ledger-occur-mode regex (current-buffer))) (defun ledger-occur-prompt () diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 8d91d9d4..8e642a61 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -73,7 +73,7 @@ text that should replace the format specifier." (defvar ledger-report-cmd-prompt-history nil) (defvar ledger-original-window-cfg nil) (defvar ledger-report-saved nil) - +(defvar ledger-minibuffer-history nil) (defvar ledger-report-mode-abbrev-table) (defun ledger-report-reverse-lines () @@ -236,7 +236,7 @@ used to generate the buffer, navigating the buffer, etc." (if default (concat " (" default "): ") ": ")))) - (read-string default-prompt nil nil default))) + (read-string default-prompt nil 'ledger-minibuffer-history default))) (defun ledger-report-payee-format-specifier () "Substitute a payee name. diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index ecd87127..3e4cec4b 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -99,9 +99,10 @@ within the transaction." (ignore (goto-char here)))))) (defun ledger-copy-transaction-at-point (date) - "Ask for a new DATE and copy the transaction under point to that date. Leave point on the first amount."(interactive (list - (read-string "Copy to date: " - (concat ledger-year "/" ledger-month "/")))) + "Ask for a new DATE and copy the transaction under point to that date. Leave point on the first amount." + (interactive (list + (read-string "Copy to date: " + (concat ledger-year "/" ledger-month "/") 'ledger-minibuffer-history))) (let* ((here (point)) (extents (ledger-find-xact-extents (point))) (transaction (buffer-substring (car extents) (cadr extents))) -- cgit v1.2.3 From 8d73979abf87e3910bd040fb4b549b7d4c98a8c2 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 18 Mar 2013 11:13:54 -0700 Subject: Updated ledger-mode-dump-variables --- lisp/ldg-new.el | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index a9c70ff4..c42e2ef8 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -92,7 +92,8 @@ (forward-line 1)))))) (defun ledger-dump-variable (var) - (insert (format "%s: %S\n" (symbol-name var) (eval var)))) + (if var + (insert (format "%s: %S\n" (symbol-name var) (eval var))))) (defun ledger-mode-dump-variables () (interactive) @@ -103,7 +104,6 @@ (insert "Emacs: " (version) "\n") (insert "System Configuration: "system-configuration "\n") (insert "ldg-commodities:\n") - (ledger-dump-variable 'ledger-use-decimal-comma) (ledger-dump-variable 'ledger-reconcile-default-commodity) (insert "ldg-exec:\n") (ledger-dump-variable 'ledger-works) @@ -114,10 +114,10 @@ (ledger-dump-variable 'ledger-occur-history) (ledger-dump-variable 'ledger-occur-last-match) (insert "ldg-post:\n") - (ledger-dump-variable 'ledger-post-auto-adjust-amounts) + (ledger-dump-variable 'ledger-post-auto-adjust-postings) + (ledger-dump-variable 'ledger-post-account-alignment-column) (ledger-dump-variable 'ledger-post-amount-alignment-column) - (ledger-dump-variable 'ledger-post-use-iswitchb) - (ledger-dump-variable 'ledger-post-use-ido) + (ledger-dump-variable 'ledger-post-use-completion-engine) (insert "ldg-reconcile:\n") (ledger-dump-variable 'ledger-recon-buffer-name) (ledger-dump-variable 'ledger-fold-on-reconcile) -- cgit v1.2.3 From adfd6bafc3e276b1e7266cf03e7ab54ac70f3f90 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 18 Mar 2013 15:01:35 -0700 Subject: Have a working candidate search --- lisp/ldg-auto.el | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/lisp/ldg-auto.el b/lisp/ldg-auto.el index 2a1a5b11..ffc6ee7d 100644 --- a/lisp/ldg-auto.el +++ b/lisp/ldg-auto.el @@ -264,7 +264,16 @@ returns true if the date meets the requirements" (ledger-auto-split-constraints descriptor))) - +(defun ledger-auto-list-upcoming-xacts (candidate-items early horizon) + "Search CANDIDATE-ITEMS for xacts that occur within the perios today - EARLY to today + HORIZON" + (let ((start-date (time-subtract (current-time) (days-to-time early))) + test-date items) + (loop for day from 0 to (+ early horizon) by 1 do + (setq test-date (time-add start-date (days-to-time day))) + (dolist (candidate candidate-items items) + (if (funcall (car candidate) test-date) + (setq items (append items (list test-date (cdr candidate))))))) + items)) ;; ;; Test harnesses for use in ielm ;; @@ -277,11 +286,15 @@ returns true if the date meets the requirements" (defun ledger-auto-test-predict () (let ((today (current-time)) - test-date) + test-date items) (loop for day from 0 to ledger-auto-look-forward by 1 do (setq test-date (time-add today (days-to-time day))) - (message "date: %S" (decode-time test-date))))) + ;;(message "date: %S" (decode-time test-date)) + (dolist (item auto-items items) + (if (funcall (car item) test-date) + (setq items (append items (list (decode-time test-date) (cdr item))))))) + items)) (provide 'ldg-auto) -- cgit v1.2.3 From 5df242424ab507ca51b7b98c85cde594549510c6 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 18 Mar 2013 15:05:54 -0700 Subject: Bug 916: Added back in old ledger-post-align-amount code for Thierry. --- lisp/ldg-post.el | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index c871df28..d37b2f51 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -173,6 +173,55 @@ the account" (goto-char (1+ (line-end-position))) (ledger-post-align-postings))) +;; +;; This is the orignal ledger align amount code it does not attempt to format accounts +;; + + +(defun ledger-align-amounts (&optional column) + "Align amounts and accounts in the current region. +This is done so that the last digit falls in COLUMN, which +defaults to 52. ledger-default-acct-transaction-indent positions +the account" + (interactive "p") + (if (or (null column) (= column 1)) + (setq column ledger-post-amount-alignment-column)) + (save-excursion + ;; Position the account + ;; (beginning-of-line) + (set-mark (point)) + ;; (delete-horizontal-space) + ;; (insert ledger-default-acct-transaction-indent) + (goto-char (1+ (line-end-position))) + (let* ((mark-first (< (mark) (point))) + (begin (if mark-first (mark) (point))) + (end (if mark-first (point-marker) (mark-marker))) + offset) + ;; Position the amount + (goto-char begin) + (while (setq offset (ledger-next-amount end)) + (let ((col (current-column)) + (target-col (- column offset)) + adjust) + (setq adjust (- target-col col)) + (if (< col target-col) + (insert (make-string (- target-col col) ? )) + (move-to-column target-col) + (if (looking-back " ") + (delete-char (- col target-col)) + (skip-chars-forward "^ \t") + (delete-horizontal-space) + (insert " "))) + (forward-line)))))) + +(defun ledger-post-align-amount () + "Align the amounts in this posting." + (interactive) + (save-excursion + (set-mark (line-beginning-position)) + (goto-char (1+ (line-end-position))) + (ledger-align-amounts))) + (defun ledger-post-maybe-align (beg end len) "Align amounts only if point is in a posting. BEG, END, and LEN control how far it can align." -- cgit v1.2.3 From 5b7186ee1fd99e547b6a9f062f155a1a8050e9c3 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 18 Mar 2013 15:22:41 -0700 Subject: Ensure the ledger but tracks the reconcile buffer after a save. --- lisp/ldg-reconcile.el | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 40795ca2..511f8f70 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -209,9 +209,11 @@ Return the number of uncleared xacts found." (dolist (buf (cons ledger-buf ledger-bufs)) (with-current-buffer buf (save-buffer))) - (set-buffer-modified-p nil) - (ledger-display-balance) - (goto-char curpoint))) + (with-current-buffer (get-buffer ledger-recon-buffer-name) + (set-buffer-modified-p nil) + (ledger-display-balance) + (goto-char curpoint) + (ledger-reconcile-visit t)))) (defun ledger-reconcile-finish () "Mark all pending posting or transactions as cleared. -- cgit v1.2.3 From 06579c504d051f9609e7377ae7db4f451bdb44b7 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 19 Mar 2013 09:16:07 -0700 Subject: Check 'auto' package name to 'schedule' --- lisp/ldg-auto.el | 301 ------------------------------------------------------- 1 file changed, 301 deletions(-) delete mode 100644 lisp/ldg-auto.el diff --git a/lisp/ldg-auto.el b/lisp/ldg-auto.el deleted file mode 100644 index ffc6ee7d..00000000 --- a/lisp/ldg-auto.el +++ /dev/null @@ -1,301 +0,0 @@ -;;; ldg-auto.el --- Helper code for use with the "ledger" command-line tool - -;; Copyright (C) 2013 Craig Earls (enderw88 at gmail dot com) - -;; This file is not part of GNU Emacs. - -;; This is free software; you can redistribute it and/or modify it -;; under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. -;; -;; This is distributed in the hope that it will be useful, but WITHOUT -;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -;; License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;;; Commentary: -;; -;; This module provides for automatically adding transactions to a -;; ledger buffer on a periodic basis. Recurrence expressions are -;; inspired by Martin Fowler's "Recurring Events for Calendars", -;; martinfowler.com/apsupp/recurring.pdf - -;; use (fset 'VARNAME (macro args)) to put the macro definition in the -;; function slot of the symbol VARNAME. Then use VARNAME as the -;; function without have to use funcall. - -(defgroup ledger-auto nil - "Support for automatically recommendation transactions." - :group 'ledger) - -(defcustom ledger-auto-look-forward 14 - "Number of days auto look forward to recommend transactions" - :type 'integer - :group 'ledger-auto) - - -(defsubst between (val low high) - (and (>= val low) (<= val high))) - -(defun ledger-auto-days-in-month (month year) - "Return number of days in the MONTH, MONTH is from 1 to 12. -If year is nil, assume it is not a leap year" - (if (between month 1 12) - (if (and year (date-leap-year-p year) (= 2 month)) - 29 - (nth (1- month) '(31 28 31 30 31 30 31 31 30 31 30 31))) - (error "Month out of range, MONTH=%S" month))) - -;; Macros to handle date expressions - -(defmacro ledger-auto-constrain-day-in-month-macro (count day-of-week) - "Return a form that evaluates DATE that returns true for the COUNT DAY-OF-WEEK. -For example, return true if date is the 3rd Thursday of the -month. Negative COUNT starts from the end of the month. (EQ -COUNT 0) means EVERY day-of-week (eg. every Saturday)" - (if (and (between count -6 6) (between day-of-week 0 6)) - (cond ((zerop count) ;; Return true if day-of-week matches - `(eq (nth 6 (decode-time date)) ,day-of-week)) - ((> count 0) ;; Positive count - (let ((decoded (gensym))) - `(let ((,decoded (decode-time date))) - (if (and (eq (nth 6 ,decoded) ,day-of-week) - (between (nth 3 ,decoded) - ,(* (1- count) 7) - ,(* count 7))) - t - nil)))) - ((< count 0) - (let ((days-in-month (gensym)) - (decoded (gensym))) - `(let* ((,decoded (decode-time date)) - (,days-in-month (ledger-auto-days-in-month - (nth 4 ,decoded) - (nth 5 ,decoded)))) - (if (and (eq (nth 6 ,decoded) ,day-of-week) - (between (nth 3 ,decoded) - (+ ,days-in-month ,(* count 7)) - (+ ,days-in-month ,(* (1+ count) 7)))) - t - nil)))) - (t - (error "COUNT out of range, COUNT=%S" count))) - (error "Invalid argument to ledger-auto-day-in-month-macro %S %S" - count - day-of-week))) - -(defmacro ledger-auto-constrain-numerical-date-macro (year month day) - "Return a function of date that is only true if all constraints are met. -A nil constraint matches any input, a numerical entry must match that field -of date." - ;; Do bounds checking to make sure the incoming date constraint is sane - (if - (if (eval month) ;; if we have a month - (and (between (eval month) 1 12) ;; make sure it is between 1 - ;; and twelve and the number - ;; of days are ok - (between (eval day) 1 (ledger-auto-days-in-month (eval month) (eval year)))) - (between (eval day) 1 31)) ;; no month specified, assume 31 days. - `'(and ,(if (eval year) - `(if (eq (nth 5 (decode-time date)) ,(eval year)) t) - `t) - ,(if (eval month) - `(if (eq (nth 4 (decode-time date)) ,(eval month)) t) - `t) - ,(if (eval day) - `(if (eq (nth 3 (decode-time date)) ,(eval day)) t))) - (error "ledger-auto-constraint-numerical-date-macro: date out of range %S %S %S" (eval year) (eval month) (eval day)))) - - - -(defmacro ledger-auto-constrain-every-count-day-macro (day-of-week skip start-date) - "Return a form that is true for every DAY skipping SKIP, starting on START. -For example every second Friday, regardless of month." - (let ((start-day (nth 6 (decode-time (eval start-date))))) - (if (eq start-day day-of-week) ;; good, can proceed - `(if (zerop (mod (- (time-to-days date) ,(time-to-days (eval start-date))) ,(* skip 7))) - t - nil) - (error "START-DATE day of week doesn't match DAY-OF-WEEK")))) - -(defmacro ledger-auto-constrain-date-range-macro (month1 day1 month2 day2) - "Return a form of DATE that is true if DATE falls between MONTH1 DAY1 and MONTH2 DAY2." - (let ((decoded (gensym)) - (target-month (gensym)) - (target-day (gensym))) - `(let* ((,decoded (decode-time date)) - (,target-month (nth 4 decoded)) - (,target-day (nth 3 decoded))) - (and (and (> ,target-month ,month1) - (< ,target-month ,month2)) - (and (> ,target-day ,day1) - (< ,target-day ,day2)))))) - - -(defun ledger-auto-is-holiday (date) - "Return true if DATE is a holiday.") - -(defun ledger-auto-scan-transactions (auto-file) - "Scans AUTO_FILE and returns a list of transactions with date predicates. -The car of each item is a fuction of date that returns true if -the transaction should be logged for that day." - (interactive "fFile name: ") - (let ((xact-list (list))) - (with-current-buffer - (find-file-noselect auto-file) - (goto-char (point-min)) - (while (re-search-forward "^\\[\\(.*\\)\\] " nil t) - (let ((date-descriptor "") - (transaction nil) - (xact-start (match-end 0))) - (setq date-descriptors - (ledger-auto-read-descriptor-tree - (buffer-substring-no-properties - (match-beginning 0) - (match-end 0)))) - (forward-paragraph) - (setq transaction (list date-descriptors - (buffer-substring-no-properties - xact-start - (point)))) - (setq xact-list (cons transaction xact-list)))) - xact-list))) - -(defun ledger-auto-replace-brackets () - "Replace all brackets with parens" - (goto-char (point-min)) - (while (search-forward "]" nil t) - (replace-match ")" nil t)) - (goto-char (point-min)) - (while (search-forward "[" nil t) - (replace-match "(" nil t))) - -(defun ledger-auto-read-descriptor-tree (descriptor-string) - "Take a date descriptor string and return a function that -returns true if the date meets the requirements" - (with-temp-buffer - ;; copy the descriptor string into a temp buffer for manipulation - (let (pos) - ;; Replace brackets with parens - (insert descriptor-string) - (ledger-auto-replace-brackets) - - (goto-char (point-max)) - ;; double quote all the descriptors for string processing later - (while (re-search-backward - (concat "\\(20[0-9][0-9]\\|[\*]\\)[/\\-]" ;; Year slot - "\\([\*EO]\\|[01][0-9]\\)[/\\-]" ;; Month slot - "\\([\*]\\|\\([0-3][0-9]\\)\\|" - "\\([0-5]" - "\\(\\(Su\\)\\|" - "\\(Mo\\)\\|" - "\\(Tu\\)\\|" - "\\(We\\)\\|" - "\\(Th\\)\\|" - "\\(Fr\\)\\|" - "\\(Sa\\)\\)\\)\\)") nil t) ;; Day slot - (goto-char - (match-end 0)) - (insert ?\") - (goto-char (match-beginning 0)) - (insert "\"" ))) - - ;; read the descriptor string into a lisp object the transform the - ;; string descriptor into useable things - (ledger-transform-auto-tree - (read (buffer-substring (point-min) (point-max)))))) - -(defun ledger-transform-auto-tree (tree) -"Takes a lisp list of date descriptor strings, TREE, and returns a string with a lambda function of date." -;; use funcall to use the lambda function spit out here - (if (consp tree) - (let (result) - (while (consp tree) - (let ((newcar (car tree))) - (if (consp newcar) - (setq newcar (ledger-transform-auto-tree (car tree)))) - (if (consp newcar) - (push newcar result) - (push (ledger-auto-parse-date-descriptor newcar) result)) ) - (setq tree (cdr tree))) - - ;; tie up all the clauses in a big or and lambda - `(lambda (date) - ,(nconc (list 'or) (nreverse result) tree))))) - -(defun ledger-auto-split-constraints (descriptor-string) - "Return a list with the year, month and day fields split" - (let ((fields (split-string descriptor-string "[/\\-]" t)) - constrain-year constrain-month constrain-day) - (if (string= (car fields) "*") - (setq constrain-year nil) - (setq constrain-year (car fields))) - (if (string= (cadr fields) "*") - (setq constrain-month nil) - (setq constrain-month (cadr fields))) - (if (string= (nth 2 fields) "*") - (setq constrain-day nil) - (setq constrain-day (nth 2 fields))) - (list constrain-year constrain-month constrain-day))) - -(defun ledger-string-to-number-or-nil (str) - (if str - (string-to-number str) - nil)) - -(defun ledger-auto-compile-constraints (constraint-list) - (let ((year-constraint (ledger-string-to-number-or-nil (nth 0 constraint-list))) - (month-constraint (ledger-string-to-number-or-nil (nth 1 constraint-list))) - (day-constraint (ledger-string-to-number-or-nil (nth 2 constraint-list)))) - (ledger-auto-constrain-numerical-date-macro - year-constraint - month-constraint - day-constraint))) - -(defun ledger-auto-parse-date-descriptor (descriptor) - "Parse the date descriptor, return the evaluator" - (ledger-auto-compile-constraints - (ledger-auto-split-constraints descriptor))) - - -(defun ledger-auto-list-upcoming-xacts (candidate-items early horizon) - "Search CANDIDATE-ITEMS for xacts that occur within the perios today - EARLY to today + HORIZON" - (let ((start-date (time-subtract (current-time) (days-to-time early))) - test-date items) - (loop for day from 0 to (+ early horizon) by 1 do - (setq test-date (time-add start-date (days-to-time day))) - (dolist (candidate candidate-items items) - (if (funcall (car candidate) test-date) - (setq items (append items (list test-date (cdr candidate))))))) - items)) -;; -;; Test harnesses for use in ielm -;; -(defvar auto-items) - -(defun ledger-auto-test-setup () - (setq auto-items - (ledger-auto-scan-transactions "~/FinanceData/ledger-auto.ledger"))) - - -(defun ledger-auto-test-predict () - (let ((today (current-time)) - test-date items) - - (loop for day from 0 to ledger-auto-look-forward by 1 do - (setq test-date (time-add today (days-to-time day))) - ;;(message "date: %S" (decode-time test-date)) - (dolist (item auto-items items) - (if (funcall (car item) test-date) - (setq items (append items (list (decode-time test-date) (cdr item))))))) - items)) - -(provide 'ldg-auto) - -;;; ldg-auto.el ends here -- cgit v1.2.3 From 17496feda0452bc7add76252534f6239722d3bed Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 19 Mar 2013 09:17:06 -0700 Subject: Initial commit of ldg-schedule.el. Changed name from leg-auto.el and renamed internal functions --- lisp/ldg-schedule.el | 314 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 lisp/ldg-schedule.el diff --git a/lisp/ldg-schedule.el b/lisp/ldg-schedule.el new file mode 100644 index 00000000..b6b94308 --- /dev/null +++ b/lisp/ldg-schedule.el @@ -0,0 +1,314 @@ +;;; ldg-schedule.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2013 Craig Earls (enderw88 at gmail dot com) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: +;; +;; This module provides for automatically adding transactions to a +;; ledger buffer on a periodic basis. Recurrence expressions are +;; inspired by Martin Fowler's "Recurring Events for Calendars", +;; martinfowler.com/apsupp/recurring.pdf + +;; use (fset 'VARNAME (macro args)) to put the macro definition in the +;; function slot of the symbol VARNAME. Then use VARNAME as the +;; function without have to use funcall. + +(defgroup ledger-schedule nil + "Support for automatically recommendation transactions." + :group 'ledger) + +(defcustom ledger-schedule-look-forward 14 + "Number of days auto look forward to recommend transactions" + :type 'integer + :group 'ledger-schedule) + +(defcustom ledger-schedule-file "ledger-schedule.ledger" + "File to find scheduled transactions." + :type 'file + :group 'ledger-schedule) +(defsubst between (val low high) + (and (>= val low) (<= val high))) + +(defun ledger-schedule-days-in-month (month year) + "Return number of days in the MONTH, MONTH is from 1 to 12. +If year is nil, assume it is not a leap year" + (if (between month 1 12) + (if (and year (date-leap-year-p year) (= 2 month)) + 29 + (nth (1- month) '(31 28 31 30 31 30 31 31 30 31 30 31))) + (error "Month out of range, MONTH=%S" month))) + +;; Macros to handle date expressions + +(defmacro ledger-schedule-constrain-day-in-month-macro (count day-of-week) + "Return a form that evaluates DATE that returns true for the COUNT DAY-OF-WEEK. +For example, return true if date is the 3rd Thursday of the +month. Negative COUNT starts from the end of the month. (EQ +COUNT 0) means EVERY day-of-week (eg. every Saturday)" + (if (and (between count -6 6) (between day-of-week 0 6)) + (cond ((zerop count) ;; Return true if day-of-week matches + `(eq (nth 6 (decode-time date)) ,day-of-week)) + ((> count 0) ;; Positive count + (let ((decoded (gensym))) + `(let ((,decoded (decode-time date))) + (if (and (eq (nth 6 ,decoded) ,day-of-week) + (between (nth 3 ,decoded) + ,(* (1- count) 7) + ,(* count 7))) + t + nil)))) + ((< count 0) + (let ((days-in-month (gensym)) + (decoded (gensym))) + `(let* ((,decoded (decode-time date)) + (,days-in-month (ledger-schedule-days-in-month + (nth 4 ,decoded) + (nth 5 ,decoded)))) + (if (and (eq (nth 6 ,decoded) ,day-of-week) + (between (nth 3 ,decoded) + (+ ,days-in-month ,(* count 7)) + (+ ,days-in-month ,(* (1+ count) 7)))) + t + nil)))) + (t + (error "COUNT out of range, COUNT=%S" count))) + (error "Invalid argument to ledger-schedule-day-in-month-macro %S %S" + count + day-of-week))) + +(defmacro ledger-schedule-constrain-numerical-date-macro (year month day) + "Return a function of date that is only true if all constraints are met. +A nil constraint matches any input, a numerical entry must match that field +of date." + ;; Do bounds checking to make sure the incoming date constraint is sane + (if + (if (eval month) ;; if we have a month + (and (between (eval month) 1 12) ;; make sure it is between 1 + ;; and twelve and the number + ;; of days are ok + (between (eval day) 1 (ledger-schedule-days-in-month (eval month) (eval year)))) + (between (eval day) 1 31)) ;; no month specified, assume 31 days. + `'(and ,(if (eval year) + `(if (eq (nth 5 (decode-time date)) ,(eval year)) t) + `t) + ,(if (eval month) + `(if (eq (nth 4 (decode-time date)) ,(eval month)) t) + `t) + ,(if (eval day) + `(if (eq (nth 3 (decode-time date)) ,(eval day)) t))) + (error "ledger-schedule-constraint-numerical-date-macro: date out of range %S %S %S" (eval year) (eval month) (eval day)))) + + + +(defmacro ledger-schedule-constrain-every-count-day-macro (day-of-week skip start-date) + "Return a form that is true for every DAY skipping SKIP, starting on START. +For example every second Friday, regardless of month." + (let ((start-day (nth 6 (decode-time (eval start-date))))) + (if (eq start-day day-of-week) ;; good, can proceed + `(if (zerop (mod (- (time-to-days date) ,(time-to-days (eval start-date))) ,(* skip 7))) + t + nil) + (error "START-DATE day of week doesn't match DAY-OF-WEEK")))) + +(defmacro ledger-schedule-constrain-date-range-macro (month1 day1 month2 day2) + "Return a form of DATE that is true if DATE falls between MONTH1 DAY1 and MONTH2 DAY2." + (let ((decoded (gensym)) + (target-month (gensym)) + (target-day (gensym))) + `(let* ((,decoded (decode-time date)) + (,target-month (nth 4 decoded)) + (,target-day (nth 3 decoded))) + (and (and (> ,target-month ,month1) + (< ,target-month ,month2)) + (and (> ,target-day ,day1) + (< ,target-day ,day2)))))) + + +(defun ledger-schedule-is-holiday (date) + "Return true if DATE is a holiday.") + +(defun ledger-schedule-scan-transactions (auto-file) + "Scans AUTO_FILE and returns a list of transactions with date predicates. +The car of each item is a fuction of date that returns true if +the transaction should be logged for that day." + (interactive "fFile name: ") + (let ((xact-list (list))) + (with-current-buffer + (find-file-noselect auto-file) + (goto-char (point-min)) + (while (re-search-forward "^\\[\\(.*\\)\\] " nil t) + (let ((date-descriptor "") + (transaction nil) + (xact-start (match-end 0))) + (setq date-descriptors + (ledger-schedule-read-descriptor-tree + (buffer-substring-no-properties + (match-beginning 0) + (match-end 0)))) + (forward-paragraph) + (setq transaction (list date-descriptors + (buffer-substring-no-properties + xact-start + (point)))) + (setq xact-list (cons transaction xact-list)))) + xact-list))) + +(defun ledger-schedule-replace-brackets () + "Replace all brackets with parens" + (goto-char (point-min)) + (while (search-forward "]" nil t) + (replace-match ")" nil t)) + (goto-char (point-min)) + (while (search-forward "[" nil t) + (replace-match "(" nil t))) + +(defun ledger-schedule-read-descriptor-tree (descriptor-string) + "Take a date descriptor string and return a function that +returns true if the date meets the requirements" + (with-temp-buffer + ;; copy the descriptor string into a temp buffer for manipulation + (let (pos) + ;; Replace brackets with parens + (insert descriptor-string) + (ledger-schedule-replace-brackets) + + (goto-char (point-max)) + ;; double quote all the descriptors for string processing later + (while (re-search-backward + (concat "\\(20[0-9][0-9]\\|[\*]\\)[/\\-]" ;; Year slot + "\\([\*EO]\\|[01][0-9]\\)[/\\-]" ;; Month slot + "\\([\*]\\|\\([0-3][0-9]\\)\\|" + "\\([0-5]" + "\\(\\(Su\\)\\|" + "\\(Mo\\)\\|" + "\\(Tu\\)\\|" + "\\(We\\)\\|" + "\\(Th\\)\\|" + "\\(Fr\\)\\|" + "\\(Sa\\)\\)\\)\\)") nil t) ;; Day slot + (goto-char + (match-end 0)) + (insert ?\") + (goto-char (match-beginning 0)) + (insert "\"" ))) + + ;; read the descriptor string into a lisp object the transform the + ;; string descriptor into useable things + (ledger-transform-auto-tree + (read (buffer-substring (point-min) (point-max)))))) + +(defun ledger-transform-auto-tree (tree) +"Takes a lisp list of date descriptor strings, TREE, and returns a string with a lambda function of date." +;; use funcall to use the lambda function spit out here + (if (consp tree) + (let (result) + (while (consp tree) + (let ((newcar (car tree))) + (if (consp newcar) + (setq newcar (ledger-transform-auto-tree (car tree)))) + (if (consp newcar) + (push newcar result) + (push (ledger-schedule-parse-date-descriptor newcar) result)) ) + (setq tree (cdr tree))) + + ;; tie up all the clauses in a big or and lambda + `(lambda (date) + ,(nconc (list 'or) (nreverse result) tree))))) + +(defun ledger-schedule-split-constraints (descriptor-string) + "Return a list with the year, month and day fields split" + (let ((fields (split-string descriptor-string "[/\\-]" t)) + constrain-year constrain-month constrain-day) + (if (string= (car fields) "*") + (setq constrain-year nil) + (setq constrain-year (car fields))) + (if (string= (cadr fields) "*") + (setq constrain-month nil) + (setq constrain-month (cadr fields))) + (if (string= (nth 2 fields) "*") + (setq constrain-day nil) + (setq constrain-day (nth 2 fields))) + (list constrain-year constrain-month constrain-day))) + +(defun ledger-string-to-number-or-nil (str) + (if str + (string-to-number str) + nil)) + +(defun ledger-schedule-compile-constraints (constraint-list) + (let ((year-constraint (ledger-string-to-number-or-nil (nth 0 constraint-list))) + (month-constraint (ledger-string-to-number-or-nil (nth 1 constraint-list))) + (day-constraint (ledger-string-to-number-or-nil (nth 2 constraint-list)))) + (ledger-schedule-constrain-numerical-date-macro + year-constraint + month-constraint + day-constraint))) + +(defun ledger-schedule-parse-date-descriptor (descriptor) + "Parse the date descriptor, return the evaluator" + (ledger-schedule-compile-constraints + (ledger-schedule-split-constraints descriptor))) + + +(defun ledger-schedule-list-upcoming-xacts (candidate-items early horizon) + "Search CANDIDATE-ITEMS for xacts that occur within the perios today - EARLY to today + HORIZON" + (let ((start-date (time-subtract (current-time) (days-to-time early))) + test-date items) + (loop for day from 0 to (+ early horizon) by 1 do + (setq test-date (time-add start-date (days-to-time day))) + (dolist (candidate candidate-items items) + (if (funcall (car candidate) test-date) + (setq items (append items (list (list test-date (cadr candidate)))))))) + items)) + +(defun ledger-schedule-create-auto-buffer (candidate-items early horizon) + "Format CANDIDATE-ITEMS for display." + (let ((candidates (ledger-schedule-list-upcoming-xacts candidate-items early horizon)) + (auto-buf (get-buffer-create "*Ledger Auto*")) + (date-format (cdr (assoc "date-format" ledger-environment-alist)))) + (with-current-buffer auto-buf + (erase-buffer) + (dolist (candidate candidates) + (insert (format-time-string date-format (car candidate) ) " " (cadr candidate) "/n"))))) +;; +;; Test harnesses for use in ielm +;; +(defvar auto-items) + +(defun ledger-schedule-test-setup () + (setq auto-items + (ledger-schedule-scan-transactions "~/FinanceData/ledger-schedule.ledger"))) + + +(defun ledger-schedule-test-predict () + (let ((today (current-time)) + test-date items) + + (loop for day from 0 to ledger-schedule-look-forward by 1 do + (setq test-date (time-add today (days-to-time day))) + ;;(message "date: %S" (decode-time test-date)) + (dolist (item auto-items items) + (if (funcall (car item) test-date) + (setq items (append items (list (decode-time test-date) (cdr item))))))) + items)) + +(provide 'ldg-schedule) + +;;; ldg-schedule.el ends here -- cgit v1.2.3 From 7c6f9005922dc22b257b4acc9b6639f4c5589638 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 20 Mar 2013 12:23:18 -0700 Subject: Improved configuration dump. Now automatically dumps all customization variables without manually update --- lisp/ldg-new.el | 56 ++++++++++++++++---------------------------------------- 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index c42e2ef8..8ff95cd3 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -91,48 +91,24 @@ (delete-char 3) (forward-line 1)))))) -(defun ledger-dump-variable (var) +(defun ledger-mode-dump-variable (var) (if var - (insert (format "%s: %S\n" (symbol-name var) (eval var))))) - -(defun ledger-mode-dump-variables () - (interactive) - (find-file "ledger-mode-dump") - (delete-region (point-min) (point-max)) - (insert "Ledger Mode Configuration Dump\n") - (insert "Date: " (current-time-string) "\n") - (insert "Emacs: " (version) "\n") - (insert "System Configuration: "system-configuration "\n") - (insert "ldg-commodities:\n") - (ledger-dump-variable 'ledger-reconcile-default-commodity) - (insert "ldg-exec:\n") - (ledger-dump-variable 'ledger-works) - (ledger-dump-variable 'ledger-binary-path) - (insert "ldg-occur:\n") - (ledger-dump-variable 'ledger-occur-use-face-unfolded) - (ledger-dump-variable 'ledger-occur-mode) - (ledger-dump-variable 'ledger-occur-history) - (ledger-dump-variable 'ledger-occur-last-match) - (insert "ldg-post:\n") - (ledger-dump-variable 'ledger-post-auto-adjust-postings) - (ledger-dump-variable 'ledger-post-account-alignment-column) - (ledger-dump-variable 'ledger-post-amount-alignment-column) - (ledger-dump-variable 'ledger-post-use-completion-engine) - (insert "ldg-reconcile:\n") - (ledger-dump-variable 'ledger-recon-buffer-name) - (ledger-dump-variable 'ledger-fold-on-reconcile) - (ledger-dump-variable 'ledger-buffer-tracks-reconcile-buffer) - (ledger-dump-variable 'ledger-reconcile-force-window-bottom) - (ledger-dump-variable 'ledger-reconcile-toggle-to-pending) - (insert "ldg-reports:\n") - (ledger-dump-variable 'ledger-reports) - (ledger-dump-variable 'ledger-report-format-specifiers) - (ledger-dump-variable 'ledger-report-buffer-name) - (insert "ldg-state:") - (ledger-dump-variable 'ledger-clear-whole-transactions) - (insert "ldg-xact:\n") - (ledger-dump-variable 'ledger-highlight-xact-under-point)) + (insert (format " %s: %S\n" (symbol-name var) (eval var))))) +(defun ledger-mode-dump-group (group) + "Dump GROUP customizations to current buffer" + (let ((members (custom-group-members group nil))) + (dolist (member members) + (cond ((eq (cadr member) 'custom-group) + (insert (format "Group %s:\n" (symbol-name (car member)))) + (ledger-mode-dump-group (car member))) + ((eq (cadr member) 'custom-variable) + (ledger-mode-dump-variable (car member))))))) + +(defun ledger-mode-dump-configuration () + "Dump all customizations" + (find-file "ledger-mode-dump") + (ledger-mode-dump-group 'ledger)) (provide 'ledger) -- cgit v1.2.3 From 045c4b19eb626b814a889ec8b5e2e66ecee39cc6 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 20 Mar 2013 22:20:00 -0700 Subject: Added checking for thousands separators in commodity split. --- lisp/ldg-commodities.el | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 9291136f..0ed52fc3 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -34,12 +34,14 @@ (defun ledger-split-commodity-string (str) "Split a commoditized amount into two parts" (if (> (length str) 0) - (let (val - comm) + (let (val comm number-regex) (with-temp-buffer (insert str) (goto-char (point-min)) - (cond ((re-search-forward "-?[1-9][0-9]*[.,][0-9]*" nil t) + (if (assoc "decimal-comma" ledger-environment-alist) + (setq number-regex "-?[1-9][0-9.]*[,][0-9]*") + (setq number-regex "-?[1-9][0-9,]*[.][0-9]*")) + (cond ((re-search-forward number-regex nil t) ;; found a decimal number (setq val (string-to-number -- cgit v1.2.3 From 75ba85ff8efc8226261203d7af063c9be3d0c034 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 20 Mar 2013 22:53:09 -0700 Subject: Updated ldg-schedule --- lisp/ldg-schedule.el | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/lisp/ldg-schedule.el b/lisp/ldg-schedule.el index b6b94308..c2e5ea01 100644 --- a/lisp/ldg-schedule.el +++ b/lisp/ldg-schedule.el @@ -32,17 +32,28 @@ (defgroup ledger-schedule nil "Support for automatically recommendation transactions." - :group 'ledger) + :group 'ledger) + +(defcustom ledger-schedule-buffer-name "*Ledger Schedule*" + "Name for the schedule buffer" + :type 'string + :group 'ledger-schedule) + +(defcustom ledger-schedule-look-backward 7 + "Number of days to look back in time for transactions." + :type 'integer + :group 'ledger-schedule) (defcustom ledger-schedule-look-forward 14 "Number of days auto look forward to recommend transactions" :type 'integer :group 'ledger-schedule) -(defcustom ledger-schedule-file "ledger-schedule.ledger" +(defcustom ledger-schedule-file "~/FinanceData/ledger-schedule.ledger" "File to find scheduled transactions." :type 'file :group 'ledger-schedule) + (defsubst between (val low high) (and (>= val low) (<= val high))) @@ -121,7 +132,7 @@ of date." "Return a form that is true for every DAY skipping SKIP, starting on START. For example every second Friday, regardless of month." (let ((start-day (nth 6 (decode-time (eval start-date))))) - (if (eq start-day day-of-week) ;; good, can proceed + (if (eq start-day day-of-week) ;; good, can proceed `(if (zerop (mod (- (time-to-days date) ,(time-to-days (eval start-date))) ,(* skip 7))) t nil) @@ -144,14 +155,14 @@ For example every second Friday, regardless of month." (defun ledger-schedule-is-holiday (date) "Return true if DATE is a holiday.") -(defun ledger-schedule-scan-transactions (auto-file) +(defun ledger-schedule-scan-transactions (schedule-file) "Scans AUTO_FILE and returns a list of transactions with date predicates. The car of each item is a fuction of date that returns true if the transaction should be logged for that day." (interactive "fFile name: ") (let ((xact-list (list))) (with-current-buffer - (find-file-noselect auto-file) + (find-file-noselect schedule-file) (goto-char (point-min)) (while (re-search-forward "^\\[\\(.*\\)\\] " nil t) (let ((date-descriptor "") @@ -268,7 +279,7 @@ returns true if the date meets the requirements" (defun ledger-schedule-list-upcoming-xacts (candidate-items early horizon) - "Search CANDIDATE-ITEMS for xacts that occur within the perios today - EARLY to today + HORIZON" + "Search CANDIDATE-ITEMS for xacts that occur within the period today - EARLY to today + HORIZON" (let ((start-date (time-subtract (current-time) (days-to-time early))) test-date items) (loop for day from 0 to (+ early horizon) by 1 do @@ -278,15 +289,23 @@ returns true if the date meets the requirements" (setq items (append items (list (list test-date (cadr candidate)))))))) items)) -(defun ledger-schedule-create-auto-buffer (candidate-items early horizon) +(defun ledger-schedule-already-entered (candidate buffer) + (let ((target-date (format-time-string date-format (car candidate))) + (target-payee (cadr candidate))) + nil)) + +(defun ledger-schedule-create-auto-buffer (candidate-items early horizon ledger-buf) "Format CANDIDATE-ITEMS for display." (let ((candidates (ledger-schedule-list-upcoming-xacts candidate-items early horizon)) - (auto-buf (get-buffer-create "*Ledger Auto*")) + (schedule-buf (get-buffer-create ledger-schedule-buffer-name)) (date-format (cdr (assoc "date-format" ledger-environment-alist)))) - (with-current-buffer auto-buf + (with-current-buffer schedule-buf (erase-buffer) (dolist (candidate candidates) - (insert (format-time-string date-format (car candidate) ) " " (cadr candidate) "/n"))))) + (if (not (ledger-schedule-already-entered candidate ledger-buf)) + (insert (format-time-string date-format (car candidate) ) " " (cadr candidate) "\n")))))) + + ;; ;; Test harnesses for use in ielm ;; @@ -294,7 +313,7 @@ returns true if the date meets the requirements" (defun ledger-schedule-test-setup () (setq auto-items - (ledger-schedule-scan-transactions "~/FinanceData/ledger-schedule.ledger"))) + (ledger-schedule-scan-transactions ledger-schedule-file))) (defun ledger-schedule-test-predict () -- cgit v1.2.3 From b73e650e5f9dd2f3b2c90f445b878258f1e994d0 Mon Sep 17 00:00:00 2001 From: Rémi Vanicat <vanicat@debian.org> Date: Thu, 21 Mar 2013 23:28:14 +0100 Subject: Don't fail cleaning after reconcile when some buffer have been killed If buffer in leger-buf has been killed, ledger-reconcile-quit-cleanup will fail with an error. Better to do nothing. --- lisp/ldg-reconcile.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 511f8f70..662ef6c1 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -252,7 +252,7 @@ and exit reconcile mode" "Cleanup all hooks established by reconcile mode." (interactive) (let ((buf ledger-buf)) - (if buf + (if (buffer-live-p buf) (with-current-buffer buf (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t) (if ledger-fold-on-reconcile -- cgit v1.2.3 From 0d9250dbe49b62e4e340d8ac8fee84b4e9bfa57d Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Fri, 22 Mar 2013 20:56:19 -0700 Subject: Fix bug 916 along amount in region --- lisp/ldg-mode.el | 1 + lisp/ldg-post.el | 66 +++++++++----------------------------------------------- lisp/ldg-sort.el | 2 +- 3 files changed, 12 insertions(+), 57 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 97662aa3..be825ddb 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -120,6 +120,7 @@ (define-key map [sort-start] '(menu-item "Mark Sort Beginning" ledger-sort-insert-start-mark)) (define-key map [sort-buff] '(menu-item "Sort Buffer" ledger-sort-buffer)) (define-key map [sort-reg] '(menu-item "Sort Region" ledger-sort-region :enable mark-active)) + (define-key map [align-reg] '(menu-item "Align Region" ledger-post-align-region :enable mark-active)) (define-key map [sep2] '(menu-item "--")) (define-key map [copy-xact] '(menu-item "Copy Trans at Point" ledger-copy-transaction)) (define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current)) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index d37b2f51..3313c8e3 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -123,8 +123,8 @@ PROMPT is a string to prompt with. CHOICES is a list of (- (or (match-end 4) (match-end 3)) (point)))) -(defun ledger-post-align-postings (&optional column) - "Align amounts and accounts in the current region. +(defun ledger-post-align-posting (&optional column) + "Align amounts and accounts in the current posting. This is done so that the last digit falls in COLUMN, which defaults to 52. ledger-post-account-column positions the account" @@ -165,62 +165,16 @@ the account" (insert " "))) (forward-line)))))) -(defun ledger-post-align-posting () - "Align the amounts in this posting." - (interactive) - (save-excursion - (set-mark (line-beginning-position)) - (goto-char (1+ (line-end-position))) - (ledger-post-align-postings))) - -;; -;; This is the orignal ledger align amount code it does not attempt to format accounts -;; - -(defun ledger-align-amounts (&optional column) - "Align amounts and accounts in the current region. -This is done so that the last digit falls in COLUMN, which -defaults to 52. ledger-default-acct-transaction-indent positions -the account" - (interactive "p") - (if (or (null column) (= column 1)) - (setq column ledger-post-amount-alignment-column)) +(defun ledger-post-align-region (beg end) + (interactive "r") (save-excursion - ;; Position the account - ;; (beginning-of-line) - (set-mark (point)) - ;; (delete-horizontal-space) - ;; (insert ledger-default-acct-transaction-indent) - (goto-char (1+ (line-end-position))) - (let* ((mark-first (< (mark) (point))) - (begin (if mark-first (mark) (point))) - (end (if mark-first (point-marker) (mark-marker))) - offset) - ;; Position the amount - (goto-char begin) - (while (setq offset (ledger-next-amount end)) - (let ((col (current-column)) - (target-col (- column offset)) - adjust) - (setq adjust (- target-col col)) - (if (< col target-col) - (insert (make-string (- target-col col) ? )) - (move-to-column target-col) - (if (looking-back " ") - (delete-char (- col target-col)) - (skip-chars-forward "^ \t") - (delete-horizontal-space) - (insert " "))) - (forward-line)))))) + (goto-char beg) + (backward-paragraph) ;; make sure we are at the beginning of an xact + (while (< (point) end) + (ledger-post-align-posting) + (forward-line)))) -(defun ledger-post-align-amount () - "Align the amounts in this posting." - (interactive) - (save-excursion - (set-mark (line-beginning-position)) - (goto-char (1+ (line-end-position))) - (ledger-align-amounts))) (defun ledger-post-maybe-align (beg end len) "Align amounts only if point is in a posting. @@ -231,7 +185,7 @@ BEG, END, and LEN control how far it can align." (when (<= end (line-end-position)) (goto-char (line-beginning-position)) (if (looking-at ledger-post-line-regexp) - (ledger-post-align-postings)))))) + (ledger-post-align-posting)))))) (defun ledger-post-edit-amount () "Call 'calc-mode' and push the amount in the posting to the top of stack." diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el index 01d8edc9..3ce429fc 100644 --- a/lisp/ldg-sort.el +++ b/lisp/ldg-sort.el @@ -76,7 +76,7 @@ (new-end end)) (save-excursion (save-restriction - (goto-char beg) + (goto-char beg) (ledger-next-record-function) ;; make sure point is at the ;; beginning of a xact (setq new-beg (point)) -- cgit v1.2.3 From 9284600a54c8b4d37b63d25dd9e16dba664badbe Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Fri, 22 Mar 2013 21:23:27 -0700 Subject: Fix bug 915, maintain post in ledger buffer after save during reconciliation. --- lisp/ldg-reconcile.el | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 511f8f70..99958aaa 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -152,15 +152,20 @@ Return the number of uncleared xacts found." (erase-buffer) (prog1 (ledger-do-reconcile) (set-buffer-modified-p t) - (goto-char (point-min))))) + ;;(goto-char (point-min)) + ))) (defun ledger-reconcile-refresh-after-save () "Refresh the recon-window after the ledger buffer is saved." - (let ((buf (get-buffer ledger-recon-buffer-name))) + (let ((curbuf (current-buffer)) + (curpoint (point)) + (buf (get-buffer ledger-recon-buffer-name))) (if buf - (with-current-buffer buf - (ledger-reconcile-refresh) - (set-buffer-modified-p nil))))) + (progn + (with-current-buffer buf + (ledger-reconcile-refresh) + (set-buffer-modified-p nil)) + (select-window (get-buffer-window curbuf)))))) (defun ledger-reconcile-add () "Use ledger xact to add a new transaction." -- cgit v1.2.3 From 8a1d990809f3b1374d57d57783cc1dc2d7f841ea Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 23 Mar 2013 14:22:47 -0700 Subject: Fix Bug 929 consistent naming of buffer narrowing. --- doc/ledger-mode.texi | 20 ++++++++++---------- lisp/ldg-mode.el | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index 001eb054..7b62a735 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -128,7 +128,7 @@ Ledger from a convenient command line. * Quick Add:: * Reconciliation:: * Reports:: -* Folding:: +* Narrowing:: @end menu @node Quick Add, Reconciliation, Quick Demo, Quick Demo @@ -177,7 +177,7 @@ reach $0. End the reconciliation by typing @code{C-c C-c}. This saves the demo.ledger buffer and marks the transactions and finally cleared. Type @code{q} to close out the reconciliation buffer. -@node Reports, Folding, Reconciliation, Quick Demo +@node Reports, Narrowing, Reconciliation, Quick Demo @subsection Reports The real power of Ledger is in it reporting capabilities. Reports can @@ -197,8 +197,8 @@ Another built-in report is the balance report. In the report to run, type @code{bal}, and a balance report of all accounts will be shown. -@node Folding, , Reports, Quick Demo -@subsection Folding +@node Narrowing, , Reports, Quick Demo +@subsection Narrowing A ledger file can get very large. It can be helpful to collapse the buffer to display only the transactions you are interested in. Ledger-mode @@ -214,7 +214,7 @@ match the regex. The regex can be on any field, or amount. * Marking Transactions:: * Deleting Transactions:: * Sorting Transactions:: -* Hiding Transactions:: +* Narrowing Transactions:: @end menu @node Adding Transactions, Editing Amounts, The Ledger Buffer, The Ledger Buffer @@ -285,7 +285,7 @@ provides an easy way to delete the transaction under point: @code{C-c C-d}. The advantage to using this method is that the complete transaction operation is in the undo buffer. -@node Sorting Transactions, Hiding Transactions, Deleting Transactions, The Ledger Buffer +@node Sorting Transactions, Narrowing Transactions, Deleting Transactions, The Ledger Buffer @section Sorting Transactions As you operating on the Ledger files, they may become disorganized. For @@ -320,10 +320,10 @@ You can use menu entries to insert start and end markers. These functions will automatically delete old markers and put new new marker at point. -@node Hiding Transactions, , Sorting Transactions, The Ledger Buffer -@section Hiding Transactions +@node Narrowing Transactions, , Sorting Transactions, The Ledger Buffer +@section Narrowing Transactions -Often you will want to run Ledger register reports just to look at ax +Often you will want to run Ledger register reports just to look at a specific set of transactions. If you don't need the running total calculation handled by Ledger, Ledger-mode provides a rapid way of narrowing what is displayed in the buffer in a way that is simpler than @@ -363,7 +363,7 @@ C-f} again. * Starting a Reconciliation:: * Mark Transactions Pending:: * Edit Transactions During Reconciliation:: -* Finalize Reconciliation:: +* Finalize Reconciliation:: * Adding and Deleting Transactions during Reconciliation:: * Changing Reconciliation Account:: * Changing Reconciliation Target:: diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index be825ddb..c8a46d6b 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -135,7 +135,7 @@ (define-key map [add-xact] '(menu-item "Add Transaction (ledger xact)" ledger-add-transaction :enable ledger-works)) (define-key map [sep3] '(menu-item "--")) (define-key map [reconcile] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works)) - (define-key map [reconcile] '(menu-item "Hide Xacts" ledger-occur)))) + (define-key map [reconcile] '(menu-item "Narrow to REGEX" ledger-occur)))) (defun ledger-time-less-p (t1 t2) "Say whether time value T1 is less than time value T2." -- cgit v1.2.3 From 059b86b30e2ba65bb4cd7b7d1415831093cefdcc Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 23 Mar 2013 14:28:10 -0700 Subject: Fixed Bug 930 Toggle transaction menu entry incorrect --- lisp/ldg-mode.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index c8a46d6b..8563030d 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -124,7 +124,7 @@ (define-key map [sep2] '(menu-item "--")) (define-key map [copy-xact] '(menu-item "Copy Trans at Point" ledger-copy-transaction)) (define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current)) - (define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-entry)) + (define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-transaction)) (define-key map [sep4] '(menu-item "--")) (define-key map [edit-amount] '(menu-item "Reconcile Account" ledger-reconcile)) (define-key map [sep6] '(menu-item "--")) -- cgit v1.2.3 From 4cf6ca6e79b891acd65db869fbf8e6b27f61c588 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 23 Mar 2013 14:30:29 -0700 Subject: Bug 931 Menu consistency Delete Transaction --- lisp/ldg-mode.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 8563030d..29f3fc09 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -130,7 +130,7 @@ (define-key map [sep6] '(menu-item "--")) (define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount)) (define-key map [sep] '(menu-item "--")) - (define-key map [delete-xact] '(menu-item "Delete Entry" ledger-delete-current-transaction)) + (define-key map [delete-xact] '(menu-item "Delete Transaction" ledger-delete-current-transaction)) (define-key map [cmp-xact] '(menu-item "Complete Transaction" ledger-fully-complete-entry)) (define-key map [add-xact] '(menu-item "Add Transaction (ledger xact)" ledger-add-transaction :enable ledger-works)) (define-key map [sep3] '(menu-item "--")) -- cgit v1.2.3 From 89d480f5109c197c3fad658a45eaee4b95ba76db Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 23 Mar 2013 18:59:07 -0700 Subject: ledger-mode.texi patches from Thierry --- doc/ledger-mode.texi | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index 7b62a735..def583ca 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -306,13 +306,13 @@ there is no key sequence. You can limit the allowed sort region by using embedded Ledger-mode markup within your ledger. For exmaple @smallexample -<<< infomration to not sort >>> +<<< information to not sort >>> ; Ledger-mode: Start sort <<< xacts to sort >>> -;Ledger-mode: End sort +; Ledger-mode: End sort <<< information to not sort >>> @end smallexample @@ -349,11 +349,13 @@ Show only transactions that have a posting to the `Groceries' account. Show only transactions occurring in January of 2011. @item ^2011/.*/25 Show only transactions occurring on the 25th of the month in 2011 -@item .*ore -Show only transaction with payees or accounts ending in `ore' +@item auto +Show only transactions with payees or accounts or comments containing `auto' +@item harley$ +Show only transcations with any line ending with `harley' @end table -To show all transactions simply invoke @code{Hide Xacts} or @code{C-c +To show back all transactions simply invoke @code{Hide Xacts} or @code{C-c C-f} again. @node The Reconcile Buffer, The Report Buffer, The Ledger Buffer, Top @@ -401,13 +403,13 @@ particular about what you enter for the account. You can leave it blank and Reconcile Mode will show you ALL uncleared transactions. After you enter the account enter the target amount. Ledger expects you to enter an amount with a commodity. It assumes initially that you are using $ -(USD) as your default commodity. If you are working in a difference +(USD) as your default commodity. If you are working in a different currency you can change the default in variable @code{ledger-reconcile-default-commodity} to whatever you need. If you work in multiple commodities simply enter the commoditized amount (for example @code{340 VSDX}, for 340 shares of VSDX). -Ledger-mode reconcile cannot currently reconcile accounts the have +Ledger-mode reconcile cannot currently reconcile accounts that have multiple commodities, such as brokerage accounts. You may use reconciliation mode to clear transactions, but balance calculations will not display the complete list of commodities. @@ -416,7 +418,7 @@ not display the complete list of commodities. @section Mark Transactions Pending The @file{*Reconcile*} buffer will show all the uncleared transactions -that meeting the criteria set in the regex. By default uncleared +that meet the criteria set in the regex. By default uncleared transactions are shown in red. When you have verified that a transaction has been correctly and completely recorded by the opposing party, mark the transaction as pending using the space bar. Continue @@ -448,7 +450,7 @@ into your ledger. Simply type @code{a} to bring up the quick add for the ledger buffer. Typing @code{d} will delete the transaction under point in the -@file{*Reconcile*} buffer form the ledger buffer. +@file{*Reconcile*} buffer from the ledger buffer. @node Changing Reconciliation Account, Changing Reconciliation Target, Adding and Deleting Transactions during Reconciliation, The Reconcile Buffer @section Changing Reconciliation Account @@ -512,11 +514,11 @@ to provide a prefix argument to the run-report command. For example, type @code{M-1 C-c C-o C-r}. This will prompt you for the report name, then present the report command line to be edited. When you hit enter, the report will be run, but it will not be permanently saved. If you -want to save it, type @code{S} in the the @file{*Ledger Report*} buffer you +want to save it, type @code{S} in the @file{*Ledger Report*} buffer you will have the option to give it a new name, or overwrite the old report. -Deleting reports is accomplished by type @code{C-c C-o C-e} Edit Reports -in the ledger buffer, or typing @code{E} in the @file{*Ledger Report*} +Deleting reports is accomplished by typing @code{C-c C-o C-e} Edit Reports +in the ledger buffer, or typing @code{e} in the @file{*Ledger Report*} buffer. This takes you to the Emacs customization window for the @code{ledger-reports} variable. Use the widgets to delete the report you want removed. @@ -547,8 +549,7 @@ example, if you wanted to specify a register report the displayed transactions from a user-determined account with a particular meta-data tag value, you specify the following command line: @smallexample -ledger -f %(ledger-file) reg %(account) --limit \"tag('my-tag') =~ -/%(value)/\" +ledger -f %(ledger-file) reg %(account) --limit \"tag('my-tag') =~/%(value)/\" @end smallexample @noindent Note how the double-quotes are escaped with back-slashes. @@ -589,9 +590,9 @@ mathematical sense. @section Ledger-mode Customization Ledger-mode has several options available for configuration. All -options can be configure through the Emacs customization menus, or +options can be configured through the Emacs customization menus, or specified in your Emacs initialization file. The complete list of -options is show below. To change the option using the Emacs +options is shown below. To change the option using the Emacs customization menu, simply chose customize in the Options menu and look for Ledger under the data options. Alternately you can choose ``Customize Specific Group'' and enter ``Ledger'' as the group. @@ -614,11 +615,11 @@ for Ledger under the data options. Alternately you can choose @subsection Ledger Customization Group @table @code @item ledger-occur-use-face-unfolded - If non-nil use a custom face for xacts shown in `ledger-occur' mode using @code{ledger-occur-xact-face}. + If non-nil, use a custom face for xacts shown in `ledger-occur' mode using @code{ledger-occur-xact-face}. @item ledger-clear-whole-transactions If non-nil, clear whole transactions, not individual postings. @item ledger-highlight-xact-under-point - If non-nil highlight xact under point using @code{ledger-font-highlight-face}. + If non-nil, highlight xact under point using @code{ledger-font-highlight-face}. @end table @node Ledger Reconcile Customization Group, Ledger Report Customization Group, Ledger Customization Group, Customization Variables -- cgit v1.2.3 From 99973d0c0c8ac95d2bf73df807df8da1356fe1c9 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 23 Mar 2013 19:54:40 -0700 Subject: Rewrote ledger-post-align-postings to address bugs 923 924 925 926 927 and 928. --- lisp/ldg-mode.el | 20 +++++++--- lisp/ldg-post.el | 111 +++++++++++++++++++++++++++++-------------------------- 2 files changed, 72 insertions(+), 59 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 29f3fc09..c900d3d3 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -41,9 +41,17 @@ (defun ledger-remove-overlays () "Remove all overlays from the ledger buffer." -(interactive) - "remove overlays formthe buffer, used if the buffer is reverted" - (remove-overlays)) + (interactive) + (remove-overlays)) + +(defun ledger-magic-tab () + "Decide what to with with <TAB> . +Can be pcomplete, or align-posting" + (interactive) + (if (and (> (point) 1) + (looking-back "[:A-Za-z0-9]" 1)) + (pcomplete) + (ledger-post-align-postings))) (defvar ledger-mode-abbrev-table) @@ -70,7 +78,7 @@ (add-hook 'post-command-hook 'ledger-highlight-xact-under-point nil t) (add-hook 'before-revert-hook 'ledger-remove-overlays nil t) (make-variable-buffer-local 'highlight-overlay) - + (ledger-init-load-init-file) (let ((map (current-local-map))) @@ -86,8 +94,8 @@ (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) (define-key map [(control ?c) (control ?t)] 'ledger-test-run) (define-key map [(control ?c) (control ?y)] 'ledger-set-year) - (define-key map [tab] 'pcomplete) - (define-key map [(control ?i)] 'pcomplete) + (define-key map [tab] 'ledger-magic-tab) + (define-key map [(control ?i)] 'ledger-magic-tab) (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry) (define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 3313c8e3..934e70a1 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -116,76 +116,81 @@ PROMPT is a string to prompt with. CHOICES is a list of (goto-char pos))) (defun ledger-next-amount (&optional end) - "Move point to the next amount, as long as it is not past END." + "Move point to the next amount, as long as it is not past END. +Return the width of the amount field as an integer." + (beginning-of-line) (when (re-search-forward "\\( \\|\t\\| \t\\)[ \t]*-?\\([A-Z$€£]+ *\\)?\\(-?[0-9,]+?\\)\\(.[0-9]+\\)?\\( *[A-Z$€£]+\\)?\\([ \t]*@@?[^\n;]+?\\)?\\([ \t]+;.+?\\|[ \t]*\\)?$" (marker-position end) t) (goto-char (match-beginning 0)) (skip-syntax-forward " ") (- (or (match-end 4) (match-end 3)) (point)))) -(defun ledger-post-align-posting (&optional column) - "Align amounts and accounts in the current posting. -This is done so that the last digit falls in COLUMN, which -defaults to 52. ledger-post-account-column positions -the account" - (interactive "p") - (if (or (null column) (= column 1)) - (setq column ledger-post-amount-alignment-column)) +(defun ledger-next-account (&optional end) + "Move point to the beginning of the next account, or status marker (!*), as long as it is not past END. +Return the column of the beginning of the account" + (beginning-of-line) + (if (> (marker-position end) (point)) + (when (re-search-forward "\\(^[ ]+\\)\\([*!;a-zA-Z0-9]+?\\)" (marker-position end) t) + (goto-char (match-beginning 2)) + (current-column)))) + +(defun ledger-post-align-postings () + "Align all accounts and amounts within region, if there is no +region alight the posting on the current line." + (interactive) (save-excursion - ;; Position the account - (if (not (or (looking-at "[ \t]*[1-9]") - (and (looking-at "[ \t]+\n") - (looking-back "[ \n]" (- (point) 2))))) - (save-excursion - (beginning-of-line) - (set-mark (point)) - (delete-horizontal-space) - (insert (make-string ledger-post-account-alignment-column ? ))) - (set-mark (point))) - (set-mark (point)) - (goto-char (1+ (line-end-position))) + ;; If there is no region set + (when (or (not (mark)) + (= (point) (mark))) + (beginning-of-line) + (set-mark (point)) + (goto-char (1+ (line-end-position)))) + (let* ((mark-first (< (mark) (point))) (begin (if mark-first (mark) (point))) (end (if mark-first (point-marker) (mark-marker))) - offset) - ;; Position the amount + acc-col amt-offset) + (goto-char end) + (end-of-line) + (setq end (point-marker)) (goto-char begin) - (while (setq offset (ledger-next-amount end)) - (let ((col (current-column)) - (target-col (- column offset)) - adjust) - (setq adjust (- target-col col)) - (if (< col target-col) - (insert (make-string (- target-col col) ? )) - (move-to-column target-col) - (if (looking-back " ") - (delete-char (- col target-col)) - (skip-chars-forward "^ \t") - (delete-horizontal-space) - (insert " "))) - (forward-line)))))) - - -(defun ledger-post-align-region (beg end) - (interactive "r") - (save-excursion - (goto-char beg) - (backward-paragraph) ;; make sure we are at the beginning of an xact - (while (< (point) end) - (ledger-post-align-posting) - (forward-line)))) - + (beginning-of-line) + (setq begin (point-marker)) + (while (setq acc-col (ledger-next-account end)) + ;; Adjust account position if necessary + (let ((acc-adjust (- ledger-post-account-alignment-column acc-col))) + (if (/= acc-adjust 0) + (if (> acc-adjust 0) + (insert (make-string acc-adjust ? )) ;; Account too far left + (if (looking-back " " (- (point) 3)) + (delete-char acc-adjust) + (skip-chars-forward "^ \t") + (delete-horizontal-space) + (insert " "))))) + (when (setq amt-offset (ledger-next-amount end)) + (let* ((amt-adjust (- ledger-post-amount-alignment-column + amt-offset + (current-column)))) + (if (/= amt-adjust 0) + (if (> amt-adjust 0) + (insert (make-string amt-adjust ? )) + (if (looking-back " ") + (delete-char amt-adjust) + (skip-chars-forward "^ \t") + (delete-horizontal-space) + (insert " ")))))) + (forward-line))))) (defun ledger-post-maybe-align (beg end len) "Align amounts only if point is in a posting. BEG, END, and LEN control how far it can align." (if ledger-post-auto-adjust-postings (save-excursion - (goto-char beg) - (when (<= end (line-end-position)) - (goto-char (line-beginning-position)) - (if (looking-at ledger-post-line-regexp) - (ledger-post-align-posting)))))) + (goto-char beg) + (when (<= end (line-end-position)) + (goto-char (line-beginning-position)) + (if (looking-at ledger-post-line-regexp) + (ledger-post-align-postings)))))) (defun ledger-post-edit-amount () "Call 'calc-mode' and push the amount in the posting to the top of stack." -- cgit v1.2.3 From f855d7e745a41f8c91f0d6f593274df794a83589 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 23 Mar 2013 20:09:07 -0700 Subject: Finish bug 929 got rid of all references to folding, use narrowing instead. --- doc/ledger-mode.texi | 6 +++--- lisp/ldg-fonts.el | 2 +- lisp/ldg-occur.el | 14 +++++++------- lisp/ldg-reconcile.el | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index def583ca..70a5d97a 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -614,7 +614,7 @@ for Ledger under the data options. Alternately you can choose @node Ledger Customization Group, Ledger Reconcile Customization Group, Customization Variables, Customization Variables @subsection Ledger Customization Group @table @code -@item ledger-occur-use-face-unfolded +@item ledger-occur-use-face-shown If non-nil, use a custom face for xacts shown in `ledger-occur' mode using @code{ledger-occur-xact-face}. @item ledger-clear-whole-transactions If non-nil, clear whole transactions, not individual postings. @@ -631,7 +631,7 @@ The default commodity for use in target calculations in ledger reconcile. Defaults to $ (USD) @item ledger-recon-buffer-name Name to use for reconciliation window. -@item ledger-fold-on-reconcile +@item ledger-narrow-on-reconcile If non-nil, limit transactions shown in main buffer to those matching the reconcile regex. @item ledger-buffer-tracks-reconcile-buffer @@ -674,7 +674,7 @@ Default face for other transactions Face for Ledger accounts @item ledger-font-posting-amount-face Face for Ledger amounts -@item ledger-occur-folded-face +@item ledger-occur-narrowed-face Default face for Ledger occur mode hidden transactions @item ledger-occur-xact-face Default face for Ledger occur mode shown transactions diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index d760140c..76bfc03d 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -62,7 +62,7 @@ "Face for Ledger amounts" :group 'ledger-faces) -(defface ledger-occur-folded-face +(defface ledger-occur-narrowed-face `((t :foreground "grey70" :invisible t )) "Default face for Ledger occur mode hidden transactions" :group 'ledger-faces) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index 35ca7f3d..28d87b78 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -20,7 +20,7 @@ ;; MA 02111-1307, USA. ;;; Commentary: -;; Provide code folding to ledger mode. Adapted from original loccur +;; Provide buffer narrowing to ledger mode. Adapted from original loccur ;; mode by Alexey Veretennikov <alexey dot veretennikov at gmail dot ;; com> ;; @@ -31,11 +31,11 @@ (defconst ledger-occur-overlay-property-name 'ledger-occur-custom-buffer-grep) -(defcustom ledger-occur-use-face-unfolded t +(defcustom ledger-occur-use-face-shown t "If non-nil, use a custom face for xacts shown in `ledger-occur' mode using ledger-occur-xact-face." :type 'boolean :group 'ledger) -(make-variable-buffer-local 'ledger-occur-use-face-unfolded) +(make-variable-buffer-local 'ledger-occur-use-face-shown) (defvar ledger-occur-mode nil @@ -69,7 +69,7 @@ When REGEX is nil, unhide everything, and remove higlight" (if (or (null regex) (zerop (length regex))) nil - (concat " Ledger-Folded: " regex))) + (concat " Ledger-Narrowed: " regex))) (force-mode-line-update) (ledger-occur-remove-overlays) (if ledger-occur-mode @@ -79,7 +79,7 @@ When REGEX is nil, unhide everything, and remove higlight" (ledger-occur-create-xact-overlays ovl-bounds)) (setq ledger-occur-overlay-list (append ledger-occur-overlay-list - (ledger-occur-create-folded-overlays buffer-matches))) + (ledger-occur-create-narrowed-overlays buffer-matches))) (setq ledger-occur-last-match regex) (if (get-buffer-window buffer) (select-window (get-buffer-window buffer))))) @@ -116,7 +116,7 @@ When REGEX is nil, unhide everything, and remove higlight" (current-word)))) prompt)) -(defun ledger-occur-create-folded-overlays(buffer-matches) +(defun ledger-occur-create-narrowed-overlays(buffer-matches) (if buffer-matches (let ((overlays (let ((prev-end (point-min)) @@ -156,7 +156,7 @@ Argument OVL-BOUNDS contains bounds for the transactions to be left visible." ovl-bounds))) (mapcar (lambda (ovl) (overlay-put ovl ledger-occur-overlay-property-name t) - (if ledger-occur-use-face-unfolded + (if ledger-occur-use-face-shown (overlay-put ovl 'face 'ledger-occur-xact-face ))) overlays))) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index c33eef2e..a4960260 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -40,7 +40,7 @@ "Name to use for reconciliation window." :group 'ledger-reconcile) -(defcustom ledger-fold-on-reconcile t +(defcustom ledger-narrow-on-reconcile t "If t, limit transactions shown in main buffer to those matching the reconcile regex." :type 'boolean :group 'ledger-reconcile) @@ -260,7 +260,7 @@ and exit reconcile mode" (if (buffer-live-p buf) (with-current-buffer buf (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t) - (if ledger-fold-on-reconcile + (if ledger-narrow-on-reconcile (progn (ledger-occur-quit-buffer buf) (ledger-highlight-xact-under-point))))))) @@ -400,12 +400,12 @@ moved and recentered. If they aren't strange things happen." (set (make-local-variable 'ledger-buf) buf) (set (make-local-variable 'ledger-acct) account)))) - ;; Fold the ledger buffer + ;; Narrow the ledger buffer ;; Now, actually run the reconciliation (with-current-buffer rbuf (save-excursion - (if ledger-fold-on-reconcile + (if ledger-narrow-on-reconcile (ledger-occur-mode account ledger-buf))) (if (> (ledger-reconcile-refresh) 0) (ledger-reconcile-change-target)) -- cgit v1.2.3 From 0bcef93e29a67310cef209074f2162415f1cffd3 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 23 Mar 2013 20:22:40 -0700 Subject: Bug 915 maintain point in buffer when saved. --- lisp/ldg-reconcile.el | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index a4960260..3d73cca9 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -159,13 +159,14 @@ Return the number of uncleared xacts found." "Refresh the recon-window after the ledger buffer is saved." (let ((curbuf (current-buffer)) (curpoint (point)) - (buf (get-buffer ledger-recon-buffer-name))) - (if buf + (recon-buf (get-buffer ledger-recon-buffer-name))) + (if (buffer-live-p recon-buf) (progn - (with-current-buffer buf - (ledger-reconcile-refresh) - (set-buffer-modified-p nil)) - (select-window (get-buffer-window curbuf)))))) + (with-current-buffer recon-buf + (ledger-reconcile-refresh) + (set-buffer-modified-p nil)) + (select-window (get-buffer-window curbuf)) + (goto-char curpoint))))) (defun ledger-reconcile-add () "Use ledger xact to add a new transaction." @@ -211,14 +212,14 @@ Return the number of uncleared xacts found." "Save the ledger buffer." (interactive) (let ((curpoint (point))) - (dolist (buf (cons ledger-buf ledger-bufs)) - (with-current-buffer buf - (save-buffer))) - (with-current-buffer (get-buffer ledger-recon-buffer-name) - (set-buffer-modified-p nil) - (ledger-display-balance) - (goto-char curpoint) - (ledger-reconcile-visit t)))) + (dolist (buf (cons ledger-buf ledger-bufs)) + (with-current-buffer buf + (save-buffer))) + (with-current-buffer (get-buffer ledger-recon-buffer-name) + (set-buffer-modified-p nil) + (ledger-display-balance) + (goto-char curpoint) + (ledger-reconcile-visit t)))) (defun ledger-reconcile-finish () "Mark all pending posting or transactions as cleared. @@ -401,8 +402,6 @@ moved and recentered. If they aren't strange things happen." (set (make-local-variable 'ledger-acct) account)))) ;; Narrow the ledger buffer - - ;; Now, actually run the reconciliation (with-current-buffer rbuf (save-excursion (if ledger-narrow-on-reconcile -- cgit v1.2.3 From 53778317cbc70f1714afbb7346d7abc9d3467edd Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 23 Mar 2013 21:51:27 -0700 Subject: More armor plating on ledger-post-align-postings --- lisp/ldg-post.el | 88 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 934e70a1..906ff315 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -138,48 +138,52 @@ Return the column of the beginning of the account" "Align all accounts and amounts within region, if there is no region alight the posting on the current line." (interactive) - (save-excursion - ;; If there is no region set - (when (or (not (mark)) - (= (point) (mark))) - (beginning-of-line) - (set-mark (point)) - (goto-char (1+ (line-end-position)))) - - (let* ((mark-first (< (mark) (point))) - (begin (if mark-first (mark) (point))) - (end (if mark-first (point-marker) (mark-marker))) - acc-col amt-offset) - (goto-char end) - (end-of-line) - (setq end (point-marker)) - (goto-char begin) - (beginning-of-line) - (setq begin (point-marker)) - (while (setq acc-col (ledger-next-account end)) - ;; Adjust account position if necessary - (let ((acc-adjust (- ledger-post-account-alignment-column acc-col))) - (if (/= acc-adjust 0) - (if (> acc-adjust 0) - (insert (make-string acc-adjust ? )) ;; Account too far left - (if (looking-back " " (- (point) 3)) - (delete-char acc-adjust) - (skip-chars-forward "^ \t") - (delete-horizontal-space) - (insert " "))))) - (when (setq amt-offset (ledger-next-amount end)) - (let* ((amt-adjust (- ledger-post-amount-alignment-column - amt-offset - (current-column)))) - (if (/= amt-adjust 0) - (if (> amt-adjust 0) - (insert (make-string amt-adjust ? )) - (if (looking-back " ") - (delete-char amt-adjust) - (skip-chars-forward "^ \t") - (delete-horizontal-space) - (insert " ")))))) - (forward-line))))) + (let ((region-boundaries-verified nil)) (save-excursion + ;; If there is no region set + (when (or (not (mark)) + (= (point) (mark))) + (beginning-of-line) + (set-mark (point)) + (goto-char (line-end-position)) + (setq region-boundaries-verified t)) + + (let* ((mark-first (< (mark) (point))) + (begin (if mark-first (mark) (point))) + (end (if mark-first (point-marker) (mark-marker))) + acc-col amt-offset) + (if (not region-boundaries-verified) + (progn + (goto-char end) + (end-of-line) + (setq end (point-marker)) + (goto-char begin) + (beginning-of-line) + (setq begin (point-marker))) + (goto-char begin)) + (while (setq acc-col (ledger-next-account end)) + ;; Adjust account position if necessary + (let ((acc-adjust (- ledger-post-account-alignment-column acc-col))) + (if (/= acc-adjust 0) + (if (> acc-adjust 0) + (insert (make-string acc-adjust ? )) ;; Account too far left + (if (looking-back " " (- (point) 3)) + (delete-char acc-adjust) + (skip-chars-forward "^ \t") + (delete-horizontal-space) + (insert " "))))) + (when (setq amt-offset (ledger-next-amount end)) + (let* ((amt-adjust (- ledger-post-amount-alignment-column + amt-offset + (current-column)))) + (if (/= amt-adjust 0) + (if (> amt-adjust 0) + (insert (make-string amt-adjust ? )) + (if (looking-back " ") + (delete-char amt-adjust) + (skip-chars-forward "^ \t") + (delete-horizontal-space) + (insert " ")))))) + (forward-line)))))) (defun ledger-post-maybe-align (beg end len) "Align amounts only if point is in a posting. -- cgit v1.2.3 From 6ff330911dc67fefa0762bbb8aa349cb82cf474e Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 24 Mar 2013 04:46:35 -0700 Subject: Fixed Align Region menu entry --- lisp/ldg-mode.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index c900d3d3..75004072 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -128,7 +128,7 @@ Can be pcomplete, or align-posting" (define-key map [sort-start] '(menu-item "Mark Sort Beginning" ledger-sort-insert-start-mark)) (define-key map [sort-buff] '(menu-item "Sort Buffer" ledger-sort-buffer)) (define-key map [sort-reg] '(menu-item "Sort Region" ledger-sort-region :enable mark-active)) - (define-key map [align-reg] '(menu-item "Align Region" ledger-post-align-region :enable mark-active)) + (define-key map [align-reg] '(menu-item "Align Region" ledger-post-align-postings :enable mark-active)) (define-key map [sep2] '(menu-item "--")) (define-key map [copy-xact] '(menu-item "Copy Trans at Point" ledger-copy-transaction)) (define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current)) -- cgit v1.2.3 From 5797623fd7bb998f2e5fd9cd71e0dbe4c4f826dd Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 24 Mar 2013 13:57:03 -0400 Subject: Second rewrite of ledger-post-align-postings. Will probably perfect with the NEXT rewrite. --- lisp/ldg-post.el | 95 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 906ff315..b3fdcb1f 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -119,7 +119,7 @@ PROMPT is a string to prompt with. CHOICES is a list of "Move point to the next amount, as long as it is not past END. Return the width of the amount field as an integer." (beginning-of-line) - (when (re-search-forward "\\( \\|\t\\| \t\\)[ \t]*-?\\([A-Z$€£]+ *\\)?\\(-?[0-9,]+?\\)\\(.[0-9]+\\)?\\( *[A-Z$€£]+\\)?\\([ \t]*@@?[^\n;]+?\\)?\\([ \t]+;.+?\\|[ \t]*\\)?$" (marker-position end) t) + (when (re-search-forward "\\( \\|\t\\| \t\\)[ \t]*-?\\([A-Z$€£_]+ *\\)?\\(-?[0-9,]+?\\)\\(.[0-9]+\\)?\\( *[[:word:]€£_\"]+\\)?\\([ \t]*[@={]@?[^\n;]+?\\)?\\([ \t]+;.+?\\|[ \t]*\\)?$" (marker-position end) t) (goto-char (match-beginning 0)) (skip-syntax-forward " ") (- (or (match-end 4) @@ -130,60 +130,59 @@ Return the width of the amount field as an integer." Return the column of the beginning of the account" (beginning-of-line) (if (> (marker-position end) (point)) - (when (re-search-forward "\\(^[ ]+\\)\\([*!;a-zA-Z0-9]+?\\)" (marker-position end) t) + (when (re-search-forward "\\(^[ ]+\\)\\([\\[(*!;a-zA-Z0-9]+?\\)" (marker-position end) t) (goto-char (match-beginning 2)) (current-column)))) + +(defun end-of-line-or-region (end-region) + "Return a number or marker to the END-REGION or end of line +position, whichever is closer." + (let ((end (if (< end-region (line-end-position)) + end-region + (line-end-position)))) + (if (markerp end-region) + (copy-marker end) + end))) + +(defun ledger-post-adjust (adjust-by) + (if (> adjust-by 0) + (insert (make-string adjust-by ? )) + (if (looking-back " " (- (point) 3)) + (delete-char adjust-by) + (skip-chars-forward "^ \t") + (delete-horizontal-space) + (insert " ")))) + (defun ledger-post-align-postings () "Align all accounts and amounts within region, if there is no region alight the posting on the current line." (interactive) - (let ((region-boundaries-verified nil)) (save-excursion - ;; If there is no region set - (when (or (not (mark)) - (= (point) (mark))) - (beginning-of-line) - (set-mark (point)) - (goto-char (line-end-position)) - (setq region-boundaries-verified t)) - - (let* ((mark-first (< (mark) (point))) - (begin (if mark-first (mark) (point))) - (end (if mark-first (point-marker) (mark-marker))) - acc-col amt-offset) - (if (not region-boundaries-verified) - (progn - (goto-char end) - (end-of-line) - (setq end (point-marker)) - (goto-char begin) - (beginning-of-line) - (setq begin (point-marker))) - (goto-char begin)) - (while (setq acc-col (ledger-next-account end)) - ;; Adjust account position if necessary - (let ((acc-adjust (- ledger-post-account-alignment-column acc-col))) - (if (/= acc-adjust 0) - (if (> acc-adjust 0) - (insert (make-string acc-adjust ? )) ;; Account too far left - (if (looking-back " " (- (point) 3)) - (delete-char acc-adjust) - (skip-chars-forward "^ \t") - (delete-horizontal-space) - (insert " "))))) - (when (setq amt-offset (ledger-next-amount end)) - (let* ((amt-adjust (- ledger-post-amount-alignment-column - amt-offset - (current-column)))) - (if (/= amt-adjust 0) - (if (> amt-adjust 0) - (insert (make-string amt-adjust ? )) - (if (looking-back " ") - (delete-char amt-adjust) - (skip-chars-forward "^ \t") - (delete-horizontal-space) - (insert " ")))))) - (forward-line)))))) + (save-excursion + (let* ((mark-first (< (mark) (point))) + (begin-region (if mark-first (mark) (point))) + (end-region (if mark-first (point-marker) (mark-marker))) + acc-col amt-offset acc-adjust) + ;; Condition point and mark to the beginning and end of lines + (goto-char end-region) + (setq end-region (copy-marker (line-end-position))) + (goto-char begin-region) + (setq begin-region (copy-marker (line-beginning-position))) + (goto-char begin-region) + (while (or (setq acc-col (ledger-next-account (end-of-line-or-region end-region))) + (< (point) (marker-position end-region))) + (when acc-col + (setq acc-adjust (- ledger-post-account-alignment-column acc-col)) + (if (/= acc-adjust 0) + (ledger-post-adjust acc-adjust)) + + (when (setq amt-offset (ledger-next-amount (end-of-line-or-region end-region))) + (let* ((amt-adjust (- ledger-post-amount-alignment-column + amt-offset + (current-column)))) + (if (/= amt-adjust 0) + (ledger-post-adjust amt-adjust))))) + (forward-line))))) (defun ledger-post-maybe-align (beg end len) "Align amounts only if point is in a posting. -- cgit v1.2.3 From 59e8967d06d0895ece75b27aeb6b4dbf518fcf0a Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 24 Mar 2013 14:06:41 -0400 Subject: Fix bug 923 --- lisp/ldg-mode.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 75004072..dafd0740 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -81,6 +81,8 @@ Can be pcomplete, or align-posting" (ledger-init-load-init-file) + (setq indent-line-function 'ledger-post-align-postings) + (let ((map (current-local-map))) (define-key map [(control ?c) (control ?a)] 'ledger-add-transaction) (define-key map [(control ?c) (control ?b)] 'ledger-post-edit-amount) -- cgit v1.2.3 From 9079ae8a69b7fad33b4c227e95e5474e514d1453 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 24 Mar 2013 15:58:21 -0400 Subject: Clean up ldg-post.el --- lisp/ldg-post.el | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index b3fdcb1f..0de2de7d 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -115,22 +115,35 @@ PROMPT is a string to prompt with. CHOICES is a list of (delete-char 1))))))) (goto-char pos))) +(defvar ledger-post-amount-regex + (concat "\\( \\|\t\\| \t\\)[ \t]*-?" + "\\([A-Z$€£_]+ *\\)?" + "\\(-?[0-9,]+?\\)" + "\\(.[0-9]+\\)?" + "\\( *[[:word:]€£_\"]+\\)?" + "\\([ \t]*[@={]@?[^\n;]+?\\)?" + "\\([ \t]+;.+?\\|[ \t]*\\)?$")) + (defun ledger-next-amount (&optional end) "Move point to the next amount, as long as it is not past END. Return the width of the amount field as an integer." (beginning-of-line) - (when (re-search-forward "\\( \\|\t\\| \t\\)[ \t]*-?\\([A-Z$€£_]+ *\\)?\\(-?[0-9,]+?\\)\\(.[0-9]+\\)?\\( *[[:word:]€£_\"]+\\)?\\([ \t]*[@={]@?[^\n;]+?\\)?\\([ \t]+;.+?\\|[ \t]*\\)?$" (marker-position end) t) + (when (re-search-forward ledger-post-amount-regex (marker-position end) t) (goto-char (match-beginning 0)) (skip-syntax-forward " ") (- (or (match-end 4) (match-end 3)) (point)))) +(defvar ledger-post-account-regex + (concat "\\(^[ ]+\\)" + "\\([\\[(*!;a-zA-Z0-9]+?\\)")) + (defun ledger-next-account (&optional end) "Move point to the beginning of the next account, or status marker (!*), as long as it is not past END. Return the column of the beginning of the account" (beginning-of-line) (if (> (marker-position end) (point)) - (when (re-search-forward "\\(^[ ]+\\)\\([\\[(*!;a-zA-Z0-9]+?\\)" (marker-position end) t) + (when (re-search-forward ledger-post-account-regex (marker-position end) t) (goto-char (match-beginning 2)) (current-column)))) -- cgit v1.2.3 From 0d0e996e072072c2b203ff9eef2690d5f8c11c4f Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 24 Mar 2013 17:20:36 -0400 Subject: Improve ledger-split-commodities to handle multi character commodities. --- lisp/ldg-commodities.el | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 0ed52fc3..7dc0a900 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -32,7 +32,7 @@ :group 'ledger-reconcile) (defun ledger-split-commodity-string (str) - "Split a commoditized amount into two parts" + "Split a commoditized amount into two parts" (if (> (length str) 0) (let (val comm number-regex) (with-temp-buffer @@ -48,18 +48,16 @@ (ledger-commodity-string-number-decimalize (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user))) (goto-char (point-min)) - (re-search-forward "[^[:space:]]" nil t) - (setq comm - (delete-and-extract-region (match-beginning 0) (match-end 0))) + (setq comm (nth 0 (split-string (buffer-substring (point-min) (point-max))))) (list val comm)) ((re-search-forward "0" nil t) - ;; couldn't find a decimal number, look for a single 0, - ;; indicating account with zero balance - (list 0 ledger-reconcile-default-commodity)) - (t - (error "split-commodity-string: cannot parse commodity string: %S" str))))) + ;; couldn't find a decimal number, look for a single 0, + ;; indicating account with zero balance + (list 0 ledger-reconcile-default-commodity)) + ))) + + ;; nothing found, return 0 (list 0 ledger-reconcile-default-commodity))) - (defun ledger-string-balance-to-commoditized-amount (str) "Return a commoditized amount (val, 'comm') from STR." -- cgit v1.2.3 From 6a753e155eb8b4c1bb6dada200582d293985e0f2 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 24 Mar 2013 17:23:50 -0400 Subject: Fix ledger-split-commodities to handle integer balances --- lisp/ldg-commodities.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 7dc0a900..e7014604 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -39,8 +39,8 @@ (insert str) (goto-char (point-min)) (if (assoc "decimal-comma" ledger-environment-alist) - (setq number-regex "-?[1-9][0-9.]*[,][0-9]*") - (setq number-regex "-?[1-9][0-9,]*[.][0-9]*")) + (setq number-regex "-?[1-9][0-9.]*[,]?[0-9]*") + (setq number-regex "-?[1-9][0-9,]*[.]?[0-9]*")) (cond ((re-search-forward number-regex nil t) ;; found a decimal number (setq val -- cgit v1.2.3 From e8a2ebb6993eb025d536495caae02852caf291d1 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 24 Mar 2013 18:12:44 -0400 Subject: Insert Effective Date to xact --- lisp/ldg-mode.el | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index dafd0740..434d7448 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -55,6 +55,17 @@ Can be pcomplete, or align-posting" (defvar ledger-mode-abbrev-table) +(defun ledger-insert-effective-date () + (interactive) + (let ((context (car (ledger-context-at-point))) + (date-string (format-time-string (cdr (assoc "date-format" ledger-environment-alist))))) + (cond ((eq 'entry context) + (beginning-of-line) + (insert date-string "=")) + ((eq 'acct-transaction context) + (end-of-line) + (insert " ; [=" date-string "]"))))) + ;;;###autoload (define-derived-mode ledger-mode text-mode "Ledger" "A mode for editing ledger data files." @@ -94,7 +105,7 @@ Can be pcomplete, or align-posting" (define-key map [(control ?c) (control ?m)] 'ledger-set-month) (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) - (define-key map [(control ?c) (control ?t)] 'ledger-test-run) + (define-key map [(control ?c) (control ?t)] 'ledger-insert-effective-date) (define-key map [(control ?c) (control ?y)] 'ledger-set-year) (define-key map [tab] 'ledger-magic-tab) (define-key map [(control ?i)] 'ledger-magic-tab) @@ -126,6 +137,7 @@ Can be pcomplete, or align-posting" (interactive) (customize-group 'ledger)))) (define-key map [sep1] '("--")) + (define-key map [effective-date] '(menu-item "Set effective date" ledger-insert-effective-date)) (define-key map [sort-end] '(menu-item "Mark Sort End" ledger-sort-insert-end-mark)) (define-key map [sort-start] '(menu-item "Mark Sort Beginning" ledger-sort-insert-start-mark)) (define-key map [sort-buff] '(menu-item "Sort Buffer" ledger-sort-buffer)) @@ -136,7 +148,7 @@ Can be pcomplete, or align-posting" (define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current)) (define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-transaction)) (define-key map [sep4] '(menu-item "--")) - (define-key map [edit-amount] '(menu-item "Reconcile Account" ledger-reconcile)) + (define-key map [recon-account] '(menu-item "Reconcile Account" ledger-reconcile)) (define-key map [sep6] '(menu-item "--")) (define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount)) (define-key map [sep] '(menu-item "--")) -- cgit v1.2.3 From 15efb41abacfe81aaa921ec46472bbdffc4b222d Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 24 Mar 2013 23:26:23 -0400 Subject: Make complete play nice with auto alignment --- lisp/ldg-complete.el | 45 +++++++++++++++++++++++++++++++++++++++++++++ lisp/ldg-mode.el | 6 +++--- lisp/ldg-post.el | 8 ++++++-- 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index 6607d372..fa0bf87a 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -177,6 +177,51 @@ Does not use ledger xact" (if (re-search-backward "\\(\t\\| [ \t]\\)" nil t) (goto-char (match-end 0)))))) + +(defun ledger-pcomplete (&optional interactively) + "Complete rip-off of pcomplete from pcomplete.el, only added +ledger-magic-tab in the previos commads list so that +ledger-magic-tab would cycle properly" + (interactive "p") + (if (and interactively + pcomplete-cycle-completions + pcomplete-current-completions + (memq last-command '(ledger-magic-tab + ledger-pcomplete + pcomplete-expand-and-complete + pcomplete-reverse))) + (progn + (delete-backward-char pcomplete-last-completion-length) + (if (eq this-command 'pcomplete-reverse) + (progn + (push (car (last pcomplete-current-completions)) + pcomplete-current-completions) + (setcdr (last pcomplete-current-completions 2) nil)) + (nconc pcomplete-current-completions + (list (car pcomplete-current-completions))) + (setq pcomplete-current-completions + (cdr pcomplete-current-completions))) + (pcomplete-insert-entry pcomplete-last-completion-stub + (car pcomplete-current-completions) + nil pcomplete-last-completion-raw)) + (setq pcomplete-current-completions nil + pcomplete-last-completion-raw nil) + (catch 'pcompleted + (let* ((pcomplete-stub) + pcomplete-seen pcomplete-norm-func + pcomplete-args pcomplete-last pcomplete-index + (pcomplete-autolist pcomplete-autolist) + (pcomplete-suffix-list pcomplete-suffix-list) + (completions (pcomplete-completions)) + (result (pcomplete-do-complete pcomplete-stub completions))) + (and result + (not (eq (car result) 'listed)) + (cdr result) + (pcomplete-insert-entry pcomplete-stub (cdr result) + (memq (car result) + '(sole shortest)) + pcomplete-last-completion-raw)))))) + (provide 'ldg-complete) ;;; ldg-complete.el ends here diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 434d7448..b435ada2 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -44,13 +44,13 @@ (interactive) (remove-overlays)) -(defun ledger-magic-tab () +(defun ledger-magic-tab (&optional interactively) "Decide what to with with <TAB> . Can be pcomplete, or align-posting" - (interactive) + (interactive "p") (if (and (> (point) 1) (looking-back "[:A-Za-z0-9]" 1)) - (pcomplete) + (ledger-pcomplete interactively) (ledger-post-align-postings))) (defvar ledger-mode-abbrev-table) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 0de2de7d..bbed297d 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -172,6 +172,9 @@ position, whichever is closer." region alight the posting on the current line." (interactive) (save-excursion + (if (or (not (mark)) + (not (use-region-p))) + (set-mark (point))) (let* ((mark-first (< (mark) (point))) (begin-region (if mark-first (mark) (point))) (end-region (if mark-first (point-marker) (mark-marker))) @@ -180,8 +183,9 @@ region alight the posting on the current line." (goto-char end-region) (setq end-region (copy-marker (line-end-position))) (goto-char begin-region) - (setq begin-region (copy-marker (line-beginning-position))) - (goto-char begin-region) + (goto-char + (setq begin-region + (copy-marker (line-beginning-position)))) (while (or (setq acc-col (ledger-next-account (end-of-line-or-region end-region))) (< (point) (marker-position end-region))) (when acc-col -- cgit v1.2.3 From cc62e6a886d72bbe2a1a3c673df92b912deefd0c Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 25 Mar 2013 00:04:43 -0400 Subject: Code cleanup in ldg-exec and ledger-split-commodity --- lisp/ldg-commodities.el | 45 ++++++++++++++++++++++----------------------- lisp/ldg-exec.el | 9 --------- 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index e7014604..f664c472 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -21,7 +21,7 @@ ;;; Commentary: ;; Helper functions to deal with commoditized numbers. A commoditized -;; number will be a cons of value and string where the string contains +;; number will be a list of value and string where the string contains ;; the commodity ;;; Code: @@ -32,30 +32,29 @@ :group 'ledger-reconcile) (defun ledger-split-commodity-string (str) - "Split a commoditized amount into two parts" + "Split a commoditized amount into two parts" (if (> (length str) 0) - (let (val comm number-regex) + (let ((number-regex (if (assoc "decimal-comma" ledger-environment-alist) + "-?[1-9][0-9.]*[,]?[0-9]*" + "-?[1-9][0-9,]*[.]?[0-9]*"))) (with-temp-buffer (insert str) (goto-char (point-min)) - (if (assoc "decimal-comma" ledger-environment-alist) - (setq number-regex "-?[1-9][0-9.]*[,]?[0-9]*") - (setq number-regex "-?[1-9][0-9,]*[.]?[0-9]*")) (cond ((re-search-forward number-regex nil t) - ;; found a decimal number - (setq val - (string-to-number - (ledger-commodity-string-number-decimalize - (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user))) - (goto-char (point-min)) - (setq comm (nth 0 (split-string (buffer-substring (point-min) (point-max))))) - (list val comm)) + ;; found a number in the current locale, return it in + ;; the car. Anything left over is annotation, + ;; the first thing should be the commodity, separated + ;; by whitespace, return it in the cdr. I can't think of any + ;; counterexamples + (list + (string-to-number + (ledger-commodity-string-number-decimalize + (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user)) + (nth 0 (split-string (buffer-substring (point-min) (point-max)))))) ((re-search-forward "0" nil t) - ;; couldn't find a decimal number, look for a single 0, - ;; indicating account with zero balance - (list 0 ledger-reconcile-default-commodity)) - ))) - + ;; couldn't find a decimal number, look for a single 0, + ;; indicating account with zero balance + (list 0 ledger-reconcile-default-commodity))))) ;; nothing found, return 0 (list 0 ledger-reconcile-default-commodity))) @@ -68,7 +67,6 @@ (ledger-split-commodity-string str)) fields))) - (defun -commodity (c1 c2) "Subtract C2 from C1, ensuring their commodities match." (if (string= (cadr c1) (cadr c2)) @@ -108,7 +106,7 @@ which must be translated both directions." (defun ledger-commodity-to-string (c1) "Return string representing C1. Single character commodities are placed ahead of the value, -longer one are after the value." +longer ones are after the value." (let ((val (ledger-commodity-string-number-decimalize (number-to-string (car c1)) :to-user)) (commodity (cadr c1))) @@ -122,12 +120,13 @@ Assumes a space between the value and the commodity." (let ((parts (split-string (read-from-minibuffer (concat prompt " (" ledger-reconcile-default-commodity "): "))))) (if parts - (if (/= (length parts) 2) ;;assume a number was entered and use default commodity + (if (/= (length parts) 2) ;;assume a number was entered and + ;;use default commodity (list (string-to-number (car parts)) ledger-reconcile-default-commodity) (let ((valp1 (string-to-number (car parts))) (valp2 (string-to-number (cadr parts)))) - (cond ((and (= valp1 valp2) (= 0 valp1));; means neither contained a valid number (both = 0) + (cond ((and (= valp1 valp2) (= 0 valp1)) ;; means neither contained a valid number (both = 0) (list 0 "")) ((and (/= 0 valp1) (= valp2 0)) (list valp1 (cadr parts))) diff --git a/lisp/ldg-exec.el b/lisp/ldg-exec.el index 46775914..31621f9f 100644 --- a/lisp/ldg-exec.el +++ b/lisp/ldg-exec.el @@ -74,15 +74,6 @@ outbuf (ledger-exec-handle-error outbuf)))))) -;; (defun ledger-exec-read (&optional input-buffer &rest args) -;; "Run ledger from option INPUT-BUFFER using ARGS, return a list structure of the ledger Emacs output." -;; (with-current-buffer -;; (apply #'ledger-exec-ledger input-buffer nil "emacs" args) -;; (goto-char (point-min)) -;; (prog1 -;; (read (current-buffer)) -;; (kill-buffer (current-buffer))))) - (defun ledger-version-greater-p (needed) "Verify the ledger binary is usable for `ledger-mode' (version greater than NEEDED)." (let ((buffer ledger-buf) -- cgit v1.2.3 From d3fe4c666ff37912245d2a0386ac749737f34843 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 25 Mar 2013 01:21:19 -0400 Subject: Lots of code cleanup. (if () (progn …) ==> (when () …) all over the place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lisp/ldg-commodities.el | 2 +- lisp/ldg-complete.el | 11 ++--- lisp/ldg-exec.el | 31 ++++++------- lisp/ldg-init.el | 22 ++++----- lisp/ldg-occur.el | 50 ++++++++++----------- lisp/ldg-post.el | 2 +- lisp/ldg-reconcile.el | 117 +++++++++++++++++++++++------------------------- lisp/ldg-report.el | 53 +++++++++++----------- lisp/ldg-schedule.el | 2 +- lisp/ldg-sort.el | 32 ++++++------- lisp/ldg-state.el | 7 ++- lisp/ldg-xact.el | 13 +++--- 12 files changed, 156 insertions(+), 186 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index f664c472..0eb435b5 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -50,7 +50,7 @@ (string-to-number (ledger-commodity-string-number-decimalize (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user)) - (nth 0 (split-string (buffer-substring (point-min) (point-max)))))) + (nth 0 (split-string (buffer-substring-no-properties (point-min) (point-max)))))) ((re-search-forward "0" nil t) ;; couldn't find a decimal number, look for a single 0, ;; indicating account with zero balance diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index fa0bf87a..a8e73b88 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -19,9 +19,6 @@ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ;; MA 02111-1307, USA. -;;(require 'esh-util) -;;(require 'esh-arg) - ;;; Commentary: ;; Functions providing payee and account auto complete. @@ -126,8 +123,8 @@ Return tree structure" (if (null current-prefix-arg) (ledger-payees-in-buffer) ;; this completes against payee names (progn - (let ((text (buffer-substring (line-beginning-position) - (line-end-position)))) + (let ((text (buffer-substring-no-properties (line-beginning-position) + (line-end-position)))) (delete-region (line-beginning-position) (line-end-position)) (condition-case err @@ -154,7 +151,7 @@ Does not use ledger xact" ;; Search backward for a matching payee (when (re-search-backward (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+\\(.*" - (regexp-quote name) ".*\\)" ) nil t) ;; "\\(\t\\|\n\\| [ \t]\\)" + (regexp-quote name) ".*\\)" ) nil t) (setq rest-of-name (match-string 3)) ;; Start copying the postings (forward-line) @@ -180,7 +177,7 @@ Does not use ledger xact" (defun ledger-pcomplete (&optional interactively) "Complete rip-off of pcomplete from pcomplete.el, only added -ledger-magic-tab in the previos commads list so that +ledger-magic-tab in the previous commands list so that ledger-magic-tab would cycle properly" (interactive "p") (if (and interactively diff --git a/lisp/ldg-exec.el b/lisp/ldg-exec.el index 31621f9f..4a485072 100644 --- a/lisp/ldg-exec.el +++ b/lisp/ldg-exec.el @@ -53,7 +53,7 @@ (with-current-buffer ledger-output-buffer (goto-char (point-min)) (if (and (> (buffer-size) 1) (looking-at (regexp-quote "While"))) - nil + nil ;; failure, there is an error starting with "While" ledger-output-buffer))) (defun ledger-exec-ledger (input-buffer &optional output-buffer &rest args) @@ -77,27 +77,24 @@ (defun ledger-version-greater-p (needed) "Verify the ledger binary is usable for `ledger-mode' (version greater than NEEDED)." (let ((buffer ledger-buf) - (version-strings '()) - (version-number)) + (version-strings '())) (with-temp-buffer - (if (ledger-exec-ledger (current-buffer) (current-buffer) "--version") - (progn - (goto-char (point-min)) - (delete-horizontal-space) - (setq version-strings (split-string - (buffer-substring-no-properties (point) - (point-max)))) - (if (and (string-match (regexp-quote "Ledger") (car version-strings)) - (or (string= needed (car (cdr version-strings))) - (string< needed (car (cdr version-strings))))) - t - nil)))))) + (when (ledger-exec-ledger (current-buffer) (current-buffer) "--version") + (goto-char (point-min)) + (delete-horizontal-space) + (setq version-strings (split-string + (buffer-substring-no-properties (point) + (point-max)))) + (if (and (string-match (regexp-quote "Ledger") (car version-strings)) + (or (string= needed (cadr version-strings)) + (string< needed (cadr version-strings)))) + t ;; success + nil))))) ;;failure (defun ledger-check-version () "Verify that ledger works and is modern enough." (interactive) - (setq ledger-works (ledger-version-greater-p ledger-version-needed)) - (if ledger-works + (if (setq ledger-works (ledger-version-greater-p ledger-version-needed)) (message "Good Ledger Version") (message "Bad Ledger Version"))) diff --git a/lisp/ldg-init.el b/lisp/ldg-init.el index 72317088..8e657323 100644 --- a/lisp/ldg-init.el +++ b/lisp/ldg-init.el @@ -33,16 +33,16 @@ (setq ledger-environment-alist nil) (goto-char (point-min)) (while (re-search-forward "^--.+?\\($\\|[ ]\\)" nil t ) - (let ((matchb (match-beginning 0)) ;; save the match data, string-match stomp on it + (let ((matchb (match-beginning 0)) ;; save the match data, string-match stamp on it (matche (match-end 0))) (end-of-line) (setq ledger-environment-alist (append ledger-environment-alist - (list (cons (let ((flag (buffer-substring (+ 2 matchb) matche))) + (list (cons (let ((flag (buffer-substring-no-properties (+ 2 matchb) matche))) (if (string-match "[ \t\n\r]+\\'" flag) (replace-match "" t t flag) flag)) - (let ((value (buffer-substring matche (point) ))) + (let ((value (buffer-substring-no-properties matche (point) ))) (if (> (length value) 0) value t)))))))) @@ -53,16 +53,12 @@ (let ((init-base-name (file-name-nondirectory ledger-init-file-name))) (if (get-buffer init-base-name) ;; init file already loaded, parse it and leave it (ledger-init-parse-initialization init-base-name) - (if (and ;; init file not loaded, load, parse and kill - ledger-init-file-name - (file-exists-p ledger-init-file-name) - (file-readable-p ledger-init-file-name)) - (progn - (find-file-noselect ledger-init-file-name) - (ledger-init-parse-initialization init-base-name) - (kill-buffer init-base-name)))))) - - + (when (and ledger-init-file-name + (file-exists-p ledger-init-file-name) + (file-readable-p ledger-init-file-name)) + (find-file-noselect ledger-init-file-name) + (ledger-init-parse-initialization init-base-name) + (kill-buffer init-base-name))))) (provide 'ldg-init) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index 28d87b78..a2e53cb0 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -63,27 +63,24 @@ "Highlight transactions that match REGEX in BUFFER, hiding others. When REGEX is nil, unhide everything, and remove higlight" - (progn - (set-buffer buffer) - (setq ledger-occur-mode - (if (or (null regex) - (zerop (length regex))) - nil - (concat " Ledger-Narrowed: " regex))) - (force-mode-line-update) - (ledger-occur-remove-overlays) - (if ledger-occur-mode - (let* ((buffer-matches (ledger-occur-find-matches regex)) - (ovl-bounds (ledger-occur-create-xact-overlay-bounds buffer-matches))) - (setq ledger-occur-overlay-list - (ledger-occur-create-xact-overlays ovl-bounds)) - (setq ledger-occur-overlay-list - (append ledger-occur-overlay-list - (ledger-occur-create-narrowed-overlays buffer-matches))) - (setq ledger-occur-last-match regex) - (if (get-buffer-window buffer) - (select-window (get-buffer-window buffer))))) - (recenter))) + (set-buffer buffer) + (setq ledger-occur-mode + (if (or (null regex) + (zerop (length regex))) + nil + (concat " Ledger-Narrowed: " regex))) + (force-mode-line-update) + (ledger-occur-remove-overlays) + (if ledger-occur-mode + (let* ((buffer-matches (ledger-occur-find-matches regex)) + (ovl-bounds (ledger-occur-create-xact-overlay-bounds buffer-matches))) + (setq ledger-occur-overlay-list + (append (ledger-occur-create-xact-overlays ovl-bounds) + (ledger-occur-create-narrowed-overlays buffer-matches))) + (setq ledger-occur-last-match regex) + (if (get-buffer-window buffer) + (select-window (get-buffer-window buffer))))) + (recenter)) (defun ledger-occur (regex) "Perform a simple grep in current buffer for the regular expression REGEX. @@ -163,12 +160,11 @@ Argument OVL-BOUNDS contains bounds for the transactions to be left visible." (defun ledger-occur-quit-buffer (buffer) "Quits hidings transaction in the given BUFFER. Used for coordinating `ledger-occur' with other buffers, like reconcile." - (progn - (set-buffer buffer) - (setq ledger-occur-mode nil) - (force-mode-line-update) - (ledger-occur-remove-overlays) - (recenter))) + (set-buffer buffer) + (setq ledger-occur-mode nil) + (force-mode-line-update) + (ledger-occur-remove-overlays) + (recenter)) (defun ledger-occur-remove-overlays () "Remove the transaction hiding overlays." diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index bbed297d..c831f01a 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -135,7 +135,7 @@ Return the width of the amount field as an integer." (match-end 3)) (point)))) (defvar ledger-post-account-regex - (concat "\\(^[ ]+\\)" + (concat "\\(^[ \t]+\\)" "\\([\\[(*!;a-zA-Z0-9]+?\\)")) (defun ledger-next-account (&optional end) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 3d73cca9..3d3b7c92 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -66,9 +66,10 @@ reconcile-finish will mark all pending posting cleared." (defun ledger-reconcile-get-cleared-or-pending-balance () "Calculate the cleared or pending balance of the account." (interactive) - (let ((buffer ledger-buf) - (account ledger-acct) - (val nil)) + ;; these vars are buffer local, need to hold them for use in the + ;; temp buffer below + (let ((buffer ledger-buf) + (account ledger-acct)) (with-temp-buffer ;; note that in the line below, the --format option is ;; separated from the actual format string. emacs does not @@ -77,16 +78,15 @@ reconcile-finish will mark all pending posting cleared." (if (ledger-exec-ledger buffer (current-buffer) "balance" "--limit" "cleared or pending" "--empty" "--format" "%(display_total)" account) - (setq val - (ledger-split-commodity-string - (buffer-substring-no-properties (point-min) (point-max)))))))) + (ledger-split-commodity-string + (buffer-substring-no-properties (point-min) (point-max))))))) (defun ledger-display-balance () "Display the cleared-or-pending balance. And calculate the target-delta of the account being reconciled." (interactive) (let* ((pending (ledger-reconcile-get-cleared-or-pending-balance))) - (if pending + (when pending (if ledger-target (message "Pending balance: %s, Difference from target: %s" (ledger-commodity-to-string pending) @@ -150,23 +150,21 @@ Return the number of uncleared xacts found." (interactive) (let ((inhibit-read-only t)) (erase-buffer) - (prog1 (ledger-do-reconcile) - (set-buffer-modified-p t) - ;;(goto-char (point-min)) - ))) + (prog1 + (ledger-do-reconcile) + (set-buffer-modified-p t)))) (defun ledger-reconcile-refresh-after-save () "Refresh the recon-window after the ledger buffer is saved." (let ((curbuf (current-buffer)) (curpoint (point)) (recon-buf (get-buffer ledger-recon-buffer-name))) - (if (buffer-live-p recon-buf) - (progn - (with-current-buffer recon-buf - (ledger-reconcile-refresh) - (set-buffer-modified-p nil)) - (select-window (get-buffer-window curbuf)) - (goto-char curpoint))))) + (when (buffer-live-p recon-buf) + (with-current-buffer recon-buf + (ledger-reconcile-refresh) + (set-buffer-modified-p nil)) + (select-window (get-buffer-window curbuf)) + (goto-char curpoint)))) (defun ledger-reconcile-add () "Use ledger xact to add a new transaction." @@ -247,7 +245,7 @@ and exit reconcile mode" (if recon-buf (with-current-buffer recon-buf (ledger-reconcile-quit-cleanup) - (set 'buf ledger-buf) + (setq buf ledger-buf) ;; Make sure you delete the window before you delete the buffer, ;; otherwise, madness ensues (delete-window (get-buffer-window recon-buf)) @@ -261,10 +259,9 @@ and exit reconcile mode" (if (buffer-live-p buf) (with-current-buffer buf (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t) - (if ledger-narrow-on-reconcile - (progn - (ledger-occur-quit-buffer buf) - (ledger-highlight-xact-under-point))))))) + (when ledger-narrow-on-reconcile + (ledger-occur-quit-buffer buf) + (ledger-highlight-xact-under-point)))))) (defun ledger-marker-where-xact-is (emacs-xact posting) "Find the position of the EMACS-XACT in the `ledger-buf'. @@ -285,14 +282,13 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (ledger-success nil) (xacts (with-temp-buffer - (if (ledger-exec-ledger buf (current-buffer) - "--uncleared" "--real" "emacs" account) - (progn - (setq ledger-success t) - (goto-char (point-min)) - (unless (eobp) - (if (looking-at "(") - (read (current-buffer))))))))) ;current-buffer is the *temp* created above + (when (ledger-exec-ledger buf (current-buffer) + "--uncleared" "--real" "emacs" account) + (setq ledger-success t) + (goto-char (point-min)) + (unless (eobp) + (if (looking-at "(") + (read (current-buffer)))))))) ;current-buffer is the *temp* created above (if (and ledger-success (> (length xacts) 0)) (let ((date-format (cdr (assoc "date-format" ledger-environment-alist)))) (dolist (xact xacts) @@ -351,15 +347,15 @@ moved and recentered. If they aren't strange things happen." (defun ledger-reconcile-track-xact () "Force the ledger buffer to recenter on the transaction at point in the reconcile buffer." - (if (member this-command (list 'next-line - 'previous-line - 'mouse-set-point - 'ledger-reconcile-toggle - 'end-of-buffer - 'beginning-of-buffer)) - (if ledger-buffer-tracks-reconcile-buffer - (save-excursion - (ledger-reconcile-visit t))))) + (if (and ledger-buffer-tracks-reconcile-buffer + (member this-command (list 'next-line + 'previous-line + 'mouse-set-point + 'ledger-reconcile-toggle + 'end-of-buffer + 'beginning-of-buffer))) + (save-excursion + (ledger-reconcile-visit t)))) (defun ledger-reconcile-open-windows (buf rbuf) "Ensure that the ledger buffer BUF is split by RBUF." @@ -373,33 +369,30 @@ moved and recentered. If they aren't strange things happen." (interactive) (let ((account (ledger-post-read-account-with-prompt "Account to reconcile")) (buf (current-buffer)) - (rbuf (get-buffer ledger-recon-buffer-name))) ;; this means - ;; only one - ;; *Reconcile* - ;; buffer, ever - ;; Set up the reconcile buffer - (if rbuf ;; *Reconcile* already exists + (rbuf (get-buffer ledger-recon-buffer-name))) + ;; this means only one *Reconcile* buffer, ever Set up the + ;; reconcile buffer + (if rbuf ;; *Reconcile* already exists (with-current-buffer rbuf - (set 'ledger-acct account) ;; already buffer local - (if (not (eq buf rbuf)) - (progn ;; called from some other ledger-mode buffer - (ledger-reconcile-quit-cleanup) - (set 'ledger-buf buf))) ;; should already be - ;; buffer-local + (set 'ledger-acct account) ;; already buffer local + (when (not (eq buf rbuf)) + ;; called from some other ledger-mode buffer + (ledger-reconcile-quit-cleanup) + (set 'ledger-buf buf)) ;; should already be buffer-local (unless (get-buffer-window rbuf) (ledger-reconcile-open-windows buf rbuf))) - (progn ;; no recon-buffer, starting from scratch. - (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save nil t) - - (with-current-buffer (setq rbuf - (get-buffer-create ledger-recon-buffer-name)) - (ledger-reconcile-open-windows buf rbuf) - (ledger-reconcile-mode) - (make-local-variable 'ledger-target) - (set (make-local-variable 'ledger-buf) buf) - (set (make-local-variable 'ledger-acct) account)))) + ;; no recon-buffer, starting from scratch. + (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save nil t) + + (with-current-buffer (setq rbuf + (get-buffer-create ledger-recon-buffer-name)) + (ledger-reconcile-open-windows buf rbuf) + (ledger-reconcile-mode) + (make-local-variable 'ledger-target) + (set (make-local-variable 'ledger-buf) buf) + (set (make-local-variable 'ledger-acct) account))) ;; Narrow the ledger buffer (with-current-buffer rbuf diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 8e642a61..4f14fdcb 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -30,8 +30,7 @@ (defgroup ledger-report nil "Customization option for the Report buffer" - :group 'ledger -) + :group 'ledger) (defcustom ledger-reports '(("bal" "ledger -f %(ledger-file) bal") @@ -319,18 +318,17 @@ Optional EDIT the command." (let ((file (match-string 1)) (line (string-to-number (match-string 2)))) (delete-region (match-beginning 0) (match-end 0)) - (if file - (progn - (set-text-properties (line-beginning-position) (line-end-position) - (list 'ledger-source (cons file (save-window-excursion - (save-excursion - (find-file file) - (widen) - (ledger-goto-line line) - (point-marker)))))) - (add-text-properties (line-beginning-position) (line-end-position) - (list 'face 'ledger-font-report-clickable-face)) - (end-of-line)))))) + (when file + (set-text-properties (line-beginning-position) (line-end-position) + (list 'ledger-source (cons file (save-window-excursion + (save-excursion + (find-file file) + (widen) + (ledger-goto-line line) + (point-marker)))))) + (add-text-properties (line-beginning-position) (line-end-position) + (list 'face 'ledger-font-report-clickable-face)) + (end-of-line))))) (goto-char data-pos))) @@ -340,20 +338,19 @@ Optional EDIT the command." (let* ((prop (get-text-property (point) 'ledger-source)) (file (if prop (car prop))) (line-or-marker (if prop (cdr prop)))) - (if (and file line-or-marker) - (progn - (find-file-other-window file) - (widen) - (if (markerp line-or-marker) - (goto-char line-or-marker) - (goto-char (point-min)) - (forward-line (1- line-or-marker)) - (re-search-backward "^[0-9]+") - (beginning-of-line) - (let ((start-of-txn (point))) - (forward-paragraph) - (narrow-to-region start-of-txn (point)) - (backward-paragraph))))))) + (when (and file line-or-marker) + (find-file-other-window file) + (widen) + (if (markerp line-or-marker) + (goto-char line-or-marker) + (goto-char (point-min)) + (forward-line (1- line-or-marker)) + (re-search-backward "^[0-9]+") + (beginning-of-line) + (let ((start-of-txn (point))) + (forward-paragraph) + (narrow-to-region start-of-txn (point)) + (backward-paragraph)))))) (defun ledger-report-goto () "Goto the ledger report buffer." diff --git a/lisp/ldg-schedule.el b/lisp/ldg-schedule.el index c2e5ea01..effa20b5 100644 --- a/lisp/ldg-schedule.el +++ b/lisp/ldg-schedule.el @@ -223,7 +223,7 @@ returns true if the date meets the requirements" ;; read the descriptor string into a lisp object the transform the ;; string descriptor into useable things (ledger-transform-auto-tree - (read (buffer-substring (point-min) (point-max)))))) + (read (buffer-substring-no-properties (point-min) (point-max)))))) (defun ledger-transform-auto-tree (tree) "Takes a lisp list of date descriptor strings, TREE, and returns a string with a lambda function of date." diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el index 3ce429fc..ecb86371 100644 --- a/lisp/ldg-sort.el +++ b/lisp/ldg-sort.el @@ -47,26 +47,22 @@ (match-end 0))) (defun ledger-sort-insert-start-mark () - (interactive) - (let (has-old-marker) - (save-excursion - (goto-char (point-min)) - (setq has-old-marker (ledger-sort-find-start)) - (if has-old-marker - (delete-region (match-beginning 0) (match-end 0)))) - (beginning-of-line) - (insert "\n; Ledger-mode: Start sort\n\n"))) + (interactive) + (save-excursion + (goto-char (point-min)) + (if (ledger-sort-find-start) + (delete-region (match-beginning 0) (match-end 0)))) + (beginning-of-line) + (insert "\n; Ledger-mode: Start sort\n\n")) (defun ledger-sort-insert-end-mark () - (interactive) - (let (has-old-marker) - (save-excursion - (goto-char (point-min)) - (setq has-old-marker (ledger-sort-find-end)) - (if has-old-marker - (delete-region (match-beginning 0) (match-end 0)))) - (beginning-of-line) - (insert "\n; Ledger-mode: End sort\n\n"))) + (interactive) + (save-excursion + (goto-char (point-min)) + (if (ledger-sort-find-end) + (delete-region (match-beginning 0) (match-end 0)))) + (beginning-of-line) + (insert "\n; Ledger-mode: End sort\n\n")) (defun ledger-sort-region (beg end) "Sort the region from BEG to END in chronological order." diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index dd5e42ad..c1027f5c 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -245,10 +245,9 @@ dropped." (eq (ledger-state-from-char (char-after)) 'cleared)) (progn (delete-char 1) - (if (and style (eq style 'cleared)) - (progn - (insert " *") - (setq status 'cleared)))) + (when (and style (eq style 'cleared)) + (insert " *") + (setq status 'cleared))) (if (and style (eq style 'pending)) (progn (insert " ! ") diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index 3e4cec4b..e2180b57 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -44,12 +44,10 @@ within the transaction." (backward-paragraph) (if (/= (point) (point-min)) (forward-line)) - (beginning-of-line) - (setq beg-pos (point)) + (setq beg-pos (line-beginning-position)) (forward-paragraph) (forward-line -1) - (end-of-line) - (setq end-pos (1+ (point))) + (setq end-pos (1+ (line-end-position))) (list beg-pos end-pos)))) @@ -80,11 +78,12 @@ within the transaction." (defsubst ledger-goto-line (line-number) "Rapidly move point to line LINE-NUMBER." -(goto-char (point-min)) (forward-line (1- line-number))) + (goto-char (point-min)) + (forward-line (1- line-number))) (defun ledger-thing-at-point () "Describe thing at points. Return 'transaction, 'posting, or nil." -(let ((here (point))) + (let ((here (point))) (goto-char (line-beginning-position)) (cond ((looking-at "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.+?)\\)?\\s-+") (goto-char (match-end 0)) @@ -105,7 +104,7 @@ within the transaction." (concat ledger-year "/" ledger-month "/") 'ledger-minibuffer-history))) (let* ((here (point)) (extents (ledger-find-xact-extents (point))) - (transaction (buffer-substring (car extents) (cadr extents))) + (transaction (buffer-substring-no-properties (car extents) (cadr extents))) encoded-date) (if (string-match ledger-date-regex date) (setq encoded-date -- cgit v1.2.3 From e5525130c023862a58277c248047c3e1cc80d613 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 25 Mar 2013 13:35:59 -0400 Subject: Improve complete-all and reconcile saving --- lisp/ldg-commodities.el | 3 ++- lisp/ldg-complete.el | 2 +- lisp/ldg-reconcile.el | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 0eb435b5..3485d93f 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -32,7 +32,8 @@ :group 'ledger-reconcile) (defun ledger-split-commodity-string (str) - "Split a commoditized amount into two parts" + "Split a commoditized string, STR, into two parts. +Returns a list with (value commodity)." (if (> (length str) 0) (let ((number-regex (if (assoc "decimal-comma" ledger-environment-alist) "-?[1-9][0-9.]*[,]?[0-9]*" diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index a8e73b88..7e37163b 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -155,7 +155,7 @@ Does not use ledger xact" (setq rest-of-name (match-string 3)) ;; Start copying the postings (forward-line) - (while (looking-at "^\\s-+") + (while (looking-at ledger-post-account-regex) (setq xacts (cons (buffer-substring-no-properties (line-beginning-position) (line-end-position)) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 3d3b7c92..a05a61c0 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -217,7 +217,8 @@ Return the number of uncleared xacts found." (set-buffer-modified-p nil) (ledger-display-balance) (goto-char curpoint) - (ledger-reconcile-visit t)))) + ;; (ledger-reconcile-visit t) + ))) (defun ledger-reconcile-finish () "Mark all pending posting or transactions as cleared. -- cgit v1.2.3 From 862a83e7927ed0d18e5d297801d28f82595bb2a5 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 25 Mar 2013 14:05:29 -0400 Subject: add --collapse to reconcile balance calculation --- lisp/ldg-reconcile.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index a05a61c0..5a6a117a 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -76,7 +76,7 @@ reconcile-finish will mark all pending posting cleared." ;; split arguments like the shell does, so you need to ;; specify the individual fields in the command line. (if (ledger-exec-ledger buffer (current-buffer) - "balance" "--limit" "cleared or pending" "--empty" + "balance" "--limit" "cleared or pending" "--empty" "--collapse" "--format" "%(display_total)" account) (ledger-split-commodity-string (buffer-substring-no-properties (point-min) (point-max))))))) -- cgit v1.2.3 From 48266d110758e54716177e5c87e33103247414a0 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 25 Mar 2013 18:48:28 -0400 Subject: Fix bug 928 Refix slow indent-region behavior. Need to bing ledger-post-align-postings to indent-region-function, not indent-line-function, others it tries to align the entire region once for every line in the region. --- lisp/ldg-mode.el | 2 +- lisp/ldg-post.el | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index b435ada2..1d587d63 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -92,7 +92,7 @@ Can be pcomplete, or align-posting" (ledger-init-load-init-file) - (setq indent-line-function 'ledger-post-align-postings) + (setq indent-region-function 'ledger-post-align-postings) (let ((map (current-local-map))) (define-key map [(control ?c) (control ?a)] 'ledger-add-transaction) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index c831f01a..75efb83c 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -167,17 +167,22 @@ position, whichever is closer." (delete-horizontal-space) (insert " ")))) -(defun ledger-post-align-postings () +(defun ledger-post-align-postings (&optional beg end) "Align all accounts and amounts within region, if there is no -region alight the posting on the current line." +region align the posting on the current line." (interactive) (save-excursion (if (or (not (mark)) (not (use-region-p))) (set-mark (point))) + (let* ((mark-first (< (mark) (point))) - (begin-region (if mark-first (mark) (point))) - (end-region (if mark-first (point-marker) (mark-marker))) + (begin-region (if beg + beg + (if mark-first (mark) (point)))) + (end-region (if end + end + (if mark-first (point-marker) (mark-marker)))) acc-col amt-offset acc-adjust) ;; Condition point and mark to the beginning and end of lines (goto-char end-region) -- cgit v1.2.3 From bc7a885eb711f4a6cf83d8e7701d90f0079e0359 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 25 Mar 2013 21:19:17 -0400 Subject: Speed improvement to align-postings. In some cases align-posting was getting called twice --- lisp/ldg-post.el | 13 +++++++++---- lisp/ldg-state.el | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 75efb83c..5ac97893 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -158,10 +158,10 @@ position, whichever is closer." (copy-marker end) end))) -(defun ledger-post-adjust (adjust-by) +(defsubst ledger-post-adjust (adjust-by) (if (> adjust-by 0) (insert (make-string adjust-by ? )) - (if (looking-back " " (- (point) 3)) + (if (looking-back " " (- (point) 1)) (delete-char adjust-by) (skip-chars-forward "^ \t") (delete-horizontal-space) @@ -176,7 +176,10 @@ region align the posting on the current line." (not (use-region-p))) (set-mark (point))) - (let* ((mark-first (< (mark) (point))) + (let* ((has-align-hook (remove-hook + 'after-change-functions + 'ledger-post-maybe-align t)) + (mark-first (< (mark) (point))) (begin-region (if beg beg (if mark-first (mark) (point)))) @@ -204,7 +207,9 @@ region align the posting on the current line." (current-column)))) (if (/= amt-adjust 0) (ledger-post-adjust amt-adjust))))) - (forward-line))))) + (forward-line)) + (if has-align-hook + (add-hook 'after-change-functions 'ledger-post-maybe-align t t))))) (defun ledger-post-maybe-align (beg end len) "Align amounts only if point is in a posting. diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index c1027f5c..88891aff 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -163,7 +163,7 @@ dropped." (delete-char 1)))) (setq new-status inserted)))) (if has-align-hook - (add-hook 'after-change-functions 'ledger-post-maybe-align t t)))) + (add-hook 'after-change-functions 'ledger-post-maybe-align t t)))) ;; This excursion cleans up the entry so that it displays ;; minimally. This means that if all posts are cleared, remove -- cgit v1.2.3 From b947bae1a8bf9a9ca326db46d8f5c907bedc3f1c Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 25 Mar 2013 23:50:26 -0400 Subject: Fix align-postings to deal with being at end of buffer --- lisp/ldg-complete.el | 5 ++--- lisp/ldg-post.el | 8 +++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index 7e37163b..9d524b86 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -127,10 +127,9 @@ Return tree structure" (line-end-position)))) (delete-region (line-beginning-position) (line-end-position)) - (condition-case err + (condition-case nil (ledger-add-transaction text t) - ((error "ledger-complete-at-point") - (insert text)))) + (error nil))) (forward-line) (goto-char (line-end-position)) (search-backward ";" (line-beginning-position) t) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 5ac97893..702518d3 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -186,7 +186,8 @@ region align the posting on the current line." (end-region (if end end (if mark-first (point-marker) (mark-marker)))) - acc-col amt-offset acc-adjust) + acc-col amt-offset acc-adjust + (lines-left 1)) ;; Condition point and mark to the beginning and end of lines (goto-char end-region) (setq end-region (copy-marker (line-end-position))) @@ -195,7 +196,8 @@ region align the posting on the current line." (setq begin-region (copy-marker (line-beginning-position)))) (while (or (setq acc-col (ledger-next-account (end-of-line-or-region end-region))) - (< (point) (marker-position end-region))) + (and (< (point) (marker-position end-region)) + (> lines-left 0))) (when acc-col (setq acc-adjust (- ledger-post-account-alignment-column acc-col)) (if (/= acc-adjust 0) @@ -207,7 +209,7 @@ region align the posting on the current line." (current-column)))) (if (/= amt-adjust 0) (ledger-post-adjust amt-adjust))))) - (forward-line)) + (setq lines-left (forward-line))) (if has-align-hook (add-hook 'after-change-functions 'ledger-post-maybe-align t t))))) -- cgit v1.2.3 From fec1c179e33225778fa4b69667d5382e7a2b5718 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 26 Mar 2013 00:35:38 -0400 Subject: Do not include xact level comments in account list for auto completion. --- lisp/ldg-complete.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index 9d524b86..65206026 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -77,7 +77,8 @@ Return tree structure" (split-string (match-string-no-properties 2) ":")) (let ((root account-tree)) - (while account-elements + (while (and account-elements + (not (char-equal (string-to-char (car account-elements)) ?\;))) (let ((entry (assoc (car account-elements) root))) (if entry (setq root (cdr entry)) -- cgit v1.2.3 From f1882d0a56f8b5828aaadfe06e5207a9b43d2ef0 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 26 Mar 2013 02:33:05 -0400 Subject: Major speed improvements to ledger-post-align-postings Got rid of markers. Use inhibit-modification-hook to suppress any other buffer stuff happening. Got giant-buffer down to around 3.5 seconds with full modifications. --- lisp/ldg-post.el | 70 +++++++++++++++++++++++++------------------------------ lisp/ldg-state.el | 11 ++++----- 2 files changed, 36 insertions(+), 45 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 702518d3..a39dea65 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -124,11 +124,12 @@ PROMPT is a string to prompt with. CHOICES is a list of "\\([ \t]*[@={]@?[^\n;]+?\\)?" "\\([ \t]+;.+?\\|[ \t]*\\)?$")) -(defun ledger-next-amount (&optional end) +(defsubst ledger-next-amount (&optional end) "Move point to the next amount, as long as it is not past END. -Return the width of the amount field as an integer." - (beginning-of-line) - (when (re-search-forward ledger-post-amount-regex (marker-position end) t) +Return the width of the amount field as an integer and leave +point at beginning of the commodity." + ;;(beginning-of-line) + (when (re-search-forward ledger-post-amount-regex end t) (goto-char (match-beginning 0)) (skip-syntax-forward " ") (- (or (match-end 4) @@ -138,34 +139,29 @@ Return the width of the amount field as an integer." (concat "\\(^[ \t]+\\)" "\\([\\[(*!;a-zA-Z0-9]+?\\)")) -(defun ledger-next-account (&optional end) +(defsubst ledger-next-account (&optional end) "Move point to the beginning of the next account, or status marker (!*), as long as it is not past END. -Return the column of the beginning of the account" - (beginning-of-line) - (if (> (marker-position end) (point)) - (when (re-search-forward ledger-post-account-regex (marker-position end) t) - (goto-char (match-beginning 2)) - (current-column)))) +Return the column of the beginning of the account and leave point +at beginning of account" + ;; (beginning-of-line) + (if (> end (point)) + (when (re-search-forward ledger-post-account-regex end t) + (goto-char (match-beginning 2)) + (current-column)))) -(defun end-of-line-or-region (end-region) - "Return a number or marker to the END-REGION or end of line +(defsubst ledger-post-end-of-line-or-region (end-region) + "Return a number the END-REGION or end of line position, whichever is closer." - (let ((end (if (< end-region (line-end-position)) - end-region - (line-end-position)))) - (if (markerp end-region) - (copy-marker end) - end))) + (let ((eol (line-end-position))) + (if (< end-region eol) + end-region + eol))) (defsubst ledger-post-adjust (adjust-by) (if (> adjust-by 0) (insert (make-string adjust-by ? )) - (if (looking-back " " (- (point) 1)) - (delete-char adjust-by) - (skip-chars-forward "^ \t") - (delete-horizontal-space) - (insert " ")))) + (delete-char adjust-by))) (defun ledger-post-align-postings (&optional beg end) "Align all accounts and amounts within region, if there is no @@ -176,42 +172,40 @@ region align the posting on the current line." (not (use-region-p))) (set-mark (point))) - (let* ((has-align-hook (remove-hook - 'after-change-functions - 'ledger-post-maybe-align t)) + (let* ((inhibit-modification-hooks t) (mark-first (< (mark) (point))) (begin-region (if beg beg (if mark-first (mark) (point)))) (end-region (if end end - (if mark-first (point-marker) (mark-marker)))) + (if mark-first (point) (mark)))) acc-col amt-offset acc-adjust (lines-left 1)) ;; Condition point and mark to the beginning and end of lines (goto-char end-region) - (setq end-region (copy-marker (line-end-position))) + (setq end-region (line-end-position)) (goto-char begin-region) (goto-char - (setq begin-region - (copy-marker (line-beginning-position)))) - (while (or (setq acc-col (ledger-next-account (end-of-line-or-region end-region))) - (and (< (point) (marker-position end-region)) - (> lines-left 0))) + (setq begin-region + (line-beginning-position))) + (while (or (setq acc-col (ledger-next-account (ledger-post-end-of-line-or-region end-region))) + (and (< (point) end-region) + lines-left)) (when acc-col (setq acc-adjust (- ledger-post-account-alignment-column acc-col)) (if (/= acc-adjust 0) (ledger-post-adjust acc-adjust)) - (when (setq amt-offset (ledger-next-amount (end-of-line-or-region end-region))) + (when (setq amt-offset (ledger-next-amount (ledger-post-end-of-line-or-region end-region))) (let* ((amt-adjust (- ledger-post-amount-alignment-column amt-offset (current-column)))) (if (/= amt-adjust 0) (ledger-post-adjust amt-adjust))))) - (setq lines-left (forward-line))) - (if has-align-hook - (add-hook 'after-change-functions 'ledger-post-maybe-align t t))))) + (forward-line) + (setq lines-left (not (eobp)))) + (setq inhibit-modification-hooks nil)))) (defun ledger-post-maybe-align (beg end len) "Align amounts only if point is in a posting. diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index 88891aff..4f1b3695 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -122,12 +122,10 @@ dropped." ;;this excursion toggles the posting status (save-excursion - (let ((has-align-hook (remove-hook - 'after-change-functions - 'ledger-post-maybe-align t))) + (setq inhibit-modification-hooks t) - (goto-char (line-beginning-position)) - (when (looking-at "[ \t]") + (goto-char (line-beginning-position)) + (when (looking-at "[ \t]") (skip-chars-forward " \t") (let ((here (point)) (cur-status (ledger-state-from-char (char-after)))) @@ -162,8 +160,7 @@ dropped." ((looking-at " ") (delete-char 1)))) (setq new-status inserted)))) - (if has-align-hook - (add-hook 'after-change-functions 'ledger-post-maybe-align t t)))) + (setq inhibit-modification-hooks nil)) ;; This excursion cleans up the entry so that it displays ;; minimally. This means that if all posts are cleared, remove -- cgit v1.2.3 From c8c94e960206f705610b92b6957a2209208c69c5 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 26 Mar 2013 13:55:31 -0400 Subject: Handle quoted commodities in ledger-split-commodity-string --- lisp/ldg-commodities.el | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 3485d93f..831d770b 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -41,21 +41,32 @@ Returns a list with (value commodity)." (with-temp-buffer (insert str) (goto-char (point-min)) - (cond ((re-search-forward number-regex nil t) - ;; found a number in the current locale, return it in - ;; the car. Anything left over is annotation, - ;; the first thing should be the commodity, separated - ;; by whitespace, return it in the cdr. I can't think of any - ;; counterexamples - (list - (string-to-number - (ledger-commodity-string-number-decimalize - (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user)) - (nth 0 (split-string (buffer-substring-no-properties (point-min) (point-max)))))) - ((re-search-forward "0" nil t) - ;; couldn't find a decimal number, look for a single 0, - ;; indicating account with zero balance - (list 0 ledger-reconcile-default-commodity))))) + (cond + ((re-search-forward "\"\\(.*\\)\"" nil t) + (let ((com (delete-and-extract-region + (match-beginning 1) + (match-end 1)))) + (if (re-search-forward number-regex nil t) + (list + (string-to-number + (ledger-commodity-string-number-decimalize + (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user)) + com)))) + ((re-search-forward number-regex nil t) + ;; found a number in the current locale, return it in + ;; the car. Anything left over is annotation, + ;; the first thing should be the commodity, separated + ;; by whitespace, return it in the cdr. I can't think of any + ;; counterexamples + (list + (string-to-number + (ledger-commodity-string-number-decimalize + (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user)) + (nth 0 (split-string (buffer-substring-no-properties (point-min) (point-max)))))) + ((re-search-forward "0" nil t) + ;; couldn't find a decimal number, look for a single 0, + ;; indicating account with zero balance + (list 0 ledger-reconcile-default-commodity))))) ;; nothing found, return 0 (list 0 ledger-reconcile-default-commodity))) -- cgit v1.2.3 From 5b1778b3ca8202677aeb7096c17452e8445a25c9 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 26 Mar 2013 19:34:37 -0400 Subject: More speed improvements for align-postings. --- lisp/ldg-post.el | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index a39dea65..e0b5f8fa 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -137,27 +137,17 @@ point at beginning of the commodity." (defvar ledger-post-account-regex (concat "\\(^[ \t]+\\)" - "\\([\\[(*!;a-zA-Z0-9]+?\\)")) + "\\([\\[(*!;a-zA-Z0-9]\\)")) (defsubst ledger-next-account (&optional end) "Move point to the beginning of the next account, or status marker (!*), as long as it is not past END. Return the column of the beginning of the account and leave point at beginning of account" - ;; (beginning-of-line) (if (> end (point)) (when (re-search-forward ledger-post-account-regex end t) (goto-char (match-beginning 2)) (current-column)))) - -(defsubst ledger-post-end-of-line-or-region (end-region) - "Return a number the END-REGION or end of line -position, whichever is closer." - (let ((eol (line-end-position))) - (if (< end-region eol) - end-region - eol))) - (defsubst ledger-post-adjust (adjust-by) (if (> adjust-by 0) (insert (make-string adjust-by ? )) @@ -189,15 +179,16 @@ region align the posting on the current line." (goto-char (setq begin-region (line-beginning-position))) - (while (or (setq acc-col (ledger-next-account (ledger-post-end-of-line-or-region end-region))) + + ;; This is the guts of the alignment loop + (while (or (setq acc-col (ledger-next-account (line-end-position))) (and (< (point) end-region) lines-left)) (when acc-col - (setq acc-adjust (- ledger-post-account-alignment-column acc-col)) - (if (/= acc-adjust 0) + (if (/= (setq acc-adjust (- ledger-post-account-alignment-column acc-col)) 0) (ledger-post-adjust acc-adjust)) - (when (setq amt-offset (ledger-next-amount (ledger-post-end-of-line-or-region end-region))) + (when (setq amt-offset (ledger-next-amount (line-end-position))) (let* ((amt-adjust (- ledger-post-amount-alignment-column amt-offset (current-column)))) -- cgit v1.2.3 From 5418e77c638ac34a340ab3ed368f800cb6f02353 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 26 Mar 2013 23:50:14 -0400 Subject: Better end testing for align-postings --- lisp/ldg-post.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index e0b5f8fa..d5646702 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -181,9 +181,9 @@ region align the posting on the current line." (line-beginning-position))) ;; This is the guts of the alignment loop - (while (or (setq acc-col (ledger-next-account (line-end-position))) - (and (< (point) end-region) - lines-left)) + (while (and (or (setq acc-col (ledger-next-account (line-end-position))) + lines-left) + (< (point) end-region)) (when acc-col (if (/= (setq acc-adjust (- ledger-post-account-alignment-column acc-col)) 0) (ledger-post-adjust acc-adjust)) -- cgit v1.2.3 From 15b1d36fa298b0eb743ee4839096899787e11b8d Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 27 Mar 2013 13:54:44 -0400 Subject: Cleaned up entrant macros to only return clauses --- lisp/ldg-schedule.el | 108 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 42 deletions(-) diff --git a/lisp/ldg-schedule.el b/lisp/ldg-schedule.el index effa20b5..c3c77548 100644 --- a/lisp/ldg-schedule.el +++ b/lisp/ldg-schedule.el @@ -79,12 +79,10 @@ COUNT 0) means EVERY day-of-week (eg. every Saturday)" ((> count 0) ;; Positive count (let ((decoded (gensym))) `(let ((,decoded (decode-time date))) - (if (and (eq (nth 6 ,decoded) ,day-of-week) - (between (nth 3 ,decoded) - ,(* (1- count) 7) - ,(* count 7))) - t - nil)))) + (and (eq (nth 6 ,decoded) ,day-of-week) + (between (nth 3 ,decoded) + ,(* (1- count) 7) + ,(* count 7)))))) ((< count 0) (let ((days-in-month (gensym)) (decoded (gensym))) @@ -92,12 +90,10 @@ COUNT 0) means EVERY day-of-week (eg. every Saturday)" (,days-in-month (ledger-schedule-days-in-month (nth 4 ,decoded) (nth 5 ,decoded)))) - (if (and (eq (nth 6 ,decoded) ,day-of-week) - (between (nth 3 ,decoded) - (+ ,days-in-month ,(* count 7)) - (+ ,days-in-month ,(* (1+ count) 7)))) - t - nil)))) + (and (eq (nth 6 ,decoded) ,day-of-week) + (between (nth 3 ,decoded) + (+ ,days-in-month ,(* count 7)) + (+ ,days-in-month ,(* (1+ count) 7))))))) (t (error "COUNT out of range, COUNT=%S" count))) (error "Invalid argument to ledger-schedule-day-in-month-macro %S %S" @@ -117,13 +113,13 @@ of date." (between (eval day) 1 (ledger-schedule-days-in-month (eval month) (eval year)))) (between (eval day) 1 31)) ;; no month specified, assume 31 days. `'(and ,(if (eval year) - `(if (eq (nth 5 (decode-time date)) ,(eval year)) t) - `t) + `(eq (nth 5 (decode-time date)) ,(eval year)) + `t) ,(if (eval month) - `(if (eq (nth 4 (decode-time date)) ,(eval month)) t) + `(eq (nth 4 (decode-time date)) ,(eval month)) `t) ,(if (eval day) - `(if (eq (nth 3 (decode-time date)) ,(eval day)) t))) + `(eq (nth 3 (decode-time date)) ,(eval day)))) (error "ledger-schedule-constraint-numerical-date-macro: date out of range %S %S %S" (eval year) (eval month) (eval day)))) @@ -133,10 +129,8 @@ of date." For example every second Friday, regardless of month." (let ((start-day (nth 6 (decode-time (eval start-date))))) (if (eq start-day day-of-week) ;; good, can proceed - `(if (zerop (mod (- (time-to-days date) ,(time-to-days (eval start-date))) ,(* skip 7))) - t - nil) - (error "START-DATE day of week doesn't match DAY-OF-WEEK")))) + `(zerop (mod (- (time-to-days date) ,(time-to-days (eval start-date))) ,(* skip 7))) + (error "START-DATE day of week doesn't match DAY-OF-WEEK")))) (defmacro ledger-schedule-constrain-date-range-macro (month1 day1 month2 day2) "Return a form of DATE that is true if DATE falls between MONTH1 DAY1 and MONTH2 DAY2." @@ -191,7 +185,7 @@ the transaction should be logged for that day." (replace-match "(" nil t))) (defun ledger-schedule-read-descriptor-tree (descriptor-string) - "Take a date descriptor string and return a function that + "Take a date DESCRIPTOR-STRING and return a function of date that returns true if the date meets the requirements" (with-temp-buffer ;; copy the descriptor string into a temp buffer for manipulation @@ -222,51 +216,76 @@ returns true if the date meets the requirements" ;; read the descriptor string into a lisp object the transform the ;; string descriptor into useable things - (ledger-transform-auto-tree + (ledger-schedule-transform-auto-tree (read (buffer-substring-no-properties (point-min) (point-max)))))) -(defun ledger-transform-auto-tree (tree) +(defun ledger-schedule-transform-auto-tree (descriptor-string-list) "Takes a lisp list of date descriptor strings, TREE, and returns a string with a lambda function of date." ;; use funcall to use the lambda function spit out here - (if (consp tree) + (if (consp descriptor-string-list) (let (result) - (while (consp tree) - (let ((newcar (car tree))) + (while (consp descriptor-string-list) + (let ((newcar (car descriptor-string-list))) (if (consp newcar) - (setq newcar (ledger-transform-auto-tree (car tree)))) + (setq newcar (ledger-schedule-transform-auto-tree (car descriptor-string-list)))) + ;; newcar may be a cons now, after ledger-schedule-transfrom-auto-tree (if (consp newcar) (push newcar result) + ;; this is where we actually turn the string descriptor into useful lisp (push (ledger-schedule-parse-date-descriptor newcar) result)) ) - (setq tree (cdr tree))) + (setq descriptor-string-list (cdr descriptor-string-list))) - ;; tie up all the clauses in a big or and lambda + ;; tie up all the clauses in a big or and lambda, and return + ;; the lambda function as list to be executed by funcall `(lambda (date) - ,(nconc (list 'or) (nreverse result) tree))))) + ,(nconc (list 'or) (nreverse result) descriptor-string-list))))) (defun ledger-schedule-split-constraints (descriptor-string) "Return a list with the year, month and day fields split" (let ((fields (split-string descriptor-string "[/\\-]" t)) constrain-year constrain-month constrain-day) - (if (string= (car fields) "*") + (if (string= (nth 0 fields) "*") (setq constrain-year nil) - (setq constrain-year (car fields))) - (if (string= (cadr fields) "*") + (setq constrain-year (nth 0 fields))) + + ;;(setq constrain-month (ledger-schedule-classify-month-constraint (nth 1 fields))) + + (if (string= (nth 1 fields) "*") (setq constrain-month nil) - (setq constrain-month (cadr fields))) + (setq constrain-month (nth 1 fields))) + (if (string= (nth 2 fields) "*") (setq constrain-day nil) (setq constrain-day (nth 2 fields))) (list constrain-year constrain-month constrain-day))) -(defun ledger-string-to-number-or-nil (str) +(defun ledger-schedule-string-to-number-or-nil (str) (if str (string-to-number str) nil)) +(defun ledger-schedule-classify-month-constraint (str) + (cond ((string= str "*") + t) + ((/= 0 (string-to-number str)) + (ledger-schedule-constrain-month-numerical (string-to-number str))) + (t + (error "Improperly specified month constraint: " str)))) + +(defun ledger-schedule-constrain-numerical-month (month) + "Return an exprssion of date that is only true if all constraints are met. +A nil constraint matches any input, a numerical entry must match that field +of date." + ;; Do bounds checking to make sure the incoming date constraint is sane + + (if (between (eval month) 1 12) ;; no month specified, assume 31 days. + `(eq (nth 4 (decode-time date)) ,(eval month)) + (error "ledger-schedule-constrain-numerical-month: month out of range %S" (eval month)))) + (defun ledger-schedule-compile-constraints (constraint-list) - (let ((year-constraint (ledger-string-to-number-or-nil (nth 0 constraint-list))) - (month-constraint (ledger-string-to-number-or-nil (nth 1 constraint-list))) - (day-constraint (ledger-string-to-number-or-nil (nth 2 constraint-list)))) + (let ((year-constraint (ledger-schedule-string-to-number-or-nil (nth 0 constraint-list))) + (month-constraint (ledger-schedule-string-to-number-or-nil (nth 1 constraint-list))) + (day-constraint (ledger-schedule-string-to-number-or-nil (nth 2 constraint-list)))) (ledger-schedule-constrain-numerical-date-macro year-constraint month-constraint @@ -303,7 +322,9 @@ returns true if the date meets the requirements" (erase-buffer) (dolist (candidate candidates) (if (not (ledger-schedule-already-entered candidate ledger-buf)) - (insert (format-time-string date-format (car candidate) ) " " (cadr candidate) "\n")))))) + (insert (format-time-string date-format (car candidate) ) " " (cadr candidate) "\n"))) + (ledger-mode)) + (length candidates))) ;; @@ -311,9 +332,12 @@ returns true if the date meets the requirements" ;; (defvar auto-items) -(defun ledger-schedule-test-setup () - (setq auto-items - (ledger-schedule-scan-transactions ledger-schedule-file))) +(defun ledger-schedule-test ( early horizon) + (ledger-schedule-create-auto-buffer + (ledger-schedule-scan-transactions ledger-schedule-file) + early + horizon + (get-buffer "2013.ledger"))) (defun ledger-schedule-test-predict () -- cgit v1.2.3 From ad07d2842737a72a600603c8cd6cde870e477d81 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 27 Mar 2013 16:35:43 -0400 Subject: Bug 936 Fixes ledger-add-transaction. Symptom was no empty line after xact, real problem was not putting ledger output into the temp buffer. --- lisp/ldg-mode.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 1d587d63..c9814918 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -249,7 +249,7 @@ correct chronological place in the buffer." (insert (with-temp-buffer (setq exit-code - (apply #'ledger-exec-ledger ledger-buf ledger-buf "xact" + (apply #'ledger-exec-ledger ledger-buf (current-buffer) "xact" (mapcar 'eval args))) (goto-char (point-min)) (if (looking-at "Error: ") -- cgit v1.2.3 From 4ca0e8916b5a821a4659918a754427799b5b9036 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 27 Mar 2013 15:37:52 -0700 Subject: Fix bug 935, very long account names can get stomped on. This works, but hammers performance --- lisp/ldg-post.el | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index d5646702..f2adc676 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -136,17 +136,16 @@ point at beginning of the commodity." (match-end 3)) (point)))) (defvar ledger-post-account-regex - (concat "\\(^[ \t]+\\)" - "\\([\\[(*!;a-zA-Z0-9]\\)")) + "\\(^[ \t]+\\)\\([\\[(;!*A-Za-z0-9]\\)\\(.+?\\)\\( \\|\n\\)") -(defsubst ledger-next-account (&optional end) +(defun ledger-next-account (&optional end) "Move point to the beginning of the next account, or status marker (!*), as long as it is not past END. Return the column of the beginning of the account and leave point at beginning of account" (if (> end (point)) - (when (re-search-forward ledger-post-account-regex end t) + (when (re-search-forward ledger-post-account-regex (1+ end) t) (goto-char (match-beginning 2)) - (current-column)))) + (list (current-column) (length (match-string-no-properties 3)))))) (defsubst ledger-post-adjust (adjust-by) (if (> adjust-by 0) @@ -185,10 +184,12 @@ region align the posting on the current line." lines-left) (< (point) end-region)) (when acc-col - (if (/= (setq acc-adjust (- ledger-post-account-alignment-column acc-col)) 0) + (if (/= (setq acc-adjust (- ledger-post-account-alignment-column (car acc-col))) 0) (ledger-post-adjust acc-adjust)) - (when (setq amt-offset (ledger-next-amount (line-end-position))) + (when (and + (> ledger-post-amount-alignment-column (+ ledger-post-account-alignment-column (cadr acc-col))) + (setq amt-offset (ledger-next-amount (line-end-position)))) (let* ((amt-adjust (- ledger-post-amount-alignment-column amt-offset (current-column)))) -- cgit v1.2.3 From 7fea9d21fb72e1d66423a928297dd3cc29c7cc78 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 27 Mar 2013 20:02:11 -0700 Subject: Align post speed improvements after adding the long account name handling. --- lisp/ldg-post.el | 49 ++++++++++++++++++++++++++----------------------- lisp/ldg-xact.el | 2 +- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index f2adc676..91ee623d 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -136,21 +136,17 @@ point at beginning of the commodity." (match-end 3)) (point)))) (defvar ledger-post-account-regex - "\\(^[ \t]+\\)\\([\\[(;!*A-Za-z0-9]\\)\\(.+?\\)\\( \\|\n\\)") + "\\(^[ \t]+\\)\\(.+?\\)\\( \\|\n\\)") (defun ledger-next-account (&optional end) "Move point to the beginning of the next account, or status marker (!*), as long as it is not past END. Return the column of the beginning of the account and leave point at beginning of account" (if (> end (point)) - (when (re-search-forward ledger-post-account-regex (1+ end) t) + (when (re-search-forward ledger-post-account-regex (1+ end) t) + ;; the 1+ is to make sure we can catch the newline (goto-char (match-beginning 2)) - (list (current-column) (length (match-string-no-properties 3)))))) - -(defsubst ledger-post-adjust (adjust-by) - (if (> adjust-by 0) - (insert (make-string adjust-by ? )) - (delete-char adjust-by))) + (current-column)))) (defun ledger-post-align-postings (&optional beg end) "Align all accounts and amounts within region, if there is no @@ -178,24 +174,31 @@ region align the posting on the current line." (goto-char (setq begin-region (line-beginning-position))) - + ;; This is the guts of the alignment loop (while (and (or (setq acc-col (ledger-next-account (line-end-position))) - lines-left) - (< (point) end-region)) + lines-left) + (< (point) end-region)) (when acc-col - (if (/= (setq acc-adjust (- ledger-post-account-alignment-column (car acc-col))) 0) - (ledger-post-adjust acc-adjust)) - - (when (and - (> ledger-post-amount-alignment-column (+ ledger-post-account-alignment-column (cadr acc-col))) - (setq amt-offset (ledger-next-amount (line-end-position)))) - (let* ((amt-adjust (- ledger-post-amount-alignment-column - amt-offset - (current-column)))) - (if (/= amt-adjust 0) - (ledger-post-adjust amt-adjust))))) - (forward-line) + (when (/= (setq acc-adjust (- ledger-post-account-alignment-column acc-col)) 0) + (if (> acc-adjust 0) + (insert (make-string acc-adjust ? )) + (delete-char acc-adjust))) + (when (setq amt-offset (ledger-next-amount (line-end-position))) + (let* ((amt-adjust (- ledger-post-amount-alignment-column + amt-offset + (current-column)))) + (if (/= amt-adjust 0) + (if (> amt-adjust 0) + (insert (make-string amt-adjust ? )) + (let ((curpoint (point))) + (beginning-of-line) + (ledger-next-account (line-end-position)) + (when (> (+ curpoint amt-adjust) + (match-end 2)) + (goto-char curpoint) + (delete-char amt-adjust)))))))) + (forward-line) (setq lines-left (not (eobp)))) (setq inhibit-modification-hooks nil)))) diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index e2180b57..d6ccc2bf 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -21,7 +21,7 @@ ;;; Commentary: -;; Utilites for running ledger synchronously. +;; Utilities for running ledger synchronously. ;;; Code: -- cgit v1.2.3 From 69c0927772f74fd0c45b1250c171e86cc205c76d Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 30 Mar 2013 07:30:40 -0700 Subject: Fix bug 937 maintain sort order of xact on the same actual date. --- lisp/ldg-sort.el | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el index ecb86371..45b55c47 100644 --- a/lisp/ldg-sort.el +++ b/lisp/ldg-sort.el @@ -64,13 +64,17 @@ (beginning-of-line) (insert "\n; Ledger-mode: End sort\n\n")) +(defun ledger-sort-startkey () + "Return the actual date so the sort-subr doesn't sort onthe entire first line." + (buffer-substring-no-properties (point) (+ 10 (point)))) + (defun ledger-sort-region (beg end) "Sort the region from BEG to END in chronological order." (interactive "r") ;; load beg and end from point and mark ;; automagically (let ((new-beg beg) (new-end end)) - (save-excursion + (save-excursion (save-restriction (goto-char beg) (ledger-next-record-function) ;; make sure point is at the @@ -88,7 +92,8 @@ (sort-subr nil 'ledger-next-record-function - 'ledger-end-record-function)))))) + 'ledger-end-record-function + 'ledger-sort-startkey)))))) (defun ledger-sort-buffer () "Sort the entire buffer." -- cgit v1.2.3 From 44ae6e0f16fe8677f491487b948eeb5e8cc2998f Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 30 Mar 2013 08:27:16 -0700 Subject: Start integrating schedule into the overall mode --- lisp/ldg-mode.el | 12 ++-- lisp/ldg-new.el | 2 +- lisp/ldg-schedule.el | 153 +++++++++++++++++++++------------------------------ 3 files changed, 71 insertions(+), 96 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index c9814918..e9e233af 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -106,18 +106,20 @@ Can be pcomplete, or align-posting" (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) (define-key map [(control ?c) (control ?t)] 'ledger-insert-effective-date) + (define-key map [(control ?c) (control ?u)] 'ledger-schedule-upcoming) (define-key map [(control ?c) (control ?y)] 'ledger-set-year) - (define-key map [tab] 'ledger-magic-tab) + (define-key map [tab] 'ledger-magic-tab) (define-key map [(control ?i)] 'ledger-magic-tab) (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry) - (define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report) - (define-key map [(control ?c) (control ?o) (control ?g)] 'ledger-report-goto) + (define-key map [(control ?c) (control ?o) (control ?a)] 'ledger-report-redo) - (define-key map [(control ?c) (control ?o) (control ?s)] 'ledger-report-save) (define-key map [(control ?c) (control ?o) (control ?e)] 'ledger-report-edit) + (define-key map [(control ?c) (control ?o) (control ?g)] 'ledger-report-goto) (define-key map [(control ?c) (control ?o) (control ?k)] 'ledger-report-kill) - + (define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report) + (define-key map [(control ?c) (control ?o) (control ?s)] 'ledger-report-save) + (define-key map [(meta ?p)] 'ledger-post-prev-xact) (define-key map [(meta ?n)] 'ledger-post-next-xact) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index 8ff95cd3..db16e03e 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -50,7 +50,7 @@ (require 'ldg-test) (require 'ldg-texi) (require 'ldg-xact) - +(require 'ldg-schedule) ;;; Code: diff --git a/lisp/ldg-schedule.el b/lisp/ldg-schedule.el index c3c77548..885c0876 100644 --- a/lisp/ldg-schedule.el +++ b/lisp/ldg-schedule.el @@ -68,7 +68,7 @@ If year is nil, assume it is not a leap year" ;; Macros to handle date expressions -(defmacro ledger-schedule-constrain-day-in-month-macro (count day-of-week) +(defun ledger-schedule-constrain-day-in-month (count day-of-week) "Return a form that evaluates DATE that returns true for the COUNT DAY-OF-WEEK. For example, return true if date is the 3rd Thursday of the month. Negative COUNT starts from the end of the month. (EQ @@ -100,31 +100,7 @@ COUNT 0) means EVERY day-of-week (eg. every Saturday)" count day-of-week))) -(defmacro ledger-schedule-constrain-numerical-date-macro (year month day) - "Return a function of date that is only true if all constraints are met. -A nil constraint matches any input, a numerical entry must match that field -of date." - ;; Do bounds checking to make sure the incoming date constraint is sane - (if - (if (eval month) ;; if we have a month - (and (between (eval month) 1 12) ;; make sure it is between 1 - ;; and twelve and the number - ;; of days are ok - (between (eval day) 1 (ledger-schedule-days-in-month (eval month) (eval year)))) - (between (eval day) 1 31)) ;; no month specified, assume 31 days. - `'(and ,(if (eval year) - `(eq (nth 5 (decode-time date)) ,(eval year)) - `t) - ,(if (eval month) - `(eq (nth 4 (decode-time date)) ,(eval month)) - `t) - ,(if (eval day) - `(eq (nth 3 (decode-time date)) ,(eval day)))) - (error "ledger-schedule-constraint-numerical-date-macro: date out of range %S %S %S" (eval year) (eval month) (eval day)))) - - - -(defmacro ledger-schedule-constrain-every-count-day-macro (day-of-week skip start-date) +(defun ledger-schedule-constrain-every-count-day (day-of-week skip start-date) "Return a form that is true for every DAY skipping SKIP, starting on START. For example every second Friday, regardless of month." (let ((start-day (nth 6 (decode-time (eval start-date))))) @@ -132,7 +108,7 @@ For example every second Friday, regardless of month." `(zerop (mod (- (time-to-days date) ,(time-to-days (eval start-date))) ,(* skip 7))) (error "START-DATE day of week doesn't match DAY-OF-WEEK")))) -(defmacro ledger-schedule-constrain-date-range-macro (month1 day1 month2 day2) +(defun ledger-schedule-constrain-date-range (month1 day1 month2 day2) "Return a form of DATE that is true if DATE falls between MONTH1 DAY1 and MONTH2 DAY2." (let ((decoded (gensym)) (target-month (gensym)) @@ -184,6 +160,19 @@ the transaction should be logged for that day." (while (search-forward "[" nil t) (replace-match "(" nil t))) +(defvar ledger-schedule-descriptor-regex + (concat "\\(20[0-9][0-9]\\|[\*]\\)[/\\-]" ;; Year slot + "\\([\*EO]\\|[01][0-9]\\)[/\\-]" ;; Month slot + "\\([\*]\\|\\([0-3][0-9]\\)\\|" + "\\([0-5]" + "\\(\\(Su\\)\\|" + "\\(Mo\\)\\|" + "\\(Tu\\)\\|" + "\\(We\\)\\|" + "\\(Th\\)\\|" + "\\(Fr\\)\\|" + "\\(Sa\\)\\)\\)\\)")) + (defun ledger-schedule-read-descriptor-tree (descriptor-string) "Take a date DESCRIPTOR-STRING and return a function of date that returns true if the date meets the requirements" @@ -196,18 +185,7 @@ returns true if the date meets the requirements" (goto-char (point-max)) ;; double quote all the descriptors for string processing later - (while (re-search-backward - (concat "\\(20[0-9][0-9]\\|[\*]\\)[/\\-]" ;; Year slot - "\\([\*EO]\\|[01][0-9]\\)[/\\-]" ;; Month slot - "\\([\*]\\|\\([0-3][0-9]\\)\\|" - "\\([0-5]" - "\\(\\(Su\\)\\|" - "\\(Mo\\)\\|" - "\\(Tu\\)\\|" - "\\(We\\)\\|" - "\\(Th\\)\\|" - "\\(Fr\\)\\|" - "\\(Sa\\)\\)\\)\\)") nil t) ;; Day slot + (while (re-search-backward ledger-schedule-descriptor-regex nil t) ;; Day slot (goto-char (match-end 0)) (insert ?\") @@ -232,7 +210,7 @@ returns true if the date meets the requirements" (if (consp newcar) (push newcar result) ;; this is where we actually turn the string descriptor into useful lisp - (push (ledger-schedule-parse-date-descriptor newcar) result)) ) + (push (ledger-schedule-compile-constraints newcar) result)) ) (setq descriptor-string-list (cdr descriptor-string-list))) ;; tie up all the clauses in a big or and lambda, and return @@ -240,62 +218,49 @@ returns true if the date meets the requirements" `(lambda (date) ,(nconc (list 'or) (nreverse result) descriptor-string-list))))) -(defun ledger-schedule-split-constraints (descriptor-string) +(defun ledger-schedule-compile-constraints (descriptor-string) "Return a list with the year, month and day fields split" (let ((fields (split-string descriptor-string "[/\\-]" t)) constrain-year constrain-month constrain-day) - (if (string= (nth 0 fields) "*") - (setq constrain-year nil) - (setq constrain-year (nth 0 fields))) - - ;;(setq constrain-month (ledger-schedule-classify-month-constraint (nth 1 fields))) - - (if (string= (nth 1 fields) "*") - (setq constrain-month nil) - (setq constrain-month (nth 1 fields))) - - (if (string= (nth 2 fields) "*") - (setq constrain-day nil) - (setq constrain-day (nth 2 fields))) - (list constrain-year constrain-month constrain-day))) - -(defun ledger-schedule-string-to-number-or-nil (str) - (if str - (string-to-number str) - nil)) - -(defun ledger-schedule-classify-month-constraint (str) - (cond ((string= str "*") - t) - ((/= 0 (string-to-number str)) - (ledger-schedule-constrain-month-numerical (string-to-number str))) - (t - (error "Improperly specified month constraint: " str)))) - -(defun ledger-schedule-constrain-numerical-month (month) - "Return an exprssion of date that is only true if all constraints are met. -A nil constraint matches any input, a numerical entry must match that field -of date." - ;; Do bounds checking to make sure the incoming date constraint is sane + (setq constrain-year (ledger-schedule-constrain-year (nth 0 fields))) + (setq constrain-month (ledger-schedule-constrain-month (nth 1 fields))) + (setq constrain-day (ledger-schedule-constrain-day (nth 2 fields))) + + (list 'and constrain-year constrain-month constrain-day))) + +(defun ledger-schedule-constrain-year (str) + (let ((year-match t)) + (cond ((string= str "*") + year-match) + ((/= 0 (setq year-match (string-to-number str))) + `(eq (nth 5 (decode-time date)) ,year-match)) + (t + (error "Improperly specified year constraint: " str))))) + +(defun ledger-schedule-constrain-month (str) - (if (between (eval month) 1 12) ;; no month specified, assume 31 days. - `(eq (nth 4 (decode-time date)) ,(eval month)) - (error "ledger-schedule-constrain-numerical-month: month out of range %S" (eval month)))) - -(defun ledger-schedule-compile-constraints (constraint-list) - (let ((year-constraint (ledger-schedule-string-to-number-or-nil (nth 0 constraint-list))) - (month-constraint (ledger-schedule-string-to-number-or-nil (nth 1 constraint-list))) - (day-constraint (ledger-schedule-string-to-number-or-nil (nth 2 constraint-list)))) - (ledger-schedule-constrain-numerical-date-macro - year-constraint - month-constraint - day-constraint))) + (let ((month-match t)) + (cond ((string= str "*") + month-match) ;; always match + ((/= 0 (setq month-match (string-to-number str))) + (if (between month-match 1 12) ;; no month specified, assume 31 days. + `(eq (nth 4 (decode-time date)) ,month-match) + (error "ledger-schedule-constrain-numerical-month: month out of range %S" month-match))) + (t + (error "Improperly specified month constraint: " str))))) + +(defun ledger-schedule-constrain-day (str) + (let ((day-match t)) + (cond ((string= str "*") + t) + ((/= 0 (setq day-match (string-to-number str))) + `(eq (nth 3 (decode-time date)) ,day-match)) + (t + (error "Improperly specified day constraint: " str))))) (defun ledger-schedule-parse-date-descriptor (descriptor) "Parse the date descriptor, return the evaluator" - (ledger-schedule-compile-constraints - (ledger-schedule-split-constraints descriptor))) - + (ledger-schedule-compile-constraints descriptor)) (defun ledger-schedule-list-upcoming-xacts (candidate-items early horizon) "Search CANDIDATE-ITEMS for xacts that occur within the period today - EARLY to today + HORIZON" @@ -346,12 +311,20 @@ of date." (loop for day from 0 to ledger-schedule-look-forward by 1 do (setq test-date (time-add today (days-to-time day))) - ;;(message "date: %S" (decode-time test-date)) (dolist (item auto-items items) (if (funcall (car item) test-date) (setq items (append items (list (decode-time test-date) (cdr item))))))) items)) +(defun ledger-schedule-upcoming () + (interactive) + (ledger-schedule-create-auto-buffer + (ledger-schedule-scan-transactions ledger-schedule-file) + ledger-schedule-look-backward + ledger-schedule-look-forward + (current-buffer))) + + (provide 'ldg-schedule) ;;; ldg-schedule.el ends here -- cgit v1.2.3 From efed5eb4bfd35a75e013c70f76c34452542eee5e Mon Sep 17 00:00:00 2001 From: Rémi Vanicat <vanicat@debian.org> Date: Sat, 30 Mar 2013 13:19:54 +0100 Subject: Removing some warning when compiling ledger. * ldg-commodities.el: use #' instead of ' for function quoting * ldg-exec.el: remove the fit-frame function that don't exists and do not use toggle-read-only to make the buffer read-only * ldg-report.el: use forward-line instead of next-line --- lisp/ldg-commodities.el | 2 +- lisp/ldg-exec.el | 3 +-- lisp/ldg-report.el | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 831d770b..842613c6 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -75,7 +75,7 @@ Returns a list with (value commodity)." (let ((fields (split-string str "[\n\r]"))) ; break any balances ; with multi commodities ; into a list - (mapcar '(lambda (str) + (mapcar #'(lambda (str) (ledger-split-commodity-string str)) fields))) diff --git a/lisp/ldg-exec.el b/lisp/ldg-exec.el index 4a485072..51443ff4 100644 --- a/lisp/ldg-exec.el +++ b/lisp/ldg-exec.el @@ -45,9 +45,8 @@ (with-current-buffer (get-buffer-create "*Ledger Error*") (insert-buffer-substring ledger-output) (make-frame) - (fit-frame) (view-mode) - (toggle-read-only))) + (setq buffer-read-only t))) (defun ledger-exec-success-p (ledger-output-buffer) (with-current-buffer ledger-output-buffer diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 4f14fdcb..04c182dd 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -79,7 +79,7 @@ text that should replace the format specifier." (interactive) (goto-char (point-min)) (forward-paragraph) - (next-line) + (forward-line) (save-excursion (setq inhibit-read-only t) (reverse-region (point) (point-max)))) -- cgit v1.2.3 From e3c6ebf97f2f9f7d08f845184c19fccbcf515ce8 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 31 Mar 2013 09:19:10 -0700 Subject: Correct a solarize face --- lisp/ldg-fonts.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index 76bfc03d..5874b81f 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -38,7 +38,7 @@ :group 'ledger-faces) (defface ledger-font-highlight-face - `((t :background "white")) + `((t :background "eee8d5")) "Default face for transaction under point" :group 'ledger-faces) -- cgit v1.2.3 From 7bad6186938c7b0d02d9c01050fdcdb3b4cd47f0 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 31 Mar 2013 09:54:28 -0700 Subject: Oops, forgot a # --- lisp/ldg-fonts.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index 5874b81f..3a7d1e0a 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -38,7 +38,7 @@ :group 'ledger-faces) (defface ledger-font-highlight-face - `((t :background "eee8d5")) + `((t :background "#eee8d5")) "Default face for transaction under point" :group 'ledger-faces) -- cgit v1.2.3 From c9f91992031967e9f378da1a14b92bc6f9276c90 Mon Sep 17 00:00:00 2001 From: Rémi Vanicat <vanicat@debian.org> Date: Sun, 31 Mar 2013 21:16:39 +0200 Subject: Use (fit-window-to-buffer) for error reporting. --- lisp/ldg-exec.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/ldg-exec.el b/lisp/ldg-exec.el index 51443ff4..c09b364d 100644 --- a/lisp/ldg-exec.el +++ b/lisp/ldg-exec.el @@ -45,6 +45,7 @@ (with-current-buffer (get-buffer-create "*Ledger Error*") (insert-buffer-substring ledger-output) (make-frame) + (fit-window-to-buffer) (view-mode) (setq buffer-read-only t))) -- cgit v1.2.3 From f015d00fa5b7cb54781569a8ed3835fa5163fae1 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 31 Mar 2013 19:15:10 -0700 Subject: corrected error output --- lisp/ldg-exec.el | 2 -- 1 file changed, 2 deletions(-) diff --git a/lisp/ldg-exec.el b/lisp/ldg-exec.el index 4a485072..c9bf92ba 100644 --- a/lisp/ldg-exec.el +++ b/lisp/ldg-exec.el @@ -44,8 +44,6 @@ "Deal with ledger errors contained in LEDGER-OUTPUT." (with-current-buffer (get-buffer-create "*Ledger Error*") (insert-buffer-substring ledger-output) - (make-frame) - (fit-frame) (view-mode) (toggle-read-only))) -- cgit v1.2.3 From 62996f9366fc582f0e2cebe8d88aea9095629239 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 1 Apr 2013 10:15:48 -0700 Subject: Make 'return' visit source in reports, make Visit Source the entry in reconcile mode. --- lisp/ldg-reconcile.el | 2 +- lisp/ldg-report.el | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index 5a6a117a..bec6d175 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -434,7 +434,7 @@ moved and recentered. If they aren't strange things happen." (define-key map [menu-bar ldg-recon-menu qui] '("Quit" . ledger-reconcile-quit)) (define-key map [menu-bar ldg-recon-menu sep1] '("--")) (define-key map [menu-bar ldg-recon-menu pre] '("Previous Entry" . previous-line)) - (define-key map [menu-bar ldg-recon-menu vis] '("Visit Entry" . ledger-reconcile-visit)) + (define-key map [menu-bar ldg-recon-menu vis] '("Visit Source" . ledger-reconcile-visit)) (define-key map [menu-bar ldg-recon-menu nex] '("Next Entry" . next-line)) (define-key map [menu-bar ldg-recon-menu sep2] '("--")) (define-key map [menu-bar ldg-recon-menu del] '("Delete Entry" . ledger-reconcile-delete)) diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 04c182dd..3225d803 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -103,7 +103,7 @@ text that should replace the format specifier." 'ledger-report-kill) (define-key map [(control ?c) (control ?l) (control ?e)] 'ledger-report-edit) - (define-key map [(control ?c) (control ?c)] 'ledger-report-visit-source) + (define-key map [return] 'ledger-report-visit-source) (define-key map [menu-bar] (make-sparse-keymap "ldg-rep")) -- cgit v1.2.3 From 4adcad6b2ccae539e2dd237bb78432e0f2fabcac Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 1 Apr 2013 12:37:02 -0700 Subject: Prevent sort-buffer from calling all the after-change hooks --- lisp/ldg-sort.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el index 45b55c47..5119db5d 100644 --- a/lisp/ldg-sort.el +++ b/lisp/ldg-sort.el @@ -74,6 +74,7 @@ ;; automagically (let ((new-beg beg) (new-end end)) + (setq inhibit-modification-hooks t) (save-excursion (save-restriction (goto-char beg) @@ -93,7 +94,8 @@ nil 'ledger-next-record-function 'ledger-end-record-function - 'ledger-sort-startkey)))))) + 'ledger-sort-startkey)))) + (setq inhibit-modification-hooks nil))) (defun ledger-sort-buffer () "Sort the entire buffer." -- cgit v1.2.3 From 024697c4fcd552b6dd806c5be1a916f95393b5be Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 1 Apr 2013 16:32:45 -0700 Subject: Fix Bug 941, ensure two spaces are left between account and amount --- lisp/ldg-post.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 91ee623d..554b8578 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -187,7 +187,8 @@ region align the posting on the current line." (when (setq amt-offset (ledger-next-amount (line-end-position))) (let* ((amt-adjust (- ledger-post-amount-alignment-column amt-offset - (current-column)))) + (current-column) + 2))) (if (/= amt-adjust 0) (if (> amt-adjust 0) (insert (make-string amt-adjust ? )) -- cgit v1.2.3 From 78bedf7c8ea15e369f56fbd317d03deb35343258 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 1 Apr 2013 16:34:30 -0700 Subject: Bring back comments into account completion. --- lisp/ldg-complete.el | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index 65206026..fe27e91d 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -77,10 +77,9 @@ Return tree structure" (split-string (match-string-no-properties 2) ":")) (let ((root account-tree)) - (while (and account-elements - (not (char-equal (string-to-char (car account-elements)) ?\;))) - (let ((entry (assoc (car account-elements) root))) - (if entry + (while account-elements + (let ((entry (assoc (car account-elements) root))) + (if entry (setq root (cdr entry)) (setq entry (cons (car account-elements) (list t))) (nconc root (list entry)) -- cgit v1.2.3 From eed1d8e53ea3f75f0c6a84ab744f8310a4778981 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 1 Apr 2013 20:48:00 -0700 Subject: ledger-read-commodity-string now calls ledger-split-commodity-string --- lisp/ldg-commodities.el | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 842613c6..8755166d 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -127,25 +127,15 @@ longer ones are after the value." (concat commodity " " val)))) (defun ledger-read-commodity-string (prompt) - "Return a commoditizd value (val 'comm') from COMM. -Assumes a space between the value and the commodity." - (let ((parts (split-string (read-from-minibuffer - (concat prompt " (" ledger-reconcile-default-commodity "): "))))) - (if parts - (if (/= (length parts) 2) ;;assume a number was entered and - ;;use default commodity - (list (string-to-number (car parts)) - ledger-reconcile-default-commodity) - (let ((valp1 (string-to-number (car parts))) - (valp2 (string-to-number (cadr parts)))) - (cond ((and (= valp1 valp2) (= 0 valp1)) ;; means neither contained a valid number (both = 0) - (list 0 "")) - ((and (/= 0 valp1) (= valp2 0)) - (list valp1 (cadr parts))) - ((and (/= 0 valp2) (= valp1 0)) - (list valp2 (car parts))) - (t - (error "Cannot understand commodity")))))))) + (let ((str (read-from-minibuffer + (concat prompt " (" ledger-reconcile-default-commodity "): "))) + comm) + (if (> (length str) 0) + (progn + (setq comm (ledger-split-commodity-string str)) + (if (cadr comm) + comm + (list (car comm) ledger-reconcile-default-commodity)))))) (provide 'ldg-commodities) -- cgit v1.2.3 From 70bbc81299704b57191b1313ea44bf955345079d Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 2 Apr 2013 11:11:20 -0700 Subject: Initial chapter on time-keeping in ledger3.texi --- doc/ledger3.texi | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 3382ab33..91dd794f 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -75,6 +75,7 @@ twinkling in their father's CRT. * Reporting Commands:: * Command-line Syntax:: * Budgeting and Forecasting:: +* Time Keeping:: * Value Expressions:: * Format Strings:: * Extending with Python:: @@ -6389,7 +6390,7 @@ weekly last august @end smallexample -@node Budgeting and Forecasting, Value Expressions, Command-line Syntax, Top +@node Budgeting and Forecasting, Time Keeping, Command-line Syntax, Top @chapter Budgeting and Forecasting @menu @@ -6485,8 +6486,37 @@ only, and not against the running total: ledger --forecast "d<[2010]" bal ^assets ^liabilities @end example +@node Time Keeping, Value Expressions, Budgeting and Forecasting, Top +@chapter Time Keeping -@node Value Expressions, Format Strings, Budgeting and Forecasting, Top + +Ledger directly supports ``timelog'' entries, which have this form: + +@smallexample + i 2013/03/28 22:13:00 ACCOUNT[ PAYEE] + o 2013/03/29 03:39:00 +@end smallexample + +This records a check-in to the given ACCOUNT, and a check-out. You can +be checked-in to multiple accounts at a time, if you wish, and they can +span multiple days (use @code{--day-break} to break them up in the +report). The number of seconds between is accumulated as time to that +ACCOUNT. If the checkout uses a capital ``O'', the transaction is marked +``cleared''. You can use an optional PAYEE for whatever meaning you like. + +Now, there are a few ways to generate this information. You can use the +@file{timeclock.el} package, which is part of Emacs. Or you can write a +simple script in whichever language you prefer to emit similar +information. Or you can use Org-mode's time-clocking abilities and the +org2tc script developed by John Wiegly. + +These timelog entries can appear in a separate file, or directly in your +main ledger file. The initial "i" and "o" count as Ledger "directives", +and are accepted anywhere that ordinary transactions are. + + + +@node Value Expressions, Format Strings, Time Keeping, Top @chapter Value Expressions Ledger uses value expressions to make calculations for many different -- cgit v1.2.3 From 86d0fd87c49e20b0f5262e7ae48234986584b750 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 2 Apr 2013 14:20:29 -0700 Subject: Fixes bug 904, failure to highly pending postings. Adds two new faces for pending and cleared posting. --- doc/ledger-mode.texi | 5 +++++ lisp/ldg-fonts.el | 31 ++++++++++++++++++++++--------- lisp/ldg-post.el | 4 ++-- lisp/ldg-regex.el | 24 ++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index 70a5d97a..34c38dae 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -672,6 +672,11 @@ Default face for pending (!) transactions Default face for other transactions @item ledger-font-posting-account-face Face for Ledger accounts +@item ledger-font-posting-account-cleared-face +Face for cleared Ledger accounts +@item ledger-font-posting-account-pending-face +Face for Ledger pending accounts + @item ledger-font-posting-amount-face Face for Ledger amounts @item ledger-occur-narrowed-face diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index 3a7d1e0a..81196c10 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -26,6 +26,8 @@ ;;; Code: +(require 'ldg-regex) + (defgroup ledger-faces nil "Ledger mode highlighting" :group 'ledger) (defface ledger-font-uncleared-face `((t :foreground "#dc322f" :weight bold )) @@ -57,6 +59,16 @@ "Face for Ledger accounts" :group 'ledger-faces) +(defface ledger-font-posting-account-cleared-face + `((t :foreground "#657b83" )) + "Face for Ledger accounts" + :group 'ledger-faces) + +(defface ledger-font-posting-account-pending-face + `((t :foreground "#cb4b16" )) + "Face for Ledger accounts" + :group 'ledger-faces) + (defface ledger-font-posting-amount-face `((t :foreground "yellow" )) "Face for Ledger amounts" @@ -99,16 +111,17 @@ (defvar ledger-font-lock-keywords - '(("^[0-9]+[-/.=][-/.=0-9]+\\s-\\!\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 'ledger-font-pending-face) - ("^[0-9]+[-/.=][-/.=0-9]+\\s-\\*\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 'ledger-font-cleared-face) - ("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 'ledger-font-uncleared-face) - ("^\\s-+\\([*]\\s-*\\)?\\(\\([[(]\\)?[^*: - ]+?:\\([^]); - ]\\|\\s-\\)+?\\([])]\\)?\\)\\( \\| \\|$\\)" + `((,ledger-payee-pending-regex 2 'ledger-font-pending-face) + (,ledger-payee-cleared-regex 2 'ledger-font-cleared-face) + (,ledger-payee-uncleared-regex 2 'ledger-font-uncleared-face) + (,ledger-posting-account-cleared-regex + 2 'ledger-font-posting-account-cleared-face) + (,ledger-posting-account-pending-regex + 2 'ledger-font-posting-account-pending-face) ; works + (,ledger-posting-account-all-regex 2 'ledger-font-posting-account-face) ; works - ("\\( \\| \\|^\\)\\(;.*\\)" 2 'ledger-font-comment-face) ; works - ("^\\([~=].+\\)" 1 ledger-font-other-face) - ("^\\([A-Za-z]+ .+\\)" 1 ledger-font-other-face)) + (,ledger-comment-regex 2 'ledger-font-comment-face) ; works + (,ledger-other-entries-regex 1 ledger-font-other-face)) "Expressions to highlight in Ledger mode.") diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 554b8578..f29d8af8 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -136,14 +136,14 @@ point at beginning of the commodity." (match-end 3)) (point)))) (defvar ledger-post-account-regex - "\\(^[ \t]+\\)\\(.+?\\)\\( \\|\n\\)") + "\\(^[ \t]+\\)\\([!*]?.+?\\)\\( \\|$\\)") (defun ledger-next-account (&optional end) "Move point to the beginning of the next account, or status marker (!*), as long as it is not past END. Return the column of the beginning of the account and leave point at beginning of account" (if (> end (point)) - (when (re-search-forward ledger-post-account-regex (1+ end) t) + (when (re-search-forward ledger-posting-account-all-regex (1+ end) t) ;; the 1+ is to make sure we can catch the newline (goto-char (match-beginning 2)) (current-column)))) diff --git a/lisp/ldg-regex.el b/lisp/ldg-regex.el index 97fd6e2c..7c92bf15 100644 --- a/lisp/ldg-regex.el +++ b/lisp/ldg-regex.el @@ -24,6 +24,30 @@ (eval-when-compile (require 'cl)) +(defvar ledger-other-entries-regex + "^\\(\\([~=].+\\)\\|\\(^\\([A-Za-z]+ .+\\)\\)\\)") + +(defvar ledger-comment-regex + "\\( \\| \\|^\\)\\(;.*\\)") +(defvar ledger-payee-pending-regex + "^[0-9]+[-/.=][-/.=0-9]+\\s-\\!\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)") + +(defvar ledger-payee-cleared-regex + "^[0-9]+[-/.=][-/.=0-9]+\\s-\\*\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)") + +(defvar ledger-payee-uncleared-regex + "^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)") + + +(defvar ledger-posting-account-all-regex + "\\(^[ \t]+\\)\\(.+?\\)\\( \\|$\\)") + +(defvar ledger-posting-account-cleared-regex + "\\(^[ \t]+\\)\\(\\*.+?\\)\\( \\|$\\)") + +(defvar ledger-posting-account-pending-regex + "\\(^[ \t]+\\)\\(!.+?\\)\\( \\|$\\)") + (defvar ledger-date-regex "\\([0-9]+\\)[/-]\\([0-9]+\\)[/-]\\([0-9]+\\)") -- cgit v1.2.3 From 519e57ca1fac01ea057bea8263c6cb06a8ac4e7e Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 2 Apr 2013 23:13:23 -0700 Subject: Consolidated all major regexes into ldg-regex. Only major exception are the regex in ledger context at point. --- lisp/ldg-commodities.el | 8 +++++--- lisp/ldg-complete.el | 5 ++--- lisp/ldg-fonts.el | 44 +++++++++++++++++++++++++++----------------- lisp/ldg-init.el | 4 +++- lisp/ldg-mode.el | 2 +- lisp/ldg-new.el | 2 +- lisp/ldg-post.el | 11 +---------- lisp/ldg-reconcile.el | 14 ++++++++++++-- lisp/ldg-regex.el | 35 ++++++++++++++++++++++++++++++++++- lisp/ldg-sort.el | 5 ++--- lisp/ldg-xact.el | 4 ++-- 11 files changed, 90 insertions(+), 44 deletions(-) diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 8755166d..031bddeb 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -26,6 +26,8 @@ ;;; Code: +(require 'ldg-regex) + (defcustom ledger-reconcile-default-commodity "$" "The default commodity for use in target calculations in ledger reconcile." :type 'string @@ -36,13 +38,13 @@ Returns a list with (value commodity)." (if (> (length str) 0) (let ((number-regex (if (assoc "decimal-comma" ledger-environment-alist) - "-?[1-9][0-9.]*[,]?[0-9]*" - "-?[1-9][0-9,]*[.]?[0-9]*"))) + ledger-amount-decimal-comma-regex + ledger-amount-decimal-period-regex))) (with-temp-buffer (insert str) (goto-char (point-min)) (cond - ((re-search-forward "\"\\(.*\\)\"" nil t) + ((re-search-forward "\"\\(.*\\)\"" nil t) ; look for quoted commodities (let ((com (delete-and-extract-region (match-beginning 1) (match-end 1)))) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index fe27e91d..3462c0bb 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -52,8 +52,7 @@ (save-excursion (goto-char (point-min)) (while (re-search-forward - (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" - "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) ;; matches first line + ledger-xact-payee-regex nil t) ;; matches first line (unless (and (>= origin (match-beginning 0)) (< origin (match-end 0))) (setq payees-list (cons (match-string-no-properties 3) @@ -70,7 +69,7 @@ Return tree structure" (save-excursion (goto-char (point-min)) (while (re-search-forward - "^[ \t]+\\([*!]\\s-+\\)?[[(]?\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)" nil t) + ledger-complete-account-regex nil t) (unless (and (>= origin (match-beginning 0)) (< origin (match-end 0))) (setq account-elements diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index 81196c10..81b5b0bf 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -29,17 +29,17 @@ (require 'ldg-regex) (defgroup ledger-faces nil "Ledger mode highlighting" :group 'ledger) -(defface ledger-font-uncleared-face +(defface ledger-font-payee-uncleared-face `((t :foreground "#dc322f" :weight bold )) "Default face for Ledger" :group 'ledger-faces) -(defface ledger-font-cleared-face +(defface ledger-font-payee-cleared-face `((t :foreground "#657b83" :weight normal )) "Default face for cleared (*) transactions" :group 'ledger-faces) -(defface ledger-font-highlight-face +(defface ledger-font-xact-highlight-face `((t :background "#eee8d5")) "Default face for transaction under point" :group 'ledger-faces) @@ -50,7 +50,7 @@ :group 'ledger-faces) (defface ledger-font-other-face - `((t :foreground "yellow" )) + `((t :foreground "#657b83" :weight bold)) "Default face for other transactions" :group 'ledger-faces) @@ -70,7 +70,7 @@ :group 'ledger-faces) (defface ledger-font-posting-amount-face - `((t :foreground "yellow" )) + `((t :foreground "#cb4b16" )) "Face for Ledger amounts" :group 'ledger-faces) @@ -111,20 +111,30 @@ (defvar ledger-font-lock-keywords - `((,ledger-payee-pending-regex 2 'ledger-font-pending-face) - (,ledger-payee-cleared-regex 2 'ledger-font-cleared-face) - (,ledger-payee-uncleared-regex 2 'ledger-font-uncleared-face) - (,ledger-posting-account-cleared-regex - 2 'ledger-font-posting-account-cleared-face) - (,ledger-posting-account-pending-regex - 2 'ledger-font-posting-account-pending-face) ; works - (,ledger-posting-account-all-regex - 2 'ledger-font-posting-account-face) ; works - (,ledger-comment-regex 2 'ledger-font-comment-face) ; works - (,ledger-other-entries-regex 1 ledger-font-other-face)) + `( ;; (,ledger-other-entries-regex 1 + ;; ledger-font-other-face) + (,ledger-comment-regex 2 + 'ledger-font-comment-face) + (,ledger-payee-pending-regex 2 + 'ledger-font-payee-pending-face) ; Works + (,ledger-payee-cleared-regex 2 + 'ledger-font-payee-cleared-face) ; Works + (,ledger-payee-uncleared-regex 2 + 'ledger-font-payee-uncleared-face) ; Works + (,ledger-posting-account-cleared-regex 2 + 'ledger-font-posting-account-cleared-face) ; Works + (,ledger-posting-account-pending-regex 2 + 'ledger-font-posting-account-pending-face) ; Works + (,ledger-posting-account-all-regex 2 + 'ledger-font-posting-account-face)) ; Works "Expressions to highlight in Ledger mode.") + - +;; (defvar ledger-font-lock-keywords +;; `( (,ledger-other-entries-regex 1 +;; ledger-font-other-face)) +;; "Expressions to highlight in Ledger mode.") + (provide 'ldg-fonts) ;;; ldg-fonts.el ends here diff --git a/lisp/ldg-init.el b/lisp/ldg-init.el index 8e657323..29839c9e 100644 --- a/lisp/ldg-init.el +++ b/lisp/ldg-init.el @@ -22,6 +22,8 @@ ;;; Commentary: ;; Determine the ledger environment +(require 'ldg-regex) + (defcustom ledger-init-file-name "~/.ledgerrc" "Location of the ledger initialization file. nil if you don't have one" :group 'ledger-exec) @@ -32,7 +34,7 @@ (with-current-buffer file (setq ledger-environment-alist nil) (goto-char (point-min)) - (while (re-search-forward "^--.+?\\($\\|[ ]\\)" nil t ) + (while (re-search-forward ledger-init-string-regex nil t ) (let ((matchb (match-beginning 0)) ;; save the match data, string-match stamp on it (matche (match-end 0))) (end-of-line) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index c9814918..df9dda87 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -238,7 +238,7 @@ correct chronological place in the buffer." exit-code) (unless insert-at-point (let ((date (car args))) - (if (string-match "\\([0-9]+\\)[-/]\\([0-9]+\\)[-/]\\([0-9]+\\)" date) + (if (string-match ledger-iso-date-regex date) (setq date (encode-time 0 0 0 (string-to-number (match-string 3 date)) (string-to-number (match-string 2 date)) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index 8ff95cd3..05e18818 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -32,6 +32,7 @@ ;;; Commentary: ;; Load up the ledger mode +(require 'ldg-regex) (require 'esh-util) (require 'esh-arg) (require 'ldg-commodities) @@ -43,7 +44,6 @@ (require 'ldg-occur) (require 'ldg-post) (require 'ldg-reconcile) -(require 'ldg-regex) (require 'ldg-report) (require 'ldg-sort) (require 'ldg-state) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index f29d8af8..767a263a 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -115,14 +115,7 @@ PROMPT is a string to prompt with. CHOICES is a list of (delete-char 1))))))) (goto-char pos))) -(defvar ledger-post-amount-regex - (concat "\\( \\|\t\\| \t\\)[ \t]*-?" - "\\([A-Z$€£_]+ *\\)?" - "\\(-?[0-9,]+?\\)" - "\\(.[0-9]+\\)?" - "\\( *[[:word:]€£_\"]+\\)?" - "\\([ \t]*[@={]@?[^\n;]+?\\)?" - "\\([ \t]+;.+?\\|[ \t]*\\)?$")) + (defsubst ledger-next-amount (&optional end) "Move point to the next amount, as long as it is not past END. @@ -135,8 +128,6 @@ point at beginning of the commodity." (- (or (match-end 4) (match-end 3)) (point)))) -(defvar ledger-post-account-regex - "\\(^[ \t]+\\)\\([!*]?.+?\\)\\( \\|$\\)") (defun ledger-next-account (&optional end) "Move point to the beginning of the next account, or status marker (!*), as long as it is not past END. diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index bec6d175..ccf733b7 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -62,6 +62,16 @@ reconcile-finish will mark all pending posting cleared." :type 'boolean :group 'ledger-reconcile) +(defcustom ledger-reconcile-default-date-format "%Y/%m/%d" + "Default date format for the reconcile buffer" + :type 'string + :group 'ledger-reconcile) + +(defcustom ledger-reconcile-target-prompt-string "Target amount for reconciliation " + "Default prompt for recon target prompt" + :type 'string + :group 'ledger-reconcile) + (defun ledger-reconcile-get-cleared-or-pending-balance () "Calculate the cleared or pending balance of the account." @@ -299,7 +309,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (insert (format "%s %-4s %-30s %-30s %15s\n" (format-time-string (if date-format date-format - "%Y/%m/%d") (nth 2 xact)) + ledger-reconcile-default-date-format) (nth 2 xact)) (if (nth 3 xact) (nth 3 xact) "") @@ -409,7 +419,7 @@ moved and recentered. If they aren't strange things happen." (defun ledger-reconcile-change-target () "Change the target amount for the reconciliation process." (interactive) - (setq ledger-target (ledger-read-commodity-string "Set reconciliation target"))) + (setq ledger-target (ledger-read-commodity-string ledger-reconcile-target-prompt-string))) (define-derived-mode ledger-reconcile-mode text-mode "Reconcile" "A mode for reconciling ledger entries." diff --git a/lisp/ldg-regex.el b/lisp/ldg-regex.el index 7c92bf15..24a3ae23 100644 --- a/lisp/ldg-regex.el +++ b/lisp/ldg-regex.el @@ -24,11 +24,23 @@ (eval-when-compile (require 'cl)) +(defvar ledger-amount-decimal-comma-regex + "-?[1-9][0-9.]*[,]?[0-9]*") + +(defvar ledger-amount-decimal-period-regex + "-?[1-9][0-9.]*[.]?[0-9]*") + (defvar ledger-other-entries-regex - "^\\(\\([~=].+\\)\\|\\(^\\([A-Za-z]+ .+\\)\\)\\)") + "\\(^[~=A-Za-z].+\\)+") +;\\|^\\([A-Za-z] .+\\)\\) + +(defvar ledger-xact-payee-regex + (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" + "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)")) (defvar ledger-comment-regex "\\( \\| \\|^\\)\\(;.*\\)") + (defvar ledger-payee-pending-regex "^[0-9]+[-/.=][-/.=0-9]+\\s-\\!\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)") @@ -38,19 +50,40 @@ (defvar ledger-payee-uncleared-regex "^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)") +(defvar ledger-iso-date-regex + "\\([12][0-9]\\{3\\}\\)[-/]\\([0-9]\\{2\\}\\)[-/]\\([0-9]\\{2\\}\\)") + +(defvar ledger-init-string-regex + "^--.+?\\($\\|[ ]\\)") (defvar ledger-posting-account-all-regex "\\(^[ \t]+\\)\\(.+?\\)\\( \\|$\\)") +(defvar ledger-sort-next-record-regex + (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" + "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)")) + (defvar ledger-posting-account-cleared-regex "\\(^[ \t]+\\)\\(\\*.+?\\)\\( \\|$\\)") +(defvar ledger-complete-account-regex + "^[ \t]+\\([*!]\\s-+\\)?[[(]?\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") + (defvar ledger-posting-account-pending-regex "\\(^[ \t]+\\)\\(!.+?\\)\\( \\|$\\)") (defvar ledger-date-regex "\\([0-9]+\\)[/-]\\([0-9]+\\)[/-]\\([0-9]+\\)") +(defvar ledger-post-amount-regex + (concat "\\( \\|\t\\| \t\\)[ \t]*-?" + "\\([A-Z$€£_]+ *\\)?" + "\\(-?[0-9,]+?\\)" + "\\(.[0-9]+\\)?" + "\\( *[[:word:]€£_\"]+\\)?" + "\\([ \t]*[@={]@?[^\n;]+?\\)?" + "\\([ \t]+;.+?\\|[ \t]*\\)?$")) + (defmacro ledger-define-regexp (name regex docs &rest args) "Simplify the creation of a Ledger regex and helper functions." (let ((defs diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el index 5119db5d..b106173b 100644 --- a/lisp/ldg-sort.el +++ b/lisp/ldg-sort.el @@ -28,9 +28,8 @@ (defun ledger-next-record-function () "Move point to next transaction." - (if (re-search-forward - (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" - "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t) + (if (re-search-forward ledger-sort-next-record-regex + nil t) (goto-char (match-beginning 0)) (goto-char (point-max)))) diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index d6ccc2bf..66d3f46f 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -53,7 +53,7 @@ within the transaction." (defun ledger-highlight-xact-under-point () "Move the highlight overlay to the current transaction." -(if ledger-highlight-xact-under-point + (if ledger-highlight-xact-under-point (let ((exts (ledger-find-xact-extents (point))) (ovl highlight-overlay)) (if (not highlight-overlay) @@ -63,7 +63,7 @@ within the transaction." (cadr exts) (current-buffer) t nil))) (move-overlay ovl (car exts) (cadr exts))) - (overlay-put ovl 'face 'ledger-font-highlight-face) + (overlay-put ovl 'face 'ledger-font-xact-highlight-face) (overlay-put ovl 'priority 100)))) (defun ledger-xact-payee () -- cgit v1.2.3 From 1a52899673f02b87b065c5b29755394581b485c9 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 3 Apr 2013 16:30:36 -0700 Subject: Fix copy-at-point and more regex consolidation and cleanup --- lisp/ldg-complete.el | 6 ++-- lisp/ldg-fonts.el | 12 ++++---- lisp/ldg-mode.el | 53 +++++---------------------------- lisp/ldg-post.el | 4 +-- lisp/ldg-regex.el | 82 +++++++++++++++++++++++++--------------------------- lisp/ldg-sort.el | 4 +-- lisp/ldg-xact.el | 51 +++++++++++++++++++++++++++----- 7 files changed, 103 insertions(+), 109 deletions(-) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index 3462c0bb..0be4f438 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -52,7 +52,7 @@ (save-excursion (goto-char (point-min)) (while (re-search-forward - ledger-xact-payee-regex nil t) ;; matches first line + ledger-payee-any-status-regex nil t) ;; matches first line (unless (and (>= origin (match-beginning 0)) (< origin (match-end 0))) (setq payees-list (cons (match-string-no-properties 3) @@ -69,7 +69,7 @@ Return tree structure" (save-excursion (goto-char (point-min)) (while (re-search-forward - ledger-complete-account-regex nil t) + ledger-account-any-status-regex nil t) (unless (and (>= origin (match-beginning 0)) (< origin (match-end 0))) (setq account-elements @@ -153,7 +153,7 @@ Does not use ledger xact" (setq rest-of-name (match-string 3)) ;; Start copying the postings (forward-line) - (while (looking-at ledger-post-account-regex) + (while (looking-at ledger-complete-account-regex) (setq xacts (cons (buffer-substring-no-properties (line-beginning-position) (line-end-position)) diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index 81b5b0bf..d83e7f9b 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -121,12 +121,12 @@ 'ledger-font-payee-cleared-face) ; Works (,ledger-payee-uncleared-regex 2 'ledger-font-payee-uncleared-face) ; Works - (,ledger-posting-account-cleared-regex 2 - 'ledger-font-posting-account-cleared-face) ; Works - (,ledger-posting-account-pending-regex 2 - 'ledger-font-posting-account-pending-face) ; Works - (,ledger-posting-account-all-regex 2 - 'ledger-font-posting-account-face)) ; Works + (,ledger-account-cleared-regex 2 + 'ledger-font-posting-account-cleared-face) ; Works + (,ledger-account-pending-regex 2 + 'ledger-font-posting-account-pending-face) ; Works + (,ledger-account-any-status-regex 2 + 'ledger-font-posting-account-face)) ; Works "Expressions to highlight in Ledger mode.") diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index df9dda87..f1b434e9 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -101,7 +101,7 @@ Can be pcomplete, or align-posting" (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-transaction) (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-transaction) (define-key map [(control ?c) (control ?f)] 'ledger-occur) - (define-key map [(control ?c) (control ?k)] 'ledger-copy-transaction) + (define-key map [(control ?c) (control ?k)] 'ledger-copy-transaction-at-point) (define-key map [(control ?c) (control ?m)] 'ledger-set-month) (define-key map [(control ?c) (control ?r)] 'ledger-reconcile) (define-key map [(control ?c) (control ?s)] 'ledger-sort-region) @@ -144,7 +144,7 @@ Can be pcomplete, or align-posting" (define-key map [sort-reg] '(menu-item "Sort Region" ledger-sort-region :enable mark-active)) (define-key map [align-reg] '(menu-item "Align Region" ledger-post-align-postings :enable mark-active)) (define-key map [sep2] '(menu-item "--")) - (define-key map [copy-xact] '(menu-item "Copy Trans at Point" ledger-copy-transaction)) + (define-key map [copy-xact] '(menu-item "Copy Trans at Point" ledger-copy-transaction-at-point)) (define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current)) (define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-transaction)) (define-key map [sep4] '(menu-item "--")) @@ -172,43 +172,6 @@ Return the difference in the format of a time value." (list (- (car t1) (car t2) (if borrow 1 0)) (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2))))) -(defun ledger-find-slot (moment) - "Find the right place in the buffer for a transaction at MOMENT. -MOMENT is an encoded date" - (catch 'found - (ledger-iterate-transactions - (function - (lambda (start date mark desc) - (if (ledger-time-less-p moment date) - (throw 'found t))))))) - -(defun ledger-iterate-transactions (callback) - "Iterate through each transaction call CALLBACK for each." - (goto-char (point-min)) - (let* ((now (current-time)) - (current-year (nth 5 (decode-time now)))) - (while (not (eobp)) - (when (looking-at - (concat "\\(Y\\s-+\\([0-9]+\\)\\|" - "\\([0-9]\\{4\\}+\\)?[./-]?" - "\\([0-9]+\\)[./-]\\([0-9]+\\)\\s-+" - "\\(\\*\\s-+\\)?\\(.+\\)\\)")) - (let ((found (match-string 2))) - (if found - (setq current-year (string-to-number found)) - (let ((start (match-beginning 0)) - (year (match-string 3)) - (month (string-to-number (match-string 4))) - (day (string-to-number (match-string 5))) - (mark (match-string 6)) - (desc (match-string 7))) - (if (and year (> (length year) 0)) - (setq year (string-to-number year))) - (funcall callback start - (encode-time 0 0 0 day month - (or year current-year)) - mark desc))))) - (forward-line)))) (defun ledger-set-year (newyear) "Set ledger's idea of the current year to the prefix argument NEWYEAR." @@ -227,7 +190,7 @@ MOMENT is an encoded date" (defun ledger-add-transaction (transaction-text &optional insert-at-point) "Use ledger xact TRANSACTION-TEXT to add a transaction to the buffer. If INSERT-AT-POINT is non-nil insert the transaction -there, otherwise call `ledger-find-slot' to insert it at the +there, otherwise call `ledger-xact-find-slot' to insert it at the correct chronological place in the buffer." (interactive (list (read-string "Transaction: " (concat ledger-year "/" ledger-month "/")))) @@ -238,12 +201,12 @@ correct chronological place in the buffer." exit-code) (unless insert-at-point (let ((date (car args))) - (if (string-match ledger-iso-date-regex date) + (if (string-match ledger-iso-date-regexp date) (setq date - (encode-time 0 0 0 (string-to-number (match-string 3 date)) - (string-to-number (match-string 2 date)) - (string-to-number (match-string 1 date))))) - (ledger-find-slot date))) + (encode-time 0 0 0 (string-to-number (match-string 4 date)) + (string-to-number (match-string 3 date)) + (string-to-number (match-string 2 date))))) + (ledger-xact-find-slot date))) (if (> (length args) 1) (save-excursion (insert diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 767a263a..88387fd1 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -122,7 +122,7 @@ PROMPT is a string to prompt with. CHOICES is a list of Return the width of the amount field as an integer and leave point at beginning of the commodity." ;;(beginning-of-line) - (when (re-search-forward ledger-post-amount-regex end t) + (when (re-search-forward ledger-amount-regex end t) (goto-char (match-beginning 0)) (skip-syntax-forward " ") (- (or (match-end 4) @@ -134,7 +134,7 @@ point at beginning of the commodity." Return the column of the beginning of the account and leave point at beginning of account" (if (> end (point)) - (when (re-search-forward ledger-posting-account-all-regex (1+ end) t) + (when (re-search-forward ledger-account-any-status-regex (1+ end) t) ;; the 1+ is to make sure we can catch the newline (goto-char (match-beginning 2)) (current-column)))) diff --git a/lisp/ldg-regex.el b/lisp/ldg-regex.el index 24a3ae23..95da77e2 100644 --- a/lisp/ldg-regex.el +++ b/lisp/ldg-regex.el @@ -24,58 +24,45 @@ (eval-when-compile (require 'cl)) -(defvar ledger-amount-decimal-comma-regex +(defconst ledger-amount-decimal-comma-regex "-?[1-9][0-9.]*[,]?[0-9]*") -(defvar ledger-amount-decimal-period-regex +(defconst ledger-amount-decimal-period-regex "-?[1-9][0-9.]*[.]?[0-9]*") -(defvar ledger-other-entries-regex +(defconst ledger-other-entries-regex "\\(^[~=A-Za-z].+\\)+") ;\\|^\\([A-Za-z] .+\\)\\) -(defvar ledger-xact-payee-regex - (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" - "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)")) -(defvar ledger-comment-regex +(defconst ledger-comment-regex "\\( \\| \\|^\\)\\(;.*\\)") -(defvar ledger-payee-pending-regex - "^[0-9]+[-/.=][-/.=0-9]+\\s-\\!\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)") +(defconst ledger-payee-any-status-regex + "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") -(defvar ledger-payee-cleared-regex - "^[0-9]+[-/.=][-/.=0-9]+\\s-\\*\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)") +(defconst ledger-payee-pending-regex + "^[0-9]+[-/.=][-/.=0-9]+\\s-\\!\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(;\\|$\\)") -(defvar ledger-payee-uncleared-regex - "^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)") +(defconst ledger-payee-cleared-regex + "^[0-9]+[-/.=][-/.=0-9]+\\s-\\*\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(;\\|$\\)") -(defvar ledger-iso-date-regex - "\\([12][0-9]\\{3\\}\\)[-/]\\([0-9]\\{2\\}\\)[-/]\\([0-9]\\{2\\}\\)") +(defconst ledger-payee-uncleared-regex + "^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(;\\|$\\)") -(defvar ledger-init-string-regex +(defconst ledger-init-string-regex "^--.+?\\($\\|[ ]\\)") -(defvar ledger-posting-account-all-regex - "\\(^[ \t]+\\)\\(.+?\\)\\( \\|$\\)") +(defconst ledger-account-any-status-regex + "^[ \t]+\\([*!]\\s-+\\)?[[(]?\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") -(defvar ledger-sort-next-record-regex - (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+" - "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)")) - -(defvar ledger-posting-account-cleared-regex - "\\(^[ \t]+\\)\\(\\*.+?\\)\\( \\|$\\)") - -(defvar ledger-complete-account-regex - "^[ \t]+\\([*!]\\s-+\\)?[[(]?\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") - -(defvar ledger-posting-account-pending-regex +(defconst ledger-account-pending-regex "\\(^[ \t]+\\)\\(!.+?\\)\\( \\|$\\)") -(defvar ledger-date-regex - "\\([0-9]+\\)[/-]\\([0-9]+\\)[/-]\\([0-9]+\\)") +(defconst ledger-account-cleared-regex + "\\(^[ \t]+\\)\\(\\*.+?\\)\\( \\|$\\)") -(defvar ledger-post-amount-regex +(defconst ledger-amount-regex (concat "\\( \\|\t\\| \t\\)[ \t]*-?" "\\([A-Z$€£_]+ *\\)?" "\\(-?[0-9,]+?\\)" @@ -84,6 +71,7 @@ "\\([ \t]*[@={]@?[^\n;]+?\\)?" "\\([ \t]+;.+?\\|[ \t]*\\)?$")) + (defmacro ledger-define-regexp (name regex docs &rest args) "Simplify the creation of a Ledger regex and helper functions." (let ((defs @@ -179,23 +167,23 @@ (put 'ledger-define-regexp 'lisp-indent-function 1) -(ledger-define-regexp date - (let ((sep '(or ?- (any ?. ?/)))) ; can't do (any ?- ?. ?/) due to bug +(ledger-define-regexp iso-date + ( let ((sep '(or ?- ?/))) (rx (group - (and (? (= 4 num) - (eval sep)) - (and num (? num)) + (and (group (? (= 4 num))) + (eval sep) + (group (and num (? num))) (eval sep) - (and num (? num)))))) + (group (and num (? num))))))) "Match a single date, in its 'written' form.") (ledger-define-regexp full-date (macroexpand - `(rx (and (regexp ,ledger-date-regexp) - (? (and ?= (regexp ,ledger-date-regexp)))))) + `(rx (and (regexp ,ledger-iso-date-regexp) + (? (and ?= (regexp ,ledger-iso-date-regexp)))))) "Match a compound date, of the form ACTUAL=EFFECTIVE" - (actual date) - (effective date)) + (actual iso-date) + (effective iso-date)) (ledger-define-regexp state (rx (group (any ?! ?*))) @@ -292,7 +280,7 @@ (macroexpand `(rx (* (+ blank) (or (and ?\{ (regexp ,ledger-commoditized-amount-regexp) ?\}) - (and ?\[ (regexp ,ledger-date-regexp) ?\]) + (and ?\[ (regexp ,ledger-iso-date-regexp) ?\]) (and ?\( (not (any ?\))) ?\)))))) "") @@ -328,4 +316,12 @@ (amount full-amount) (note end-note)) +(defconst ledger-iterate-regex + (concat "\\(Y\\s-+\\([0-9]+\\)\\|" ;; Catches a Y directive + ledger-iso-date-regexp + "\\([ *!]+\\)" ;; mark + "\\((.*)\\)" ;; code + "\\(.*\\)" ;; desc + "\\)")) + (provide 'ldg-regex) diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el index b106173b..f426a7ef 100644 --- a/lisp/ldg-sort.el +++ b/lisp/ldg-sort.el @@ -28,8 +28,8 @@ (defun ledger-next-record-function () "Move point to next transaction." - (if (re-search-forward ledger-sort-next-record-regex - nil t) + (if (re-search-forward ledger-payee-any-status-regex + nil t) (goto-char (match-beginning 0)) (goto-char (point-max)))) diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index 66d3f46f..31b9818f 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -76,6 +76,41 @@ within the transaction." (ledger-context-field-value context-info 'payee) nil)))) +(defun ledger-xact-find-slot (moment) + "Find the right place in the buffer for a transaction at MOMENT. +MOMENT is an encoded date" + (catch 'found + (ledger-xact-iterate-transactions + (function + (lambda (start date mark desc) + (if (ledger-time-less-p moment date) + (throw 'found t))))))) + +(defun ledger-xact-iterate-transactions (callback) + "Iterate through each transaction call CALLBACK for each." + (goto-char (point-min)) + (let* ((now (current-time)) + (current-year (nth 5 (decode-time now)))) + (while (not (eobp)) + (when (looking-at ledger-iterate-regex) + (let ((found-y-p (match-string 2))) + (if found-y-p + (setq current-year (string-to-number found-y-p)) ;; a Y directive was found + (let ((start (match-beginning 0)) + (year (match-string 4)) + (month (string-to-number (match-string 5))) + (day (string-to-number (match-string 6))) + (mark (match-string 7)) + (code (match-string 8)) + (desc (match-string 9))) + (if (and year (> (length year) 0)) + (setq year (string-to-number year))) + (funcall callback start + (encode-time 0 0 0 day month + (or year current-year)) + mark desc))))) + (forward-line)))) + (defsubst ledger-goto-line (line-number) "Rapidly move point to line LINE-NUMBER." (goto-char (point-min)) @@ -106,17 +141,17 @@ within the transaction." (extents (ledger-find-xact-extents (point))) (transaction (buffer-substring-no-properties (car extents) (cadr extents))) encoded-date) - (if (string-match ledger-date-regex date) + (if (string-match ledger-iso-date-regexp date) (setq encoded-date - (encode-time 0 0 0 (string-to-number (match-string 3 date)) - (string-to-number (match-string 2 date)) - (string-to-number (match-string 1 date))))) - (ledger-find-slot encoded-date) + (encode-time 0 0 0 (string-to-number (match-string 4 date)) + (string-to-number (match-string 3 date)) + (string-to-number (match-string 2 date))))) + (ledger-xact-find-slot encoded-date) (insert transaction "\n") - (backward-paragraph) - (re-search-forward ledger-date-regex) + (backward-paragraph 2) + (re-search-forward ledger-iso-date-regexp) (replace-match date) - (re-search-forward "[1-9][0-9]+\.[0-9]+"))) + (ledger-next-amount))) (provide 'ldg-xact) -- cgit v1.2.3 From 063b027fbbed83c0ccd9a43dff97204590a07f02 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 4 Apr 2013 12:22:27 -0700 Subject: Fixed bug that caused ledger-mode interfere with other mode that used indent-region --- lisp/ldg-mode.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index f1b434e9..cf0f56e7 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -92,7 +92,7 @@ Can be pcomplete, or align-posting" (ledger-init-load-init-file) - (setq indent-region-function 'ledger-post-align-postings) + (set (make-local-variable 'indent-region-function) 'ledger-post-align-postings) (let ((map (current-local-map))) (define-key map [(control ?c) (control ?a)] 'ledger-add-transaction) -- cgit v1.2.3 From 2547894586b4fffb9782794e42ae62f1631d36ee Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 4 Apr 2013 12:34:16 -0700 Subject: Fix next-account so that status markers can be manually entered into a buffer when auto alignment is on. --- lisp/ldg-post.el | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 88387fd1..18a70b1a 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -136,13 +136,17 @@ at beginning of account" (if (> end (point)) (when (re-search-forward ledger-account-any-status-regex (1+ end) t) ;; the 1+ is to make sure we can catch the newline - (goto-char (match-beginning 2)) + (if (match-beginning 1) + (goto-char (match-beginning 1)) + (goto-char (match-beginning 2))) (current-column)))) (defun ledger-post-align-postings (&optional beg end) "Align all accounts and amounts within region, if there is no region align the posting on the current line." (interactive) + (assert (eq major-mode 'ledger-mode)) + (save-excursion (if (or (not (mark)) (not (use-region-p))) @@ -245,7 +249,7 @@ BEG, END, and LEN control how far it can align." (defun ledger-post-setup () "Configure `ledger-mode' to auto-align postings." (add-hook 'after-change-functions 'ledger-post-maybe-align t t) - (add-hook 'after-save-hook #'(lambda () (setq ledger-post-current-list nil)))) + (add-hook 'after-save-hook #'(lambda () (setq ledger-post-current-list nil)) t t)) (defun ledger-post-read-account-with-prompt (prompt) -- cgit v1.2.3 From 650361a6d388c98074b9d30f91361ce8cb06a65d Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 4 Apr 2013 12:34:59 -0700 Subject: Fix ledger-complete-entry for stale regex --- lisp/ldg-complete.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index 0be4f438..f01e6e90 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -153,7 +153,7 @@ Does not use ledger xact" (setq rest-of-name (match-string 3)) ;; Start copying the postings (forward-line) - (while (looking-at ledger-complete-account-regex) + (while (looking-at ledger-account-any-status-regex) (setq xacts (cons (buffer-substring-no-properties (line-beginning-position) (line-end-position)) -- cgit v1.2.3 From 2e78e61be7ba6aa73c56c157405e45ed30990b31 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Thu, 4 Apr 2013 12:35:20 -0700 Subject: Regex Cleanup --- lisp/ldg-reconcile.el | 3 +-- lisp/ldg-regex.el | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index ccf733b7..ff808485 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -227,8 +227,7 @@ Return the number of uncleared xacts found." (set-buffer-modified-p nil) (ledger-display-balance) (goto-char curpoint) - ;; (ledger-reconcile-visit t) - ))) + (ledger-reconcile-visit t)))) (defun ledger-reconcile-finish () "Mark all pending posting or transactions as cleared. diff --git a/lisp/ldg-regex.el b/lisp/ldg-regex.el index 95da77e2..1b338012 100644 --- a/lisp/ldg-regex.el +++ b/lisp/ldg-regex.el @@ -54,7 +54,7 @@ "^--.+?\\($\\|[ ]\\)") (defconst ledger-account-any-status-regex - "^[ \t]+\\([*!]\\s-+\\)?[[(]?\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") + "^[ \t]+\\([*!]\\s-+\\)?\\([[(]?.+?\\)\\(\t\\|\n\\| [ \t]\\)") (defconst ledger-account-pending-regex "\\(^[ \t]+\\)\\(!.+?\\)\\( \\|$\\)") -- cgit v1.2.3 From 35febddf3fc9be89dbe93bce85ea4fac6d6a42c9 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Fri, 5 Apr 2013 10:50:31 -0700 Subject: Fixed ledger-font-other line. Thanks Thierry! --- lisp/ldg-fonts.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index d83e7f9b..a76051fb 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -126,7 +126,9 @@ (,ledger-account-pending-regex 2 'ledger-font-posting-account-pending-face) ; Works (,ledger-account-any-status-regex 2 - 'ledger-font-posting-account-face)) ; Works + 'ledger-font-posting-account-face) ; Works + (,ledger-other-entries-regex 1 + 'ledger-font-other-face)) "Expressions to highlight in Ledger mode.") -- cgit v1.2.3 From a373f9f4e5bef088888adc234783087e71e45a78 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Fri, 5 Apr 2013 12:24:54 -0700 Subject: other font cleanup --- lisp/ldg-fonts.el | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lisp/ldg-fonts.el b/lisp/ldg-fonts.el index a76051fb..cb7a81c0 100644 --- a/lisp/ldg-fonts.el +++ b/lisp/ldg-fonts.el @@ -50,7 +50,7 @@ :group 'ledger-faces) (defface ledger-font-other-face - `((t :foreground "#657b83" :weight bold)) + `((t :foreground "#657b83" )) "Default face for other transactions" :group 'ledger-faces) @@ -132,11 +132,6 @@ "Expressions to highlight in Ledger mode.") -;; (defvar ledger-font-lock-keywords -;; `( (,ledger-other-entries-regex 1 -;; ledger-font-other-face)) -;; "Expressions to highlight in Ledger mode.") - (provide 'ldg-fonts) ;;; ldg-fonts.el ends here -- cgit v1.2.3 From 5165b19d077b8b4ea6dfe4a8902cef0c3ea5d0db Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Fri, 5 Apr 2013 23:18:24 -0700 Subject: Rewrote align-postings again to improve handling of long account-names. It now leaves exactly 2 space between the commodity and the account if the amount would have stomped on the account. --- lisp/ldg-post.el | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 18a70b1a..f5c2f0f1 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -160,7 +160,7 @@ region align the posting on the current line." (end-region (if end end (if mark-first (point) (mark)))) - acc-col amt-offset acc-adjust + acct-start-column amt-width acct-adjust acct-end-column (lines-left 1)) ;; Condition point and mark to the beginning and end of lines (goto-char end-region) @@ -171,29 +171,30 @@ region align the posting on the current line." (line-beginning-position))) ;; This is the guts of the alignment loop - (while (and (or (setq acc-col (ledger-next-account (line-end-position))) + (while (and (or (setq acct-start-column (ledger-next-account (line-end-position))) lines-left) (< (point) end-region)) - (when acc-col - (when (/= (setq acc-adjust (- ledger-post-account-alignment-column acc-col)) 0) - (if (> acc-adjust 0) - (insert (make-string acc-adjust ? )) - (delete-char acc-adjust))) - (when (setq amt-offset (ledger-next-amount (line-end-position))) - (let* ((amt-adjust (- ledger-post-amount-alignment-column - amt-offset - (current-column) - 2))) + (when acct-start-column + (setq acct-end-column (save-excursion + (goto-char (match-end 2)) + (current-column))) + (when (/= (setq acct-adjust (- ledger-post-account-alignment-column acct-start-column)) 0) + (setq acct-end-column (+ acct-end-column acct-adjust)) + (if (> acct-adjust 0) + (insert (make-string acct-adjust ? )) + (delete-char acct-adjust))) + (when (setq amt-width (ledger-next-amount (line-end-position))) + (let ((amt-adjust (- (if (> (- ledger-post-amount-alignment-column amt-width) + (+ 2 acct-end-column)) + ledger-post-amount-alignment-column + (+ acct-end-column + 2 amt-width)) + amt-width + (current-column)))) (if (/= amt-adjust 0) (if (> amt-adjust 0) (insert (make-string amt-adjust ? )) - (let ((curpoint (point))) - (beginning-of-line) - (ledger-next-account (line-end-position)) - (when (> (+ curpoint amt-adjust) - (match-end 2)) - (goto-char curpoint) - (delete-char amt-adjust)))))))) + (delete-char amt-adjust)))))) (forward-line) (setq lines-left (not (eobp)))) (setq inhibit-modification-hooks nil)))) -- cgit v1.2.3 From f80fb99039e60869ae8497914baa25ca079e5483 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 6 Apr 2013 07:34:27 -0700 Subject: Code cleanup of align postings --- lisp/ldg-post.el | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index f5c2f0f1..338264f5 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -160,7 +160,7 @@ region align the posting on the current line." (end-region (if end end (if mark-first (point) (mark)))) - acct-start-column amt-width acct-adjust acct-end-column + acct-start-column acct-end-column acct-adjust amt-width (lines-left 1)) ;; Condition point and mark to the beginning and end of lines (goto-char end-region) @@ -179,22 +179,20 @@ region align the posting on the current line." (goto-char (match-end 2)) (current-column))) (when (/= (setq acct-adjust (- ledger-post-account-alignment-column acct-start-column)) 0) - (setq acct-end-column (+ acct-end-column acct-adjust)) + (setq acct-end-column (+ acct-end-column acct-adjust)) ;;adjust the account ending column (if (> acct-adjust 0) (insert (make-string acct-adjust ? )) (delete-char acct-adjust))) (when (setq amt-width (ledger-next-amount (line-end-position))) - (let ((amt-adjust (- (if (> (- ledger-post-amount-alignment-column amt-width) - (+ 2 acct-end-column)) - ledger-post-amount-alignment-column - (+ acct-end-column - 2 amt-width)) - amt-width - (current-column)))) - (if (/= amt-adjust 0) - (if (> amt-adjust 0) - (insert (make-string amt-adjust ? )) - (delete-char amt-adjust)))))) + (if (/= 0 (setq amt-adjust (- (if (> (- ledger-post-amount-alignment-column amt-width) + (+ 2 acct-end-column)) + ledger-post-amount-alignment-column ;;we have room + (+ acct-end-column 2 amt-width)) + amt-width + (current-column)))) + (if (> amt-adjust 0) + (insert (make-string amt-adjust ? )) + (delete-char amt-adjust))))) (forward-line) (setq lines-left (not (eobp)))) (setq inhibit-modification-hooks nil)))) -- cgit v1.2.3 From 2f3053401a043495860d6d6ee1febe48c3b537aa Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 6 Apr 2013 09:12:08 -0700 Subject: Minor grammar fix --- doc/ledger3.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 91dd794f..71b8b505 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -3951,7 +3951,7 @@ functions. @subsubsection The @code{convert} command The @code{convert} command parses a comma separated value (csv) file and outputs Ledger transactions. Many banks offer csv file -downloads. Unfortunately the file formats, aside the from commas, are +downloads. Unfortunately, the file formats, aside the from commas, are all different. The ledger @code{convert} command tries to help as much as it can. -- cgit v1.2.3 From 4df990014fede0c7b0c23396f32b1f2c7c636426 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sat, 6 Apr 2013 23:13:49 -0700 Subject: Fixed reconciliation initialization. Now prompts with only account, not status and amount Moved context function to leg-context, from leg-report. Cleaned up many regex in ldg-context. --- lisp/ldg-complete.el | 30 +++++---- lisp/ldg-context.el | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++ lisp/ldg-mode.el | 30 ++++++--- lisp/ldg-new.el | 1 + lisp/ldg-occur.el | 5 ++ lisp/ldg-post.el | 9 --- lisp/ldg-reconcile.el | 2 +- lisp/ldg-report.el | 156 +----------------------------------------- lisp/ldg-state.el | 8 +-- lisp/ldg-xact.el | 19 +----- 10 files changed, 237 insertions(+), 206 deletions(-) create mode 100644 lisp/ldg-context.el diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el index f01e6e90..bd907bc8 100644 --- a/lisp/ldg-complete.el +++ b/lisp/ldg-complete.el @@ -30,9 +30,12 @@ (defun ledger-parse-arguments () "Parse whitespace separated arguments in the current region." - (let* ((info (save-excursion - (cons (ledger-thing-at-point) (point)))) - (begin (cdr info)) + ;; this is more complex than it appears to need, so that it can work + ;; with pcomplete. See pcomplete-parse-arguments-function for + ;; details + (let* ((begin (save-excursion + (ledger-thing-at-point) ;; leave point at beginning of thing under point + (point))) (end (point)) begins args) (save-excursion @@ -45,6 +48,7 @@ args))) (cons (reverse args) (reverse begins))))) + (defun ledger-payees-in-buffer () "Scan buffer and return list of all payees." (let ((origin (point)) @@ -77,12 +81,12 @@ Return tree structure" (match-string-no-properties 2) ":")) (let ((root account-tree)) (while account-elements - (let ((entry (assoc (car account-elements) root))) - (if entry - (setq root (cdr entry)) - (setq entry (cons (car account-elements) (list t))) - (nconc root (list entry)) - (setq root (cdr entry)))) + (let ((xact (assoc (car account-elements) root))) + (if xact + (setq root (cdr xact)) + (setq xact (cons (car account-elements) (list t))) + (nconc root (list xact)) + (setq root (cdr xact)))) (setq account-elements (cdr account-elements))))))) account-tree)) @@ -93,11 +97,11 @@ Return tree structure" (root (ledger-find-accounts-in-buffer)) (prefix nil)) (while (cdr elements) - (let ((entry (assoc (car elements) root))) - (if entry + (let ((xact (assoc (car elements) root))) + (if xact (setq prefix (concat prefix (and prefix ":") (car elements)) - root (cdr entry)) + root (cdr xact)) (setq root nil elements nil))) (setq elements (cdr elements))) (and root @@ -136,7 +140,7 @@ Return tree structure" (throw 'pcompleted t))) (ledger-accounts))))) -(defun ledger-fully-complete-entry () +(defun ledger-fully-complete-xact () "Completes a transaction if there is another matching payee in the buffer. Does not use ledger xact" (interactive) diff --git a/lisp/ldg-context.el b/lisp/ldg-context.el new file mode 100644 index 00000000..8861a30e --- /dev/null +++ b/lisp/ldg-context.el @@ -0,0 +1,183 @@ +;;; ldg-context.el --- Helper code for use with the "ledger" command-line tool + +;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + + +;;; Commentary: +;; Provide facilities for reflection in ledger buffers + +;;; Code: + +(eval-when-compile + (require 'cl)) + + +(defconst ledger-line-config + '((xact + (("^\\(\\([0-9][0-9][0-9][0-9]/\\)?[01]?[0-9]/[0123]?[0-9]\\)[ \t]+\\(\\([!*]\\)[ \t]\\)?[ \t]*\\((\\(.*\\))\\)?[ \t]*\\(.*?\\)[ \t]*;\\(.*\\)[ \t]*$" + (date nil status nil nil code payee comment)) + ("^\\(\\([0-9][0-9][0-9][0-9]/\\)?[01]?[0-9]/[0123]?[0-9]\\)[ \t]+\\(\\([!*]\\)[ \t]\\)?[ \t]*\\((\\(.*\\))\\)?[ \t]*\\(.*\\)[ \t]*$" + (date nil status nil nil code payee)))) + (acct-transaction + (("^\\([ \t]+;\\|;\\)\\s-?\\(.*\\)" + (indent comment)) + ("\\(^[ \t]+\\)\\([*! ]?\\)\\(.*?\\)\\s-\\s-[ \t]+\\([$€£]\\s-?\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*;[ \t]*\\(.*\\)[ \t]*$" + (indent status account commodity amount nil comment)) ;checked 2013-04-06 + ("\\(^[ \t]+\\)\\([*! ]?\\)\\(.*?\\)\\s-\\s-[ \t]+\\([$€£]\\s-?\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)$" + (indent status account commodity amount)) ;checked 2013-04-06 + ("\\(^[ \t]+\\)\\([*! ]?\\)\\(.*?\\)\\s-\\s-[ \t]+\\(-?[0-9]+\\.[0-9]*\\)[ \t]+\\(.*?\\)[ \t]*\\(;[ \t]*\\(.*?\\)[ \t]*$\\|@+\\)" + (indent status account amount nil commodity comment)) ;checked 2013-04-06 + ("\\(^[ \t]+\\)\\([*! ]?\\)\\(.*?\\)\\s-\\s-[ \t]+\\(-?[0-9]+\\.[0-9]*\\)[ \t]+\\(.*\\)" + (indent status account amount nil commodity)) ;checked 2013-04-06 + ("\\(^[ \t]+\\)\\([*! ]?\\)\\(.*?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" + (indent status account comment)) + ("\\(^[ \t]+\\)\\([*! ]?\\)\\(.*?\\)[ \t]*$" + (indent status account)))))) + +(defun ledger-extract-context-info (line-type pos) + "Get context info for current line with LINE-TYPE. + +Assumes point is at beginning of line, and the POS argument specifies +where the \"users\" point was." + (let ((linfo (assoc line-type ledger-line-config)) + found field fields) + (dolist (re-info (nth 1 linfo)) + (let ((re (nth 0 re-info)) + (names (nth 1 re-info))) + (unless found + (when (looking-at re) + (setq found t) + (dotimes (i (length names)) + (when (nth i names) + (setq fields (append fields + (list + (list (nth i names) + (match-string-no-properties (1+ i)) + (match-beginning (1+ i)))))))) + (dolist (f fields) + (and (nth 1 f) + (>= pos (nth 2 f)) + (setq field (nth 0 f)))))))) + (list line-type field fields))) + +(defun ledger-thing-at-point () + "Describe thing at points. Return 'transaction, 'posting, or nil. +Leave point at the beginning of the thing under point" + (let ((here (point))) + (goto-char (line-beginning-position)) + (cond ((looking-at "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.+?)\\)?\\s-+") + (goto-char (match-end 0)) + 'transaction) + ((looking-at "^\\s-+\\([*!]\\s-+\\)?[[(]?\\(.\\)") + (goto-char (match-beginning 2)) + 'posting) + ((looking-at "^\\(sun\\|mon\\|tue\\|wed\\|thu\\|fri\\|sat\\)\\s-+") + (goto-char (match-end 0)) + 'day) + (t + (ignore (goto-char here)))))) + +(defun ledger-context-at-point () + "Return a list describing the context around point. + +The contents of the list are the line type, the name of the field +containing point, and for selected line types, the content of +the fields in the line in a association list." + (let ((pos (point))) + (save-excursion + (beginning-of-line) + (let ((first-char (char-after))) + (cond ((equal (point) (line-end-position)) + '(empty-line nil nil)) + ((memq first-char '(?\ ?\t)) + (ledger-extract-context-info 'acct-transaction pos)) + ((memq first-char '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9)) + (ledger-extract-context-info 'xact pos)) + ((equal first-char ?\=) + '(automated-xact nil nil)) + ((equal first-char ?\~) + '(period-xact nil nil)) + ((equal first-char ?\!) + '(command-directive)) + ((equal first-char ?\;) + '(comment nil nil)) + ((equal first-char ?Y) + '(default-year nil nil)) + ((equal first-char ?P) + '(commodity-price nil nil)) + ((equal first-char ?N) + '(price-ignored-commodity nil nil)) + ((equal first-char ?D) + '(default-commodity nil nil)) + ((equal first-char ?C) + '(commodity-conversion nil nil)) + ((equal first-char ?i) + '(timeclock-i nil nil)) + ((equal first-char ?o) + '(timeclock-o nil nil)) + ((equal first-char ?b) + '(timeclock-b nil nil)) + ((equal first-char ?h) + '(timeclock-h nil nil)) + (t + '(unknown nil nil))))))) + +(defun ledger-context-other-line (offset) + "Return a list describing context of line OFFSET from existing position. + +Offset can be positive or negative. If run out of buffer before reaching +specified line, returns nil." + (save-excursion + (let ((left (forward-line offset))) + (if (not (equal left 0)) + nil + (ledger-context-at-point))))) + +(defun ledger-context-line-type (context-info) + (nth 0 context-info)) + +(defun ledger-context-current-field (context-info) + (nth 1 context-info)) + +(defun ledger-context-field-info (context-info field-name) + (assoc field-name (nth 2 context-info))) + +(defun ledger-context-field-present-p (context-info field-name) + (not (null (ledger-context-field-info context-info field-name)))) + +(defun ledger-context-field-value (context-info field-name) + (nth 1 (ledger-context-field-info context-info field-name))) + +(defun ledger-context-field-position (context-info field-name) + (nth 2 (ledger-context-field-info context-info field-name))) + +(defun ledger-context-field-end-position (context-info field-name) + (+ (ledger-context-field-position context-info field-name) + (length (ledger-context-field-value context-info field-name)))) + +(defun ledger-context-goto-field-start (context-info field-name) + (goto-char (ledger-context-field-position context-info field-name))) + +(defun ledger-context-goto-field-end (context-info field-name) + (goto-char (ledger-context-field-end-position context-info field-name))) + +(provide 'ldg-context) + +;;; ldg-report.el ends here diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index f0af4383..6dea1735 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -39,10 +39,22 @@ (defvar ledger-month (ledger-current-month) "Start a ledger session with the current month, but make it customizable to ease retro-entry.") -(defun ledger-remove-overlays () - "Remove all overlays from the ledger buffer." - (interactive) - (remove-overlays)) +(defun ledger-read-account-with-prompt (prompt) + (let* ((context (ledger-context-at-point)) + (default + (if (and (eq (ledger-context-line-type context) 'acct-transaction) + (eq (ledger-context-current-field context) 'account)) + (regexp-quote (ledger-context-field-value context 'account)) + nil))) + (ledger-read-string-with-default prompt default))) + +(defun ledger-read-string-with-default (prompt default) + "Return user supplied string after PROMPT, or DEFAULT." + (let ((default-prompt (concat prompt + (if default + (concat " (" default "): ") + ": ")))) + (read-string default-prompt nil 'ledger-minibuffer-history default))) (defun ledger-magic-tab (&optional interactively) "Decide what to with with <TAB> . @@ -59,7 +71,7 @@ Can be pcomplete, or align-posting" (interactive) (let ((context (car (ledger-context-at-point))) (date-string (format-time-string (cdr (assoc "date-format" ledger-environment-alist))))) - (cond ((eq 'entry context) + (cond ((eq 'xact context) (beginning-of-line) (insert date-string "=")) ((eq 'acct-transaction context) @@ -87,7 +99,7 @@ Can be pcomplete, or align-posting" (set (make-local-variable 'pcomplete-termination-string) "") (add-hook 'post-command-hook 'ledger-highlight-xact-under-point nil t) - (add-hook 'before-revert-hook 'ledger-remove-overlays nil t) + (add-hook 'before-revert-hook 'ledger-occur-remove-all-overlays nil t) (make-variable-buffer-local 'highlight-overlay) (ledger-init-load-init-file) @@ -110,8 +122,8 @@ Can be pcomplete, or align-posting" (define-key map [(control ?c) (control ?y)] 'ledger-set-year) (define-key map [tab] 'ledger-magic-tab) (define-key map [(control ?i)] 'ledger-magic-tab) - (define-key map [(control ?c) tab] 'ledger-fully-complete-entry) - (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-entry) + (define-key map [(control ?c) tab] 'ledger-fully-complete-xact) + (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-xact) (define-key map [(control ?c) (control ?o) (control ?a)] 'ledger-report-redo) (define-key map [(control ?c) (control ?o) (control ?e)] 'ledger-report-edit) @@ -155,7 +167,7 @@ Can be pcomplete, or align-posting" (define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount)) (define-key map [sep] '(menu-item "--")) (define-key map [delete-xact] '(menu-item "Delete Transaction" ledger-delete-current-transaction)) - (define-key map [cmp-xact] '(menu-item "Complete Transaction" ledger-fully-complete-entry)) + (define-key map [cmp-xact] '(menu-item "Complete Transaction" ledger-fully-complete-xact)) (define-key map [add-xact] '(menu-item "Add Transaction (ledger xact)" ledger-add-transaction :enable ledger-works)) (define-key map [sep3] '(menu-item "--")) (define-key map [reconcile] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works)) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index b018d217..7c13c80e 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -37,6 +37,7 @@ (require 'esh-arg) (require 'ldg-commodities) (require 'ldg-complete) +(require 'ldg-context) (require 'ldg-exec) (require 'ldg-fonts) (require 'ldg-init) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index a2e53cb0..1e1308d0 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -59,6 +59,11 @@ "A list of currently active overlays to the ledger buffer.") (make-variable-buffer-local 'ledger-occur-overlay-list) +(defun ledger-remove-all-overlays () + "Remove all overlays from the ledger buffer." + (interactive) + (remove-overlays)) + (defun ledger-occur-mode (regex buffer) "Highlight transactions that match REGEX in BUFFER, hiding others. diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 338264f5..4f80b425 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -251,15 +251,6 @@ BEG, END, and LEN control how far it can align." (add-hook 'after-save-hook #'(lambda () (setq ledger-post-current-list nil)) t t)) -(defun ledger-post-read-account-with-prompt (prompt) - (let* ((context (ledger-context-at-point)) - (default - (if (and (eq (ledger-context-line-type context) 'acct-transaction) - (eq (ledger-context-current-field context) 'account)) - (regexp-quote (ledger-context-field-value context 'account)) - nil))) - (ledger-read-string-with-default prompt default))) - (provide 'ldg-post) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index ff808485..e5a5a8e7 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -377,7 +377,7 @@ moved and recentered. If they aren't strange things happen." (defun ledger-reconcile () "Start reconciling, prompt for account." (interactive) - (let ((account (ledger-post-read-account-with-prompt "Account to reconcile")) + (let ((account (ledger-read-account-with-prompt "Account to reconcile")) (buf (current-buffer)) (rbuf (get-buffer ledger-recon-buffer-name))) ;; this means only one *Reconcile* buffer, ever Set up the diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el index 3225d803..c3b83f55 100644 --- a/lisp/ldg-report.el +++ b/lisp/ldg-report.el @@ -229,19 +229,11 @@ used to generate the buffer, navigating the buffer, etc." (expand-file-name ledger-master-file) (buffer-file-name))) -(defun ledger-read-string-with-default (prompt default) - "Return user supplied string after PROMPT, or DEFAULT." - (let ((default-prompt (concat prompt - (if default - (concat " (" default "): ") - ": ")))) - (read-string default-prompt nil 'ledger-minibuffer-history default))) - (defun ledger-report-payee-format-specifier () "Substitute a payee name. The user is prompted to enter a payee and that is substitued. If - point is in an entry, the payee for that entry is used as the + point is in an xact, the payee for that xact is used as the default." ;; It is intended completion should be available on existing ;; payees, but the list of possible completions needs to be @@ -253,11 +245,11 @@ used to generate the buffer, navigating the buffer, etc." The user is prompted to enter an account name, which can be any regular expression identifying an account. If point is on an account - transaction line for an entry, the full account name on that line is + posting line for an xact, the full account name on that line is the default." ;; It is intended completion should be available on existing account ;; names, but it remains to be implemented. - (ledger-post-read-account-with-prompt "Account")) + (ledger-read-account-with-prompt "Account")) (defun ledger-report-expand-format-specifiers (report-cmd) "Expand %(account) and %(payee) appearing in REPORT-CMD with thing under point." @@ -422,148 +414,6 @@ Optional EDIT the command." (ledger-reports-add ledger-report-name ledger-report-cmd) (ledger-reports-custom-save))))))) -(defconst ledger-line-config - '((entry - (("^\\(\\([0-9][0-9][0-9][0-9]/\\)?[01]?[0-9]/[0123]?[0-9]\\)[ \t]+\\(\\([!*]\\)[ \t]\\)?[ \t]*\\((\\(.*\\))\\)?[ \t]*\\(.*?\\)[ \t]*;\\(.*\\)[ \t]*$" - (date nil status nil nil code payee comment)) - ("^\\(\\([0-9][0-9][0-9][0-9]/\\)?[01]?[0-9]/[0123]?[0-9]\\)[ \t]+\\(\\([!*]\\)[ \t]\\)?[ \t]*\\((\\(.*\\))\\)?[ \t]*\\(.*\\)[ \t]*$" - (date nil status nil nil code payee)))) - (acct-transaction - (("^\\([ \t]+;\\|;\\)\\s-?\\(.*\\)" - (indent comment)) - ("\\(^[ \t]+\\)\\([:A-Za-z0-9]+?\\)\\s-\\s-+\\([$€£]\\s-?\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)$" - (indent account commodity amount)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\([$€£]\\s-?\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" - (indent account commodity amount nil comment)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\(-?[0-9]+\\(\\.[0-9]*\\)?\\)[ \t]+\\(.*?\\)[ \t]*\\(;[ \t]*\\(.*?\\)[ \t]*$\\|@+\\)" - (indent account amount nil commodity comment)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\(-?[0-9]+\\(\\.[0-9]*\\)?\\)[ \t]+\\(.*?\\)[ \t]*$" - (indent account amount nil commodity)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\(-?\\(\\.[0-9]*\\)\\)[ \t]+\\(.*?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" - (indent account amount nil commodity comment)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\(-?\\(\\.[0-9]*\\)\\)[ \t]+\\(.*?\\)[ \t]*$" - (indent account amount nil commodity)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" - (indent account comment)) - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]*$" - (indent account)) - -;; Bad regexes - ("\\(^[ \t]+\\)\\(.*?\\)[ \t]+\\([$€£]\\s-?\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*$" - (indent account commodity amount nil)) - - )))) - -(defun ledger-extract-context-info (line-type pos) - "Get context info for current line with LINE-TYPE. - -Assumes point is at beginning of line, and the POS argument specifies -where the \"users\" point was." - (let ((linfo (assoc line-type ledger-line-config)) - found field fields) - (dolist (re-info (nth 1 linfo)) - (let ((re (nth 0 re-info)) - (names (nth 1 re-info))) - (unless found - (when (looking-at re) - (setq found t) - (dotimes (i (length names)) - (when (nth i names) - (setq fields (append fields - (list - (list (nth i names) - (match-string-no-properties (1+ i)) - (match-beginning (1+ i)))))))) - (dolist (f fields) - (and (nth 1 f) - (>= pos (nth 2 f)) - (setq field (nth 0 f)))))))) - (list line-type field fields))) - -(defun ledger-context-at-point () - "Return a list describing the context around point. - -The contents of the list are the line type, the name of the field -point containing point, and for selected line types, the content of -the fields in the line in a association list." - (let ((pos (point))) - (save-excursion - (beginning-of-line) - (let ((first-char (char-after))) - (cond ((equal (point) (line-end-position)) - '(empty-line nil nil)) - ((memq first-char '(?\ ?\t)) - (ledger-extract-context-info 'acct-transaction pos)) - ((memq first-char '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9)) - (ledger-extract-context-info 'entry pos)) - ((equal first-char ?\=) - '(automated-entry nil nil)) - ((equal first-char ?\~) - '(period-entry nil nil)) - ((equal first-char ?\!) - '(command-directive)) - ((equal first-char ?\;) - '(comment nil nil)) - ((equal first-char ?Y) - '(default-year nil nil)) - ((equal first-char ?P) - '(commodity-price nil nil)) - ((equal first-char ?N) - '(price-ignored-commodity nil nil)) - ((equal first-char ?D) - '(default-commodity nil nil)) - ((equal first-char ?C) - '(commodity-conversion nil nil)) - ((equal first-char ?i) - '(timeclock-i nil nil)) - ((equal first-char ?o) - '(timeclock-o nil nil)) - ((equal first-char ?b) - '(timeclock-b nil nil)) - ((equal first-char ?h) - '(timeclock-h nil nil)) - (t - '(unknown nil nil))))))) - -(defun ledger-context-other-line (offset) - "Return a list describing context of line OFFSET from existing position. - -Offset can be positive or negative. If run out of buffer before reaching -specified line, returns nil." - (save-excursion - (let ((left (forward-line offset))) - (if (not (equal left 0)) - nil - (ledger-context-at-point))))) - -(defun ledger-context-line-type (context-info) - (nth 0 context-info)) - -(defun ledger-context-current-field (context-info) - (nth 1 context-info)) - -(defun ledger-context-field-info (context-info field-name) - (assoc field-name (nth 2 context-info))) - -(defun ledger-context-field-present-p (context-info field-name) - (not (null (ledger-context-field-info context-info field-name)))) - -(defun ledger-context-field-value (context-info field-name) - (nth 1 (ledger-context-field-info context-info field-name))) - -(defun ledger-context-field-position (context-info field-name) - (nth 2 (ledger-context-field-info context-info field-name))) - -(defun ledger-context-field-end-position (context-info field-name) - (+ (ledger-context-field-position context-info field-name) - (length (ledger-context-field-value context-info field-name)))) - -(defun ledger-context-goto-field-start (context-info field-name) - (goto-char (ledger-context-field-position context-info field-name))) - -(defun ledger-context-goto-field-end (context-info field-name) - (goto-char (ledger-context-field-end-position context-info field-name))) - (provide 'ldg-report) ;;; ldg-report.el ends here diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index 4f1b3695..6c585f30 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -84,15 +84,15 @@ Optional argument STYLE may be `pending' or `cleared', depending on which type of status the caller wishes to indicate (default is `cleared'). Returns the new status as 'pending 'cleared or nil. This function is rather complicated because it must preserve both -the overall formatting of the ledger entry, as well as ensuring +the overall formatting of the ledger xact, as well as ensuring that the most minimal display format is used. This could be -achieved more certainly by passing the entry to ledger for +achieved more certainly by passing the xact to ledger for formatting, but doing so causes inline math expressions to be dropped." (interactive) (let ((bounds (ledger-current-transaction-bounds)) new-status cur-status) - ;; Uncompact the entry, to make it easier to toggle the + ;; Uncompact the xact, to make it easier to toggle the ;; transaction (save-excursion ;; this excursion checks state of entire ;; transaction and unclears if marked @@ -162,7 +162,7 @@ dropped." (setq new-status inserted)))) (setq inhibit-modification-hooks nil)) - ;; This excursion cleans up the entry so that it displays + ;; This excursion cleans up the xact so that it displays ;; minimally. This means that if all posts are cleared, remove ;; the marks and clear the entire transaction. (save-excursion diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index 31b9818f..b66bba04 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -67,12 +67,12 @@ within the transaction." (overlay-put ovl 'priority 100)))) (defun ledger-xact-payee () - "Return the payee of the entry containing point or nil." + "Return the payee of the transaction containing point or nil." (let ((i 0)) (while (eq (ledger-context-line-type (ledger-context-other-line i)) 'acct-transaction) (setq i (- i 1))) (let ((context-info (ledger-context-other-line i))) - (if (eq (ledger-context-line-type context-info) 'entry) + (if (eq (ledger-context-line-type context-info) 'xact) (ledger-context-field-value context-info 'payee) nil)))) @@ -116,21 +116,6 @@ MOMENT is an encoded date" (goto-char (point-min)) (forward-line (1- line-number))) -(defun ledger-thing-at-point () - "Describe thing at points. Return 'transaction, 'posting, or nil." - (let ((here (point))) - (goto-char (line-beginning-position)) - (cond ((looking-at "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.+?)\\)?\\s-+") - (goto-char (match-end 0)) - 'transaction) - ((looking-at "^\\s-+\\([*!]\\s-+\\)?[[(]?\\(.\\)") - (goto-char (match-beginning 2)) - 'posting) - ((looking-at "^\\(sun\\|mon\\|tue\\|wed\\|thu\\|fri\\|sat\\)\\s-+") - (goto-char (match-end 0)) - 'entry) - (t - (ignore (goto-char here)))))) (defun ledger-copy-transaction-at-point (date) "Ask for a new DATE and copy the transaction under point to that date. Leave point on the first amount." -- cgit v1.2.3 From 98f8df5583f16792243aeadee9ed19bd8b3f7897 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Sun, 7 Apr 2013 14:48:33 -0700 Subject: Regex consistency and cleanup. --- lisp/ldg-regex.el | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/lisp/ldg-regex.el b/lisp/ldg-regex.el index 1b338012..226475df 100644 --- a/lisp/ldg-regex.el +++ b/lisp/ldg-regex.el @@ -24,6 +24,15 @@ (eval-when-compile (require 'cl)) +(defconst ledger-amount-regex + (concat "\\( \\|\t\\| \t\\)[ \t]*-?" + "\\([A-Z$€£_]+ *\\)?" + "\\(-?[0-9,]+?\\)" + "\\(.[0-9]+\\)?" + "\\( *[[:word:]€£_\"]+\\)?" + "\\([ \t]*[@={]@?[^\n;]+?\\)?" + "\\([ \t]+;.+?\\|[ \t]*\\)?$")) + (defconst ledger-amount-decimal-comma-regex "-?[1-9][0-9.]*[,]?[0-9]*") @@ -33,8 +42,6 @@ (defconst ledger-other-entries-regex "\\(^[~=A-Za-z].+\\)+") -;\\|^\\([A-Za-z] .+\\)\\) - (defconst ledger-comment-regex "\\( \\| \\|^\\)\\(;.*\\)") @@ -42,13 +49,13 @@ "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") (defconst ledger-payee-pending-regex - "^[0-9]+[-/.=][-/.=0-9]+\\s-\\!\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(;\\|$\\)") + "^[0-9]+[-/][-/.=0-9]+\\s-\\!\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(;\\|$\\)") (defconst ledger-payee-cleared-regex - "^[0-9]+[-/.=][-/.=0-9]+\\s-\\*\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(;\\|$\\)") + "^[0-9]+[-/][-/.=0-9]+\\s-\\*\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(;\\|$\\)") (defconst ledger-payee-uncleared-regex - "^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(;\\|$\\)") + "^[0-9]+[-/][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(;\\|$\\)") (defconst ledger-init-string-regex "^--.+?\\($\\|[ ]\\)") @@ -62,14 +69,6 @@ (defconst ledger-account-cleared-regex "\\(^[ \t]+\\)\\(\\*.+?\\)\\( \\|$\\)") -(defconst ledger-amount-regex - (concat "\\( \\|\t\\| \t\\)[ \t]*-?" - "\\([A-Z$€£_]+ *\\)?" - "\\(-?[0-9,]+?\\)" - "\\(.[0-9]+\\)?" - "\\( *[[:word:]€£_\"]+\\)?" - "\\([ \t]*[@={]@?[^\n;]+?\\)?" - "\\([ \t]+;.+?\\|[ \t]*\\)?$")) (defmacro ledger-define-regexp (name regex docs &rest args) -- cgit v1.2.3 From 33c046d06876915864de397ed1c3d8d671ffd1db Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 8 Apr 2013 10:35:55 -0700 Subject: Added quick balance check to ledger-mode --- doc/ledger-mode.texi | 8 ++++++++ lisp/ldg-mode.el | 17 ++++++++++++++++ lisp/ldg-reconcile.el | 56 ++++++++++++++++++++++++--------------------------- 3 files changed, 51 insertions(+), 30 deletions(-) diff --git a/doc/ledger-mode.texi b/doc/ledger-mode.texi index 34c38dae..d7144112 100644 --- a/doc/ledger-mode.texi +++ b/doc/ledger-mode.texi @@ -233,6 +233,14 @@ automatically place any amounts such that their last digit is aligned to the column specified by @code{ledger-post-amount-alignment-column}, which defaults to 52. @xref{Ledger Post Customization Group}. +@node Quick Balance Display +@subsection Quick Balance Display +You will often want to quickly check the balance of an account. The +easiest way it to position point on the account you are interested in, +and type @code{C-C C-P}. The minibuffer will ask you to verify the name +of the account you want, if it is already correct hit return, then the +balance of the account will be displayed in the minibuffer. + @node Editing Amounts, Marking Transactions, Adding Transactions, The Ledger Buffer @section Editing Amounts GNU Calc is a very powerful Reverse Polish Notation calculator built diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 6dea1735..98236980 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -56,6 +56,21 @@ ": ")))) (read-string default-prompt nil 'ledger-minibuffer-history default))) +(defun ledger-display-balance-at-point () + "Display the cleared-or-pending balance. +And calculate the target-delta of the account being reconciled." + (interactive) + + (let* ((account (ledger-read-account-with-prompt "Account balance to show")) + (pending (ledger-reconcile-get-cleared-or-pending-balance (current-buffer) account))) + (when pending + (if ledger-target + (message "Pending balance: %s, Difference from target: %s" + (ledger-commodity-to-string pending) + (ledger-commodity-to-string (-commodity ledger-target pending))) + (message "Pending balance: %s" + (ledger-commodity-to-string pending)))))) + (defun ledger-magic-tab (&optional interactively) "Decide what to with with <TAB> . Can be pcomplete, or align-posting" @@ -120,6 +135,7 @@ Can be pcomplete, or align-posting" (define-key map [(control ?c) (control ?t)] 'ledger-insert-effective-date) (define-key map [(control ?c) (control ?u)] 'ledger-schedule-upcoming) (define-key map [(control ?c) (control ?y)] 'ledger-set-year) + (define-key map [(control ?c) (control ?p)] 'ledger-display-balance-at-point) (define-key map [tab] 'ledger-magic-tab) (define-key map [(control ?i)] 'ledger-magic-tab) (define-key map [(control ?c) tab] 'ledger-fully-complete-xact) @@ -163,6 +179,7 @@ Can be pcomplete, or align-posting" (define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-transaction)) (define-key map [sep4] '(menu-item "--")) (define-key map [recon-account] '(menu-item "Reconcile Account" ledger-reconcile)) + (define-key map [check-balance] '(menu-item "Check Balance" ledger-display-balance-at-point)) (define-key map [sep6] '(menu-item "--")) (define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount)) (define-key map [sep] '(menu-item "--")) diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el index e5a5a8e7..ca4d0004 100644 --- a/lisp/ldg-reconcile.el +++ b/lisp/ldg-reconcile.el @@ -73,29 +73,28 @@ reconcile-finish will mark all pending posting cleared." :group 'ledger-reconcile) -(defun ledger-reconcile-get-cleared-or-pending-balance () +(defun ledger-reconcile-get-cleared-or-pending-balance (buffer account) "Calculate the cleared or pending balance of the account." - (interactive) + ;; these vars are buffer local, need to hold them for use in the ;; temp buffer below - (let ((buffer ledger-buf) - (account ledger-acct)) - (with-temp-buffer - ;; note that in the line below, the --format option is - ;; separated from the actual format string. emacs does not - ;; split arguments like the shell does, so you need to - ;; specify the individual fields in the command line. - (if (ledger-exec-ledger buffer (current-buffer) - "balance" "--limit" "cleared or pending" "--empty" "--collapse" - "--format" "%(display_total)" account) - (ledger-split-commodity-string - (buffer-substring-no-properties (point-min) (point-max))))))) + + (with-temp-buffer + ;; note that in the line below, the --format option is + ;; separated from the actual format string. emacs does not + ;; split arguments like the shell does, so you need to + ;; specify the individual fields in the command line. + (if (ledger-exec-ledger buffer (current-buffer) + "balance" "--limit" "cleared or pending" "--empty" "--collapse" + "--format" "%(display_total)" account) + (ledger-split-commodity-string + (buffer-substring-no-properties (point-min) (point-max)))))) (defun ledger-display-balance () "Display the cleared-or-pending balance. And calculate the target-delta of the account being reconciled." (interactive) - (let* ((pending (ledger-reconcile-get-cleared-or-pending-balance))) + (let* ((pending (ledger-reconcile-get-cleared-or-pending-balance ledger-buf ledger-acct))) (when pending (if ledger-target (message "Pending balance: %s, Difference from target: %s" @@ -103,9 +102,6 @@ And calculate the target-delta of the account being reconciled." (ledger-commodity-to-string (-commodity ledger-target pending))) (message "Pending balance: %s" (ledger-commodity-to-string pending)))))) - - - (defun is-stdin (file) "True if ledger FILE is standard input." @@ -169,7 +165,7 @@ Return the number of uncleared xacts found." (let ((curbuf (current-buffer)) (curpoint (point)) (recon-buf (get-buffer ledger-recon-buffer-name))) - (when (buffer-live-p recon-buf) + (when (buffer-live-p recon-buf) (with-current-buffer recon-buf (ledger-reconcile-refresh) (set-buffer-modified-p nil)) @@ -223,7 +219,7 @@ Return the number of uncleared xacts found." (dolist (buf (cons ledger-buf ledger-bufs)) (with-current-buffer buf (save-buffer))) - (with-current-buffer (get-buffer ledger-recon-buffer-name) + (with-current-buffer (get-buffer ledger-recon-buffer-name) (set-buffer-modified-p nil) (ledger-display-balance) (goto-char curpoint) @@ -293,7 +289,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." (xacts (with-temp-buffer (when (ledger-exec-ledger buf (current-buffer) - "--uncleared" "--real" "emacs" account) + "--uncleared" "--real" "emacs" account) (setq ledger-success t) (goto-char (point-min)) (unless (eobp) @@ -326,7 +322,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." 'where where)))) )) (goto-char (point-max)) (delete-char -1)) ;gets rid of the extra line feed at the bottom of the list - (if ledger-success + (if ledger-success (insert (concat "There are no uncleared entries for " account)) (insert "Ledger has reported a problem. Check *Ledger Error* buffer."))) (goto-char (point-min)) @@ -341,7 +337,7 @@ POSTING is used in `ledger-clear-whole-transactions' is nil." ledger buffer is at the bottom of the main window. The key to this is to ensure the window is selected when the buffer point is moved and recentered. If they aren't strange things happen." - + (let ((recon-window (get-buffer-window (get-buffer ledger-recon-buffer-name)))) (when recon-window (fit-window-to-buffer recon-window) @@ -379,7 +375,7 @@ moved and recentered. If they aren't strange things happen." (interactive) (let ((account (ledger-read-account-with-prompt "Account to reconcile")) (buf (current-buffer)) - (rbuf (get-buffer ledger-recon-buffer-name))) + (rbuf (get-buffer ledger-recon-buffer-name))) ;; this means only one *Reconcile* buffer, ever Set up the ;; reconcile buffer (if rbuf ;; *Reconcile* already exists @@ -389,21 +385,21 @@ moved and recentered. If they aren't strange things happen." ;; called from some other ledger-mode buffer (ledger-reconcile-quit-cleanup) (set 'ledger-buf buf)) ;; should already be buffer-local - + (unless (get-buffer-window rbuf) (ledger-reconcile-open-windows buf rbuf))) ;; no recon-buffer, starting from scratch. (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save nil t) - - (with-current-buffer (setq rbuf + + (with-current-buffer (setq rbuf (get-buffer-create ledger-recon-buffer-name)) (ledger-reconcile-open-windows buf rbuf) (ledger-reconcile-mode) (make-local-variable 'ledger-target) (set (make-local-variable 'ledger-buf) buf) (set (make-local-variable 'ledger-acct) account))) - + ;; Narrow the ledger buffer (with-current-buffer rbuf (save-excursion @@ -437,7 +433,7 @@ moved and recentered. If they aren't strange things happen." (define-key map [?s] 'ledger-reconcile-save) (define-key map [?q] 'ledger-reconcile-quit) (define-key map [?b] 'ledger-display-balance) - + (define-key map [menu-bar] (make-sparse-keymap "ldg-recon-menu")) (define-key map [menu-bar ldg-recon-menu] (cons "Reconcile" map)) (define-key map [menu-bar ldg-recon-menu qui] '("Quit" . ledger-reconcile-quit)) @@ -458,7 +454,7 @@ moved and recentered. If they aren't strange things happen." (define-key map [menu-bar ldg-recon-menu fin] '("Finish" . ledger-reconcile-finish)) (define-key map [menu-bar ldg-recon-menu ref] '("Refresh" . ledger-reconcile-refresh)) (define-key map [menu-bar ldg-recon-menu sav] '("Save" . ledger-reconcile-save)) - + (use-local-map map))) (provide 'ldg-reconcile) -- cgit v1.2.3 From 3adab52660d8b7aacf13669140d7a9414fb9a0a9 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 8 Apr 2013 10:45:04 -0700 Subject: Improve quick display. --- lisp/ldg-mode.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 98236980..85cec39f 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -65,10 +65,12 @@ And calculate the target-delta of the account being reconciled." (pending (ledger-reconcile-get-cleared-or-pending-balance (current-buffer) account))) (when pending (if ledger-target - (message "Pending balance: %s, Difference from target: %s" + (message "%s balance: %s, Difference from target: %s" + account (ledger-commodity-to-string pending) (ledger-commodity-to-string (-commodity ledger-target pending))) - (message "Pending balance: %s" + (message "%s balance: %s" + account (ledger-commodity-to-string pending)))))) (defun ledger-magic-tab (&optional interactively) -- cgit v1.2.3 From 76145828fd8b0ca6ec19b5f192bbd5829d0fa263 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Mon, 8 Apr 2013 11:40:10 -0700 Subject: Make quick balance showed "cleared" results --- lisp/ldg-mode.el | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 85cec39f..57fba674 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -62,16 +62,12 @@ And calculate the target-delta of the account being reconciled." (interactive) (let* ((account (ledger-read-account-with-prompt "Account balance to show")) - (pending (ledger-reconcile-get-cleared-or-pending-balance (current-buffer) account))) - (when pending - (if ledger-target - (message "%s balance: %s, Difference from target: %s" - account - (ledger-commodity-to-string pending) - (ledger-commodity-to-string (-commodity ledger-target pending))) - (message "%s balance: %s" - account - (ledger-commodity-to-string pending)))))) + (buffer (current-buffer)) + (balance (with-temp-buffer + (ledger-exec-ledger buffer (current-buffer) "cleared" account) + (buffer-substring-no-properties (point-min) (1- (point-max)))))) + (when balance + (message balance)))) (defun ledger-magic-tab (&optional interactively) "Decide what to with with <TAB> . -- cgit v1.2.3 From dde09ef1a10580393ed44d07f7aab779219b8dcf Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Tue, 9 Apr 2013 21:22:11 -0700 Subject: Regex cleanup in ldg-context --- lisp/ldg-context.el | 53 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/lisp/ldg-context.el b/lisp/ldg-context.el index 8861a30e..80e2d544 100644 --- a/lisp/ldg-context.el +++ b/lisp/ldg-context.el @@ -29,27 +29,40 @@ (require 'cl)) +(defconst indent-string "\\(^[ \t]+\\)") +(defconst status-string "\\([*! ]?\\)") +(defconst account-string "[\\[(]?\\(.*?\\)[])]?") +(defconst amount-string "\\s-\\s-[ \t]+\\(-?[0-9]+\\.[0-9]*\\)") +(defconst comment-string "[ \t]*;[ \t]*\\(.*?\\)") +(defconst nil-string "[ \t]+") +(defconst commodity-string "\\(.*\\)") +(defconst date-string "^\\(\\([0-9]\\{4\\}[/-]\\)?[01]?[0-9][/-][0123]?[0-9]\\)") +(defconst code-string "\\((\\(.*\\))\\)?") +(defconst payee-string "\\(.*\\)") + +(defmacro single-line-config (&rest elements) +"Take list of ELEMENTS and return regex and element list for use in context-at-point" + (let (regex-string) + `'(,(concat (dolist (e elements regex-string) + (setq regex-string + (concat regex-string + (eval + (intern + (concat (symbol-name e) "-string")))))) "[ \t]*$") + ,(append elements)))) + + (defconst ledger-line-config - '((xact - (("^\\(\\([0-9][0-9][0-9][0-9]/\\)?[01]?[0-9]/[0123]?[0-9]\\)[ \t]+\\(\\([!*]\\)[ \t]\\)?[ \t]*\\((\\(.*\\))\\)?[ \t]*\\(.*?\\)[ \t]*;\\(.*\\)[ \t]*$" - (date nil status nil nil code payee comment)) - ("^\\(\\([0-9][0-9][0-9][0-9]/\\)?[01]?[0-9]/[0123]?[0-9]\\)[ \t]+\\(\\([!*]\\)[ \t]\\)?[ \t]*\\((\\(.*\\))\\)?[ \t]*\\(.*\\)[ \t]*$" - (date nil status nil nil code payee)))) - (acct-transaction - (("^\\([ \t]+;\\|;\\)\\s-?\\(.*\\)" - (indent comment)) - ("\\(^[ \t]+\\)\\([*! ]?\\)\\(.*?\\)\\s-\\s-[ \t]+\\([$€£]\\s-?\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)[ \t]*;[ \t]*\\(.*\\)[ \t]*$" - (indent status account commodity amount nil comment)) ;checked 2013-04-06 - ("\\(^[ \t]+\\)\\([*! ]?\\)\\(.*?\\)\\s-\\s-[ \t]+\\([$€£]\\s-?\\)\\(-?[0-9]*\\(\\.[0-9]*\\)?\\)$" - (indent status account commodity amount)) ;checked 2013-04-06 - ("\\(^[ \t]+\\)\\([*! ]?\\)\\(.*?\\)\\s-\\s-[ \t]+\\(-?[0-9]+\\.[0-9]*\\)[ \t]+\\(.*?\\)[ \t]*\\(;[ \t]*\\(.*?\\)[ \t]*$\\|@+\\)" - (indent status account amount nil commodity comment)) ;checked 2013-04-06 - ("\\(^[ \t]+\\)\\([*! ]?\\)\\(.*?\\)\\s-\\s-[ \t]+\\(-?[0-9]+\\.[0-9]*\\)[ \t]+\\(.*\\)" - (indent status account amount nil commodity)) ;checked 2013-04-06 - ("\\(^[ \t]+\\)\\([*! ]?\\)\\(.*?\\)[ \t]*;[ \t]*\\(.*?\\)[ \t]*$" - (indent status account comment)) - ("\\(^[ \t]+\\)\\([*! ]?\\)\\(.*?\\)[ \t]*$" - (indent status account)))))) + `((xact (,(single-line-config date nil status nil nil code payee comment) + ,(single-line-config date nil status nil nil code payee))) + (acct-transaction (,(single-line-config indent comment) + ,(single-line-config indent status account commodity amount nil comment) + ,(single-line-config indent status account commodity amount) + ,(single-line-config indent status account amount nil commodity comment) + ,(single-line-config indent status account amount nil commodity) + ,(single-line-config indent status account amount) + ,(single-line-config indent status account comment) + ,(single-line-config indent status account))))) (defun ledger-extract-context-info (line-type pos) "Get context info for current line with LINE-TYPE. -- cgit v1.2.3 From 838266f79b07e46be7feeca63d78cf2b7b70599f Mon Sep 17 00:00:00 2001 From: George Kettleborough <g.kettleborough@member.fsf.org> Date: Wed, 10 Apr 2013 10:53:06 +0100 Subject: Minor formatting fixes for Emacs and Org mode --- doc/ledger3.texi | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 71b8b505..3f099d93 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -1236,7 +1236,7 @@ For example, you do not need to tell Ledger about the accounts you use. Any time Ledger sees a posting involving an account it knows nothing about, it will create it@footnote{This also means if you misspell an account it will end up getting counted separately from what -you intended. The provided EMACS major mode provides for automatically +you intended. The provided Emacs major mode provides for automatically filling in account names.}. If you use a commodity that is new to Ledger, it will create that commodity, and determine its display characteristics (placement of the symbol before or after the amount, @@ -3925,7 +3925,7 @@ file whose formatting has gotten out of hand. @menu * Comma Separated Variable files:: * The lisp command:: -* EMACS org mode:: +* Emacs Org mode:: * The pricemap Command:: * The xml Command:: * prices and pricedb:: @@ -4039,11 +4039,11 @@ passed through @code{ledger print} a second time if you want to match on the new payee field. During the @code{ledger convert} run only the original payee name as specified in the csv data seems to be used. -@node The lisp command, EMACS org mode, Comma Separated Variable files, Reports in other Formats +@node The lisp command, Emacs Org mode, Comma Separated Variable files, Reports in other Formats @subsection The @code{lisp} command The @command{lisp} command outputs results in a form that can be read -directly by EMACS Lisp. The format of the @code{sexp} is: +directly by Emacs Lisp. The format of the @code{sexp} is: @smallexample ((BEG-POS CLEARED DATE CODE PAYEE @@ -4053,10 +4053,10 @@ directly by EMACS Lisp. The format of the @code{sexp} is: @noindent @code{emacs} can also be used as a synonym for @code{lisp} -@node EMACS org mode, The pricemap Command, The lisp command, Reports in other Formats -@subsection EMACS @code{org} Mode +@node Emacs Org mode, The pricemap Command, The lisp command, Reports in other Formats +@subsection Emacs @code{org} Mode The @code{org} command produces a journal file suitable for use in the -EMACS org mode. More details on using org mode can be found at +Emacs Org mode. More details on using Org mode can be found at @url{http://www.orgmode.org}. Org mode has a sub-system known as Babel which allows for literate @@ -4069,7 +4069,7 @@ have ledger commands embedded in a text file and have the output of ledger commands also appear in the text file. The output can be updated whenever any new ledger entries are added. -For instance, the following org mode text document snippet illustrates a +For instance, the following Org mode text document snippet illustrates a very naive but still useful of the @code{org+babel} system: @smallexample @@ -4110,7 +4110,7 @@ You can combine multiple source code blocks before executing ledger and do all kinds of other wonderful things with Babel (and org). -@subsection Org-mode with Babel +@subsection Org mode with Babel Using Babel, it is possible to record financial transactions conveniently in an org file and subsequently generate the financial @@ -4363,7 +4363,7 @@ file and manipulated using Babel. However, only simple Ledger features have been illustrated; please refer to the Ledger documentation for examples of more complex operations with a ledger. -@node The pricemap Command, The xml Command, EMACS org mode, Reports in other Formats +@node The pricemap Command, The xml Command, Emacs Org mode, Reports in other Formats @subsection The @code{pricemap} Command If you have the @code{graphviz} graph visualization package installed, ledger @@ -4719,7 +4719,7 @@ commands. @item @code{csv} @tab Show transactions in csv format, for exporting to other programs @item @code{print} @tab Print transaction in a ledger readable format @item @code{xml} @tab Produce XML output of the register command -@item @code{emacs} @tab Produce EMACS lisp output +@item @code{emacs} @tab Produce Emacs lisp output @item @code{equity} @tab Print account balances as transactions @item @code{prices} @tab Print price history for matching commodities @item @code{pricedb} @tab Print price history for matching commodities in ledger readable format @@ -6507,7 +6507,7 @@ ACCOUNT. If the checkout uses a capital ``O'', the transaction is marked Now, there are a few ways to generate this information. You can use the @file{timeclock.el} package, which is part of Emacs. Or you can write a simple script in whichever language you prefer to emit similar -information. Or you can use Org-mode's time-clocking abilities and the +information. Or you can use Org mode's time-clocking abilities and the org2tc script developed by John Wiegly. These timelog entries can appear in a separate file, or directly in your -- cgit v1.2.3 From 1286bdeda07792696bb9dfc462488744920695e2 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 10 Apr 2013 06:33:46 -0700 Subject: even better context regex generation --- lisp/ldg-context.el | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/lisp/ldg-context.el b/lisp/ldg-context.el index 80e2d544..2915133c 100644 --- a/lisp/ldg-context.el +++ b/lisp/ldg-context.el @@ -28,7 +28,8 @@ (eval-when-compile (require 'cl)) - +;; *-string constants are assembled in the single-line-config macro to +;; form the regex and list of elements (defconst indent-string "\\(^[ \t]+\\)") (defconst status-string "\\([*! ]?\\)") (defconst account-string "[\\[(]?\\(.*?\\)[])]?") @@ -49,20 +50,20 @@ (eval (intern (concat (symbol-name e) "-string")))))) "[ \t]*$") - ,(append elements)))) + ,elements))) (defconst ledger-line-config - `((xact (,(single-line-config date nil status nil nil code payee comment) - ,(single-line-config date nil status nil nil code payee))) - (acct-transaction (,(single-line-config indent comment) - ,(single-line-config indent status account commodity amount nil comment) - ,(single-line-config indent status account commodity amount) - ,(single-line-config indent status account amount nil commodity comment) - ,(single-line-config indent status account amount nil commodity) - ,(single-line-config indent status account amount) - ,(single-line-config indent status account comment) - ,(single-line-config indent status account))))) + (list (list 'xact (list (single-line-config date nil status nil nil code payee comment) + (single-line-config date nil status nil nil code payee))) + (list 'acct-transaction (list (single-line-config indent comment) + (single-line-config indent status account commodity amount nil comment) + (single-line-config indent status account commodity amount) + (single-line-config indent status account amount nil commodity comment) + (single-line-config indent status account amount nil commodity) + (single-line-config indent status account amount) + (single-line-config indent status account comment) + (single-line-config indent status account))))) (defun ledger-extract-context-info (line-type pos) "Get context info for current line with LINE-TYPE. -- cgit v1.2.3 From 345f4a977e289d8eedd6e63bfa91236d30de5444 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 10 Apr 2013 13:48:52 -0700 Subject: Refactoring and style. --- lisp/ldg-context.el | 13 ++++++-- lisp/ldg-init.el | 41 +++++++++++++------------- lisp/ldg-mode.el | 85 +++++++---------------------------------------------- lisp/ldg-new.el | 27 ----------------- lisp/ldg-occur.el | 36 ++++++++--------------- lisp/ldg-post.el | 26 ++++++++-------- lisp/ldg-sort.el | 3 +- lisp/ldg-state.el | 63 +++++++++++++++------------------------ lisp/ldg-test.el | 27 +++++++++++++++++ lisp/ldg-xact.el | 68 +++++++++++++++++++++++++++++++++++------- 10 files changed, 178 insertions(+), 211 deletions(-) diff --git a/lisp/ldg-context.el b/lisp/ldg-context.el index 2915133c..4b6aa26c 100644 --- a/lisp/ldg-context.el +++ b/lisp/ldg-context.el @@ -41,6 +41,15 @@ (defconst code-string "\\((\\(.*\\))\\)?") (defconst payee-string "\\(.*\\)") +(defmacro line-regex (&rest elements) + (let (regex-string) + (concat (dolist (e elements regex-string) + (setq regex-string + (concat regex-string + (eval + (intern + (concat (symbol-name e) "-string")))))) "[ \t]*$"))) + (defmacro single-line-config (&rest elements) "Take list of ELEMENTS and return regex and element list for use in context-at-point" (let (regex-string) @@ -96,8 +105,8 @@ where the \"users\" point was." Leave point at the beginning of the thing under point" (let ((here (point))) (goto-char (line-beginning-position)) - (cond ((looking-at "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.+?)\\)?\\s-+") - (goto-char (match-end 0)) + (cond ((looking-at "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.+?)\\)?\\s-+") + (goto-char (match-end 0)) 'transaction) ((looking-at "^\\s-+\\([*!]\\s-+\\)?[[(]?\\(.\\)") (goto-char (match-beginning 2)) diff --git a/lisp/ldg-init.el b/lisp/ldg-init.el index 29839c9e..f283c77c 100644 --- a/lisp/ldg-init.el +++ b/lisp/ldg-init.el @@ -30,25 +30,25 @@ (defvar ledger-environment-alist nil) -(defun ledger-init-parse-initialization (file) - (with-current-buffer file - (setq ledger-environment-alist nil) - (goto-char (point-min)) - (while (re-search-forward ledger-init-string-regex nil t ) - (let ((matchb (match-beginning 0)) ;; save the match data, string-match stamp on it - (matche (match-end 0))) - (end-of-line) - (setq ledger-environment-alist - (append ledger-environment-alist - (list (cons (let ((flag (buffer-substring-no-properties (+ 2 matchb) matche))) - (if (string-match "[ \t\n\r]+\\'" flag) - (replace-match "" t t flag) - flag)) - (let ((value (buffer-substring-no-properties matche (point) ))) - (if (> (length value) 0) - value - t)))))))) - ledger-environment-alist)) +(defun ledger-init-parse-initialization (buffer) + (with-current-buffer buffer + (let (environment-alist) + (goto-char (point-min)) + (while (re-search-forward ledger-init-string-regex nil t ) + (let ((matchb (match-beginning 0)) ;; save the match data, string-match stamp on it + (matche (match-end 0))) + (end-of-line) + (setq environment-alist + (append environment-alist + (list (cons (let ((flag (buffer-substring-no-properties (+ 2 matchb) matche))) + (if (string-match "[ \t\n\r]+\\'" flag) + (replace-match "" t t flag) + flag)) + (let ((value (buffer-substring-no-properties matche (point) ))) + (if (> (length value) 0) + value + t)))))))) + environment-alist))) (defun ledger-init-load-init-file () (interactive) @@ -59,7 +59,8 @@ (file-exists-p ledger-init-file-name) (file-readable-p ledger-init-file-name)) (find-file-noselect ledger-init-file-name) - (ledger-init-parse-initialization init-base-name) + (setq ledger-environment-alist + (ledger-init-parse-initialization init-base-name)) (kill-buffer init-base-name))))) (provide 'ldg-init) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 57fba674..4bc195ed 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -41,26 +41,24 @@ (defun ledger-read-account-with-prompt (prompt) (let* ((context (ledger-context-at-point)) - (default - (if (and (eq (ledger-context-line-type context) 'acct-transaction) - (eq (ledger-context-current-field context) 'account)) - (regexp-quote (ledger-context-field-value context 'account)) - nil))) + (default (if (and (eq (ledger-context-line-type context) 'acct-transaction) + (eq (ledger-context-current-field context) 'account)) + (regexp-quote (ledger-context-field-value context 'account)) + nil))) (ledger-read-string-with-default prompt default))) (defun ledger-read-string-with-default (prompt default) "Return user supplied string after PROMPT, or DEFAULT." - (let ((default-prompt (concat prompt - (if default - (concat " (" default "): ") - ": ")))) - (read-string default-prompt nil 'ledger-minibuffer-history default))) + (read-string (concat prompt + (if default + (concat " (" default "): ") + ": ")) + nil 'ledger-minibuffer-history default)) (defun ledger-display-balance-at-point () "Display the cleared-or-pending balance. And calculate the target-delta of the account being reconciled." (interactive) - (let* ((account (ledger-read-account-with-prompt "Account balance to show")) (buffer (current-buffer)) (balance (with-temp-buffer @@ -134,7 +132,7 @@ Can be pcomplete, or align-posting" (define-key map [(control ?c) (control ?u)] 'ledger-schedule-upcoming) (define-key map [(control ?c) (control ?y)] 'ledger-set-year) (define-key map [(control ?c) (control ?p)] 'ledger-display-balance-at-point) - (define-key map [tab] 'ledger-magic-tab) + (define-key map [tab] 'ledger-magic-tab) (define-key map [(control ?i)] 'ledger-magic-tab) (define-key map [(control ?c) tab] 'ledger-fully-complete-xact) (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-xact) @@ -188,18 +186,7 @@ Can be pcomplete, or align-posting" (define-key map [reconcile] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works)) (define-key map [reconcile] '(menu-item "Narrow to REGEX" ledger-occur)))) -(defun ledger-time-less-p (t1 t2) - "Say whether time value T1 is less than time value T2." - (or (< (car t1) (car t2)) - (and (= (car t1) (car t2)) - (< (nth 1 t1) (nth 1 t2))))) -(defun ledger-time-subtract (t1 t2) - "Subtract two time values, T1 - T2. -Return the difference in the format of a time value." - (let ((borrow (< (cadr t1) (cadr t2)))) - (list (- (car t1) (car t2) (if borrow 1 0)) - (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2))))) (defun ledger-set-year (newyear) @@ -216,57 +203,7 @@ Return the difference in the format of a time value." (setq ledger-month (read-string "Month: " (ledger-current-month))) (setq ledger-month (format "%02d" newmonth)))) -(defun ledger-add-transaction (transaction-text &optional insert-at-point) - "Use ledger xact TRANSACTION-TEXT to add a transaction to the buffer. -If INSERT-AT-POINT is non-nil insert the transaction -there, otherwise call `ledger-xact-find-slot' to insert it at the -correct chronological place in the buffer." - (interactive (list - (read-string "Transaction: " (concat ledger-year "/" ledger-month "/")))) - (let* ((args (with-temp-buffer - (insert transaction-text) - (eshell-parse-arguments (point-min) (point-max)))) - (ledger-buf (current-buffer)) - exit-code) - (unless insert-at-point - (let ((date (car args))) - (if (string-match ledger-iso-date-regexp date) - (setq date - (encode-time 0 0 0 (string-to-number (match-string 4 date)) - (string-to-number (match-string 3 date)) - (string-to-number (match-string 2 date))))) - (ledger-xact-find-slot date))) - (if (> (length args) 1) - (save-excursion - (insert - (with-temp-buffer - (setq exit-code - (apply #'ledger-exec-ledger ledger-buf (current-buffer) "xact" - (mapcar 'eval args))) - (goto-char (point-min)) - (if (looking-at "Error: ") - (error (concat "Error in ledger-add-transaction: " (buffer-string))) - (buffer-string))) - "\n")) - (progn - (insert (car args) " \n\n") - (end-of-line -1))))) - -(defun ledger-current-transaction-bounds () - "Return markers for the beginning and end of transaction surrounding point." - (save-excursion - (when (or (looking-at "^[0-9]") - (re-search-backward "^[0-9]" nil t)) - (let ((beg (point))) - (while (not (eolp)) - (forward-line)) - (cons (copy-marker beg) (point-marker)))))) - -(defun ledger-delete-current-transaction () - "Delete the transaction surrounging point." - (interactive) - (let ((bounds (ledger-current-transaction-bounds))) - (delete-region (car bounds) (cdr bounds)))) + (provide 'ldg-mode) diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index 7c13c80e..bed99ac0 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -65,33 +65,6 @@ (defconst ledger-version "3.0" "The version of ledger.el currently loaded.") -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun ledger-create-test () - "Create a regression test." - (interactive) - (save-restriction - (org-narrow-to-subtree) - (save-excursion - (let (text beg) - (goto-char (point-min)) - (forward-line 1) - (setq beg (point)) - (search-forward ":PROPERTIES:") - (goto-char (line-beginning-position)) - (setq text (buffer-substring-no-properties beg (point))) - (goto-char (point-min)) - (re-search-forward ":ID:\\s-+\\([^-]+\\)") - (find-file-other-window - (format "~/src/ledger/test/regress/%s.test" (match-string 1))) - (sit-for 0) - (insert text) - (goto-char (point-min)) - (while (not (eobp)) - (goto-char (line-beginning-position)) - (delete-char 3) - (forward-line 1)))))) - (defun ledger-mode-dump-variable (var) (if var (insert (format " %s: %S\n" (symbol-name var) (eval var))))) diff --git a/lisp/ldg-occur.el b/lisp/ldg-occur.el index 1e1308d0..96c364d6 100644 --- a/lisp/ldg-occur.el +++ b/lisp/ldg-occur.el @@ -96,8 +96,8 @@ When REGEX is nil, unhide everything, and remove higlight" (interactive (if ledger-occur-mode (list nil) - (list (read-string (concat "Regexp<" (ledger-occur-prompt) - ">: ") nil 'ledger-occur-history (ledger-occur-prompt))))) + (list (read-string (concat "Regexp<" (ledger-occur-prompt) ">: ") + nil 'ledger-occur-history (ledger-occur-prompt))))) (ledger-occur-mode regex (current-buffer))) (defun ledger-occur-prompt () @@ -121,21 +121,12 @@ When REGEX is nil, unhide everything, and remove higlight" (defun ledger-occur-create-narrowed-overlays(buffer-matches) (if buffer-matches (let ((overlays - (let ((prev-end (point-min)) - (temp (point-max))) + (let ((prev-end (point-min))) (mapcar (lambda (match) - (progn - (setq temp prev-end) ;; need a swap so that - ;; the last form in - ;; the lambda is the - ;; (make-overlay) - (setq prev-end (1+ (cadr match))) - ;; add 1 so that we skip the - ;; empty line after the xact - (make-overlay - temp - (car match) - (current-buffer) t nil))) + (prog1 + (make-overlay prev-end (car match) + (current-buffer) t nil) + (setq prev-end (1+ (cadr match))))) buffer-matches)))) (mapcar (lambda (ovl) (overlay-put ovl ledger-occur-overlay-property-name t) @@ -151,10 +142,9 @@ When REGEX is nil, unhide everything, and remove higlight" Argument OVL-BOUNDS contains bounds for the transactions to be left visible." (let ((overlays (mapcar (lambda (bnd) - (make-overlay - (car bnd) - (cadr bnd) - (current-buffer) t nil)) + (make-overlay (car bnd) + (cadr bnd) + (current-buffer) t nil)) ovl-bounds))) (mapcar (lambda (ovl) (overlay-put ovl ledger-occur-overlay-property-name t) @@ -196,9 +186,9 @@ Used for coordinating `ledger-occur' with other buffers, like reconcile." (save-excursion (goto-char (point-min)) ;; Set initial values for variables - (let ((curpoint nil) - (endpoint nil) - (lines (list))) + (let (curpoint + endpoint + (lines (list))) ;; Search loop (while (not (eobp)) (setq curpoint (point)) diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el index 4f80b425..37722fbc 100644 --- a/lisp/ldg-post.el +++ b/lisp/ldg-post.el @@ -69,23 +69,23 @@ (declare-function iswitchb-read-buffer "iswitchb" (prompt &optional default require-match start matches-set)) + (defvar iswitchb-temp-buflist) (defun ledger-post-completing-read (prompt choices) "Use iswitchb as a `completing-read' replacement to choose from choices. -PROMPT is a string to prompt with. CHOICES is a list of - strings to choose from." - (cond - ((eq ledger-post-use-completion-engine :iswitchb) - (let* ((iswitchb-use-virtual-buffers nil) - (iswitchb-make-buflist-hook - (lambda () - (setq iswitchb-temp-buflist choices)))) - (iswitchb-read-buffer prompt))) - ((eq ledger-post-use-completion-engine :ido) - (ido-completing-read prompt choices)) - (t - (completing-read prompt choices)))) +PROMPT is a string to prompt with. CHOICES is a list of strings +to choose from." + (cond ((eq ledger-post-use-completion-engine :iswitchb) + (let* ((iswitchb-use-virtual-buffers nil) + (iswitchb-make-buflist-hook + (lambda () + (setq iswitchb-temp-buflist choices)))) + (iswitchb-read-buffer prompt))) + ((eq ledger-post-use-completion-engine :ido) + (ido-completing-read prompt choices)) + (t + (completing-read prompt choices)))) (defvar ledger-post-current-list nil) diff --git a/lisp/ldg-sort.el b/lisp/ldg-sort.el index f426a7ef..a50cd1cc 100644 --- a/lisp/ldg-sort.el +++ b/lisp/ldg-sort.el @@ -28,8 +28,7 @@ (defun ledger-next-record-function () "Move point to next transaction." - (if (re-search-forward ledger-payee-any-status-regex - nil t) + (if (re-search-forward ledger-payee-any-status-regex nil t) (goto-char (match-beginning 0)) (goto-char (point-max)))) diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el index 6c585f30..58777631 100644 --- a/lisp/ldg-state.el +++ b/lisp/ldg-state.el @@ -30,15 +30,6 @@ :type 'boolean :group 'ledger) -(defun ledger-toggle-state (state &optional style) - "Return the correct toggle state given the current STATE, and STYLE." - (if (not (null state)) - (if (and style (eq style 'cleared)) - 'cleared) - (if (and style (eq style 'pending)) - 'pending - 'cleared))) - (defun ledger-transaction-state () "Return the state of the transaction at point." (save-excursion @@ -69,14 +60,10 @@ (defun ledger-state-from-char (state-char) "Get state from STATE-CHAR." - (cond ((eql state-char ?\!) - 'pending) - ((eql state-char ?\*) - 'cleared) - ((eql state-char ?\;) - 'comment) - (t - nil))) + (cond ((eql state-char ?\!) 'pending) + ((eql state-char ?\*) 'cleared) + ((eql state-char ?\;) 'comment) + (t nil))) (defun ledger-toggle-current-posting (&optional style) "Toggle the cleared status of the transaction under point. @@ -90,7 +77,7 @@ achieved more certainly by passing the xact to ledger for formatting, but doing so causes inline math expressions to be dropped." (interactive) - (let ((bounds (ledger-current-transaction-bounds)) + (let ((bounds (ledger-find-xact-extents (point))) new-status cur-status) ;; Uncompact the xact, to make it easier to toggle the ;; transaction @@ -232,27 +219,25 @@ dropped." (defun ledger-toggle-current-transaction (&optional style) "Toggle the transaction at point using optional STYLE." (interactive) - (let (status) - (save-excursion - (when (or (looking-at "^[0-9]") - (re-search-backward "^[0-9]" nil t)) - (skip-chars-forward "0-9./=\\-") - (delete-horizontal-space) - (if (or (eq (ledger-state-from-char (char-after)) 'pending) - (eq (ledger-state-from-char (char-after)) 'cleared)) - (progn - (delete-char 1) - (when (and style (eq style 'cleared)) - (insert " *") - (setq status 'cleared))) - (if (and style (eq style 'pending)) - (progn - (insert " ! ") - (setq status 'pending)) - (progn - (insert " * ") - (setq status 'cleared)))))) - status)) + (save-excursion + (when (or (looking-at "^[0-9]") + (re-search-backward "^[0-9]" nil t)) + (skip-chars-forward "0-9./=\\-") + (delete-horizontal-space) + (if (or (eq (ledger-state-from-char (char-after)) 'pending) + (eq (ledger-state-from-char (char-after)) 'cleared)) + (progn + (delete-char 1) + (when (and style (eq style 'cleared)) + (insert " *") + 'cleared)) + (if (and style (eq style 'pending)) + (progn + (insert " ! ") + 'pending) + (progn + (insert " * ") + 'cleared)))))) (provide 'ldg-state) diff --git a/lisp/ldg-test.el b/lisp/ldg-test.el index dbba9546..0c571caa 100644 --- a/lisp/ldg-test.el +++ b/lisp/ldg-test.el @@ -33,6 +33,33 @@ :type 'file :group 'ledger-test) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun ledger-create-test () + "Create a regression test." + (interactive) + (save-restriction + (org-narrow-to-subtree) + (save-excursion + (let (text beg) + (goto-char (point-min)) + (forward-line 1) + (setq beg (point)) + (search-forward ":PROPERTIES:") + (goto-char (line-beginning-position)) + (setq text (buffer-substring-no-properties beg (point))) + (goto-char (point-min)) + (re-search-forward ":ID:\\s-+\\([^-]+\\)") + (find-file-other-window + (format "~/src/ledger/test/regress/%s.test" (match-string 1))) + (sit-for 0) + (insert text) + (goto-char (point-min)) + (while (not (eobp)) + (goto-char (line-beginning-position)) + (delete-char 3) + (forward-line 1)))))) + (defun ledger-test-org-narrow-to-entry () (outline-back-to-heading) (narrow-to-region (point) (progn (outline-next-heading) (point))) diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el index b66bba04..bf50dbe2 100644 --- a/lisp/ldg-xact.el +++ b/lisp/ldg-xact.el @@ -39,17 +39,14 @@ within the transaction." (interactive "d") (save-excursion (goto-char pos) - (let ((end-pos pos) - (beg-pos pos)) - (backward-paragraph) - (if (/= (point) (point-min)) - (forward-line)) - (setq beg-pos (line-beginning-position)) - (forward-paragraph) - (forward-line -1) - (setq end-pos (1+ (line-end-position))) - (list beg-pos end-pos)))) - + (list (progn + (backward-paragraph) + (if (/= (point) (point-min)) + (forward-line)) + (line-beginning-position)) + (progn + (forward-paragraph) + (line-beginning-position))))) (defun ledger-highlight-xact-under-point () "Move the highlight overlay to the current transaction." @@ -76,6 +73,12 @@ within the transaction." (ledger-context-field-value context-info 'payee) nil)))) +(defun ledger-time-less-p (t1 t2) + "Say whether time value T1 is less than time value T2." + (or (< (car t1) (car t2)) + (and (= (car t1) (car t2)) + (< (nth 1 t1) (nth 1 t2))))) + (defun ledger-xact-find-slot (moment) "Find the right place in the buffer for a transaction at MOMENT. MOMENT is an encoded date" @@ -138,6 +141,49 @@ MOMENT is an encoded date" (replace-match date) (ledger-next-amount))) +(defun ledger-delete-current-transaction (pos) + "Delete the transaction surrounging point." + (interactive "d") + (let ((bounds (ledger-find-xact-extents pos))) + (delete-region (car bounds) (cadr bounds)))) + +(defun ledger-add-transaction (transaction-text &optional insert-at-point) + "Use ledger xact TRANSACTION-TEXT to add a transaction to the buffer. +If INSERT-AT-POINT is non-nil insert the transaction +there, otherwise call `ledger-xact-find-slot' to insert it at the +correct chronological place in the buffer." + (interactive (list + (read-string "Transaction: " (concat ledger-year "/" ledger-month "/")))) + (let* ((args (with-temp-buffer + (insert transaction-text) + (eshell-parse-arguments (point-min) (point-max)))) + (ledger-buf (current-buffer)) + exit-code) + (unless insert-at-point + (let ((date (car args))) + (if (string-match ledger-iso-date-regexp date) + (setq date + (encode-time 0 0 0 (string-to-number (match-string 4 date)) + (string-to-number (match-string 3 date)) + (string-to-number (match-string 2 date))))) + (ledger-xact-find-slot date))) + (if (> (length args) 1) + (save-excursion + (insert + (with-temp-buffer + (setq exit-code + (apply #'ledger-exec-ledger ledger-buf (current-buffer) "xact" + (mapcar 'eval args))) + (goto-char (point-min)) + (if (looking-at "Error: ") + (error (concat "Error in ledger-add-transaction: " (buffer-string))) + (buffer-string))) + "\n")) + (progn + (insert (car args) " \n\n") + (end-of-line -1))))) + + (provide 'ldg-xact) ;;; ldg-xact.el ends here -- cgit v1.2.3 From 9b5289c3e9c0d6a123f15a8a65def046bb823779 Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 10 Apr 2013 15:01:42 -0700 Subject: More regex finetuning in context --- lisp/ldg-context.el | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lisp/ldg-context.el b/lisp/ldg-context.el index 4b6aa26c..510a4cfa 100644 --- a/lisp/ldg-context.el +++ b/lisp/ldg-context.el @@ -32,11 +32,11 @@ ;; form the regex and list of elements (defconst indent-string "\\(^[ \t]+\\)") (defconst status-string "\\([*! ]?\\)") -(defconst account-string "[\\[(]?\\(.*?\\)[])]?") -(defconst amount-string "\\s-\\s-[ \t]+\\(-?[0-9]+\\.[0-9]*\\)") +(defconst account-string "[\\[(]?\\(.*?\\)[])]?[ \t]\\{2\\}") +(defconst amount-string "[ \t]?\\(-?[0-9]+\\.[0-9]*\\)") (defconst comment-string "[ \t]*;[ \t]*\\(.*?\\)") (defconst nil-string "[ \t]+") -(defconst commodity-string "\\(.*\\)") +(defconst commodity-string "\\(.+?\\)") (defconst date-string "^\\(\\([0-9]\\{4\\}[/-]\\)?[01]?[0-9][/-][0123]?[0-9]\\)") (defconst code-string "\\((\\(.*\\))\\)?") (defconst payee-string "\\(.*\\)") @@ -50,7 +50,7 @@ (intern (concat (symbol-name e) "-string")))))) "[ \t]*$"))) -(defmacro single-line-config (&rest elements) +(defmacro single-line-config2 (&rest elements) "Take list of ELEMENTS and return regex and element list for use in context-at-point" (let (regex-string) `'(,(concat (dolist (e elements regex-string) @@ -61,6 +61,10 @@ (concat (symbol-name e) "-string")))))) "[ \t]*$") ,elements))) +(defmacro single-line-config (&rest elements) + "Take list of ELEMENTS and return regex and element list for use in context-at-point" + `'(,(eval `(line-regex ,@elements)) + ,elements)) (defconst ledger-line-config (list (list 'xact (list (single-line-config date nil status nil nil code payee comment) -- cgit v1.2.3 From 15e84cbb18ff2e0423e20c3a620631c3ce97956c Mon Sep 17 00:00:00 2001 From: Craig Earls <enderw88@gmail.com> Date: Wed, 10 Apr 2013 15:48:39 -0700 Subject: More regex fine tuning --- lisp/ldg-context.el | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lisp/ldg-context.el b/lisp/ldg-context.el index 510a4cfa..ccaa39f2 100644 --- a/lisp/ldg-context.el +++ b/lisp/ldg-context.el @@ -32,10 +32,10 @@ ;; form the regex and list of elements (defconst indent-string "\\(^[ \t]+\\)") (defconst status-string "\\([*! ]?\\)") -(defconst account-string "[\\[(]?\\(.*?\\)[])]?[ \t]\\{2\\}") +(defconst account-string "[\\[(]?\\(.*?\\)[])]?") (defconst amount-string "[ \t]?\\(-?[0-9]+\\.[0-9]*\\)") (defconst comment-string "[ \t]*;[ \t]*\\(.*?\\)") -(defconst nil-string "[ \t]+") +(defconst nil-string "\\([ \t]+\\)") (defconst commodity-string "\\(.+?\\)") (defconst date-string "^\\(\\([0-9]\\{4\\}[/-]\\)?[01]?[0-9][/-][0123]?[0-9]\\)") (defconst code-string "\\((\\(.*\\))\\)?") @@ -70,12 +70,12 @@ (list (list 'xact (list (single-line-config date nil status nil nil code payee comment) (single-line-config date nil status nil nil code payee))) (list 'acct-transaction (list (single-line-config indent comment) - (single-line-config indent status account commodity amount nil comment) - (single-line-config indent status account commodity amount) - (single-line-config indent status account amount nil commodity comment) - (single-line-config indent status account amount nil commodity) - (single-line-config indent status account amount) - (single-line-config indent status account comment) + (single-line-config indent status account nil commodity amount nil comment) + (single-line-config indent status account nil commodity amount) + (single-line-config indent status account nil amount nil commodity comment) + (single-line-config indent status account nil amount nil commodity) + (single-line-config indent status account nil amount) + (single-line-config indent status account nil comment) (single-line-config indent status account))))) (defun ledger-extract-context-info (line-type pos) -- cgit v1.2.3 From 6bef247759acbdc026624e78d0fd78297bc79501 Mon Sep 17 00:00:00 2001 From: John Wiegley <johnw@newartisans.com> Date: Mon, 11 Mar 2013 01:06:01 -0500 Subject: Added .dir-locals.el --- .dir-locals.el | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .dir-locals.el diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 00000000..4f6af924 --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,31 @@ +((nil . ((tab-width . 2) + (sentence-end-double-space . t) + (fill-column . 8) + (bug-reference-url-format + . "http://bugs.ledger-cli.org/show_bug.cgi?id=%s"))) + (c-mode . ((c-file-style . "ledger") + (c-style-alist + ("ledger" + (indent-tabs-mode) + (c-basic-offset . 2) + (c-comment-only-line-offset 0 . 0) + (c-hanging-braces-alist + (substatement-open before after) + (arglist-cont-nonempty)) + (c-offsets-alist + (statement-block-intro . +) + (knr-argdecl-intro . 5) + (substatement-open . 0) + (substatement-label . 0) + (label . 0) + (case-label . 0) + (statement-case-open . 0) + (statement-cont . +) + (arglist-intro . +) + (arglist-close . +) + (inline-open . 0) + (brace-list-open . 0) + (topmost-intro-cont first c-lineup-topmost-intro-cont + c-lineup-gnu-DEFUN-intro-cont)) + (c-special-indent-hook . c-gnu-impose-minimum) + (c-block-comment-prefix . "")))))) -- cgit v1.2.3