Skip to content
This repository was archived by the owner on Oct 7, 2020. It is now read-only.

Commit d39b4ee

Browse files
committed
Move formatting over to VFS away from IdeGhcM
Makes it a lot faster
1 parent 3e21f2c commit d39b4ee

File tree

8 files changed

+85
-71
lines changed

8 files changed

+85
-71
lines changed

hie-plugin-api/Haskell/Ide/Engine/PluginUtils.hs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ module Haskell.Ide.Engine.PluginUtils
2929
, unPos
3030
, toPos
3131
, clientSupportsDocumentChanges
32+
, readVFS
33+
, getRangeFromVFS
34+
, rangeLinesFromVfs
3235
) where
3336

3437
import Control.Monad.IO.Class
@@ -47,12 +50,14 @@ import FastString
4750
import Haskell.Ide.Engine.MonadTypes
4851
import Haskell.Ide.Engine.MonadFunctions
4952
import Haskell.Ide.Engine.ArtifactMap
53+
import Language.Haskell.LSP.VFS
5054
import Language.Haskell.LSP.Types.Capabilities
5155
import qualified Language.Haskell.LSP.Types as J
5256
import Prelude hiding (log)
5357
import SrcLoc
5458
import System.Directory
5559
import System.FilePath
60+
import qualified Yi.Rope as Yi
5661

5762
-- ---------------------------------------------------------------------
5863

@@ -261,3 +266,26 @@ clientSupportsDocumentChanges = do
261266
WorkspaceEditClientCapabilities mDc <- _workspaceEdit wCaps
262267
mDc
263268
return $ fromMaybe False supports
269+
270+
-- ---------------------------------------------------------------------
271+
272+
readVFS :: MonadIde m => Uri -> m (Maybe T.Text)
273+
readVFS uri = do
274+
mvf <- getVirtualFile uri
275+
case mvf of
276+
Just (VirtualFile _ txt) -> return $ Just (Yi.toText txt)
277+
Nothing -> return Nothing
278+
279+
getRangeFromVFS :: MonadIde m => Uri -> Range -> m (Maybe T.Text)
280+
getRangeFromVFS uri rg = do
281+
mvf <- getVirtualFile uri
282+
case mvf of
283+
Just vfs -> return $ Just $ rangeLinesFromVfs vfs rg
284+
Nothing -> return Nothing
285+
286+
rangeLinesFromVfs :: VirtualFile -> Range -> T.Text
287+
rangeLinesFromVfs (VirtualFile _ yitext) (Range (Position lf _cf) (Position lt _ct)) = r
288+
where
289+
(_ ,s1) = Yi.splitAtLine lf yitext
290+
(s2, _) = Yi.splitAtLine (lt - lf) s1
291+
r = Yi.toText s2

hie-plugin-api/Haskell/Ide/Engine/PluginsIdeMonads.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ type SymbolProvider = Uri -> IdeDeferM (IdeResult [DocumentSymbol])
210210

211211
data FormattingType = FormatDocument
212212
| FormatRange Range
213-
type FormattingProvider = Uri -> FormattingType -> FormattingOptions -> IdeGhcM (IdeResult [TextEdit])
213+
type FormattingProvider = Uri -> FormattingType -> FormattingOptions -> IdeDeferM (IdeResult [TextEdit])
214214

