packages feed

hdevtools 0.1.0.4 → 0.1.0.5

raw patch · 18 files changed

+414/−4 lines, 18 filesdep ~ghc

Dependency ranges changed: ghc

Files

+ AUTHORS view
@@ -0,0 +1,1 @@+Bit Connor <mutantlemon@gmail.com>
+ README.md view
@@ -0,0 +1,182 @@+hdevtools+=========++Persistent GHC powered background server for FAST Haskell development tools++About+-----++`hdevtools` is a backend for text editor plugins, to allow for things such as+syntax and type checking of Haskell code, and retrieving type information, all+directly from within your text editor.++The advantage that `hdevtools` has over competitors, is that it runs silently+in a persistent background process, and therefore is able to keeps all of your+Haskell modules and dependent libraries loaded in memory. This way, when you+change only a single source file, only it needs to be reloaded and rechecked,+instead of having to reload everything.++This makes `hdevtools` very fast for checking syntax and type errors (runs just+as fast as the `:reload` command in GHCi).++In fact, syntax and type checking is so fast, that you can safely enable auto+checking on every save. Even for huge projects, checking is nearly instant.++Once you start using `hdevtools` and you get used to having your errors shown+to you instantly (without having to switch back and forth between GHCi and your+editor), and shown directly on your code, in your editor (without having to+wait forever for GHC to run) you will wonder how you ever lived without it.++In addition to checking Haskell source code for errors, `hdevtools` has tools+for getting info about identifiers, and getting type information for snippets+of code.++Text Editor Integration+-----------------------++`hdevtools` is designed to be integrated into text editors. The list of current+editor plugins that supply this integration is below.++But before you do anything, you must first install `hdevtools` itself. The+easiest way is from [Hackage][1] via cabal install:++    $ cabal install hdevtools++Then you should install one or more of the following editor plugins:++### Vim - [Syntastic][2] ###++[Syntastic][2] is a popular syntax checking plugin for Vim, and is the+recommended Vim integration of `hdevtools` syntax and type checking. Recent+versions of Syntastic(since Sep. 2012) have builtin support for `hdevtools`.++Simply install `hdevtools` (as above) and [Syntastic][2], and it will+automatically check your Haskell files.++[Syntastic][2] will respect the `g:hdevtools_options` variable (the same one as+used by [vim-hdevtools][3], see below). See the section "Specifying GHC+Options" below for details how to use it.++### Vim - [vim-hdevtools][3] ###++In addition to Syntastic, it is recommended that you also use+[`vim-hdevtools`][3] for additional functionality.++[`vim-hdevtools`][3] offers integration with the rest of the `hdevtools` tools,+including retrieving info about the identifier under the cursor, and getting+the type of the code under the cursor. Refer to its documentation for more+details.++### Emacs ###++I encourage the community to develop integration plugins for Emacs and other+editors. In the mean time, please see the manual integration information below.++### Manual Editor Integration for any Editor ###++Most editors allow you to run a `make` command, and will then parse the output+for errors and show line numbers, allowing you to jump between errors.++The `hdevtools check` command is suitable for such usage.++For example, in Vim something like this will work:++    :let &makeprg='hdevtools check %'++(Vim will replace the `%` character with the name of the current file). Then+you can run++    :make++And Vim will invoke `hdevtools` to check the current file for errors, and then+show a list of them and allow jumping to them.++See the "Command Line Usage" section below for more information.++Command Line Usage+------------------++Note: When using one of the above editor plugins, you don't really need to know+this.++### Available Commands and Help ###++For the list of commands available, run:++    $ hdevtools --help++To get help for a specific command, run:++    $ hdevtools [COMMAND] --help++For example:++    $ hdevtools check --help++### The `hdevtools` background process ###++The first time `hdevtools` runs a command, it will spawn a background process+that will remain running forever. You can check the status of this background+process by running:++    $ hdevtools --status++You can shutdown the background process by running:++    $ hdevtools --stop-server++Communication with the background process is done through a unix socket file.+The default name is `.hdevtools.sock`, in the current directory. This allows+you to use `hdevtools` with multiple projects simultaneously, without the+background processes getting in the way of each other.++You can use a different socket file name with the `--socket` option, which+should be used for each invocation of `hdevtools`. Remember that when telling+`hdevtools` to check a Haskell file, paths are relative to the path of the+background process, not your current directory. This can cause problems, and+therefore it is recommended that you leave the socket file as the default, and+always run `hdevtools` from the same directory.++### Specifying GHC Options ###++For most non-trivial projects, you will need to tell `hdevtools` about+additional GHC options that your project requires.++All `hdevtools` commands accept a `-g` flag for this purpose.++For example:++* Your project source code is in the directory `src`+* You want to use the GHC option `-Wall`+* You want to hide the package `transformers` to prevent conflicts++Invoke `hdevtools` with something like this:++    $ hdevtools check -g -isrc -g -Wall -g -hide-package -g transformers Foo.hs++Notice that a `-g` flag is inserted before each GHC option. Don't try to string+multiple GHC options together after a single `-g` flag:++This won't work:++    $ hdevtools check -g '-hide-package transformers' Foo.hs++The Vim plugins allow setting GHC options in the `g:hdevtools_options`+variable.  For example, for the above project, put the following in your+`.vimrc`:++    let g:hdevtools_options = '-g -isrc -g -Wall -g -hide-package -g transformers'++In general, you will need to pass to `hdevtools` the same GHC options that you+would pass to GHCi.++Credits+-------++`hdevtools` was inspired by [ghcmod][4], but has the advantage that due to its+client-server architecture it is much faster.++[1]: http://hackage.haskell.org/package/hdevtools+[2]: https://github.com/scrooloose/syntastic+[3]: https://github.com/bitc/vim-hdevtools+[4]: http://www.mew.org/~kazu/proj/ghc-mod/en/
hdevtools.cabal view
@@ -1,5 +1,5 @@ name:                hdevtools-version:             0.1.0.4+version:             0.1.0.5 synopsis:            Persistent GHC powered background server for FAST haskell development tools description:     'hdevtools' is a backend for text editor plugins, to allow for things such as@@ -60,7 +60,7 @@   build-depends:       base == 4.*,                        cmdargs,                        directory,-                       ghc,+                       ghc >= 7.2,                        ghc-paths,                        syb,                        network,
src/CommandArgs.hs view
@@ -8,6 +8,8 @@  import System.Console.CmdArgs.Implicit import System.Environment (getProgName)+import System.Info (arch, os)+import qualified Config  #ifdef CABAL import Data.Version (showVersion)@@ -22,6 +24,13 @@     "unknown-version (not built with cabal)" #endif +fullVersion :: String+fullVersion =+    concat+        [ programVersion+        , " (ghc-", Config.cProjectVersion, "-", arch, "-", os, ")"+        ]+ data HDevTools     = Admin         { socket :: Maybe FilePath@@ -35,6 +44,11 @@         , ghcOpts :: [String]         , file :: String         }+    | ModuleFile+        { socket :: Maybe FilePath+        , ghcOpts :: [String]+        , module_ :: String+        }     | Info         { socket :: Maybe FilePath         , ghcOpts :: [String]@@ -66,6 +80,13 @@     , file = ""     } +dummyModuleFile :: HDevTools+dummyModuleFile = ModuleFile+    { socket = Nothing+    , ghcOpts = []+    , module_ = ""+    }+ dummyInfo :: HDevTools dummyInfo = Info     { socket = Nothing@@ -99,6 +120,13 @@     , file     := def += typFile      += argPos 0 += opt ""     ] += help "Check a haskell source file for errors and warnings" +moduleFile :: Annotate Ann+moduleFile = record dummyModuleFile+    [ socket   := def += typFile += help "socket file to use"+    , ghcOpts  := def += typ "OPTION" += help "ghc options"+    , module_  := def += typ "MODULE" += argPos 0+    ] += help "Get the haskell source file corresponding to a module name"+ info :: Annotate Ann info = record dummyInfo     [ socket     := def += typFile += help "socket file to use"@@ -117,11 +145,11 @@     ] += help "Get the type of the expression at the specified line and column"  full :: String -> Annotate Ann-full progName = modes_ [admin += auto, check, info, type_]+full progName = modes_ [admin += auto, check, moduleFile, info, type_]         += helpArg [name "h", groupname "Help"]         += versionArg [groupname "Help"]         += program progName-        += summary (progName ++ ": " ++ programVersion)+        += summary (progName ++ ": " ++ fullVersion)  loadHDevTools :: IO HDevTools loadHDevTools = do
src/CommandLoop.hs view
@@ -6,6 +6,7 @@  import Control.Monad (when) import Data.IORef+import Data.List (find) import MonadUtils (MonadIO, liftIO) import System.Exit (ExitCode(ExitFailure, ExitSuccess)) import qualified ErrUtils@@ -109,6 +110,29 @@     liftIO $ case flag of         GHC.Succeeded -> clientSend (ClientExit ExitSuccess)         GHC.Failed -> clientSend (ClientExit (ExitFailure 1))+runCommand _ clientSend (CmdModuleFile moduleName) = do+    moduleGraph <- GHC.getModuleGraph+    case find (moduleSummaryMatchesModuleName moduleName) moduleGraph of+        Nothing ->+            liftIO $ mapM_ clientSend+                [ ClientStderr "Module not found"+                , ClientExit (ExitFailure 1)+                ]+        Just modSummary ->+            case GHC.ml_hs_file (GHC.ms_location modSummary) of+                Nothing ->+                    liftIO $ mapM_ clientSend+                        [ ClientStderr "Module does not have a source file"+                        , ClientExit (ExitFailure 1)+                        ]+                Just file ->+                    liftIO $ mapM_ clientSend+                        [ ClientStdout file+                        , ClientExit ExitSuccess+                        ]+    where+    moduleSummaryMatchesModuleName modName modSummary =+        modName == (GHC.moduleNameString . GHC.moduleName . GHC.ms_mod) modSummary runCommand state clientSend (CmdInfo file identifier) = do     result <- withWarnings state False $         getIdentifierInfo file identifier
src/Main.hs view
@@ -23,6 +23,7 @@     case args of         Admin {} -> doAdmin sock args         Check {} -> doCheck sock args+        ModuleFile {} -> doModuleFile sock args         Info {} -> doInfo sock args         Type {} -> doType sock args @@ -39,6 +40,10 @@         progName <- getProgName         hPutStrLn stderr "You must provide a command. See:"         hPutStrLn stderr $ progName ++ " --help"++doModuleFile :: FilePath -> HDevTools -> IO ()+doModuleFile sock args =+    serverCommand sock (CmdModuleFile (module_ args)) (ghcOpts args)  doFileCommand :: String -> (HDevTools -> Command) -> FilePath -> HDevTools -> IO () doFileCommand cmdName cmd sock args
src/Types.hs view
@@ -21,6 +21,7 @@  data Command     = CmdCheck FilePath+    | CmdModuleFile String     | CmdInfo FilePath String     | CmdType FilePath (Int, Int)     deriving (Read, Show)
+ test_all_hsenv.sh view
@@ -0,0 +1,2 @@+#!/bin/sh+./test_hsenv.sh `echo .hsenv_* | sed -e 's/.hsenv_//g'`
+ test_hsenv.sh view
@@ -0,0 +1,22 @@+#!/bin/bash++set -e++if [ $# -lt 1 ]+then+	echo "Usage:"+	echo "$0 <hsenv_name> [<hsenv_name2> ...]"+	exit 2+fi++for i in $*+do+	source .hsenv_$i/bin/activate+	cabal build+	export HDEVTOOLS=./dist_$i/build/hdevtools/hdevtools+	./tests/test_runner.sh+	deactivate_hsenv+done++echo+echo 'All Tests Passed in:' $*
+ tests/Child.hs view
@@ -0,0 +1,6 @@+module Child where++import Parent++child :: String+child = "child of " ++ parent
+ tests/Parent.hs view
@@ -0,0 +1,4 @@+module Parent where++parent :: String+parent = "parent"
+ tests/SampleError.hs view
@@ -0,0 +1,9 @@+-- Sample Module used for testing++-- This module should cause a compilation error:+--+-- Sample2.hs:9:1: parse error (possibly incorrect indentation)++module SampleError where++a = foo
+ tests/Simple.hs view
@@ -0,0 +1,7 @@+-- Sample Module used for testing++-- This module contains no errors or warnings+module Sample1 where++increment :: Int -> Int+increment x = x + 1
+ tests/test_module_file.sh view
@@ -0,0 +1,13 @@+#!/bin/sh++set -e++SOCK=`mktemp -u`++$HDEVTOOLS check --socket=$SOCK Child.hs++PARENT=`$HDEVTOOLS modulefile --socket=$SOCK Parent`++[ "$PARENT" = "./Parent.hs" ]++$HDEVTOOLS --socket=$SOCK --stop-server
+ tests/test_runner.sh view
@@ -0,0 +1,59 @@+#!/bin/sh++set -e++ALL_TESTS="\+	test_start_stop.sh \+	test_simple_check.sh \+	test_sample_error.sh \+	test_module_file.sh \+	"++if [ ! $HDEVTOOLS ]+then+	echo 'You must set the HDEVTOOLS environment variable to the path of the hdevtools binary'+	exit 1+fi++case "$HDEVTOOLS" in+	*/*)+		# Convert relative path to absolute:+		export HDEVTOOLS=`pwd`/$HDEVTOOLS+esac++echo $HDEVTOOLS++if [ $# -ne 0 ]+then+	TESTS=$*+else+	TESTS=$ALL_TESTS+	echo 'Running All Tests'+fi++echo '------------------------------------------------------------------------'++cd `dirname $0`++ERRORS=0+for i in $TESTS+do+	echo $i+	echo+	if sh $i+	then+		echo 'Test OK'+	else+		echo 'Test FAILED'+		ERRORS=`expr $ERRORS + 1`+	fi+	echo '------------------------------------------------------------------------'+done++if [ $ERRORS = 0 ]+then+	echo 'All Tests OK'+else+	echo $ERRORS 'FAILED Tests'+fi+exit $ERRORS
+ tests/test_sample_error.sh view
@@ -0,0 +1,16 @@+#!/bin/sh++set -e++SOCK=`mktemp -u`++EXPECTED_ERRORS='SampleError.hs:9:5: Not in scope: `foo'\'''++if ERRORS=`$HDEVTOOLS check --socket=$SOCK SampleError.hs`+then+	false+elsh+	[ "$ERRORS" = "$EXPECTED_ERRORS" ]+fi++$HDEVTOOLS --socket=$SOCK --stop-server
+ tests/test_simple_check.sh view
@@ -0,0 +1,11 @@+#!/bin/sh++set -e++SOCK=`mktemp -u`++ERRORS=`$HDEVTOOLS check --socket=$SOCK Simple.hs`++[ -z "$ERRORS" ]++$HDEVTOOLS --socket=$SOCK --stop-server
+ tests/test_start_stop.sh view
@@ -0,0 +1,20 @@+#!/bin/sh++set -e++SOCK=`mktemp -u`++echo '> Starting the server'+$HDEVTOOLS --socket=$SOCK --start-server++echo '> Checking status'+$HDEVTOOLS --socket=$SOCK --status++echo '> Checking that the socket file exists'+if [ ! -S $SOCK ]; then false; fi++echo '> Stopping the server'+$HDEVTOOLS --socket=$SOCK --stop-server++echo '> Checking that the socket file no longer exists'+if [ -e $SOCK ]; then false; fi