Skip to content

Commit 244aa04

Browse files
authored
Merge branch 'master' into ghcide-ca
2 parents 5e76ce7 + 94573be commit 244aa04

File tree

87 files changed

+1232
-889
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+1232
-889
lines changed

.github/workflows/test.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,9 @@ jobs:
135135
if: ${{ matrix.test }}
136136
run: LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-tactics-plugin --test-options="-j1"
137137

138+
- name: Test brittany plugin
139+
if: ${{ matrix.test }}
140+
env:
141+
HLS_TEST_EXE: hls
142+
HLS_WRAPPER_TEST_EXE: hls-wrapper
143+
run: cabal test hls-brittany-plugin || cabal test hls-brittany-plugin --test-options="-j1"

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ For example, `haskell-language-server` allows you to choose the formatting provi
301301
This option obviously would not make sense for language servers for other languages, or even for other Haskell language servers (which need not even support formatting).
302302

303303
Here is a list of the additional settings currently supported by `haskell-language-server`, along with their setting key (you may not need to know this) and default:
304-
- Formatting provider (`haskell.formattingProvider`, default `ormolu`): what formatter to use; one of `floskell`, `ormolu`, `fourmolu`, `stylish-haskell`, or `brittany` (if compiled with AGPL)
304+
- Formatting provider (`haskell.formattingProvider`, default `ormolu`): what formatter to use; one of `floskell`, `ormolu`, `fourmolu`, `stylish-haskell`, or `brittany` (if compiled with the brittany plugin)
305305
- Format on imports (`haskell.formatOnImportOn`, default true): whether to format after adding an import
306306
- Maximum number of problems to report (`haskell.maxNumberOfProblems`, default 100): the maximum number of problems the server will send to the client
307307
- Diagnostics on change (`haskell.diagnosticsOnChange`, default true): (currently unused)
@@ -648,7 +648,7 @@ This issue should be fixed in Stack versions >= 2.5.
648648
#### Problems with dynamic linking
649649

650650
As haskell-language-server prebuilt binaries are statically linked, they don't play well with projects using dynamic linking.
651-
An usual symptom is the presence of errors containing `unknown symbol` and it is typical in arch linux, where a dynamically linked version of ghc is used.
651+
An usual symptom is the presence of errors containing `unknown symbol` and it is typical in arch linux, where a dynamically linked version of ghc is used.
652652

653653
The workaround is to use a version of haskell-language-server compiled from source with `-dynamic` enabled`. See more details [here](https://github.com/haskell/haskell-language-server/issues/1160#issuecomment-756566273).
654654

cabal.project

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ packages:
55
./ghcide
66
./hls-plugin-api
77
./plugins/hls-tactics-plugin
8+
./plugins/hls-brittany-plugin
89
./plugins/hls-class-plugin
910
./plugins/hls-eval-plugin
1011
./plugins/hls-explicit-imports-plugin

docs/plugin-tutorial.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,7 @@ idePlugins = pluginDescToIdePlugins allPlugins
9696
, Ormolu.descriptor "ormolu"
9797
, StylishHaskell.descriptor "stylish-haskell"
9898
, Retrie.descriptor "retrie"
99-
#if AGPL
10099
, Brittany.descriptor "brittany"
101-
#endif
102100
, Eval.descriptor "eval"
103101
]
104102
```

exe/Plugins.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ import Ide.Plugin.Ormolu as Ormolu
7171
import Ide.Plugin.StylishHaskell as StylishHaskell
7272
#endif
7373

74-
#if AGPL && brittany
74+
#if brittany
7575
import Ide.Plugin.Brittany as Brittany
7676
#endif
7777

ghcide/exe/Main.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ main = do
8888
Typecheck x | not argLSP -> Just x
8989
_ -> Nothing
9090

91-
,Main.argsLogger = logger
91+
,Main.argsLogger = pure logger
9292

9393
,Main.argsRules = do
9494
-- install the main and ghcide-plugin rules

