diff --git a/hsdev.cabal b/hsdev.cabal
--- a/hsdev.cabal
+++ b/hsdev.cabal
@@ -2,7 +2,7 @@
 --  see http://haskell.org/cabal/users-guide/
 
 name:                hsdev
-version:             0.1.4.0
+version:             0.1.4.1
 synopsis:            Haskell development library and tool with support of autocompletion, symbol info, go to declaration, find references etc.
 description:
   Haskell development library and tool with support of autocompletion, symbol info, go to declaration, find references, hayoo search etc.
@@ -113,6 +113,8 @@
     hlint >= 1.9.0 && < 2.0.0,
     HTTP >= 4000.2.0,
     lens >= 4.8,
+    lifted-base >= 0.2,
+    monad-control >= 1.0,
     monad-loops >= 0.4,
     mtl >= 2.2.0,
     MonadCatchIO-transformers >= 0.3.1,
@@ -126,6 +128,7 @@
     text >= 1.2.0,
     time >= 1.5.0,
     transformers >= 0.4.0,
+    transformers-base >= 0.4.0,
     uniplate >= 1.6.0,
     unordered-containers >= 0.2.0,
     vector >= 0.10.0
@@ -133,7 +136,7 @@
 executable hsdev
   main-is: hsdev.hs
   hs-source-dirs: tools
-  ghc-options: -threaded -Wall -fno-warn-tabs
+  ghc-options: -threaded -Wall -fno-warn-tabs "-with-rtsopts=-N4"
 
   build-depends:
     base >= 4.7 && < 5,
diff --git a/src/Control/Concurrent/Task.hs b/src/Control/Concurrent/Task.hs
--- a/src/Control/Concurrent/Task.hs
+++ b/src/Control/Concurrent/Task.hs
@@ -3,7 +3,7 @@
 module Control.Concurrent.Task (
 	Task(..), TaskException(..), TaskResult(..),
 	taskStarted, taskRunning, taskStopped, taskDone, taskFailed, taskCancelled,
-	taskWaitStart, taskWait, taskKill, taskCancel, taskStop,
+	taskWaitStart, taskWait, taskJoin, taskKill, taskCancel, taskStop,
 	runTask, runTask_, runTaskTry, runTaskError, forkTask, tryT,
 
 	-- * Reexports
@@ -37,8 +37,8 @@
 instance Functor TaskResult where
 	fmap f r = TaskResult {
 		taskResultEmpty = taskResultEmpty r,
-		taskResultTryRead = fmap (fmap (fmap f)) $ taskResultTryRead r,
-		taskResultTake = fmap (fmap f) $ taskResultTake r,
+		taskResultTryRead = fmap (fmap f) <$> taskResultTryRead r,
+		taskResultTake = fmap f <$> taskResultTake r,
 		taskResultFail = taskResultFail r }
 
 instance Functor Task where
@@ -72,6 +72,10 @@
 taskWait :: Task a -> IO (Either SomeException a)
 taskWait = taskResultTake . taskResult
 
+-- | Join task, rethrowing its exceptions
+taskJoin :: Task a -> IO a
+taskJoin = taskWait >=> either throwM return
+
 -- | Kill task
 taskKill :: Task a -> IO ()
 taskKill =
@@ -89,7 +93,7 @@
 taskStop :: Task a -> IO Bool
 taskStop t = do
 	cancelled <- taskCancel t
-	when (not cancelled) $ taskKill t
+	unless cancelled $ taskKill t
 	return cancelled
 
 runTask :: (MonadCatch m, MonadIO m, MonadIO n) => (m () -> n ()) -> m a -> n (Task a)
diff --git a/src/Control/Concurrent/Util.hs b/src/Control/Concurrent/Util.hs
--- a/src/Control/Concurrent/Util.hs
+++ b/src/Control/Concurrent/Util.hs
@@ -30,7 +30,7 @@
 withSync :: a -> ((a -> IO ()) -> IO b) -> IO a
 withSync v act = do
 	sync <- newEmptyMVar
-	void $ forkIO $ void $ act (putMVar sync) `onException` (putMVar sync v)
+	void $ forkIO $ void $ act (putMVar sync) `onException` putMVar sync v
 	takeMVar sync
 
 withSync_ :: (IO () -> IO a) -> IO ()
diff --git a/src/Control/Concurrent/Worker.hs b/src/Control/Concurrent/Worker.hs
--- a/src/Control/Concurrent/Worker.hs
+++ b/src/Control/Concurrent/Worker.hs
@@ -30,7 +30,7 @@
 	taskVar <- newEmptyMVar
 	let
 		start = forkTask $ do
-			run $ initialize $ processWork
+			run $ initialize processWork
 			processSkip
 		processWork = whileJust (liftM (fmap snd) $ liftIO $ getChan ch) id
 		processSkip = whileJust (liftM (fmap fst) $ getChan ch) taskStop
diff --git a/src/Data/Mark.hs b/src/Data/Mark.hs
--- a/src/Data/Mark.hs
+++ b/src/Data/Mark.hs
@@ -1,10 +1,10 @@
 {-# LANGUAGE ViewPatterns, OverloadedStrings, GeneralizedNewtypeDeriving, TypeSynonymInstances, FlexibleInstances, RankNTypes, MultiParamTypeClasses #-}
 
 module Data.Mark (
-	Point(..), point, (.-.), (.+.), till, Size, linesSize, stringSize,
+	Point(..), point, lineStart, (.-.), (.+.), till, Size, linesSize, stringSize,
 	Range(..), rangeLines, emptyRange,
 	line,
-	range, rangeSize, at,
+	range, rangeSize, expandLines, at,
 	-- * Mappings
 	Map(..), apply, back,
 	cut, insert,
@@ -17,7 +17,7 @@
 	Editable(..), measure,
 	-- * Actions
 	EditAction(..),
-	Replace(..), run
+	Replace(..), inverse, reverseEdits, run
 	) where
 
 import Prelude hiding (splitAt, length, lines, unlines)
@@ -69,6 +69,9 @@
 	| c < 0 = error "Column can't be less then zero"
 	| otherwise = Point l c
 
+lineStart :: Int -> Point
+lineStart l = point l 0
+
 -- | Range from "Point" to "Point"
 data Range = Range {
 	rangeFrom :: Point,
@@ -81,6 +84,9 @@
 	mempty = Point 0 0
 	l `mappend` r = r .+. l
 
+rangeLength :: Range -> Size
+rangeLength (Range f t) = t .-. f
+
 -- | Range from one @Point@ to another
 till :: Point -> Point -> Range
 l `till` r = Range (min l r) (max l r)
@@ -91,7 +97,7 @@
 
 -- | Distance in @n@ chars within one line
 stringSize :: Int -> Point
-stringSize n = Point 0 n
+stringSize = Point 0
 
 instance ToJSON Range where
 	toJSON (Range f t) = object ["from" .= f, "to" .= t]
@@ -119,6 +125,10 @@
 rangeSize :: Point -> Size -> Range
 rangeSize pt sz = range pt (sz .+. pt)
 
+-- | Expand range to contain full lines
+expandLines :: Range -> Range
+expandLines (Range (Point sline _) (Point eline _)) = Range (Point sline 0) (Point (succ eline) 0)
+
 -- | Get contents at specified range
 at :: Editable a => Contents a -> Range -> Contents a
 at cts r =
@@ -147,7 +157,7 @@
 
 instance Monoid Map where
 	mempty = Map $ iso id id
-	(Map l) `mappend` (Map r) = Map (r . l)
+	(Map l) `mappend` (Map r) = Map (l . r)
 
 -- | Apply mapping
 apply :: Map -> Range -> Range
@@ -157,6 +167,10 @@
 back :: Map -> Map
 back (Map f) = Map (from f)
 
+-- | Apply mapping to starting position only
+applyStart :: Map -> Range -> Range
+applyStart m r = rangeFrom (apply m r) `rangeSize` rangeLength r
+
 -- | Cut range mapping
 cut :: Range -> Map
 cut rgn = Map $ iso (cutRange rgn) (insertRange rgn)
@@ -174,7 +188,7 @@
 -- | Update second range position as if it was data inserted at first range
 insertRange :: Range -> Range -> Range
 insertRange (Range is ie) (Range s e) = Range
-	(if is <= s then (s .-. is) .+. ie else s)
+	(if is < s then (s .-. is) .+. ie else s)
 	(if is < e then (e .-. is) .+. ie else e)
 
 -- | Contents is list of lines
@@ -199,7 +213,7 @@
 editRange :: Range -> (Range -> Edit a) -> EditM a ()
 editRange rgn edit' = do
 	rgn' <- mapRange rgn
-	modify (`mappend` (edit' rgn'))
+	modify (`mappend` edit' rgn')
 
 -- | Get mapped range
 mapRange :: Range -> EditM a Range
@@ -287,7 +301,7 @@
 		erase' :: Editable a => Range -> Contents a -> Contents a
 		erase' rgn' cts = fst (splitCts (rangeFrom rgn') cts) `concatCts` snd (splitCts (rangeTo rgn') cts)
 
-	write pt cts = editRange (pt `rangeSize` measure cts') (\r -> Edit (write' r) (insert r)) where
+	write pt cts = editRange (pt `till` pt) (\r -> Edit (write' r) (insert $ rangeFrom r `rangeSize` measure cts')) where
 		cts' = lines cts
 		write' rgn' origin = prefix (before' `concatCts` suffix cts') `concatCts` after' where
 			(before', after') = splitCts (rangeFrom rgn') origin
@@ -308,8 +322,18 @@
 
 instance EditAction Replace where
 	erase rgn = Replace rgn mempty
-	write pt cts = Replace (range pt pt) cts
-	replace rgn cts = Replace rgn cts
+	write pt = Replace (range pt pt)
+	replace = Replace
+
+-- | Inverted operation - restores previous state
+inverse :: Editable s => Contents s -> Replace s a -> Replace s a
+inverse cts (Replace r s) = Replace (rangeFrom r `rangeSize` measure (lines s)) (unlines $ cts `at` r)
+
+-- | Reverse list of operations
+reverseEdits :: Editable s => Contents s -> [Replace s ()] -> [Replace s ()]
+reverseEdits cts rs = map (remap . inverse cts) $ reverse rs where
+	edit' = snd $ runEdit $ run rs
+	remap r = r { replaceRange = editMap edit' `applyStart` replaceRange r }
 
 -- | Run replace actions to get monadic action
 run :: Editable s => [Replace s ()] -> EditM s ()
diff --git a/src/HsDev/Client/Commands.hs b/src/HsDev/Client/Commands.hs
--- a/src/HsDev/Client/Commands.hs
+++ b/src/HsDev/Client/Commands.hs
@@ -12,7 +12,6 @@
 import Control.Monad.Catch (try, SomeException(..))
 import Control.Monad.Trans.Maybe
 import Data.Aeson hiding (Result, Error)
-import Data.Either
 import Data.List
 import Data.Maybe
 import qualified Data.Map as M
@@ -28,7 +27,6 @@
 import qualified HsDev.Cache.Structured as SC
 import HsDev.Commands
 import qualified HsDev.Database.Async as DB
-import HsDev.Scan
 import HsDev.Server.Message as M
 import HsDev.Server.Types
 import HsDev.Symbols
@@ -64,13 +62,6 @@
 		ghcOpts, docsFlag, inferFlag])
 		"scan sources"
 		scan',
-	cmd' "rescan" [] (sandboxes ++ [
-		manyReq $ projectArg `desc` "project path or .cabal",
-		manyReq $ fileArg `desc` "source file",
-		manyReq $ pathArg `desc` "path to rescan",
-		ghcOpts, docsFlag, inferFlag])
-		"rescan sources"
-		rescan',
 	cmdList' "remove" [] (sandboxes ++ [
 		projectArg `desc` "module project",
 		fileArg `desc` "module source file",