215215
data PluginDescriptor =
216216
PluginDescriptor { pluginId :: PluginId

hie-plugin-api/hie-plugin-api.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ library
5050
, text
5151
, transformers
5252
, unordered-containers
53+
, yi-rope
5354
if os(windows)
5455
build-depends: Win32
5556
else

src/Haskell/Ide/Engine/Plugin/Brittany.hs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@ module Haskell.Ide.Engine.Plugin.Brittany where
55

66
import Control.Lens
77
import Control.Monad.IO.Class
8+
import Control.Monad.Trans.Class
89
import Control.Monad.Trans.Maybe (MaybeT, runMaybeT)
910
import Data.Aeson
1011
import Data.Coerce
1112
import Data.Semigroup
1213
import Data.Text (Text)
1314
import qualified Data.Text as T
14-
import qualified Data.Text.IO as T
15+
-- import qualified Data.Text.IO as T
1516
import GHC.Generics
16-
import qualified GhcMod.Utils as GM
17+
-- import qualified GhcMod.Utils as GM
1718
import Haskell.Ide.Engine.MonadTypes
1819
import Haskell.Ide.Engine.PluginUtils
1920
import Language.Haskell.Brittany
@@ -43,17 +44,18 @@ brittanyDescriptor plId = PluginDescriptor
4344
where
4445
cmd :: CommandFunc FormatParams [J.TextEdit]
4546
cmd =
46-
CmdSync $ \(FormatParams tabSize uri range) -> brittanyCmd tabSize uri range
47+
CmdSync $ \(FormatParams tabSize uri range) -> liftToGhc $ brittanyCmd tabSize uri range
4748
provider :: FormattingProvider
48-
provider uri FormatDocument opts = brittanyCmd (opts ^. J.tabSize) uri Nothing
49-
provider uri (FormatRange r) opts = brittanyCmd (opts ^. J.tabSize) uri (Just r)
49+
provider uri FormatDocument opts = lift $ brittanyCmd (opts ^. J.tabSize) uri Nothing
50+
provider uri (FormatRange r) opts = lift $ brittanyCmd (opts ^. J.tabSize) uri (Just r)
5051

51-
brittanyCmd :: Int -> Uri -> Maybe Range -> IdeGhcM (IdeResult [J.TextEdit])
52-
brittanyCmd tabSize uri range =
53-
pluginGetFile "brittanyCmd: " uri $ \file -> do
54-
confFile <- liftIO $ getConfFile file
55-
text <- GM.withMappedFile file $ liftIO . T.readFile
56-
case range of
52+
brittanyCmd :: Int -> Uri -> Maybe Range -> IdeM (IdeResult [J.TextEdit])
53+
brittanyCmd tabSize uri range = pluginGetFile "brittanyCmd: " uri $ \file -> do
54+
confFile <- liftIO $ getConfFile file
55+
mtext <- readVFS uri
56+
case mtext of
57+
Nothing -> return $ IdeResultFail (IdeError InternalError "File was not open" Null)
58+
Just text -> case range of
5759
Just r -> do
5860
-- format selection
5961
res <- liftIO $ runBrittany tabSize confFile $ extractRange r text

src/Haskell/Ide/Engine/Plugin/Floskell.hs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,10 @@ where
88
import Data.Aeson ( Value(Null) )
99
import qualified Data.ByteString.Lazy as BS
1010
import qualified Data.Text as T
11-
import qualified Data.Text.IO as T
1211
import qualified Data.Text.Encoding as T
13-
import qualified GhcMod.Utils as GM
1412
import Haskell.Ide.Engine.MonadTypes
1513
import Haskell.Ide.Engine.PluginUtils
1614
import FloskellFloskell
17-
import Control.Monad.IO.Class
1815

1916
floskellDescriptor :: PluginId -> PluginDescriptor
2017
floskellDescriptor plId = PluginDescriptor
@@ -30,12 +27,15 @@ floskellDescriptor plId = PluginDescriptor
3027
}
3128

3229
provider :: FormattingProvider
33-
provider uri typ _opts = pluginGetFile "floskell: " uri $ \file -> do
34-
contents <- GM.withMappedFile file (liftIO . T.readFile)
35-
let (range, selectedContents) = case typ of
36-
FormatDocument -> (fullRange contents, contents)
37-
FormatRange r -> (r, extractRange r contents)
38-
result = reformat defaultAppConfig (uriToFilePath uri) (T.encodeUtf8 selectedContents)
39-
case result of
40-
Left err -> return $ IdeResultFail (IdeError PluginError (T.pack err) Null)
41-
Right new -> return $ IdeResultOk [TextEdit range (T.decodeUtf8 (BS.toStrict new))]
30+
provider uri typ _opts = do
31+
mContents <- readVFS uri
32+
case mContents of
33+
Nothing -> return $ IdeResultFail (IdeError InternalError "File was not open" Null)
34+
Just contents ->
35+
let (range, selectedContents) = case typ of
36+
FormatDocument -> (fullRange contents, contents)
37+
FormatRange r -> (r, extractRange r contents)
38+
result = reformat defaultAppConfig (uriToFilePath uri) (T.encodeUtf8 selectedContents)
39+
in case result of
40+
Left err -> return $ IdeResultFail (IdeError PluginError (T.pack err) Null)
41+
Right new -> return $ IdeResultOk [TextEdit range (T.decodeUtf8 (BS.toStrict new))]