ghcide/ghcide.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ cabal-version: 2.2
22
build-type: Simple
33
category: Development
44
name: ghcide
5-
version: 1.0.0.0
5+
version: 1.1.0.0
66
license: Apache-2.0
77
license-file: LICENSE
88
author: Digital Asset and Ghcide contributors

ghcide/session-loader/Development/IDE/Session.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,8 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do
395395
lfp <- flip makeRelative cfp <$> getCurrentDirectory
396396
logInfo logger $ T.pack ("Consulting the cradle for " <> show lfp)
397397

398-
when (isNothing hieYaml) $ mRunLspT lspEnv $
399-
sendNotification SWindowShowMessage $ notifyUserImplicitCradle lfp
398+
when (isNothing hieYaml) $
399+
logWarning logger $ implicitCradleWarning lfp
400400

401401
cradle <- maybe (loadImplicitHieCradle $ addTrailingPathSeparator dir) loadCradle hieYaml
402402

@@ -820,8 +820,8 @@ getCacheDirsDefault prefix opts = do
820820
cacheDir :: String
821821
cacheDir = "ghcide"
822822

823-
notifyUserImplicitCradle:: FilePath -> ShowMessageParams
824-
notifyUserImplicitCradle fp =ShowMessageParams MtWarning $
823+
implicitCradleWarning :: FilePath -> T.Text
824+
implicitCradleWarning fp =
825825
"No [cradle](https://github.com/mpickering/hie-bios#hie-bios) found for "
826826
<> T.pack fp <>
827827
".\n Proceeding with [implicit cradle](https://hackage.haskell.org/package/implicit-hie).\n"<>

