Skip to content

Commit dc73106

Browse files
committed
run: initial implementation
1 parent edfcd35 commit dc73106

File tree

8 files changed

+182
-1
lines changed

8 files changed

+182
-1
lines changed

doc/FILES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ src/hledger/
450450
Register.md
451451
Rewrite.md
452452
Roi.md
453+
Run.md
453454
Stats.md
454455
Tags.md
455456
Test.md

hledger/Hledger/Cli.hs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ import Hledger
118118
import Hledger.Cli.CliOptions
119119
import Hledger.Cli.Conf
120120
import Hledger.Cli.Commands
121+
import Hledger.Cli.Commands.Run
121122
import Hledger.Cli.DocFiles
122123
import Hledger.Cli.Utils
123124
import Hledger.Cli.Version
@@ -417,7 +418,10 @@ main = withGhcDebug' $ do
417418
ensureJournalFileExists . NE.head =<< journalFilePathFromOpts opts
418419
withJournalDo opts (cmdaction opts)
419420

420-
-- 6.5.4. all other builtin commands - read the journal and if successful run the command with it
421+
-- 6.5.4. run needs findBuiltinCommands passed to it to avoid circular dependency in the code
422+
| cmdname == "run" -> do withJournalDo opts $ Hledger.Cli.Commands.Run.run findBuiltinCommand opts
423+
424+
-- 6.5.5. all other builtin commands - read the journal and if successful run the command with it
421425
| otherwise -> withJournalDo opts $ cmdaction opts
422426

423427
-- 6.6. external addon command found - run it,