@@ -278,45 +269,6 @@
 					("path", Update.scanDirectory)],
 				map (Update.scanCabal (listArg "ghc" as)) cabals]
 
-		-- | Rescan data
-		rescan' :: [String] -> Opts String -> CommandActionT ()
-		rescan' _ as copts = do
-			cabals <- getSandboxes copts as
-			updateProcess copts as $ map (Update.scanCabal (listArg "ghc" as)) cabals
-
-			dbval <- getDb copts
-			let
-				fileMap = M.fromList $ mapMaybe toPair $
-					selectModules (byFile . view moduleId) dbval
-
-			(errors, filteredMods) <- liftM partitionEithers $ mapM runExceptT $ concat [
-				[do
-					p' <- findProject copts p
-					return $ M.fromList $ mapMaybe toPair $
-						selectModules (inProject p' . view moduleId) dbval |
-					p <- listArg "project" as],
-				[do
-					f' <- findPath copts f
-					maybe
-						(throwError $ commandStrMsg $ "Unknown file: " ++ f')
-						(return . M.singleton f')
-						(lookupFile f' dbval) |
-					f <- listArg "file" as],
-				[do
-					d' <- findPath copts d
-					return $ M.filterWithKey (\f _ -> isParent d' f) fileMap |
-					d <- listArg "path" as]]
-			let
-				rescanMods = map (getInspected dbval) $
-					M.elems $ if null filteredMods then fileMap else M.unions filteredMods
-
-			if not (null errors)
-				then commandError (intercalate ", " [err | CommandError err _ <- errors]) (concat [ps | CommandError _ ps <- errors])
-				else updateProcess copts as [Update.runTask "rescanning modules" [] $ do
-					needRescan <- Update.liftExceptT $ filterM (changedModule dbval (listArg "ghc" as) . view inspectedId) rescanMods
-					Update.scanModules (listArg "ghc" as)
-						(map (view inspectedId &&& fromMaybe [] . preview (inspection . inspectionOpts)) needRescan)]
-
 		-- | Remove data
 		remove' :: [String] -> Opts String -> CommandActionT [ModuleId]
 		remove' _ as copts = do
@@ -438,7 +390,7 @@
 			case rs of
 				[] -> commandError "Module not found" []
 				[m] -> return m
-				ms' -> commandError "Ambiguous modules" ["modules" .= (map (view moduleId) ms')]
+				ms' -> commandError "Ambiguous modules" ["modules" .= map (view moduleId) ms']
 
 		-- | Resolve module scope
 		resolve' :: [String] -> Opts String -> CommandActionT Module
@@ -463,7 +415,7 @@
 			case rs of
 				[] -> commandError "Module not found" []
 				[m] -> return $ getScope $ resolveOne cabaldb m
-				ms' -> commandError "Ambiguous modules" ["modules" .= (map (view moduleId) ms')]
+				ms' -> commandError "Ambiguous modules" ["modules" .= map (view moduleId) ms']
 
 		-- | Get project info
 		project' :: [String] -> Opts String -> CommandActionT Project
@@ -576,9 +528,9 @@
 			column' <- maybe (commandError "column must be a number" []) return $ readMaybe column
 			dbval <- getDb copts
 			(srcFile, cabal) <- getCtx copts as
