From 47766ea9d495f370d2a6a805a02f2d6caa1fe0eb Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Thu, 2 Nov 2017 08:36:49 +0100 Subject: [PATCH 1/4] journal: support space as digits sep Resolves simonmichael/hledger#330 --- hledger-lib/Hledger/Read/Common.hs | 8 ++++++-- hledger-lib/doc/hledger_journal.5.m4.md | 6 ++++-- tests/journal/numbers.test | 26 +++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/hledger-lib/Hledger/Read/Common.hs b/hledger-lib/Hledger/Read/Common.hs index ea3a1bc04..85dac541f 100644 --- a/hledger-lib/Hledger/Read/Common.hs +++ b/hledger-lib/Hledger/Read/Common.hs @@ -24,6 +24,7 @@ import Prelude.Compat hiding (readFile) import Control.Monad.Compat import Control.Monad.Except (ExceptT(..), runExceptT, throwError) --, catchError) import Control.Monad.State.Strict +import Data.Char import Data.Data import Data.Default import Data.Functor.Identity @@ -599,7 +600,7 @@ rawnumberp = do (firstSep, groups) <- option (Nothing, []) $ do leadingDigits <- some digitChar option (Nothing, [leadingDigits]) . try $ do - firstSep <- oneOf sepChars + firstSep <- oneOf sepChars <|> whitespaceChar groups <- some digitChar `sepBy1` char firstSep return (Just firstSep, leadingDigits : groups) @@ -614,11 +615,14 @@ rawnumberp = do return (lastSep, fromMaybe [] digits) -- make sure we didn't leading part of mistyped number - notFollowedBy $ oneOf sepChars + notFollowedBy $ oneOf sepChars <|> (whitespaceChar >> digitChar) return $ dbg8 "rawnumberp" (firstSep, groups, extraGroup) "rawnumberp" +-- | Parse a unicode char that represents any non-control space char (Zs general category). +whitespaceChar :: TextParser m Char +whitespaceChar = charCategory Space -- test_numberp = do -- let s `is` n = assertParseEqual (parseWithState mempty numberp s) n diff --git a/hledger-lib/doc/hledger_journal.5.m4.md b/hledger-lib/doc/hledger_journal.5.m4.md index b5d8236fb..8550971c4 100644 --- a/hledger-lib/doc/hledger_journal.5.m4.md +++ b/hledger-lib/doc/hledger_journal.5.m4.md @@ -267,7 +267,8 @@ Amounts consist of a number and (usually) a currency symbol or commodity name. S `3 "green apples"`\ `-$1,000,000.00`\ `INR 9,99,99,999.00`\ - `EUR -2.000.000,00` + `EUR -2.000.000,00`\ + `1 999 999.9455` As you can see, the amount format is somewhat flexible: @@ -275,7 +276,8 @@ As you can see, the amount format is somewhat flexible: - the commodity is a symbol, word, or phrase, on the left or right, with or without a separating space. If the commodity contains numbers, spaces or non-word punctuation it must be enclosed in double quotes. - negative amounts with a commodity on the left can have the minus sign before or after it -- digit groups (thousands, or any other grouping) can be separated by commas (in which case period is used for decimal point) or periods (in which case comma is used for decimal point) +- digit groups (thousands, or any other grouping) can be separated by space or comma or period and should be used as separator between all groups +- decimal part can be separated by comma or period and should be different from digit groups separator You can use any of these variations when recording data. However, there is some ambiguous way of representing numbers like `$1.000` and `$1,000` both may mean either one thousand or one dollar. By default hledger will assume that this is sole delimiter is used only for decimals. On the other hand commodity format declared prior to that line will help to resolve that ambiguity differently: diff --git a/tests/journal/numbers.test b/tests/journal/numbers.test index b81669c95..01e169173 100644 --- a/tests/journal/numbers.test +++ b/tests/journal/numbers.test @@ -43,6 +43,32 @@ hledger bal -f - >>> >>>=1 +# Space between digits groups +hledger bal -f - --no-total +<<< +2017/1/1 + a 1 000.00 EUR + b -1 000.00 EUR +>>> + 1 000.00 EUR a + -1 000.00 EUR b +>>>2 +>>>=0 + +# Space between digits groups in commodity directive +hledger bal -f - --no-total +<<< +commodity 1 000.00 EUR + +2017/1/1 + a 1,000.00 EUR + b -1,000.00 EUR +>>> + 1 000.00 EUR a + -1 000.00 EUR b +>>>2 +>>>=0 + # Default commodity hledger bal -f - <<< From 2a0e12122cf7fe2f32b630881b4211226eba653e Mon Sep 17 00:00:00 2001 From: Simon Michael Date: Sat, 30 Dec 2017 08:47:47 -0800 Subject: [PATCH 2/4] tools: regen cabal files with latest stack's hpack to avoid warnings --- hledger-lib/hledger-lib.cabal | 2 +- hledger-ui/hledger-ui.cabal | 2 +- hledger/hledger.cabal | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hledger-lib/hledger-lib.cabal b/hledger-lib/hledger-lib.cabal index 2da545266..3dcc8615f 100644 --- a/hledger-lib/hledger-lib.cabal +++ b/hledger-lib/hledger-lib.cabal @@ -1,4 +1,4 @@ --- This file has been generated from package.yaml by hpack version 0.21.2. +-- This file has been generated from package.yaml by hpack version 0.20.0. -- -- see: https://github.com/sol/hpack -- diff --git a/hledger-ui/hledger-ui.cabal b/hledger-ui/hledger-ui.cabal index 591f98dea..47244773c 100644 --- a/hledger-ui/hledger-ui.cabal +++ b/hledger-ui/hledger-ui.cabal @@ -1,4 +1,4 @@ --- This file has been generated from package.yaml by hpack version 0.21.2. +-- This file has been generated from package.yaml by hpack version 0.20.0. -- -- see: https://github.com/sol/hpack -- diff --git a/hledger/hledger.cabal b/hledger/hledger.cabal index 0d9cddf00..eaae680a7 100644 --- a/hledger/hledger.cabal +++ b/hledger/hledger.cabal @@ -1,4 +1,4 @@ --- This file has been generated from package.yaml by hpack version 0.21.2. +-- This file has been generated from package.yaml by hpack version 0.20.0. -- -- see: https://github.com/sol/hpack -- From 2dc47673b788741182310b3db558beb081caa011 Mon Sep 17 00:00:00 2001 From: Simon Michael Date: Sat, 30 Dec 2017 08:56:10 -0800 Subject: [PATCH 3/4] tools: more reliable cabal file regeneration using stack Uses stack's hpack, making hpack version warnings less likely. Regenerates all local stack packages' cabal files, even if they're missing. --- Makefile | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 3d6aa82ef..4d37d70dc 100644 --- a/Makefile +++ b/Makefile @@ -1392,26 +1392,27 @@ doc/lib.m4: $(VERSIONFILE) setversion: $(VERSIONSENSITIVEFILES) #$(call def-help,setversion, update version strings & bounds from $(VERSIONFILE) (might need -B) ) updateversion: setversion $(call def-help,updateversion, update version strings & bounds from $(VERSIONFILE) and commit (might need -B) ) - @read -p "please review changes then press enter to commit: $(VERSIONFILE) $(VERSIONSENSITIVEFILES)" + @read -p "please review changes then press enter to commit $(VERSIONFILE) $(VERSIONSENSITIVEFILES)" git commit -m "bump version strings & lower bounds to $(VERSION)" $(VERSIONFILE) $(VERSIONSENSITIVEFILES) # (re)generate a cabal file from its package.yaml definition # XXX to avoid warnings, this hpack should be the same version as stack's built-in hpack -%.cabal: $$(dir $$@)package.yaml - hpack --silent $(dir $*) +#%.cabal: $$(dir $$@)package.yaml +# hpack --silent $(dir $*) +# +gencabal: $(call def-help,gencabal, regenerate cabal files from package.yaml files with stack ) + stack build --dry-run --silent -gencabal: $$(CABALFILES) #$(call def-help,gencabal, regenerate cabal files from package.yamls (might need -B) ) - -updatecabal: gencabal $(call def-help,updatecabal, regenerate and commit cabal files (might need -B) ) - @read -p "please review changes then press enter to commit: $(CABALFILES)" - git commit -m "update cabal files" $(CABALFILES) +updatecabal: gencabal $(call def-help,updatecabal, regenerate cabal files and commit ) + @read -p "please review changes then press enter to commit $(shell ls */*.cabal)" + git commit -m "update cabal files" $(shell ls */*.cabal) # we call in shake for this job; so dependencies aren't checked here genmanuals: Shake #$(call def-help,genmanuals, regenerate embedded manuals (might need -B) ) ./Shake manuals updatemanuals: genmanuals $(call def-help,updatemanuals, regenerate embedded manuals and commit (might need -B) ) - @read -p "please review changes then press enter to commit: $(shell ls hledger*/hledger*.{1,5,info,txt})" + @read -p "please review changes then press enter to commit $(shell ls hledger*/hledger*.{1,5,info,txt})" git commit -m "update embedded manuals" hledger*/hledger*.{1,5,info,txt} From e9ff1280d78fafeefd5791089bb59647e7c2e754 Mon Sep 17 00:00:00 2001 From: Simon Michael Date: Fri, 29 Dec 2017 10:53:41 -0800 Subject: [PATCH 4/4] web: don't write a session file at startup The .hledger-web_client_session_key.aes file written at startup is cluttersome and means hledger-web can only be started from a writable directory. What do we lose if I disable it ? https://hackage.haskell.org/package/yesod-core-1.4.33/docs/Yesod-Core.html#v:makeSessionBackend says "Default: Uses clientsession with a 2 hour timeout." http://hackage.haskell.org/package/clientsession-0.9.1.2 says "Securely store session data in a client-side cookie." I think: hledger-web saves (eg) the state of the sidebar as session data, in a cookie, and my web browser saves that locally. And this still seems to work, across server restarts. So what's the purpose of saving this "client session" file on the server ? Let's disable it and find out. --- hledger-web/Foundation.hs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hledger-web/Foundation.hs b/hledger-web/Foundation.hs index 59e60ec6f..90bc5d913 100644 --- a/hledger-web/Foundation.hs +++ b/hledger-web/Foundation.hs @@ -100,11 +100,13 @@ type Form x = Html -> MForm (HandlerT App IO) (FormResult x, Widget) instance Yesod App where approot = ApprootMaster $ appRoot . settings - -- Store session data on the client in encrypted cookies, - -- default session idle timeout is 120 minutes - makeSessionBackend _ = fmap Just $ defaultClientSessionBackend - (120 * 60) - ".hledger-web_client_session_key.aes" +-- -- Store session data on the client in encrypted cookies, +-- -- default session idle timeout is 120 minutes +-- makeSessionBackend _ = fmap Just $ defaultClientSessionBackend +-- (120 * 60) +-- ".hledger-web_client_session_key.aes" + -- don't use session data + makeSessionBackend _ = return Nothing defaultLayout widget = do master <- getYesod