diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,7 @@
-### 0.7.1 (2020-01-13)
+### 0.7.2 (2020-01-14)
+* Expose shakeOptions used - (Pepe Iborra)
 
+### 0.7.1 (2020-01-13)
 * Fix sticky diagnostics bug (#1188) - (Pepe Iborra)
 * Use completionSnippetsOn flag (#1195) - (Yuya Kono)
 * Update tested-with GHC in cabal config - (jneira)
@@ -13,7 +15,6 @@
 * fix suggestAddTypeAnnotation regex (#760) - (Kostas Dermentzis)
 
 ### 0.7.0 (2020-01-03)
-
 * Ghcide now loads HLS plugins internally - (Pepe Iborra)
 * Retry a failed cradle if the cradle descriptor changes (#762) - (Pepe Iborra)
 * Fix extend imports regression (#769) - (Pepe Iborra)
diff --git a/exe/Main.hs b/exe/Main.hs
--- a/exe/Main.hs
+++ b/exe/Main.hs
@@ -30,6 +30,7 @@
 import Development.IDE.Plugin
 import Development.IDE.Plugin.Test as Test
 import Development.IDE.Session (loadSession)
+import Development.Shake (ShakeOptions (shakeThreads))
 import qualified Language.Haskell.LSP.Core as LSP
 import Language.Haskell.LSP.Messages
 import Language.Haskell.LSP.Types
@@ -114,15 +115,16 @@
             hPutStrLn stderr $ "Started LSP server in " ++ showDuration t
             sessionLoader <- loadSession $ fromMaybe dir rootPath
             config <- fromMaybe def <$> getConfig
-            let options = (defaultIdeOptions sessionLoader)
+            let options = defOptions
                     { optReportProgress    = clientSupportsProgress caps
                     , optShakeProfiling    = argsShakeProfiling
                     , optOTMemoryProfiling = IdeOTMemoryProfiling argsOTMemoryProfiling
                     , optTesting           = IdeTesting argsTesting
-                    , optThreads           = argsThreads
+                    , optShakeOptions      = (optShakeOptions defOptions){shakeThreads = argsThreads}
                     , optCheckParents      = checkParents config
                     , optCheckProject      = checkProject config
                     }
+                defOptions = defaultIdeOptions sessionLoader
                 logLevel = if argsVerbose then minBound else Info
             debouncer <- newAsyncDebouncer
             let rules = do
@@ -160,14 +162,15 @@
         debouncer <- newAsyncDebouncer
         let dummyWithProg _ _ f = f (const (pure ()))
         sessionLoader <- loadSession dir
-        let options = (defaultIdeOptions sessionLoader)
+        let options = defOptions
                     { optShakeProfiling    = argsShakeProfiling
                     -- , optOTMemoryProfiling = IdeOTMemoryProfiling argsOTMemoryProfiling
                     , optTesting           = IdeTesting argsTesting
-                    , optThreads           = argsThreads
+                    , optShakeOptions      = (optShakeOptions defOptions){shakeThreads = argsThreads}
                     , optCheckParents      = NeverCheck
                     , optCheckProject      = False
                     }
+            defOptions = defaultIdeOptions sessionLoader
             logLevel = if argsVerbose then minBound else Info
         ide <- initialise def mainRule (pure $ IdInt 0) (showEvent lock) dummyWithProg (const (const id)) (logger logLevel) debouncer options vfs
 
diff --git a/ghcide.cabal b/ghcide.cabal
--- a/ghcide.cabal
+++ b/ghcide.cabal
@@ -2,7 +2,7 @@
 build-type:         Simple
 category:           Development
 name:               ghcide
-version:            0.7.1.0
+version:            0.7.2.0
 license:            Apache-2.0
 license-file:       LICENSE
 author:             Digital Asset and Ghcide contributors
@@ -277,6 +277,7 @@
         ghcide,
         lens,
         optparse-applicative,
+        shake,
         text,
         unordered-containers
     other-modules:
diff --git a/src/Development/IDE/Core/RuleTypes.hs b/src/Development/IDE/Core/RuleTypes.hs
--- a/src/Development/IDE/Core/RuleTypes.hs
+++ b/src/Development/IDE/Core/RuleTypes.hs
@@ -54,6 +54,10 @@
 -- | The parse tree for the file using GetFileContents
 type instance RuleResult GetParsedModule = ParsedModule
 
+-- | The parse tree for the file using GetFileContents,
+-- all comments included using Opt_KeepRawTokenStream
+type instance RuleResult GetParsedModuleWithComments = ParsedModule
+
 -- | The dependency information produced by following the imports recursively.
 -- This rule will succeed even if there is an error, e.g., a module could not be located,
 -- a module could not be parsed or an import cycle.
@@ -301,6 +305,12 @@
 instance Hashable GetParsedModule
 instance NFData   GetParsedModule
 instance Binary   GetParsedModule
+
+data GetParsedModuleWithComments = GetParsedModuleWithComments
+    deriving (Eq, Show, Typeable, Generic)
+instance Hashable GetParsedModuleWithComments
+instance NFData   GetParsedModuleWithComments
+instance Binary   GetParsedModuleWithComments
 
 data GetLocatedImports = GetLocatedImports
     deriving (Eq, Show, Typeable, Generic)
diff --git a/src/Development/IDE/Core/Rules.hs b/src/Development/IDE/Core/Rules.hs
--- a/src/Development/IDE/Core/Rules.hs
+++ b/src/Development/IDE/Core/Rules.hs
@@ -29,11 +29,13 @@
     highlightAtPoint,
     getDependencies,
     getParsedModule,
+    getParsedModuleWithComments,
     getClientConfigAction,
     -- * Rules
     CompiledLinkables(..),
     IsHiFileStable(..),
     getParsedModuleRule,
+    getParsedModuleWithCommentsRule,
     getLocatedImportsRule,
     getDependencyInformationRule,
     reportImportCyclesRule,
@@ -268,10 +270,15 @@
                 _ -> MaybeT $ return Nothing
         _ -> MaybeT $ return Nothing
 
--- | Parse the contents of a daml file.
+-- | Parse the contents of a haskell file.
 getParsedModule :: NormalizedFilePath -> Action (Maybe ParsedModule)
-getParsedModule file = use GetParsedModule file
+getParsedModule = use GetParsedModule
 
+-- | Parse the contents of a haskell file,
+-- ensuring comments are preserved in annotations
+getParsedModuleWithComments :: NormalizedFilePath -> Action (Maybe ParsedModule)
+getParsedModuleWithComments = use GetParsedModuleWithComments
+
 ------------------------------------------------------------
 -- Rules
 -- These typically go from key to value and are oracles.
@@ -285,12 +292,15 @@
 priorityFilesOfInterest :: Priority
 priorityFilesOfInterest = Priority (-2)
 
--- | IMPORTANT FOR HLINT INTEGRATION:
+-- | WARNING:
 -- We currently parse the module both with and without Opt_Haddock, and
 -- return the one with Haddocks if it -- succeeds. However, this may not work
--- for hlint, and we might need to save the one without haddocks too.
+-- for hlint or any client code that might need the parsed source with all
+-- annotations, including comments.
+-- For that use case you might want to use `getParsedModuleWithCommentsRule`
 -- See https://github.com/haskell/ghcide/pull/350#discussion_r370878197
 -- and https://github.com/mpickering/ghcide/pull/22#issuecomment-625070490
+-- GHC wiki about: https://gitlab.haskell.org/ghc/ghc/-/wikis/api-annotations
 getParsedModuleRule :: Rules ()
 getParsedModuleRule = defineEarlyCutoff $ \GetParsedModule file -> do
     (ms, _) <- use_ GetModSummary file
@@ -333,8 +343,10 @@
     pure res
 
 withOptHaddock :: ModSummary -> ModSummary
-withOptHaddock ms = ms{ms_hspp_opts= gopt_set (ms_hspp_opts ms) Opt_Haddock}
+withOptHaddock = withOption Opt_Haddock
 
+withOption :: GeneralFlag -> ModSummary -> ModSummary
+withOption opt ms = ms{ms_hspp_opts= gopt_set (ms_hspp_opts ms) opt}
 
 -- | Given some normal parse errors (first) and some from Haddock (second), merge them.
 --   Ignore Haddock errors that are in both. Demote Haddock-only errors to warnings.
@@ -348,6 +360,19 @@
     fixMessage x | "parse error " `T.isPrefixOf` x = "Haddock " <> x
                  | otherwise = "Haddock: " <> x
 
+-- | This rule provides a ParsedModule preserving all annotations,
+-- including keywords, punctuation and comments.
+-- So it is suitable for use cases where you need a perfect edit.
+getParsedModuleWithCommentsRule :: Rules ()
+getParsedModuleWithCommentsRule = defineEarlyCutoff $ \GetParsedModuleWithComments file -> do
+    (ms, _) <- use_ GetModSummary file
+    sess <- use_ GhcSession file
+    opt <- getIdeOptions
+
+    let ms' = withOption Opt_KeepRawTokenStream ms
+
+    liftIO $ getParsedModuleDefinition (hscEnv sess) opt file ms'
+
 getParsedModuleDefinition :: HscEnv -> IdeOptions -> NormalizedFilePath -> ModSummary -> IO (Maybe ByteString, ([FileDiagnostic], Maybe ParsedModule))
 getParsedModuleDefinition packageState opt file ms = do
     let fp = fromNormalizedFilePath file
@@ -974,6 +999,7 @@
     linkables <- liftIO $ newVar emptyModuleEnv
     addIdeGlobal $ CompiledLinkables linkables
     getParsedModuleRule
+    getParsedModuleWithCommentsRule
     getLocatedImportsRule
     getDependencyInformationRule
     reportImportCyclesRule
diff --git a/src/Development/IDE/Core/Service.hs b/src/Development/IDE/Core/Service.hs
--- a/src/Development/IDE/Core/Service.hs
+++ b/src/Development/IDE/Core/Service.hs
@@ -18,7 +18,6 @@
     updatePositionMapping,
     ) where
 
-import Data.Maybe
 import Development.IDE.Types.Options (IdeOptions(..))
 import Development.IDE.Core.Debouncer
 import           Development.IDE.Core.FileStore  (VFSHandle, fileStoreRules)
@@ -62,10 +61,8 @@
         (optShakeProfiling options)
         (optReportProgress options)
         (optTesting options)
-        shakeOptions
-          { shakeThreads = optThreads options
-          , shakeFiles   = fromMaybe "/dev/null" (optShakeFiles options)
-          } $ do
+        (optShakeOptions options)
+          $ do
             addIdeGlobal $ GlobalIdeOptions options
             fileStoreRules vfs
             ofInterestRules
diff --git a/src/Development/IDE/Types/Options.hs b/src/Development/IDE/Types/Options.hs
--- a/src/Development/IDE/Types/Options.hs
+++ b/src/Development/IDE/Types/Options.hs
@@ -15,7 +15,7 @@
   , IdeResult
   , IdeGhcSession(..)
   , OptHaddockParse(..)
-  ) where
+  ,optShakeFiles) where
 
 import Data.Default
 import Development.Shake
@@ -50,12 +50,6 @@
     -- ^ How to locate source and @.hie@ files given a module name.
   , optExtensions :: [String]
     -- ^ File extensions to search for code, defaults to Haskell sources (including @.hs@)
-
-  , optThreads :: Int
-    -- ^ Number of threads to use. Use 0 for number of threads on the machine.
-  , optShakeFiles :: Maybe FilePath
-  -- ^ Directory where the shake database should be stored. For ghcide this is always set to `Nothing` for now
-  -- meaning we keep everything in memory but the daml CLI compiler uses this for incremental builds.
   , optShakeProfiling :: Maybe FilePath
     -- ^ Set to 'Just' to create a directory of profiling reports.
   , optOTMemoryProfiling :: IdeOTMemoryProfiling
@@ -90,8 +84,16 @@
   , optCustomDynFlags :: DynFlags -> DynFlags
     -- ^ Will be called right after setting up a new cradle,
     --   allowing to customize the Ghc options used
+  , optShakeOptions :: ShakeOptions
   }
 
+optShakeFiles :: IdeOptions -> Maybe FilePath
+optShakeFiles opts
+  | value == defValue = Nothing
+  | otherwise = Just value
+  where
+    value = shakeFiles (optShakeOptions opts)
+    defValue = shakeFiles (optShakeOptions $ defaultIdeOptions undefined)
 data OptHaddockParse = HaddockParse | NoHaddockParse
   deriving (Eq,Ord,Show,Enum)
 
@@ -119,8 +121,10 @@
     ,optGhcSession = session
     ,optExtensions = ["hs", "lhs"]
     ,optPkgLocationOpts = defaultIdePkgLocationOptions
-    ,optThreads = 0
-    ,optShakeFiles = Nothing
+    ,optShakeOptions = shakeOptions
+        {shakeThreads = 0
+        ,shakeFiles = "/dev/null"
+        }
     ,optShakeProfiling = Nothing
     ,optOTMemoryProfiling = IdeOTMemoryProfiling False
     ,optReportProgress = IdeReportProgress False