-			(srcFile', _, _) <- mapCommandErrorStr $ fileCtx dbval srcFile
+			(srcFile', m', _) <- mapCommandErrorStr $ fileCtx dbval srcFile
 			mapCommandErrorStr $ GhcMod.waitMultiGhcMod (commandGhcMod copts) srcFile' $
-				GhcMod.typeOf (listArg "ghc" as) cabal srcFile' line' column'
+				GhcMod.typeOf (listArg "ghc" as ++ moduleOpts (allPackages dbval) m') cabal srcFile' line' column'
 		ghcmodType' [] _ _ = commandError "Specify line" []
 		ghcmodType' _ _ _ = commandError "Too much arguments" []
 
@@ -589,9 +541,11 @@
 			files' <- mapM (findPath copts) files
 			mproj <- (listToMaybe . catMaybes) <$> liftIO (mapM locateProject files')
 			cabal <- getCabal copts as
-			mapCommandErrorStr $ liftM concat $ forM files' $ \file' ->
+			dbval <- getDb copts
+			mapCommandErrorStr $ liftM concat $ forM files' $ \file' -> do
+				(_, m', _) <- fileCtx dbval file'
 				GhcMod.waitMultiGhcMod (commandGhcMod copts) file' $
-					GhcMod.check (listArg "ghc" as) cabal [file'] mproj
+					GhcMod.check (listArg "ghc" as ++ moduleOpts (allPackages dbval) m') cabal [file'] mproj
 
 		-- | Ghc-mod lint
 		ghcmodLint' :: [String] -> Opts String -> CommandActionT [Tools.Note Tools.OutputMessage]
@@ -609,9 +563,11 @@
 			files' <- mapM (findPath copts) files
 			mproj <- (listToMaybe . catMaybes) <$> liftIO (mapM locateProject files')
 			cabal <- getCabal copts as
-			mapCommandErrorStr $ liftM concat $ forM files' $ \file' ->
+			dbval <- getDb copts
+			mapCommandErrorStr $ liftM concat $ forM files' $ \file' -> do
+				(_, m', _) <- fileCtx dbval file'
 				GhcMod.waitMultiGhcMod (commandGhcMod copts) file' $ do
-					checked <- GhcMod.check (listArg "ghc" as) cabal [file'] mproj
+					checked <- GhcMod.check (listArg "ghc" as ++ moduleOpts (allPackages dbval) m') cabal [file'] mproj
 					linted <- GhcMod.lint (listArg "hlint" as) file'
 					return $ checked ++ linted
 
@@ -795,14 +751,16 @@
 -- | Find dependency: it may be source, project file or project name, also returns sandbox found
 findDep :: MonadIO m => CommandOptions -> String -> ExceptT CommandError m (Project, Maybe FilePath, Cabal)
 findDep copts depName = do
+	depPath <- findPath copts depName
 	proj <- msum [
 		mapCommandErrorStr $ do
-			p <- liftIO (locateProject depName)
+			p <- liftIO (locateProject depPath)
 			maybe (throwError $ "Project " ++ depName ++ " not found") (mapExceptT liftIO . loadProject) p,
 		findProject copts depName]
-	src <- if takeExtension depName == ".hs"
-		then liftM Just (findPath copts depName)
-		else return Nothing
+	let
+		src
+			| takeExtension depPath == ".hs" = Just depPath
+			| otherwise = Nothing
 	sbox <- liftIO $ searchSandbox $ view projectPath proj
 	return (proj, src, sbox)
 
@@ -812,12 +770,6 @@
 	deps' = case src of
 		Nothing -> inDepsOfProject proj
 		Just src' -> inDepsOfFile proj src'
-
--- | Supply module with its source file path if any
-toPair :: Module -> Maybe (FilePath, Module)
-toPair m = case view moduleLocation m of
-	FileModule f _ -> Just (f, m)
-	_ -> Nothing
 
 -- | Wait for DB to complete update
 waitDb :: CommandOptions -> Opts String -> CommandM ()
diff --git a/src/HsDev/Commands.hs b/src/HsDev/Commands.hs
--- a/src/HsDev/Commands.hs
+++ b/src/HsDev/Commands.hs
@@ -153,7 +153,7 @@
 -- | Check whether module is visible from source file
 visibleFrom :: Maybe Project -> Module -> ModuleId -> Bool
 visibleFrom (Just p) this m = visible p (view moduleId this) m
-visibleFrom Nothing this m = (view moduleId this) == m || byCabal m
+visibleFrom Nothing this m = view moduleId this == m || byCabal m
 
 -- | Split identifier into module name and identifier itself
 splitIdentifier :: String -> (Maybe String, String)
diff --git a/src/HsDev/Database.hs b/src/HsDev/Database.hs
--- a/src/HsDev/Database.hs
+++ b/src/HsDev/Database.hs
@@ -2,7 +2,7 @@
 
 module HsDev.Database (
 	Database(..),
-	databaseIntersection, nullDatabase, databaseLocals, allModules, allDeclarations,
+	databaseIntersection, nullDatabase, databaseLocals, allModules, allDeclarations, allPackages,
 	fromModule, fromProject,
 	filterDB,
 	projectDB, cabalDB, standaloneDB,
@@ -17,7 +17,7 @@
 	Map
 	) where
 
-import Control.Lens (set, view)
+import Control.Lens (set, view, preview, _Just)
 import Control.Monad (msum, join)
 import Control.DeepSeq (NFData(..))
 import Data.Aeson
@@ -94,6 +94,10 @@
 	m <- allModules db
 	moduleModuleDeclarations m
 
+-- | All packages
+allPackages :: Database -> [ModulePackage]
+allPackages = ordNub . mapMaybe (preview (moduleLocation . modulePackage . _Just)) . allModules
+
 -- | Make database from module
 fromModule :: InspectedModule -> Database
 fromModule m = zero {
@@ -120,7 +124,7 @@
 
 -- | Standalone database
 standaloneDB :: Database -> Database
-standaloneDB db = filterDB (check') (const False) db where
+standaloneDB db = filterDB check' (const False) db where
 	check' m = standalone m && byFile m
 
 -- | Select module by predicate
diff --git a/src/HsDev/Database/Update.hs b/src/HsDev/Database/Update.hs
--- a/src/HsDev/Database/Update.hs
+++ b/src/HsDev/Database/Update.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE FlexibleContexts, GeneralizedNewtypeDeriving, OverloadedStrings, MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleContexts, OverloadedStrings, MultiParamTypeClasses #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module HsDev.Database.Update (
@@ -23,12 +23,15 @@
 	module Control.Monad.Except
 	) where
 
+import Control.Concurrent.Lifted (fork)
+import Control.DeepSeq
 import Control.Lens (preview, _Just, view)
 import Control.Monad.Catch
 import Control.Monad.CatchIO
 import Control.Monad.Except
 import Control.Monad.Reader
 import Control.Monad.Writer
+import Control.Monad.Trans.Control
 import Data.Aeson
 import Data.Aeson.Types
 import qualified Data.HashMap.Strict as HM
@@ -60,7 +63,7 @@
 isStatus = isJust . parseMaybe (parseJSON :: Value -> Parser Task)
 
 -- | Run `UpdateDB` monad
-updateDB :: MonadCatchIO m => Settings -> ExceptT String (UpdateDB m) () -> m ()
+updateDB :: (MonadBaseControl IO m, MonadCatchIO m) => Settings -> ExceptT String (UpdateDB m) () -> m ()
 updateDB sets act = Log.scopeLog (settingsLogger sets) "update" $ do
 	updatedMods <- execWriterT (runUpdateDB (runExceptT act' >> return ()) `runReaderT` sets)
 	wait $ database sets
@@ -80,21 +83,22 @@
 			mlocs' <- liftM (filter (isJust . preview moduleFile) . snd) $ listen act
 			wait $ database sets
 			let
+				getMods :: (MonadIO m) => m [InspectedModule]
 				getMods = do
 					db' <- liftIO $ readAsync $ database sets
 					return $ catMaybes [M.lookup mloc' (databaseModules db') | mloc' <- mlocs']
 			when (updateDocs sets) $ do
-				Log.log Log.Trace "inspecting source docs"
-				(getMods >>= waiter . runTask "inspecting source docs" [] . runTasks . map scanDocs)
+				Log.log Log.Trace "forking inspecting source docs"
+				void $ fork (getMods >>= waiter . mapM_ scanDocs)
 			when (runInferTypes sets) $ do
-				Log.log Log.Trace "inferring types"
-				(getMods >>= waiter . runTask "inferring types" [] . runTasks . map inferModTypes)
-		scanDocs :: MonadIO m => InspectedModule -> ExceptT String (UpdateDB m) ()
-		scanDocs im = runTask "scanning docs" (subject (view inspectedId im) ["module" .= view inspectedId im]) $ do
+				Log.log Log.Trace "forking inferring types"
+				void $ fork (getMods >>= waiter . mapM_ inferModTypes)
+		scanDocs :: (MonadIO m, MonadReader Settings m, MonadWriter [ModuleLocation] m) => InspectedModule -> ExceptT String m ()
+		scanDocs im = do
 			im' <- liftExceptT $ S.scanModify (\opts _ -> inspectDocs opts) im
 			updater $ return $ fromModule im'
-		inferModTypes :: MonadIO m => InspectedModule -> ExceptT String (UpdateDB m) ()
-		inferModTypes im = runTask "inferring types" (subject (view inspectedId im) ["module" .= view inspectedId im]) $ do
+		inferModTypes :: (MonadIO m, MonadReader Settings m, MonadWriter [ModuleLocation] m) => InspectedModule -> ExceptT String m ()
+		inferModTypes im = do
 			-- TODO: locate sandbox
 			im' <- liftExceptT $ S.scanModify infer' im
 			updater $ return $ fromModule im'
@@ -122,15 +126,15 @@
 updater act = do
 	db <- asks database
 	db' <- act
-	update db $ return db'
-	tell $ map (view moduleLocation) $ allModules db'
+	update db $ return $!! db'
+	tell $!! map (view moduleLocation) $ allModules db'
 
 -- | Clear obsolete data from database
 cleaner :: (MonadIO m, MonadReader Settings m, MonadWriter [ModuleLocation] m) => m Database -> m ()
 cleaner act = do
 	db <- asks database
 	db' <- act
-	clear db $ return db'
+	clear db $ return $!! db'
 
 -- | Get data from cache without updating DB
 loadCache :: (MonadIO m, MonadReader Settings m, MonadWriter [ModuleLocation] m) => (FilePath -> ExceptT String IO Structured) -> m Database
@@ -216,7 +220,7 @@
 					return $ FileModule fpath' mproj
 			return [(mloc, [])]
 		False -> return []
-	mapM_ (watch watchModule) $ map fst mlocs
+	mapM_ watch [(`watchModule` m) | (m, _) <- mlocs]
 	scan
 		(Cache.loadFiles (== fpath'))
 		(filterDB (inFile fpath') (const False) . standaloneDB)
@@ -229,7 +233,7 @@
 -- | Scan cabal modules
 scanCabal :: (MonadIO m, MonadCatch m) => [String] -> Cabal -> ExceptT String (UpdateDB m) ()
 scanCabal opts cabalSandbox = runTask "scanning" (subject cabalSandbox ["sandbox" .= cabalSandbox]) $ do
-	watch watchSandbox cabalSandbox
+	watch (\w -> watchSandbox w cabalSandbox opts)
 	mlocs <- runTask "getting list of cabal modules" [] $ 
 		liftExceptT $ listModules opts cabalSandbox
 	scan (Cache.loadCabal cabalSandbox) (cabalDB cabalSandbox) (zip mlocs $ repeat []) opts $ \mlocs' -> do
@@ -250,7 +254,7 @@
 scanProject :: (MonadIO m, MonadCatch m) => [String] -> FilePath -> ExceptT String (UpdateDB m) ()
 scanProject opts cabal = runTask "scanning" (subject (project cabal) ["project" .= cabal]) $ do
 	proj <- scanProjectFile opts cabal
-	watch watchProject proj
+	watch (\w -> watchProject w proj opts)
 	(_, sources) <- liftExceptT $ S.enumProject proj
 	scan (Cache.loadProject $ view projectCabal proj) (projectDB proj) sources opts $ \ms -> do
 		scanModules opts ms
@@ -263,7 +267,7 @@
 		liftExceptT $ S.enumDirectory dir
 	runTasks [scanProject opts (view projectCabal p) | (p, _) <- projSrcs]
 	runTasks $ map (scanCabal opts) sboxes
-	mapM_ (watch watchModule) $ map fst standSrcs
+	mapM_ watch [(`watchModule` m) | (m, _) <- standSrcs]
 	scan (Cache.loadFiles (dir `isParent`)) (filterDB inDir (const False) . standaloneDB) standSrcs opts $ scanModules opts
 	where
 		inDir = maybe False (dir `isParent`) . preview (moduleIdLocation . moduleFile)
@@ -292,25 +296,35 @@
 instance Format Cabal where
 
 updateEvent :: (MonadIO m, MonadCatch m, MonadCatchIO m) => Watched -> Event -> ExceptT String (UpdateDB m) ()
-updateEvent (WatchedProject proj) e
+updateEvent (WatchedProject proj projOpts) e
 	| isSource e = do
 		Log.log Log.Info $ "File '${file}' in project ${proj} changed" ~~
 			("file" %= view eventPath e) %
 			("proj" %= view projectName proj)
-		scanFile [] $ view eventPath e
+		dbval <- readDB
+		let
+			opts = fromMaybe [] $ do
+				m <- lookupFile (view eventPath e) dbval
+				preview (inspection . inspectionOpts) $ getInspected dbval m
+		scanFile opts $ view eventPath e
 	| isCabal e = do
 		Log.log Log.Info $ "Project ${proj} changed" ~~ ("proj" %= view projectName proj)
-		scanProject [] $ view projectCabal proj
+		scanProject projOpts $ view projectCabal proj
 	| otherwise = return ()
-updateEvent (WatchedSandbox cabal) e
+updateEvent (WatchedSandbox cabal cabalOpts) e
 	| isConf e = do
 		Log.log Log.Info $ "Sandbox ${cabal} changed" ~~ ("cabal" %= cabal)
-		scanCabal [] cabal
+		scanCabal cabalOpts cabal
 	| otherwise = return ()
 updateEvent WatchedModule e
 	| isSource e = do
 		Log.log Log.Info $ "Module ${file} changed" ~~ ("file" %= view eventPath e)
-		scanFile [] $ view eventPath e
+		dbval <- readDB
+		let
+			opts = fromMaybe [] $ do
+				m <- lookupFile (view eventPath e) dbval
+				preview (inspection . inspectionOpts) $ getInspected dbval m
+		scanFile opts $ view eventPath e
 	| otherwise = return ()
 
 processEvent :: Settings -> Watched -> Event -> IO ()
@@ -323,7 +337,7 @@
 subject :: Display a => a -> [Pair] -> [Pair]
 subject x ps = ["name" .= display x, "type" .= displayType x] ++ ps
 
-watch :: (MonadIO m, MonadReader Settings m) => (Watcher -> a -> IO ()) -> a -> m ()
-watch f x = do
+watch :: (MonadIO m, MonadReader Settings m) => (Watcher -> IO ()) -> m ()
+watch f = do
 	w <- asks settingsWatcher
-	liftIO $ f w x
+	liftIO $ f w
diff --git a/src/HsDev/Database/Update/Types.hs b/src/HsDev/Database/Update/Types.hs
--- a/src/HsDev/Database/Update/Types.hs
+++ b/src/HsDev/Database/Update/Types.hs
@@ -1,15 +1,17 @@
-{-# LANGUAGE GeneralizedNewtypeDeriving, OverloadedStrings #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving, OverloadedStrings, FlexibleInstances, MultiParamTypeClasses, TypeFamilies, UndecidableInstances #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module HsDev.Database.Update.Types (
 	Status(..), Progress(..), Task(..), Settings(..), settings, UpdateDB(..)
 	) where
 
+import Control.Monad.Base
 import Control.Monad.Catch
 import Control.Monad.CatchIO
 import Control.Monad.Except
 import Control.Monad.Reader
 import Control.Monad.Writer
+import Control.Monad.Trans.Control
 import Data.Aeson
 import qualified System.Log.Simple as Log
 
@@ -111,3 +113,11 @@
 
 instance Log.MonadLog m => Log.MonadLog (ExceptT e m) where
 	askLog = lift Log.askLog
+
+instance MonadBase b m => MonadBase b (UpdateDB m) where
+	liftBase = UpdateDB . liftBase
+
+instance MonadBaseControl b m => MonadBaseControl b (UpdateDB m) where
+	type StM (UpdateDB m) a = StM (ReaderT Settings (WriterT [ModuleLocation] m)) a
+	liftBaseWith f = UpdateDB $ liftBaseWith (\f' -> f (f' . runUpdateDB))
+	restoreM = UpdateDB . restoreM
diff --git a/src/HsDev/Inspect.hs b/src/HsDev/Inspect.hs
--- a/src/HsDev/Inspect.hs
+++ b/src/HsDev/Inspect.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE TypeSynonymInstances, ViewPatterns #-}
+{-# LANGUAGE TypeSynonymInstances #-}
 
 module HsDev.Inspect (
 	analyzeModule, inspectDocsChunk, inspectDocs,
@@ -82,7 +82,7 @@
 			offsets = scanl (+) 0 $ map length parts'
 		break' :: [String] -> Maybe ([String], [String])
 		break' [] = Nothing
-		break' (l:ls) = Just $ first (l:) $ break (not . maybe True isSpace . listToMaybe) ls
+		break' (l:ls) = Just $ first (l:) $ span (maybe True isSpace . listToMaybe) ls
 
 		parseModuleName :: String -> Either String String
 		parseModuleName cts = maybe (Left "match fail") Right $ do
@@ -193,7 +193,7 @@
 	H.RecDecl n fields -> mkFun loc n (Function (Just $ oneLinePrint $ map snd fields `tyFun` dataRes) [] Nothing) : concatMap (uncurry (getRec loc dataRes)) fields
 	where
 		dataRes :: H.Type
-		dataRes = foldr H.TyApp (H.TyCon (H.UnQual t)) $ map (H.TyVar . nameOf) as where
+		dataRes = foldr (H.TyApp . H.TyVar . nameOf) (H.TyCon (H.UnQual t)) as where
 			nameOf :: H.TyVarBind -> H.Name
 			nameOf (H.KindedVar n' _) = n'
 			nameOf (H.UnkindedVar n') = n'
@@ -296,7 +296,7 @@
 	docsMap <- liftE $ if hdocsWorkaround
 		then hdocsProcess (fromMaybe (T.unpack $ view moduleName m) (preview (moduleLocation . moduleFile) m)) opts
 		else liftM Just $ hdocs (view moduleLocation m) opts
-	return $ maybe id addDocs docsMap $ m
+	return $ maybe id addDocs docsMap m
 
 -- | Inspect contents
 inspectContents :: String -> [String] -> String -> ExceptT String IO InspectedModule
@@ -366,4 +366,4 @@
 	modules <- mapM inspectFile' srcs
 	return (p', catMaybes modules)
 	where
-		inspectFile' exts = liftM return (inspectFile (opts ++ extensionsOpts (view extensions exts)) (view entity exts)) <|> return Nothing
+		inspectFile' exts = liftM return (inspectFile (opts ++ extensionsOpts exts) (view entity exts)) <|> return Nothing
diff --git a/src/HsDev/Project.hs b/src/HsDev/Project.hs
--- a/src/HsDev/Project.hs
+++ b/src/HsDev/Project.hs
@@ -12,8 +12,8 @@
 	libraryModules, libraryBuildInfo,
 	executableName, executablePath, executableBuildInfo,
 	testName, testEnabled, testBuildInfo,
-	infoDepends, infoLanguage, infoExtensions, infoSourceDirs,
-	extensions, entity,
+	infoDepends, infoLanguage, infoExtensions, infoGHCOptions, infoSourceDirs,
+	extensions, ghcOptions, entity,
 
 	-- * Helpers
 	showExtension, flagExtension, extensionFlag,
@@ -30,6 +30,7 @@
 import Data.List
 import Data.Maybe
 import Data.Ord
+import Distribution.Compiler (CompilerFlavor(GHC))
 import qualified Distribution.Package as P
 import qualified Distribution.PackageDescription as PD
 import Distribution.PackageDescription.Parse
@@ -190,6 +191,7 @@
 	_infoDepends :: [String],
 	_infoLanguage :: Maybe Language,
 	_infoExtensions :: [Extension],
+	_infoGHCOptions :: [String],
 	_infoSourceDirs :: [FilePath] }
 		deriving (Eq, Read)
 
@@ -203,11 +205,14 @@
 	set' i dirs = i { _infoSourceDirs = dirs }
 
 instance Show Info where
-	show i = unlines $ lang ++ exts ++ sources where
+	show i = unlines $ lang ++ exts ++ opts ++ sources where
 		lang = maybe [] (\l -> ["default-language: " ++ display l]) $ _infoLanguage i
 		exts
 			| null (_infoExtensions i) = []
-			| otherwise = ["extensions:"] ++ map (tab 1) (map display (_infoExtensions i))
+			| otherwise = ["extensions:"] ++ map (tab 1 . display) (_infoExtensions i)
+		opts
+			| null (_infoGHCOptions i) = []
+			| otherwise = ["ghc-options:"] ++ map (tab 1) (_infoGHCOptions i)
 		sources = ["source-dirs:"] ++
 			(map (tab 1) $ _infoSourceDirs i)
 
@@ -216,6 +221,7 @@
 		"build-depends" .= _infoDepends i,
 		"language" .= fmap display (_infoLanguage i),
 		"extensions" .= map display (_infoExtensions i),
+		"ghc-options" .= _infoGHCOptions i,
 		"source-dirs" .= _infoSourceDirs i]
 
 instance FromJSON Info where
@@ -223,6 +229,7 @@
 		v .: "build-depends" <*>
 		((v .:: "language") >>= traverse (parseDT "Language")) <*>
 		((v .:: "extensions") >>= traverse (parseDT "Extension")) <*>
+		v .:: "ghc-options" <*>
 		v .:: "source-dirs"
 
 -- | Analyze cabal file
@@ -241,6 +248,7 @@
 			_infoDepends = map pkgName (PD.targetBuildDepends info),
 			_infoLanguage = PD.defaultLanguage info,
 			_infoExtensions = PD.defaultExtensions info,
+			_infoGHCOptions = fromMaybe [] $ lookup GHC (PD.options info),
 			_infoSourceDirs = PD.hsSourceDirs info }
 
 		pkgName :: P.Dependency -> String
@@ -300,6 +308,7 @@
 -- | Entity with project extensions
 data Extensions a = Extensions {
 	_extensions :: [Extension],
+	_ghcOptions :: [String],
 	_entity :: a }
 		deriving (Eq, Read, Show)
 
@@ -307,22 +316,23 @@
 	compare = comparing _entity
 
 instance Functor Extensions where
-	fmap f (Extensions e x) = Extensions e (f x)
+	fmap f (Extensions e o x) = Extensions e o (f x)
 
 instance Applicative Extensions where
-	pure = Extensions []
-	(Extensions l f) <*> (Extensions r x) = Extensions (l ++ r) (f x)
+	pure = Extensions [] []
+	(Extensions l lo f) <*> (Extensions r ro x) = Extensions (ordNub $ l ++ r) (ordNub $ lo ++ ro) (f x)
 
 instance Foldable Extensions where
-	foldMap f (Extensions _ x) = f x
+	foldMap f (Extensions _ _ x) = f x
 
 instance Traversable Extensions where
-	traverse f (Extensions e x) = Extensions e <$> f x
+	traverse f (Extensions e o x) = Extensions e o <$> f x
 
 -- | Extensions for target
 withExtensions :: a -> Info -> Extensions a
 withExtensions x i = Extensions {
 	_extensions = _infoExtensions i,
+	_ghcOptions = _infoGHCOptions i,
 	_entity = x }
 
 -- | Returns build targets infos
@@ -374,8 +384,8 @@
 extensionFlag = ("-X" ++)
 
 -- | Extensions as opts to GHC
-extensionsOpts :: [Extension] -> [String]
-extensionsOpts = map (extensionFlag . showExtension)
+extensionsOpts :: Extensions a -> [String]
+extensionsOpts e = map (extensionFlag . showExtension) (_extensions e) ++ _ghcOptions e
 
 makeLenses ''Project
 makeLenses ''ProjectDescription
diff --git a/src/HsDev/Scan.hs b/src/HsDev/Scan.hs
--- a/src/HsDev/Scan.hs
+++ b/src/HsDev/Scan.hs
@@ -62,7 +62,7 @@
 				["-package " ++ view projectName p'],
 				["-package " ++ dep | dep <- view infoDepends i, dep `elem` pkgs]]
 	srcs <- projectSources p'
-	return (p', [(FileModule (view entity src) (Just p'), extensionsOpts (view extensions src) ++ projOpts (view entity src)) | src <- srcs])
+	return (p', [(FileModule (view entity src) (Just p'), extensionsOpts src ++ projOpts (view entity src)) | src <- srcs])
 
 -- | Enum directory modules
 enumDirectory :: FilePath -> ExceptT String IO ScanContents
@@ -76,7 +76,7 @@
 	projs <- triesMap (enumProject . project) projects
 	let
 		projPaths = map (view projectPath . fst) projs
-		standalone = map (\f -> FileModule f Nothing) $ filter (\s -> not (any (`isParent` s) projPaths)) sources
+		standalone = map ((`FileModule` Nothing)) $ filter (\s -> not (any (`isParent` s) projPaths)) sources
 	return $ ScanContents {
 		modulesToScan = [(s, []) | s <- standalone],
 		projectsToScan = projs,
@@ -129,4 +129,4 @@
 
 -- | Returns new (to scan) and changed (to rescan) modules
 changedModules :: Database -> [String] -> [ModuleToScan] -> ExceptT String IO [ModuleToScan]
-changedModules db opts ms = filterM (\(m, opts') -> changedModule db (opts ++ opts') m) ms
+changedModules db opts = filterM (\ (m, opts') -> changedModule db (opts ++ opts') m)
diff --git a/src/HsDev/Scan/Browse.hs b/src/HsDev/Scan/Browse.hs
--- a/src/HsDev/Scan/Browse.hs
+++ b/src/HsDev/Scan/Browse.hs
@@ -39,7 +39,7 @@
 
 -- | Browse packages
 browsePackages :: [String] -> Cabal -> ExceptT String IO [ModulePackage]
-browsePackages opts cabal = liftIOErrors $ withPackages (cabalOpt cabal ++ opts) $ \dflags -> do
+browsePackages opts cabal = liftIOErrors $ withPackages (cabalOpt cabal ++ opts) $ \dflags ->
 	return $ mapMaybe readPackage $ fromMaybe [] $ GHC.pkgDatabase dflags
 
 listModules :: [String] -> Cabal -> ExceptT String IO [ModuleLocation]
diff --git a/src/HsDev/Symbols.hs b/src/HsDev/Symbols.hs
--- a/src/HsDev/Symbols.hs
+++ b/src/HsDev/Symbols.hs
@@ -22,8 +22,7 @@
 	Canonicalize(..),
 	locateProject, searchProject,
 	locateSourceDir,
-	sourceModuleRoot,
-	importedModulePath,
+	moduleOpts,
 
 	-- * Modifiers
 	addDeclaration,
@@ -47,7 +46,7 @@
 import Data.Maybe (fromMaybe)
 import Data.Ord (comparing)
 import Data.Text (Text)
-import qualified Data.Text as T (concat, split, unpack)
+import qualified Data.Text as T (concat)
 import System.Directory
 import System.FilePath
 
@@ -213,22 +212,24 @@
 	proj <- MaybeT $ fmap (either (const Nothing) Just) $ runExceptT $ loadProject p
 	MaybeT $ return $ findSourceDir proj file
 
--- | Get source module root directory, i.e. for "...\src\Foo\Bar.hs" with module 'Foo.Bar' will return "...\src"
-sourceModuleRoot :: Text -> FilePath -> FilePath
-sourceModuleRoot mname = 
-	joinPath .
-	reverse . drop (length $ T.split (== '.') mname) . reverse .
-	splitDirectories
-
--- | Get path of imported module
--- >importedModulePath "Foo.Bar" "...\src\Foo\Bar.hs" "Quux.Blah" = "...\src\Quux\Blah.hs"
-importedModulePath :: Text -> FilePath -> Text -> FilePath
-importedModulePath mname file imp =
-	(`addExtension` "hs") . joinPath .
-	(++ ipath) . splitDirectories $
-	sourceModuleRoot mname file
-	where
-		ipath = map T.unpack $ T.split (== '.') imp
+-- | Options for GHC of module and project
+moduleOpts :: [ModulePackage] -> Module -> [String]
+moduleOpts pkgs m = case view moduleLocation m of
+	FileModule file proj -> concat [
+		["-i" ++ s | s <- srcDirs],
+		concatMap extensionsOpts exts,
+		hidePackages,
+		["-package " ++ p | p <- deps, p `elem` pkgs']]
+		where
+			infos' = maybe [] (`fileTargets` file) proj
+			srcDirs = concatMap (view infoSourceDirs) infos'
+			exts = map (file `withExtensions`) infos'
+			deps = concatMap (view infoDepends) infos'
+			pkgs' = map (view packageName) pkgs
+			hidePackages
+				| null infos' = []
+				| otherwise = ["-hide-all-packages"]
+	_ -> []
 
 -- | Add declaration to module
 addDeclaration :: Declaration -> Module -> Module
diff --git a/src/HsDev/Symbols/Location.hs b/src/HsDev/Symbols/Location.hs
--- a/src/HsDev/Symbols/Location.hs
+++ b/src/HsDev/Symbols/Location.hs
@@ -11,6 +11,8 @@
 	regionFrom, regionTo,
 	locationModule, locationPosition,
 
+	sourceModuleRoot,
+	importedModulePath,
 	packageOpt,
 	RecalcTabs(..),
 
@@ -25,6 +27,9 @@
 import Data.Char (isSpace, isDigit)
 import Data.List (intercalate, findIndex)
 import Data.Maybe
+import Data.Text (Text)
+import qualified Data.Text as T (split, unpack)
+import System.FilePath
 import Text.Read (readMaybe)
 
 import HsDev.Cabal
@@ -140,13 +145,9 @@
 
 -- | Get string at region
 regionStr :: Region -> String -> String
-regionStr r@(Region f t) s = intercalate "\n" $ drop (pred $ view positionColumn f) fline' : tl where
+regionStr r@(Region f t) s = intercalate "\n" $ drop (pred $ view positionColumn f) fline : tl where
 	s' = take (regionLines r) $ drop (pred (view positionLine f)) $ lines s
 	(fline:tl) = init s' ++ [take (pred $ view positionColumn t) (last s')]
-	fline' = concatMap untab fline where
-		untab :: Char -> String
-		untab '\t' = replicate 8 ' '
-		untab ch = [ch]
 
 instance NFData Region where
 	rnf (Region f t) = rnf f `seq` rnf t
@@ -188,15 +189,35 @@
 		v .:: "module" <*>
 		v .:: "pos"
 
+-- | Get source module root directory, i.e. for "...\src\Foo\Bar.hs" with module 'Foo.Bar' will return "...\src"
+sourceModuleRoot :: Text -> FilePath -> FilePath
+sourceModuleRoot mname = 
+	joinPath .
+	reverse . drop (length $ T.split (== '.') mname) . reverse .
+	splitDirectories
+
+-- | Get path of imported module
+-- >importedModulePath "Foo.Bar" "...\src\Foo\Bar.hs" "Quux.Blah" = "...\src\Quux\Blah.hs"
+importedModulePath :: Text -> FilePath -> Text -> FilePath
+importedModulePath mname file imp =
+	(`addExtension` "hs") . joinPath .
+	(++ ipath) . splitDirectories $
+	sourceModuleRoot mname file
+	where
+		ipath = map T.unpack $ T.split (== '.') imp
+
 packageOpt :: Maybe ModulePackage -> [String]
 packageOpt = maybeToList . fmap (("-package " ++) . view packageName)
 
--- | Recalc positions to interpret '\t' as one symbol instead of 8
+-- | Recalc positions to interpret '\t' as one symbol instead of N
 class RecalcTabs a where
-	recalcTabs :: String -> a -> a
+	-- | Interpret '\t' as one symbol instead of N
+	recalcTabs :: String -> Int -> a -> a
+	-- | Inverse of `recalcTabs`: interpret '\t' as N symbols instead of 1
+	calcTabs :: String -> Int -> a -> a
 
 instance RecalcTabs Position where
-	recalcTabs cts (Position l c) = Position l c' where
+	recalcTabs cts n (Position l c) = Position l c' where
 		line = listToMaybe $ drop (pred l) $ lines cts
 		c' = case line of
 			Nothing -> c
@@ -205,8 +226,15 @@
 				findIndex (>= pred c) .
 				scanl (+) 0 $ sizes
 		charSize :: Char -> Int
-		charSize '\t' = 8
+		charSize '\t' = n
 		charSize _ = 1
+	calcTabs cts n (Position l c) = Position l c' where
+		line = listToMaybe $ drop (pred l) $ lines cts
+		c' = maybe c (succ . sum . map charSize . take (pred c)) line
+		charSize :: Char -> Int
+		charSize '\t' = n
+		charSize _ = 1
 
 instance RecalcTabs Region where
-	recalcTabs cts (Region f t) = Region (recalcTabs cts f) (recalcTabs cts t)
+	recalcTabs cts n (Region f t) = Region (recalcTabs cts n f) (recalcTabs cts n t)
+	calcTabs cts n (Region f t) = Region (calcTabs cts n f) (calcTabs cts n t)
diff --git a/src/HsDev/Symbols/Resolve.hs b/src/HsDev/Symbols/Resolve.hs
--- a/src/HsDev/Symbols/Resolve.hs
+++ b/src/HsDev/Symbols/Resolve.hs
@@ -135,8 +135,8 @@
 		db <- ask
 		return $
 			fromMaybe [] $
-			listToMaybe $ dropWhile null $
-			[selectModules (select' f) db | f <- byImport i' : fs]
+			listToMaybe $ dropWhile null
+				[selectModules (select' f) db | f <- byImport i' : fs]
 		where
 			select' f md  = view moduleName md == view importModuleName i' && f (view moduleId md)
 	filterImportList :: [Declaration] -> [Declaration]
diff --git a/src/HsDev/Symbols/Types.hs b/src/HsDev/Symbols/Types.hs
--- a/src/HsDev/Symbols/Types.hs
+++ b/src/HsDev/Symbols/Types.hs
@@ -518,7 +518,7 @@
 		qualifiedName :: ModuleId -> Declaration -> Text
 		qualifiedName m' d' = T.concat [_moduleIdName m', ".", _declarationName d']
 	symbolDocs = _declarationDocs . _moduleDeclaration
-	symbolLocation d = set locationPosition (_declarationPosition $ _moduleDeclaration d) $
+	symbolLocation d = set locationPosition (_declarationPosition $ _moduleDeclaration d)
 		(symbolLocation . _declarationModuleId $ d)
 
 instance Documented ModuleId where
diff --git a/src/HsDev/Tools/AutoFix.hs b/src/HsDev/Tools/AutoFix.hs
--- a/src/HsDev/Tools/AutoFix.hs
+++ b/src/HsDev/Tools/AutoFix.hs
@@ -77,9 +77,9 @@
 correctors :: [CorrectorMatch]
 correctors = [
 	match "^The import of `([\\w\\.]+)' is redundant" $ \_ rgn -> Correction
-		"Redunant import"
+		"Redundant import"
 		(replace
-			(rangeFrom rgn `rangeSize` linesSize 1)
+			(expandLines rgn)
 			""),
 	match "^(.*?)\nFound:\n  (.*?)\nWhy not:\n  (.*?)$" $ \g rgn -> Correction
 		(g `at` 1)
diff --git a/src/HsDev/Tools/Ghc/Check.hs b/src/HsDev/Tools/Ghc/Check.hs
--- a/src/HsDev/Tools/Ghc/Check.hs
+++ b/src/HsDev/Tools/Ghc/Check.hs
@@ -26,7 +26,7 @@
 import FastString (unpackFS)
 import qualified ErrUtils as E
 
-import HsDev.Symbols (Canonicalize(..), sourceModuleRoot)
+import HsDev.Symbols (Canonicalize(..), moduleOpts)
 import HsDev.Symbols.Location
 import HsDev.Symbols.Types
 import HsDev.Tools.Base
@@ -41,7 +41,7 @@
 		modifyFlags (\fs -> fs { log_action = logAction ch })
 		_ <- addCmdOpts ("-Wall" : (cabalOpt cabal ++ opts))
 		clearTargets
-		mapM (flip makeTarget Nothing) files >>= loadTargets
+		mapM (`makeTarget` Nothing) files >>= loadTargets
 	notes <- liftIO $ stopChan ch
 	liftIO $ recalcNotesTabs notes
 
@@ -50,27 +50,17 @@
 check opts cabal m = case view moduleLocation m of
 	FileModule file proj -> do
 		ch <- liftIO newChan
-		pkgs <- lift $ liftM (map $ view packageName) listPackages
+		pkgs <- lift listPackages
 		let
 			dir = fromMaybe
 				(sourceModuleRoot (view moduleName m) file) $
 				preview (_Just . projectPath) proj
-			infos' = maybe [] (`fileTargets` file) proj
-			srcDirs = concatMap (view infoSourceDirs) infos'
-			exts = concatMap (view infoExtensions) infos'
-			deps = concatMap (view infoDepends) infos'
-			hidePackages
-				| null infos' = []
-				| otherwise = ["-hide-all-packages"]
 		lift $ withFlags $ withCurrentDirectory dir $ do
 			modifyFlags (\fs -> fs { log_action = logAction ch })
 			_ <- addCmdOpts $ concat [
 				["-Wall"],
 				cabalOpt cabal,
-				["-i" ++ s | s <- srcDirs],
-				extensionsOpts exts,
-				hidePackages,
-				["-package " ++ p | p <- deps, p `elem` pkgs],
+				moduleOpts pkgs m,
 				opts]
 			clearTargets
 			target <- makeTarget (makeRelative dir file) Nothing
@@ -122,7 +112,7 @@
 		recalc' n = fromMaybe n $ do
 			fname <- preview (noteSource . moduleFile) n
 			cts' <- lookup fname (zip files cts)
-			return $ recalcTabs cts' n
+			return $ recalcTabs cts' 8 n
 	return $ map recalc' notes
 	where
 		files = ordNub $ notes ^.. each . noteSource . moduleFile
diff --git a/src/HsDev/Tools/GhcMod.hs b/src/HsDev/Tools/GhcMod.hs
--- a/src/HsDev/Tools/GhcMod.hs
+++ b/src/HsDev/Tools/GhcMod.hs
@@ -124,7 +124,7 @@
 			maybe (throwError $ GhcMod.GMEString $ "Can't parse info: '" ++ sname ++ "'") return $
 			parseData s `mplus` parseFunction s
 		recalcDeclTabs :: String -> Declaration -> Declaration
-		recalcDeclTabs fstr = over (declarationPosition . _Just) (recalcTabs fstr)
+		recalcDeclTabs fstr = over (declarationPosition . _Just) (recalcTabs fstr 8)
 		parseFunction s = do
 			groups <- matchRx (sname ++ "\\s+::\\s+(.*?)(\\s+-- Defined (at (.*)|in `(.*)'))?$") s
 			return (decl (fromString sname) (Function (Just $ fromString $ groups `at` 1) [] Nothing)) {
@@ -175,7 +175,9 @@
 typeOf :: [String] -> Cabal -> FilePath -> Int -> Int -> GhcModT IO [TypedRegion]
 typeOf opts cabal file line col = withOptions (\o -> o { GhcMod.ghcUserOptions = cabalOpt cabal ++ opts }) $ do
 	fileCts <- liftIO $ readFileUtf8 file
-	ts <- lines <$> GhcMod.types file line col
+	let
+		Position line' col' = calcTabs fileCts 8 (Position line col)
+	ts <- lines <$> GhcMod.types file line' col'
 	return $ mapMaybe (toRegionType fileCts) ts
 	where
 		toRegionType :: String -> String -> Maybe TypedRegion
@@ -185,7 +187,7 @@
 		parseRegion :: String -> ReadM Region
 		parseRegion fstr = Region <$> parsePosition fstr <*> parsePosition fstr
 		parsePosition :: String -> ReadM Position
-		parsePosition fstr = recalcTabs fstr <$> (Position <$> readParse <*> readParse)
+		parsePosition fstr = recalcTabs fstr 8 <$> (Position <$> readParse <*> readParse)
 
 parseOutputMessages :: String -> [Note OutputMessage]
 parseOutputMessages = mapMaybe parseOutputMessage . lines
@@ -205,7 +207,7 @@
 recalcOutputMessageTabs fileCts n = fromMaybe n $ do
 	src <- preview (noteSource . moduleFile) n
 	cts <- lookup src fileCts
-	return $ recalcTabs cts n
+	return $ recalcTabs cts 8 n
 
 -- | Replace NULL with newline
 nullToNL :: String -> String
diff --git a/src/HsDev/Tools/HDocs.hs b/src/HsDev/Tools/HDocs.hs
--- a/src/HsDev/Tools/HDocs.hs
+++ b/src/HsDev/Tools/HDocs.hs
@@ -9,6 +9,7 @@
 	) where
 
 import Control.Exception
+import Control.DeepSeq
 import Control.Lens (set, view, over)
 import Control.Monad ()
 import Control.Monad.Except
@@ -27,13 +28,13 @@
 
 -- | Get docs for modules
 hdocsy :: [ModuleLocation] -> [String] -> IO [Map String String]
-hdocsy mlocs opts = runExceptT (docs' mlocs) >>= return . either (const $ replicate (length mlocs) M.empty) (map HDocs.formatDocs) where
+hdocsy mlocs opts = runExceptT (docs' mlocs) >>= return . either (const $ replicate (length mlocs) M.empty) (map $ force . HDocs.formatDocs) where
 	docs' :: [ModuleLocation] -> ExceptT String IO [HDocs.ModuleDocMap]
 	docs' ms = liftM (map snd) $ HDocs.readSources_ opts $ map (view moduleFile) ms
 
 -- | Get docs for module
 hdocs :: ModuleLocation -> [String] -> IO (Map String String)
-hdocs mloc opts = runExceptT (docs' mloc) >>= return . either (const M.empty) HDocs.formatDocs where
+hdocs mloc opts = runExceptT (docs' mloc) >>= return . either (const M.empty) (force . HDocs.formatDocs) where
 	docs' :: ModuleLocation -> ExceptT String IO HDocs.ModuleDocMap
 	docs' (FileModule fpath _) = liftM snd $ HDocs.readSource opts fpath
 	docs' (CabalModule _ _ mname) = HDocs.moduleDocs opts mname
@@ -41,7 +42,7 @@
 
 -- | Get all docs
 hdocsCabal :: Cabal -> [String] -> ExceptT String IO (Map String (Map String String))
-hdocsCabal cabal opts = liftM (M.map HDocs.formatDocs) $ HDocs.installedDocs (cabalOpt cabal ++ opts)
+hdocsCabal cabal opts = liftM (M.map $ force . HDocs.formatDocs) $ HDocs.installedDocs (cabalOpt cabal ++ opts)
 
 -- | Set docs for module
 setDocs :: Map String String -> Module -> Module
diff --git a/src/HsDev/Tools/HLint.hs b/src/HsDev/Tools/HLint.hs
--- a/src/HsDev/Tools/HLint.hs
+++ b/src/HsDev/Tools/HLint.hs
@@ -4,24 +4,30 @@
 	module Control.Monad.Except
 	) where
 
+import Control.Arrow
+import Control.Lens (over, view, _Just)
 import Control.Monad.Except
-import Language.Haskell.HLint3 (autoSettings, parseModuleEx, applyHints, Idea(..), parseErrorMessage)
+import Data.Char
+import Data.List
+import Data.Maybe (mapMaybe)
+import Data.Ord
+import Language.Haskell.HLint3 (autoSettings, parseModuleEx, applyHints, Idea(..), parseErrorMessage, ParseFlags(..), CppFlags(..))
 import Language.Haskell.Exts.SrcLoc
 import qualified Language.Haskell.HLint3 as HL (Severity(..))
 
 import HsDev.Symbols (Canonicalize(..))
 import HsDev.Symbols.Location
 import HsDev.Tools.Base
-import HsDev.Util (readFileUtf8)
+import HsDev.Util (readFileUtf8, split)
 
 hlint :: FilePath -> ExceptT String IO [Note OutputMessage]
 hlint file = do
 	file' <- liftIO $ canonicalize file
 	cts <- liftIO $ readFileUtf8 file'
 	(flags, classify, hint) <- liftIO autoSettings
-	p <- liftIO $ parseModuleEx flags file' (Just cts)
+	p <- liftIO $ parseModuleEx (flags { cppFlags = CppSimple }) file' (Just cts)
 	m <- either (throwError . parseErrorMessage) return p
-	return $ map (recalcTabs cts . fromIdea) $ applyHints classify hint [m]
+	return $ map (recalcTabs cts 8 . indentIdea cts . fromIdea) $ applyHints classify hint [m]
 
 fromIdea :: Idea -> Note OutputMessage
 fromIdea idea = Note {
@@ -36,3 +42,50 @@
 		_messageSuggestion = ideaTo idea } }
 	where
 		src = ideaSpan idea
+
+indentIdea :: String -> Note OutputMessage -> Note OutputMessage
+indentIdea cts idea = case analyzeIndent cts of
+	Nothing -> idea
+	Just i -> over (note . messageSuggestion . _Just) (indent' i) idea
+	where
+		indent' i' = intercalate "\n" . indentTail . map (uncurry (++) . first (concat . (`replicate` i') . (`div` 2) . length) . span isSpace) . split (== '\n')
+		indentTail [] = []
+		indentTail (h : hs) = h : map (firstIndent ++) hs
+		firstIndent = takeWhile isSpace firstLine
+		firstLine = regionStr (Position firstLineNum 1 `region` Position (succ firstLineNum) 1) cts
+		firstLineNum = view (noteRegion . regionFrom . positionLine) idea
+
+-- | Indent in source
+data Indent = Spaces Int | Tabs deriving (Eq, Ord)
+
+instance Show Indent where
+	show (Spaces n) = replicate n ' '
+	show Tabs = "\t"
+
+-- | Analyze source indentation to convert suggestion to same indentation
+-- Returns one indent
+analyzeIndent :: String -> Maybe String
+analyzeIndent =
+	fmap show . selectIndent . map fst . dropUnusual .
+	sortBy (comparing $ negate . snd) .
+	map (head &&& length) .
+	group . sort .
+	mapMaybe (guessIndent . takeWhile isSpace) . lines
+	where
+		selectIndent :: [Indent] -> Maybe Indent
+		selectIndent [] = Nothing
+		selectIndent (Tabs : _) = Just Tabs
+		selectIndent indents = Just $ Spaces $ foldr1 gcd $ mapMaybe spaces indents where
+			spaces :: Indent -> Maybe Int
+			spaces Tabs = Nothing
+			spaces (Spaces n) = Just n
+		dropUnusual :: [(Indent, Int)] -> [(Indent, Int)]
+		dropUnusual [] = []
+		dropUnusual is@((_, freq):_) = takeWhile ((> freq `div` 5) . snd) is
+
+-- | Guess indent of one line
+guessIndent :: String -> Maybe Indent
+guessIndent s
+	| all (== ' ') s = Just $ Spaces $ length s
+	| all (== '\t') s = Just Tabs
+	| otherwise = Nothing
diff --git a/src/HsDev/Tools/Types.hs b/src/HsDev/Tools/Types.hs
--- a/src/HsDev/Tools/Types.hs
+++ b/src/HsDev/Tools/Types.hs
@@ -67,7 +67,8 @@
 		v .:: "note"
 
 instance RecalcTabs (Note a) where
-	recalcTabs cts (Note s r l n) = Note s (recalcTabs cts r) l n
+	recalcTabs cts n' (Note s r l n) = Note s (recalcTabs cts n' r) l n
+	calcTabs cts n' (Note s r l n) = Note s (calcTabs cts n' r) l n
 
 instance Canonicalize (Note a) where
 	canonicalize (Note s r l n) = Note <$> canonicalize s <*> pure r <*> pure l <*> pure n
diff --git a/src/HsDev/Watcher.hs b/src/HsDev/Watcher.hs
--- a/src/HsDev/Watcher.hs
+++ b/src/HsDev/Watcher.hs
@@ -7,7 +7,7 @@
 	) where
 
 import Control.Lens (view)
-import System.FilePath (takeDirectory, takeExtension)
+import System.FilePath (takeDirectory, takeExtension, (</>))
 
 import System.Directory.Watcher hiding (Watcher)
 import HsDev.Project
@@ -15,24 +15,25 @@
 import HsDev.Watcher.Types
 
 -- | Watch for project sources changes
-watchProject :: Watcher -> Project -> IO ()
-watchProject w proj = do
-	mapM_ (\dir -> watchTree w dir isSource (WatchedProject proj)) dirs
-	watchDir w (view projectPath proj) isCabal (WatchedProject proj)
+watchProject :: Watcher -> Project -> [String] -> IO ()
+watchProject w proj opts = do
+	mapM_ (\dir -> watchTree w dir isSource (WatchedProject proj opts)) dirs
+	watchDir w projDir isCabal (WatchedProject proj opts)
 	where
-		dirs = map (view entity) $ maybe [] sourceDirs $ view projectDescription proj
+		dirs = map ((projDir </>) . view entity) $ maybe [] sourceDirs $ view projectDescription proj
+		projDir = view projectPath proj
 
 -- | Watch for standalone source
 watchModule :: Watcher -> ModuleLocation -> IO ()
 watchModule w (FileModule f Nothing) = watchDir w (takeDirectory f) isSource WatchedModule
-watchModule w (FileModule _ (Just proj)) = watchProject w proj
-watchModule w (CabalModule cabal _ _) = watchSandbox w cabal
+watchModule w (FileModule _ (Just proj)) = watchProject w proj []
+watchModule w (CabalModule cabal _ _) = watchSandbox w cabal []
 watchModule _ _ = return ()
 
 -- | Watch for sandbox
-watchSandbox :: Watcher -> Cabal -> IO ()
-watchSandbox _ Cabal = return ()
-watchSandbox w (Sandbox f) = watchTree w f isConf (WatchedSandbox $ Sandbox f)
+watchSandbox :: Watcher -> Cabal -> [String] -> IO ()
+watchSandbox _ Cabal _ = return ()
+watchSandbox w (Sandbox f) opts = watchTree w f isConf (WatchedSandbox (Sandbox f) opts)
 
 isSource :: Event -> Bool
 isSource (Event _ f _) = takeExtension f == ".hs"
diff --git a/src/HsDev/Watcher/Types.hs b/src/HsDev/Watcher/Types.hs
--- a/src/HsDev/Watcher/Types.hs
+++ b/src/HsDev/Watcher/Types.hs
@@ -9,6 +9,6 @@
 import HsDev.Project (Project)
 import HsDev.Cabal (Cabal)
 
-data Watched = WatchedProject Project | WatchedSandbox Cabal | WatchedModule
+data Watched = WatchedProject Project [String] | WatchedSandbox Cabal [String] | WatchedModule
 
 type Watcher = W.Watcher Watched
diff --git a/src/System/Directory/Watcher.hs b/src/System/Directory/Watcher.hs
--- a/src/System/Directory/Watcher.hs
+++ b/src/System/Directory/Watcher.hs
@@ -53,16 +53,16 @@
 -- | Watch directory
 watchDir :: Watcher a -> FilePath -> (Event -> Bool) -> a -> IO ()
 watchDir w f p v = do
-	f' <- canonicalizePath f
-	e <- doesDirectoryExist f'
+	e <- doesDirectoryExist f
 	when e $ do
+		f' <- canonicalizePath f
 		watching <- isWatchingDir w f'
 		unless watching $ do
 			stop <- FS.watchDir
 				(watcherMan w)
 				(fromString f')
 				(p . fromEvent)
-				(writeChan (watcherChan w) . ((,) v) . fromEvent)
+				(writeChan (watcherChan w) . (,) v . fromEvent)
 			modifyMVar_ (watcherDirs w) $ return . M.insert f' (False, stop)
 
 watchDir_ :: Watcher () -> FilePath -> (Event -> Bool) -> IO ()
@@ -92,16 +92,16 @@
 -- | Watch directory tree
 watchTree :: Watcher a -> FilePath -> (Event -> Bool) -> a -> IO ()
 watchTree w f p v = do
-	f' <- canonicalizePath f
-	e <- doesDirectoryExist f'
+	e <- doesDirectoryExist f
 	when e $ do
+		f' <- canonicalizePath f
 		watching <- isWatchingTree w f'
 		unless watching $ do
 			stop <- FS.watchTree
 				(watcherMan w)
 				(fromString f')
 				(p . fromEvent)
-				(writeChan (watcherChan w) . ((,) v) . fromEvent)
+				(writeChan (watcherChan w) . (,) v . fromEvent)
 			modifyMVar_ (watcherDirs w) $ return . M.insert f' (True, stop)
 
 watchTree_ :: Watcher () -> FilePath -> (Event -> Bool) -> IO ()
diff --git a/src/System/Win32/PowerShell.hs b/src/System/Win32/PowerShell.hs
--- a/src/System/Win32/PowerShell.hs
+++ b/src/System/Win32/PowerShell.hs
@@ -110,8 +110,8 @@
 	invoke' = case e of
 		Var n -> n
 		_ -> unwords ["&", compile $ cbra e]
-	p' = intercalate " " $ map (compile . cbra) p
-	ns' = intercalate " " $ concatMap named' $ M.toList ns where
+	p' = unwords $ map (compile . cbra) p
+	ns' = unwords $ concatMap named' $ M.toList ns where
 		named' :: (String, Maybe Expr) -> [String]
 		named' (n, Just v) = ['-':n, compile $ cbra v]
 		named' (n, Nothing) = ['-':n]
@@ -156,7 +156,7 @@
 call f pos named' = CmdLet f $ Args pos (M.fromList named')
 
 cmdlet :: String -> [Expr] -> [(String, Maybe Expr)] -> CmdLet
-cmdlet n pos = call (name n) pos
+cmdlet n = call (name n)
 
 lambda :: [String] -> ([Expr] -> Expr) -> Expr
 lambda = Lambda
