Safe Haskell | None |
---|---|
Language | Haskell2010 |
Twitch is a monadic DSL and library for file watching. It conveniently utilizes 'do' notation in the style of Shake and clay to expose the functionality of the fsnotify cross-platform file system watcher.
Here is an example that converts Markdown files to HTML and reloads Safari whenever the input files change.
{-# LANGUAGE OverloadedStrings #-} import Twitch import Filesystem.Path.CurrentOS main = defaultMain $ do "*.md" |> \filePath -> system $ "pandoc -t html " ++ encodeString filePath "*.html" |> \_ -> system $ "osascript refreshSafari.AppleScript"
Rules are specified in the Dep
(for Dependency) monad. The library takes advantage
of the OverloadedStrings extension to create a Dep
value from a glob pattern.
After creating a Dep
value using a glob, event callbacks are added using prefix
or infix API.
There are three types of events: 'add', 'modify' and 'delete'. In many cases, the 'add' and 'modify' responses are the same, so an 'add and modify' API is provided
In the example above, an 'add and modify' callback was added to both the "*.md"
and "*.html" globs using the |>
operator.
Although this is the common case, differing callbacks can be added with |+
(or add
)
and |%
(or modify
) functions. Finally, delete callbacks are added with
|-
(of delete
).
Here is a more complex usage example, handling all three events separately.
handleHaskellFiles :: Dep handleHaskellFiles = "src/**/*.hs" |+ addToCabalFile |% reloadFile |- removeFromCabalFile
The glob above is also more complicated and incorporates a recursive wildcard. For complete documentation on the glob syntax, consult the Glob library's documentation.
Since a command pattern is calling system commands with a file path, a useful addition to twitch is the file-command-qq quasiquoter.
Here is a slightly more complicated version the example from earlier, using the FileCommand quasiquoter.
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} import Twitch import FileCommand main = defaultMain $ do "*.md" |> [s|pandoc -t html -o$directory$basename-test.html $path|] "*.html" |> [s|osascript refreshSafari.AppleScript|]
- type Dep = DepM ()
- defaultMain :: Dep -> IO ()
- (|+) :: Dep -> (FilePath -> IO a) -> Dep
- (|%) :: Dep -> (FilePath -> IO a) -> Dep
- (|-) :: Dep -> (FilePath -> IO a) -> Dep
- (|>) :: Dep -> (FilePath -> IO a) -> Dep
- (|#) :: Dep -> Text -> Dep
- add :: (FilePath -> IO a) -> Dep -> Dep
- modify :: (FilePath -> IO a) -> Dep -> Dep
- delete :: (FilePath -> IO a) -> Dep -> Dep
- addModify :: (FilePath -> IO a) -> Dep -> Dep
- name :: Text -> Dep -> Dep
- data DebounceType
- data LoggerType
- data Options = Options {}
- defaultMainWithOptions :: Options -> Dep -> IO ()
- data Issue
- data InternalRule
- data Config = Config {
- logger :: Issue -> IO ()
- dirs :: [FilePath]
- watchConfig :: WatchConfig
- run :: Dep -> IO WatchManager
- runWithConfig :: FilePath -> Config -> Dep -> IO WatchManager
- data DepM a
Documentation
defaultMain :: Dep -> IO () Source
Simplest way to create a file watcher app. Set your main equal to defaultMain and you are good to go. See the module documentation for examples.
The command line is parsed to make Options
value. For more information on
the arguments that can be passed see the doc for Options
and the run the
executable made with defaultMain with the --help argument.
Infix API
(|+) :: Dep -> (FilePath -> IO a) -> Dep infixl 8 Source
Add a 'add' callback ex.
"*.png" |+ addToManifest
(|%) :: Dep -> (FilePath -> IO a) -> Dep infixl 8 Source
Add a 'modify' callback ex.
"*.c" |% [s|gcc -o$directory$basename.o $path|]
(|-) :: Dep -> (FilePath -> IO a) -> Dep infixl 8 Source
Add a 'delete' callback ex.
"*.c" |- [s|gcc -o$directory$basename.o $path|]
(|#) :: Dep -> Text -> Dep infixl 8 Source
Set the name of a rule. Useful for debugging when logging is enabled. Rules names default to the glob pattern. ex.
"*.md" |> [s|pandoc -t html $path|] |# "markdown to html"
Prefix API
modify :: (FilePath -> IO a) -> Dep -> Dep Source
Add a 'modify' callback ex.
mod [s|gcc -o$directory$basename.o $path|] "*.c"
delete :: (FilePath -> IO a) -> Dep -> Dep Source
Add a 'delete' callback ex.
delete [s|gcc -o$directory$basename.o $path|] "*.c"
addModify :: (FilePath -> IO a) -> Dep -> Dep Source
Add the same callback for the 'add' and the 'modify' events. ex.
addModify [s|pandoc -t html $path|] "*.md"
name :: Text -> Dep -> Dep Source
Set the name of a rule. Useful for debugging when logging is enabled. Rules names default to the glob pattern. ex.
name "markdown to html" $ addModify [s|pandoc -t html $path|] "*.md"
Advanced Main
data DebounceType Source
data LoggerType Source
Options | |
|
defaultMainWithOptions :: Options -> Dep -> IO () Source
A main file that uses manually supplied options instead of parsing the passed in arguments.
Running as a library
A sum type for the various issues that can be logged
IEvent Event | logged every time an event is fired |
IRuleFired Event InternalRule | logged every time an rule is fired |
Configuration to run the file watcher
Config | |
|
run :: Dep -> IO WatchManager Source
runWithConfig :: FilePath -> Config -> Dep -> IO WatchManager Source