hledger/Hledger/Cli/Commands.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ module Hledger.Cli.Commands (
4646
,module Hledger.Cli.Commands.Print
4747
,module Hledger.Cli.Commands.Register
4848
,module Hledger.Cli.Commands.Rewrite
49+
,module Hledger.Cli.Commands.Run
4950
,module Hledger.Cli.Commands.Stats
5051
,module Hledger.Cli.Commands.Tags
5152
)
@@ -91,6 +92,7 @@ import Hledger.Cli.Commands.Print
9192
import Hledger.Cli.Commands.Register
9293
import Hledger.Cli.Commands.Rewrite
9394
import Hledger.Cli.Commands.Roi
95+
import Hledger.Cli.Commands.Run
9496
import Hledger.Cli.Commands.Stats
9597
import Hledger.Cli.Commands.Tags
9698
import Hledger.Cli.Utils (tests_Cli_Utils)
@@ -126,6 +128,7 @@ builtinCommands = [
126128
,(registermode , register)
127129
,(rewritemode , rewrite)
128130
,(roimode , roi)
131+
,(runmode , run')
129132
,(statsmode , stats)
130133
,(tagsmode , tags)
131134
,(testmode , testcmd)
@@ -253,6 +256,7 @@ commandsList progversion othercmds =
253256
," balance (bal) show balance changes, end balances, gains, budgets.."
254257
,"+lots show a commodity's lots" -- hledger-lots
255258
," roi show return on investments"
259+
," run run multiple commands from a file"
256260
,""
257261
-----------------------------------------80-------------------------------------
258262
,bold' "CHARTS (bar charts, line graphs..)"

hledger/Hledger/Cli/Commands/Run.hs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
{-|
2+
3+
The @run@ command allows you to run multiple commands via REPL or from the supplied file(s).
4+
5+
-}
6+
7+
{-# LANGUAGE MultiWayIf #-}
8+
{-# LANGUAGE OverloadedStrings #-}
9+
{-# LANGUAGE ScopedTypeVariables #-}
10+
{-# LANGUAGE TemplateHaskell #-}
11+
12+
module Hledger.Cli.Commands.Run (
13+
runmode
14+
,run
15+
,run'
16+
) where
17+
18+
import qualified Data.Text as T
19+
import qualified Data.Text.IO as T
20+
import System.Console.CmdArgs.Explicit as C ( Mode )
21+
import Hledger
22+
import Hledger.Cli.CliOptions
23+
24+
import Control.Monad (forM_)
25+
import Control.Monad.IO.Class (liftIO)
26+
import Control.Monad.Extra (concatMapM)
27+
28+
import System.Console.Haskeline
29+
30+
import Safe (headMay)
31+
32+
-- | Command line options for this command.
33+
runmode = hledgerCommandMode
34+
$(embedFileRelative "Hledger/Cli/Commands/Run.txt")
35+
(
36+
[]
37+
)
38+
cligeneralflagsgroups1
39+
hiddenflags
40+
([], Just $ argsFlag "[COMMANDS_FILE1 COMMANDS_FILE2 ...]")
41+
42+
-- | The fake run command introduced to break circular dependency
43+
run' :: CliOpts -> Journal -> IO ()
44+
run' _opts _j = return ()
45+
46+
-- | The actual run command.
47+
run :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> CliOpts -> Journal -> IO ()
48+
run findBuiltinCommand CliOpts{rawopts_=rawopts} j = do
49+
let inputfiles = listofstringopt "args" rawopts
50+
case inputfiles of
51+
[] -> runREPL findBuiltinCommand j
52+
_ -> runFromFiles findBuiltinCommand inputfiles j
53+
54+
runFromFiles :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> [String] -> Journal -> IO ()
55+
runFromFiles findBuiltinCommand inputfiles j = do
56+
dbg1IO "inputfiles" inputfiles
57+
-- read commands from all the inputfiles
58+
commands <- (flip concatMapM) inputfiles $ \f -> do
59+
dbg1IO "reading commands" f
60+
lines . T.unpack <$> T.readFile f
61+
62+
forM_ commands (runCommand findBuiltinCommand j)
63+
64+
runCommand :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> Journal -> String -> IO ()
65+
runCommand findBuiltinCommand j cmdline = do
66+
dbg1IO "running command" cmdline
67+
-- # begins a comment, ignore everything after #
68+
case takeWhile (not. ((Just '#')==) . headMay) $ words' (strip cmdline) of
69+
"echo":args -> putStrLn $ unwords $ args
70+
cmdname:args ->
71+
case findBuiltinCommand cmdname of
72+
Nothing -> putStrLn $ unwords (cmdname:args)
73+
Just (cmdmode,cmdaction) -> do
74+
opts <- getHledgerCliOpts' cmdmode args
75+
cmdaction opts j
76+
[] -> return ()
77+
78+
runREPL :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> Journal -> IO ()
79+
runREPL findBuiltinCommand j = do
80+
putStrLn "Enter hledger commands, or 'help' for help."
81+
runInputT defaultSettings loop
82+
where
83+
loop :: InputT IO ()
84+
loop = do
85+
minput <- getInputLine "% "
86+
case minput of
87+
Nothing -> return ()
88+
Just "quit" -> return ()
89+
Just "exit" -> return ()
90+
Just input -> do
91+
liftIO $ runCommand findBuiltinCommand j input
92+
loop

hledger/Hledger/Cli/Commands/Run.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
## run
2+
3+
Runs hledged commands via interactive read-eval-print loop (REPL) or from a file or files.
4+
5+
All commands would be applied to the same journal(s), specified by `-f` as usual.
6+
7+
When no positional arguments are specified, interactive REPL is started, otherwise positional
8+
arguments are treated as the files to read and run the commands from.
9+
10+
Use "exit" or "quit", or send EOF to exit from REPL.
11+
12+
Syntax of the files is intentionally simple:
13+
- each line is a single hledger command
14+
- lines that can't be interpreted as hledger commands are printed out (including empty lines)
15+
- everything after # is considered to be a comment and will be ignored
16+
- `echo <text>` will print out text, even if it could be recognized as a hledger command
17+
18+
You can use single quotes or double quotes to quote aguments that need quoting.
19+
20+
You can use `#!/usr/bin/env hledger run` in the first line of the file to make it a runnable script.
21+
22+
For example:
23+
24+
```cli
25+
#!/usr/bin/env hledger run
26+
echo "List of accounts"
27+
accounts
28+
29+
echo "Assets"
30+
balance assets --depth 2
31+
32+
echo "Liabilities"
33+
balance liabilities --depth 3 --transpose
34+
```
35+
```flags
36+
Flags:
37+
no command-specific flags

hledger/Hledger/Cli/Commands/Run.txt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
run
2+
3+
Runs hledged commands via interactive read-eval-print loop (REPL) or
4+
from a file or files.
5+
6+
All commands would be applied to the same journal(s), specified by -f as
7+
usual.
8+
9+
When no positional arguments are specified, interactive REPL is started,
10+
otherwise positional arguments are treated as the files to read and run
11+
the commands from.
12+
13+
Use "exit" or "quit", or send EOF to exit from REPL.
14+
15+
Syntax of the files is intentionally simple: - each line is a single
16+
hledger command - lines that can't be interpreted as hledger commands
17+
are printed out (including empty lines) - everything after # is
18+
considered to be a comment and will be ignored - echo <text> will print
19+
out text, even if it could be recognized as a hledger command
20+
21+
You can use single quotes or double quotes to quote aguments that need
22+
quoting.
23+
24+
You can use #!/usr/bin/env hledger run in the first line of the file to
25+
make it a runnable script.
26+
27+
For example:
28+
29+
#!/usr/bin/env hledger run
30+
echo "List of accounts"
31+
accounts
32+
33+
echo "Assets"
34+
balance assets --depth 2
35+
36+
echo "Liabilities"
37+
balance liabilities --depth 3 --transpose
38+
39+
```flags Flags: no command-specific flags

hledger/hledger.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ extra-source-files:
8484
Hledger/Cli/Commands/Register.txt
8585
Hledger/Cli/Commands/Rewrite.txt
8686
Hledger/Cli/Commands/Roi.txt
87+
Hledger/Cli/Commands/Run.txt
8788
Hledger/Cli/Commands/Stats.txt
8889
Hledger/Cli/Commands/Tags.txt
8990
Hledger/Cli/Commands/Test.txt
@@ -140,6 +141,7 @@ library
140141
Hledger.Cli.Commands.Register
141142
Hledger.Cli.Commands.Rewrite
142143
Hledger.Cli.Commands.Roi
144+
Hledger.Cli.Commands.Run
143145
Hledger.Cli.Commands.Stats
144146
Hledger.Cli.Commands.Tags
145147
Hledger.Cli.CompoundBalanceCommand

hledger/package.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ extra-source-files:
8383
- Hledger/Cli/Commands/Register.txt
8484
- Hledger/Cli/Commands/Rewrite.txt
8585
- Hledger/Cli/Commands/Roi.txt
86+
- Hledger/Cli/Commands/Run.txt
8687
- Hledger/Cli/Commands/Stats.txt
8788
- Hledger/Cli/Commands/Tags.txt
8889
- Hledger/Cli/Commands/Test.txt
@@ -201,6 +202,7 @@ library:
201202
- Hledger.Cli.Commands.Register
202203
- Hledger.Cli.Commands.Rewrite
203204
- Hledger.Cli.Commands.Roi
205+
- Hledger.Cli.Commands.Run
204206
- Hledger.Cli.Commands.Stats
205207
- Hledger.Cli.Commands.Tags
206208
- Hledger.Cli.CompoundBalanceCommand

0 commit comments

Comments
 (0)