halive (empty) → 0.1.0.0
raw patch · 5 files changed
+184/−0 lines, 5 filesdep +basedep +bin-package-dbdep +directorysetup-changed
Dependencies added: base, bin-package-db, directory, filepath, foreign-store, fsnotify, ghc, ghc-paths, system-filepath, transformers
Files
- LICENSE +26/−0
- Setup.hs +2/−0
- exec/main.hs +12/−0
- halive.cabal +119/−0
- src/Halive/Utils.hs +25/−0
+ LICENSE view
@@ -0,0 +1,26 @@+Copyright (c) 2015, Luke Iannini+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:++1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++2. 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.++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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ exec/main.hs view
@@ -0,0 +1,12 @@+import Halive+import Banner+import System.Environment++main :: IO ()+main = do+ args <- getArgs+ case args of+ [] -> putStrLn "Usage: halive <main.hs> <include dir>"+ (mainName:includeDirs) -> do+ putStrLn banner+ recompiler mainName includeDirs
+ halive.cabal view
@@ -0,0 +1,119 @@+-- Initial halive.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/++name: halive+version: 0.1.0.0+synopsis: A live recompiler+description: + > ██╗ ██╗ █████╗ ██╗ ██╗██╗ ██╗███████╗+ > ██║ ██║██╔══██╗██║ ██║██║ ██║██╔════╝+ > ███████║███████║██║ ██║██║ ██║█████╗ + > ██╔══██║██╔══██║██║ ██║╚██╗ ██╔╝██╔══╝ + > ██║ ██║██║ ██║███████╗██║ ╚████╔╝ ███████╗+ > ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝ ╚══════╝+ + Live recompiler for Haskell+ + <<http://lukexi.github.io/HaliveDemo.gif Halive Demo>>+ + Halive uses the GHC API to instantly recompile+ and reload your code any time you change it.+ + Usage:+ @cabal install@+ + and then+ + @halive \<path\/to\/mymain.hs> \<extra-include-dirs>@+ + Any time you change a file in the current directory or its+ subdirectories,+ halive will recompile and rerun the @main@ function in the file you gave+ it.+ + If the program is long-running (e.g. a daemon, GUI or game loop) it will+ be+ killed and restarted. Learn how to maintain state in the next section.+ + Try a live-coding GL demo by running @halive demo\/Main.hs@ (in the+ source package)+ and changing values in @Main.hs@ and @Green.hs@+ (requires @gl@, @GLFW-b@, @foreign-store@, @linear@, and @random@).+ + == Keeping values alive+ #keeping-values-alive#+ + To keep state alive, import @Halive.Utils@ and wrap+ your value in @reacquire@ along with a unique identifier, like:+ + @win \<- reacquire 0 (setupGLFW \"HotGLFW\" 640 480)@+ + to only create the resource the first time you run the program, and then+ reuse it on subsequent recompilations.+ + You can see this in action in @test\/glfw.hs@.+ + Thanks to Chris Done\'s+ <https://hackage.haskell.org/package/foreign-store @foreign-store@>+ library for enabling this.+ + == Notes+ #notes#+ + Creating, updating, and deleting modules in the include path should+ work fine during a Halive session.+ + Halive also supports Cabal sandboxes;+ if run within a directory containing a cabal.sandbox.config file it will+ use the package database defined therein.+ + Halive also works nicely with either batch-processing or run-loop type+ programs — if the program finishes, it will be restarted on next save,+ and if it\'s still running, it will be killed and restarted on save.+ + To kill Halive during run-loop type programs, you may need to hold down+ Ctrl-C+ to get GHC to recognize the double-Control-C-kill sequence.+ + <http://twitter.com/lukexi \@lukexi>+homepage: tree.is+license: BSD2+license-file: LICENSE+author: Luke Iannini+maintainer: lukexi@me.com+-- copyright: +category: Development+build-type: Simple+-- extra-source-files: +cabal-version: >=1.10++source-repository head+ type: git+ location: git://github.com/lukexi/halive.git++library+ hs-source-dirs: src+ exposed-modules:+ Halive.Utils+ default-language: Haskell2010+ ghc-options: -Wall+ build-depends:+ base,+ foreign-store+ ++executable halive+ main-is: main.hs+ hs-source-dirs: exec+ default-language: Haskell2010+ ghc-options: -Wall -threaded -dynamic+ -- other-modules: + -- other-extensions: + build-depends:+ base >=4.7 && <4.9,+ ghc, ghc-paths, bin-package-db,+ transformers,+ directory, + filepath, + fsnotify, + system-filepath
+ src/Halive/Utils.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE ScopedTypeVariables #-}+module Halive.Utils where+import Foreign.Store+import Data.Word++-- | Takes a unique integer representing your value,+-- along with an IO action to create the first instance+-- of your value to be used on subsequent recompilations.+reacquire :: forall a. Word32 -> IO a -> IO a+reacquire storeID create = do+ -- See if an existing store exists.+ maybeStore <- lookupStore storeID :: IO (Maybe (Store a))+ case maybeStore of+ -- If so, return the value inside+ Just store -> readStore store+ -- Otherwise, create the value, store it, and return it.+ Nothing -> do+ value <- create+ writeStore (Store storeID) value+ return value++-- TODO: a version of forkIO that records each threadID so they+-- can be killed when the program restarts, probably via+-- a 'killOldThreads' function the user calls at the +-- start of their program.