ghcide/src/Development/IDE.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import Development.IDE.Core.IdeConfiguration as X (IdeConfiguration (.
1212
isWorkspaceFile)
1313
import Development.IDE.Core.OfInterest as X (getFilesOfInterest)
1414
import Development.IDE.Core.RuleTypes as X
15-
import Development.IDE.Core.Rules as X (getAtPoint,
15+
import Development.IDE.Core.Rules as X (IsHiFileStable (..),
16+
getAtPoint,
1617
getClientConfigAction,
1718
getDefinition,
1819
getParsedModule,
@@ -21,10 +22,12 @@ import Development.IDE.Core.Service as X (runAction)
2122
import Development.IDE.Core.Shake as X (FastResult (..),
2223
IdeAction (..),
2324
IdeRule, IdeState,
25+
RuleBody (..),
2426
ShakeExtras,
2527
actionLogger,
2628
define,
2729
defineEarlyCutoff,
30+
defineNoDiagnostics,
2831
getClientConfig,
2932
getPluginConfig,
3033
ideLogger,

ghcide/src/Development/IDE/Core/Compile.hs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,12 @@ import Control.Concurrent.STM hiding (orElse)
115115
import Data.Aeson (toJSON)
116116
import Data.Binary
117117
import Data.Binary.Put
118-
import Data.Bits (shiftR)
119118
import qualified Data.ByteString.Lazy as LBS
120119
import Data.Coerce
121120
import Data.Functor
122121
import qualified Data.HashMap.Strict as HashMap
123122
import Data.Tuple.Extra (dupe)
124123
import Data.Unique
125-
import Data.Word
126-
import Foreign.Marshal.Array (withArrayLen)
127124
import GHC.Fingerprint
128125
import qualified Language.LSP.Server as LSP
129126
import qualified Language.LSP.Types as LSP

ghcide/src/Development/IDE/Core/FileExists.hs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ modifyFileExists state changes = do
103103
modifyVar_ var $ evaluate . HashMap.union changesMap
104104
-- See Note [Invalidating file existence results]
105105
-- flush previous values
106-
mapM_ (deleteValue state GetFileExists) (HashMap.keys changesMap)
106+
mapM_ (deleteValue (shakeExtras state) GetFileExists) (HashMap.keys changesMap)
107107

108108
fromChange :: FileChangeType -> Maybe Bool
109109
fromChange FcCreated = Just True
@@ -200,7 +200,7 @@ fileExistsRules lspEnv vfs = do
200200
-- Requires an lsp client that provides WatchedFiles notifications, but assumes that this has already been checked.
201201
fileExistsRulesFast :: (NormalizedFilePath -> Action Bool) -> VFSHandle -> Rules ()
202202
fileExistsRulesFast isWatched vfs =
203-
defineEarlyCutoff $ \GetFileExists file -> do
203+
defineEarlyCutoff $ RuleNoDiagnostics $ \GetFileExists file -> do
204204
isWF <- isWatched file
205205
if isWF
206206
then fileExistsFast vfs file
@@ -222,7 +222,7 @@ For the VFS lookup, however, we won't get prompted to flush the result, so inste
222222
we use 'alwaysRerun'.
223223
-}
224224

225-
fileExistsFast :: VFSHandle -> NormalizedFilePath -> Action (Maybe BS.ByteString, ([a], Maybe Bool))
225+
fileExistsFast :: VFSHandle -> NormalizedFilePath -> Action (Maybe BS.ByteString, Maybe Bool)
226226
fileExistsFast vfs file = do
227227
-- Could in principle use 'alwaysRerun' here, but it's too slwo, See Note [Invalidating file existence results]
228228
mp <- getFileExistsMapUntracked
@@ -233,21 +233,21 @@ fileExistsFast vfs file = do
233233
-- We don't know about it: use the slow route.
234234
-- Note that we do *not* call 'fileExistsSlow', as that would trigger 'alwaysRerun'.
235235
Nothing -> liftIO $ getFileExistsVFS vfs file
236-
pure (summarizeExists exist, ([], Just exist))
236+
pure (summarizeExists exist, Just exist)
237237

238238
summarizeExists :: Bool -> Maybe BS.ByteString
239239
summarizeExists x = Just $ if x then BS.singleton 1 else BS.empty
240240

241241
fileExistsRulesSlow :: VFSHandle -> Rules ()
242242
fileExistsRulesSlow vfs =
243-
defineEarlyCutoff $ \GetFileExists file -> fileExistsSlow vfs file
243+
defineEarlyCutoff $ RuleNoDiagnostics $ \GetFileExists file -> fileExistsSlow vfs file
244244

245-
fileExistsSlow :: VFSHandle -> NormalizedFilePath -> Action (Maybe BS.ByteString, ([a], Maybe Bool))
245+
fileExistsSlow :: VFSHandle -> NormalizedFilePath -> Action (Maybe BS.ByteString, Maybe Bool)
246246
fileExistsSlow vfs file = do
247247
-- See Note [Invalidating file existence results]
248248
alwaysRerun
249249
exist <- liftIO $ getFileExistsVFS vfs file
250-
pure (summarizeExists exist, ([], Just exist))
250+
pure (summarizeExists exist, Just exist)
251251

252252
getFileExistsVFS :: VFSHandle -> NormalizedFilePath -> IO Bool
253253
getFileExistsVFS vfs file = do

ghcide/src/Development/IDE/Core/FileStore.hs

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@ module Development.IDE.Core.FileStore(
1414
VFSHandle,
1515
makeVFSHandle,
1616
makeLSPVFSHandle,
17-
isFileOfInterestRule
18-
,resetFileStore) where
17+
isFileOfInterestRule,
18+
resetFileStore,
19+
resetInterfaceStore,
20+
getModificationTimeImpl,
21+
addIdeGlobal,
22+
getFileContentsImpl
23+
) where
1924

2025
import Control.Concurrent.Extra
2126
import Control.Concurrent.STM (atomically)
@@ -31,7 +36,8 @@ import Data.Maybe
3136
import qualified Data.Rope.UTF16 as Rope
3237
import qualified Data.Text as T
3338
import Data.Time
34-
import Development.IDE.Core.OfInterest (getFilesOfInterest, OfInterestVar(..))
39+
import Development.IDE.Core.OfInterest (OfInterestVar (..),
40+
getFilesOfInterest)
3541
import Development.IDE.Core.RuleTypes
3642
import Development.IDE.Core.Shake
3743
import Development.IDE.GHC.Orphans ()
@@ -65,8 +71,11 @@ import Language.LSP.Server hiding
6571
import qualified Language.LSP.Server as LSP
6672
import Language.LSP.Types (FileChangeType (FcChanged),
6773
FileEvent (FileEvent),
68-
uriToFilePath, toNormalizedFilePath)
74+
NormalizedFilePath (NormalizedFilePath),
75+
toNormalizedFilePath,
76+
uriToFilePath)
6977
import Language.LSP.VFS
78+
import System.FilePath
7079

7180
makeVFSHandle :: IO VFSHandle
7281
makeVFSHandle = do
@@ -91,14 +100,22 @@ makeLSPVFSHandle lspEnv = VFSHandle
91100

92101

93102
isFileOfInterestRule :: Rules ()
94-
isFileOfInterestRule = defineEarlyCutoff $ \IsFileOfInterest f -> do
103+
isFileOfInterestRule = defineEarlyCutoff $ RuleNoDiagnostics $ \IsFileOfInterest f -> do
95104
filesOfInterest <- getFilesOfInterest
96105
let res = maybe NotFOI IsFOI $ f `HM.lookup` filesOfInterest
97-
return (Just $ BS.pack $ show $ hash res, ([], Just res))
106+
return (Just $ BS.pack $ show $ hash res, Just res)
98107

99108
getModificationTimeRule :: VFSHandle -> (NormalizedFilePath -> Action Bool) -> Rules ()
100-
getModificationTimeRule vfs isWatched =
101-
defineEarlyCutoff $ \(GetModificationTime_ missingFileDiags) file -> do
109+
getModificationTimeRule vfs isWatched = defineEarlyCutoff $ Rule $ \(GetModificationTime_ missingFileDiags) file ->
110+
getModificationTimeImpl vfs isWatched missingFileDiags file
111+
112+
getModificationTimeImpl :: VFSHandle
113+
-> (NormalizedFilePath -> Action Bool)
114+
-> Bool
115+
-> NormalizedFilePath
116+
-> Action
117+
(Maybe BS.ByteString, ([FileDiagnostic], Maybe FileVersion))
118+
getModificationTimeImpl vfs isWatched missingFileDiags file = do
102119
let file' = fromNormalizedFilePath file
103120
let wrap time@(l,s) = (Just $ BS.pack $ show time, ([], Just $ ModificationTime l s))
104121
mbVirtual <- liftIO $ getVirtualFile vfs $ filePathToUri' file
@@ -111,7 +128,7 @@ getModificationTimeRule vfs isWatched =
111128
pure (Just $ BS.pack $ show ver, ([], Just $ VFSVersion ver))
112129
Nothing -> do
113130
isWF <- isWatched file
114-
unless isWF alwaysRerun
131+
unless (isWF || isInterface file) alwaysRerun
115132
liftIO $ fmap wrap (getModTime file')
116133
`catch` \(e :: IOException) -> do
117134
let err | isDoesNotExistError e = "File does not exist: " ++ file'
@@ -121,6 +138,18 @@ getModificationTimeRule vfs isWatched =
121138
then return (Nothing, ([], Nothing))
122139
else return (Nothing, ([diag], Nothing))
123140

141+
-- | Interface files cannot be watched, since they live outside the workspace.
142+
-- But interface files are private, in that only HLS writes them.
143+
-- So we implement watching ourselves, and bypass the need for alwaysRerun.
144+
isInterface :: NormalizedFilePath -> Bool
145+
isInterface f = takeExtension (fromNormalizedFilePath f) `elem` [".hi", ".hi-boot"]
146+
147+
-- | Reset the GetModificationTime state of interface files
148+
resetInterfaceStore :: ShakeExtras -> NormalizedFilePath -> IO ()
149+
resetInterfaceStore state f = do
150+
deleteValue state (GetModificationTime_ True) f
151+
deleteValue state (GetModificationTime_ False) f
152+
124153
-- | Reset the GetModificationTime state of watched files
125154
resetFileStore :: IdeState -> [FileEvent] -> IO ()
126155
resetFileStore ideState changes = mask $ \_ ->
@@ -134,8 +163,8 @@ resetFileStore ideState changes = mask $ \_ ->
134163
OfInterestVar foisVar <- getIdeGlobalExtras (shakeExtras ideState)
135164
fois <- readVar foisVar
136165
unless (HM.member (toNormalizedFilePath f) fois) $ do
137-
deleteValue ideState (GetModificationTime_ True) (toNormalizedFilePath' f)
138-
deleteValue ideState (GetModificationTime_ False) (toNormalizedFilePath' f)
166+
deleteValue (shakeExtras ideState) (GetModificationTime_ True) (toNormalizedFilePath' f)
167+
deleteValue (shakeExtras ideState) (GetModificationTime_ False) (toNormalizedFilePath' f)
139168
_ -> pure ()
140169

141170
-- Dir.getModificationTime is surprisingly slow since it performs
@@ -181,16 +210,21 @@ internalTimeToUTCTime large small =
181210
#endif
182211

183212
getFileContentsRule :: VFSHandle -> Rules ()
184-
getFileContentsRule vfs =
185-
define $ \GetFileContents file -> do
186-
-- need to depend on modification time to introduce a dependency with Cutoff
187-
time <- use_ GetModificationTime file
188-
res <- liftIO $ ideTryIOException file $ do
189-
mbVirtual <- getVirtualFile vfs $ filePathToUri' file
190-
pure $ Rope.toText . _text <$> mbVirtual
191-
case res of
192-
Left err -> return ([err], Nothing)
193-
Right contents -> return ([], Just (time, contents))
213+
getFileContentsRule vfs = define $ \GetFileContents file -> getFileContentsImpl vfs file
214+
215+
getFileContentsImpl
216+
:: VFSHandle
217+
-> NormalizedFilePath
218+
-> Action ([FileDiagnostic], Maybe (FileVersion, Maybe T.Text))
219+
getFileContentsImpl vfs file = do
220+
-- need to depend on modification time to introduce a dependency with Cutoff
221+
time <- use_ GetModificationTime file
222+
res <- liftIO $ ideTryIOException file $ do
223+
mbVirtual <- getVirtualFile vfs $ filePathToUri' file
224+
pure $ Rope.toText . _text <$> mbVirtual
225+
case res of
226+
Left err -> return ([err], Nothing)
227+
Right contents -> return ([], Just (time, contents))
194228

195229
ideTryIOException :: NormalizedFilePath -> IO a -> IO (Either FileDiagnostic a)
196230
ideTryIOException fp act =

ghcide/src/Development/IDE/Core/OfInterest.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@ instance Binary GetFilesOfInterest
5656
ofInterestRules :: Rules ()
5757
ofInterestRules = do
5858
addIdeGlobal . OfInterestVar =<< liftIO (newVar HashMap.empty)
59-
defineEarlyCutoff $ \GetFilesOfInterest _file -> assert (null $ fromNormalizedFilePath _file) $ do
59+
defineEarlyCutoff $ RuleNoDiagnostics $ \GetFilesOfInterest _file -> assert (null $ fromNormalizedFilePath _file) $ do
6060
alwaysRerun
6161
filesOfInterest <- getFilesOfInterestUntracked
62-
pure (Just $ BS.fromString $ show filesOfInterest, ([], Just filesOfInterest))
62+
pure (Just $ BS.fromString $ show filesOfInterest, Just filesOfInterest)
6363

6464

6565
-- | Get the files that are open in the IDE.

0 commit comments

Comments
 (0)