src/Haskell/Ide/Engine/Plugin/HfaAlign.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import Data.Aeson
1212
import qualified Data.HashMap.Strict as H
1313
import qualified GHC.Generics as Generics
1414
import Haskell.Ide.Engine.MonadTypes hiding (_range)
15-
import Haskell.Ide.Engine.Plugin.HieExtras
15+
import Haskell.Ide.Engine.PluginUtils
1616
import qualified Language.Haskell.LSP.Types as J
1717
import qualified Language.Haskell.LSP.Types.Lens as J
1818

@@ -50,7 +50,7 @@ data AlignParams = AlignParams
5050

5151
alignCmd :: CommandFunc AlignParams J.WorkspaceEdit
5252
alignCmd = CmdSync $ \(AlignParams uri rg) -> do
53-
mtext <- liftToGhc $ getRangeFromVFS uri rg
53+
mtext <- getRangeFromVFS uri rg
5454
case mtext of
5555
Nothing -> return $ IdeResultOk $ J.WorkspaceEdit Nothing Nothing
5656
Just txt -> do

src/Haskell/Ide/Engine/Plugin/HieExtras.hs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ module Haskell.Ide.Engine.Plugin.HieExtras
1515
, showName
1616
, safeTyThingId
1717
, PosPrefixInfo(..)
18-
, getRangeFromVFS
19-
, rangeLinesFromVfs
2018
, HarePoint(..)
2119
, customOptions
2220
, runGhcModCommand
@@ -59,7 +57,6 @@ import Haskell.Ide.Engine.MonadTypes
5957
import Haskell.Ide.Engine.PluginUtils
6058
import qualified Haskell.Ide.Engine.Plugin.Fuzzy as Fuzzy
6159
import HscTypes
62-
import qualified Language.Haskell.LSP.VFS as VFS
6360
import qualified Language.Haskell.LSP.Types as J
6461
import qualified Language.Haskell.LSP.Types.Lens as J
6562
import Language.Haskell.Refact.API (showGhc)
@@ -73,7 +70,6 @@ import SrcLoc
7370
import TcEnv
7471
import Type
7572
import Var
76-
import qualified Yi.Rope as Yi
7773

7874
-- ---------------------------------------------------------------------
7975

@@ -600,22 +596,6 @@ findDef uri pos = pluginGetFile "findDef: " uri $ \file ->
600596

601597
-- ---------------------------------------------------------------------
602598

