journal: the include directive now accepts a file format prefix

This works with glob patterns too, applying the prefix to each path.
This can be useful when included files don't have the standard file
extension, eg:

include timedot:2020*.md
This commit is contained in:
Simon Michael 2020-06-02 17:13:07 -07:00
parent 9bc8c5d668
commit 00e9e844ac
2 changed files with 27 additions and 18 deletions

View File

@ -240,19 +240,23 @@ directivep = (do
]
) <?> "directive"
-- | Parse an include directive. include's argument is an optionally
-- file-format-prefixed file path or glob pattern. In the latter case,
-- the prefix is applied to each matched path. Examples:
-- foo.j, foo/bar.j, timedot:foo/2020*.md
includedirectivep :: MonadIO m => ErroringJournalParser m ()
includedirectivep = do
string "include"
lift (skipSome spacenonewline)
filename <- T.unpack <$> takeWhileP Nothing (/= '\n') -- don't consume newline yet
prefixedglob <- T.unpack <$> takeWhileP Nothing (/= '\n') -- don't consume newline yet
parentoff <- getOffset
parentpos <- getSourcePos
filepaths <- getFilePaths parentoff parentpos filename
forM_ filepaths $ parseChild parentpos
let (mprefix,glob) = splitReaderPrefix prefixedglob
paths <- getFilePaths parentoff parentpos glob
let prefixedpaths = case mprefix of
Nothing -> paths
Just fmt -> map ((fmt++":")++) paths
forM_ prefixedpaths $ parseChild parentpos
void newline
where
@ -275,10 +279,11 @@ includedirectivep = do
else customFailure $ parseErrorAt parseroff $
"No existing files match pattern: " ++ filename
parseChild :: MonadIO m => SourcePos -> FilePath -> ErroringJournalParser m ()
parseChild parentpos filepath = do
parentj <- get
parseChild :: MonadIO m => SourcePos -> PrefixedFilePath -> ErroringJournalParser m ()
parseChild parentpos prefixedpath = do
let (_mprefix,filepath) = splitReaderPrefix prefixedpath
parentj <- get
let parentfilestack = jincludefilestack parentj
when (filepath `elem` parentfilestack) $
Fail.fail ("Cyclic include: " ++ filepath)
@ -289,7 +294,7 @@ includedirectivep = do
-- Choose a reader/format based on the file path, or fall back
-- on journal. Duplicating readJournal a bit here.
let r = fromMaybe reader $ findReader Nothing (Just filepath)
let r = fromMaybe reader $ findReader Nothing (Just prefixedpath)
parser = rParser r
dbg1IO "trying reader" (rFormat r)
updatedChildj <- journalAddFile (filepath, childInput) <$>

View File

@ -878,16 +878,20 @@ See also [comments](#comments).
You can pull in the content of additional files by writing an include directive, like this:
```journal
include path/to/file.journal
include FILEPATH
```
If the path does not begin with a slash, it is relative to the current file.
The include file path may contain
[common glob patterns](https://hackage.haskell.org/package/Glob-0.9.2/docs/System-FilePath-Glob.html#v:compile)
(e.g. `*`).
Only journal files can include, and only journal, timeclock or timedot files can be included (not CSV files, currently).
The `include` directive can only be used in journal files.
It can include journal, timeclock or timedot files, but not CSV files.
If the file path does not begin with a slash, it is relative to the current file's folder.
It may contain [glob patterns] to match multiple files, eg: `include *.journal`.
Or a tilde, meaning home directory: `include ~/main.journal`.
It may also be prefixed to force a specific file format, overriding the file extension (as described in [hledger.1 -> Input files](hledger.html#input-files)): `include timedot:~/notes/2020*.md`.
[glob patterns]: https://hackage.haskell.org/package/Glob-0.9.2/docs/System-FilePath-Glob.html#v:compile
### Default year