603-
getRangeFromVFS :: Uri -> Range -> IdeM (Maybe T.Text)
604-
getRangeFromVFS uri rg = do
605-
mvf <- getVirtualFile uri
606-
case mvf of
607-
Just vfs -> return $ Just $ rangeLinesFromVfs vfs rg
608-
Nothing -> return Nothing
609-
610-
rangeLinesFromVfs :: VFS.VirtualFile -> Range -> T.Text
611-
rangeLinesFromVfs (VFS.VirtualFile _ yitext) (Range (Position lf _cf) (Position lt _ct)) = r
612-
where
613-
(_ ,s1) = Yi.splitAtLine lf yitext
614-
(s2, _) = Yi.splitAtLine (lt - lf) s1
615-
r = Yi.toText s2
616-
617-
-- ---------------------------------------------------------------------
618-
619599
data HarePoint =
620600
HP { hpFile :: Uri
621601
, hpPos :: Position

src/Haskell/Ide/Engine/Transport/LspStdio.hs

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ import Haskell.Ide.Engine.LSP.Reactor
5252
import qualified Haskell.Ide.Engine.Plugin.HaRe as HaRe
5353
import qualified Haskell.Ide.Engine.Plugin.GhcMod as GhcMod
5454
import qualified Haskell.Ide.Engine.Plugin.ApplyRefact as ApplyRefact
55-
import qualified Haskell.Ide.Engine.Plugin.Brittany as Brittany
5655
import qualified Haskell.Ide.Engine.Plugin.Hoogle as Hoogle
5756
import qualified Haskell.Ide.Engine.Plugin.HieExtras as Hie
5857
import Haskell.Ide.Engine.Plugin.Base
@@ -721,39 +720,23 @@ reactor inp diagIn = do
721720

722721
ReqDocumentFormatting req -> do
723722
liftIO $ U.logs $ "reactor:got FormatRequest:" ++ show req
724-
providers <- asks formattingProviders
725-
lf <- asks lspFuncs
726-
mc <- liftIO $ Core.config lf
727-
let providerName = formattingProvider (fromMaybe def mc)
728-
providerType = Map.lookup providerName providers
729-
case providerType of
730-
Nothing -> do
731-
reactorSend (RspDocumentFormatting (Core.makeResponseMessage req (J.List [])))
732-
unless (providerName == "none") $ do
733-
let msg = providerName <> " is not a recognised plugin for formatting. Check your config"
734-
reactorSend $ NotShowMessage $ fmServerShowMessageNotification J.MtWarning msg
735-
reactorSend $ NotLogMessage $ fmServerLogMessageNotification J.MtWarning msg
736-
Just provider ->
737-
-- LL: Is this overengineered? Do we need a pluginFormattingProvider
738-
-- or should we just call plugins straight from here based on the providerType?
739-
let params = req ^. J.params
740-
doc = params ^. J.textDocument . J.uri
741-
callback = reactorSend . RspDocumentFormatting . Core.makeResponseMessage req . J.List
742-
hreq = GReq tn (Just doc) Nothing (Just $ req ^. J.id) callback
743-
$ provider doc FormatDocument (params ^. J.options)
744-
in makeRequest hreq
723+
provider <- getFormattingProvider
724+
let params = req ^. J.params
725+
doc = params ^. J.textDocument . J.uri
726+
callback = reactorSend . RspDocumentFormatting . Core.makeResponseMessage req . J.List
727+
hreq = IReq tn (req ^. J.id) callback $ provider doc FormatDocument (params ^. J.options)
728+
makeRequest hreq
745729

746730
-- -------------------------------
747731

748732
ReqDocumentRangeFormatting req -> do
749733
liftIO $ U.logs $ "reactor:got FormatRequest:" ++ show req
734+
provider <- getFormattingProvider
750735
let params = req ^. J.params
751736
doc = params ^. J.textDocument . J.uri
752737
range = params ^. J.range
753-
tabSize = params ^. J.options . J.tabSize
754738
callback = reactorSend . RspDocumentRangeFormatting . Core.makeResponseMessage req . J.List
755-
let hreq = GReq tn (Just doc) Nothing (Just $ req ^. J.id) callback
756-
$ Brittany.brittanyCmd tabSize doc (Just range)
739+
hreq = IReq tn (req ^. J.id) callback $ provider doc (FormatRange range) (params ^. J.options)
757740
makeRequest hreq
758741

759742
-- -------------------------------
@@ -812,6 +795,26 @@ reactor inp diagIn = do
812795

813796
-- ---------------------------------------------------------------------
814797

798+
getFormattingProvider :: R FormattingProvider
799+
getFormattingProvider = do
800+
providers <- asks formattingProviders
801+
lf <- asks lspFuncs
802+
mc <- liftIO $ Core.config lf
803+
-- LL: Is this overengineered? Do we need a pluginFormattingProvider
804+
-- or should we just call plugins straight from here based on the providerType?
805+
let providerName = formattingProvider (fromMaybe def mc)
806+
mProvider = Map.lookup providerName providers
807+
case mProvider of
808+
Nothing -> do
809+
unless (providerName == "none") $ do
810+
let msg = providerName <> " is not a recognised plugin for formatting. Check your config"
811+
reactorSend $ NotShowMessage $ fmServerShowMessageNotification J.MtWarning msg
812+
reactorSend $ NotLogMessage $ fmServerLogMessageNotification J.MtWarning msg
813+
return (\_ _ _ -> return (IdeResultOk [])) -- nop formatter
814+
Just provider -> return provider
815+
816+
-- ---------------------------------------------------------------------
817+
815818
-- | Queue a diagnostics request to be performed after a timeout. This prevents recompiling
816819
-- too often when there is a quick stream of changes.
817820
queueDiagnosticsRequest

0 commit comments

Comments
 (0)