Skip to content

Commit e65c4c9

Browse files
authored
Merge branch 'master' into type-signature
2 parents 212f4ad + 0769f23 commit e65c4c9

Some content is hidden

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

56 files changed

+1083
-26
lines changed

.github/workflows/test.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ jobs:
246246
name: Test hls-change-type-signature test suite
247247
run: cabal test hls-change-type-signature-plugin --test-options="$TEST_OPTS" || cabal test hls-change-type-signature-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-change-type-signature-plugin --test-options="$TEST_OPTS"
248248

249+
- if: matrix.test
250+
name: Test hls-gadt-plugin test suit
251+
run: cabal test hls-gadt-plugin --test-options="$TEST_OPTS" || cabal test hls-gadt-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-gadt-plugin --test-options="$TEST_OPTS"
252+
249253
test_post_job:
250254
if: always()
251255
runs-on: ubuntu-latest

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
/plugins/hls-explicit-imports-plugin @pepeiborra
1616
/plugins/hls-floskell-plugin @Ailrun
1717
/plugins/hls-fourmolu-plugin @georgefst
18+
/plugins/hls-gadt-plugin @July541
1819
/plugins/hls-haddock-comments-plugin @berberman
1920
/plugins/hls-hlint-plugin @jneira @eddiemundo
2021
/plugins/hls-module-name-plugin

cabal.project

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ packages:
2828
./plugins/hls-qualify-imported-names-plugin
2929
./plugins/hls-selection-range-plugin
3030
./plugins/hls-change-type-signature-plugin
31+
./plugins/hls-gadt-plugin
3132

3233
-- Standard location for temporary packages needed for particular environments
3334
-- For example it is used in the project gitlab mirror to help in the MAcOS M1 build script

docs/features.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,19 @@ Known Limitations:
256256

257257
![Change Type Signature Demo](../plugins/hls-change-type-signature-plugin/change2.gif)
258258

259-
[Link to Docs](../plugins/hls-change-type-signature/README.md)
259+
![Link to Docs](../plugins/hls-change-type-signature-plugin/README.md)
260+
261+
### Convert to GADT syntax
262+
263+
Provided by: `hls-gadt-plugin`
264+
265+
Code action kind: `refactor.rewrite`
266+
267+
Convert a datatype to GADT syntax.
268+
269+
![GADT Demo](../plugins/hls-gadt-plugin/gadt.gif)
270+
271+
![Link to Docs](../plugins/hls-gadt-plugin/README.md)
260272

261273
## Code lenses
262274

docs/installation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ In addition make sure `haskell-language-server.exe` is not running by closing yo
110110
### Download the source code
111111

112112
```bash
113-
git clone https://github.com/haskell/haskell-language-server --recurse-submodules
113+
git clone https://github.com/haskell/haskell-language-server
114114
cd haskell-language-server
115115
```
116116

docs/supported-versions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ Sometimes a plugin will be supported in the prebuilt binaries but not in a HLS b
5555
| `hls-stylish-haskell-plugin` | |
5656
| `hls-tactics-plugin` | 9.2 |
5757
| `hls-selection-range-plugin` | |
58+
| `hls-gadt-plugin` | |
5859

5960
### Using deprecated GHC versions
6061

exe/Plugins.hs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ import Ide.Plugin.SelectionRange as SelectionRange
8282
#if changeTypeSignature
8383
import Ide.Plugin.ChangeTypeSignature as ChangeTypeSignature
8484
#endif
85+
86+
#if gadt
87+
import Ide.Plugin.GADT as GADT
88+
#endif
8589
-- formatters
8690

8791
#if floskell
@@ -190,6 +194,9 @@ idePlugins recorder includeExamples = pluginDescToIdePlugins allPlugins
190194
#endif
191195
#if changeTypeSignature
192196
ChangeTypeSignature.descriptor "changeTypeSignature" :
197+
#endif
198+
#if gadt
199+
GADT.descriptor "gadt" :
193200
#endif
194201
-- The ghcide descriptors should come last so that the notification handlers
195202
-- (which restart the Shake build) run after everything else

ghcide/src/Development/IDE/Plugin/CodeAction.hs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,15 +1561,57 @@ mkRenameEdit contents range name =
15611561
-- require understanding both the precedence of the context of the hole and of
15621562
-- the signature itself. Inserting them (almost) unconditionally is ugly but safe.
15631563
extractWildCardTypeSignature :: T.Text -> T.Text
1564-
extractWildCardTypeSignature msg = (if enclosed || not application then id else bracket) signature
1564+
extractWildCardTypeSignature msg
1565+
| enclosed || not isApp || isToplevelSig = sig
1566+
| otherwise = "(" <> sig <> ")"
15651567
where
1566-
msgSigPart = snd $ T.breakOnEnd "standing for " msg
1567-
signature = T.takeWhile (/='') . T.dropWhile (=='') . T.dropWhile (/='') $ msgSigPart
1568-
-- parenthesize type applications, e.g. (Maybe Char)
1569-
application = any isSpace . T.unpack $ signature
1570-
-- do not add extra parentheses to lists, tuples and already parenthesized types
1571-
enclosed = not (T.null signature) && (T.head signature, T.last signature) `elem` [('(',')'), ('[',']')]
1572-
bracket = ("(" `T.append`) . (`T.append` ")")
1568+
msgSigPart = snd $ T.breakOnEnd "standing for " msg
1569+
(sig, rest) = T.span (/='') . T.dropWhile (=='') . T.dropWhile (/='') $ msgSigPart
1570+
-- If we're completing something like ‘foo :: _’ parens can be safely omitted.
1571+
isToplevelSig = errorMessageRefersToToplevelHole rest
1572+
-- Parenthesize type applications, e.g. (Maybe Char).
1573+
isApp = T.any isSpace sig
1574+
-- Do not add extra parentheses to lists, tuples and already parenthesized types.
1575+
enclosed = not (T.null sig) && (T.head sig, T.last sig) `elem` [('(', ')'), ('[', ']')]
1576+
1577+
-- | Detect whether user wrote something like @foo :: _@ or @foo :: (_, Int)@.
1578+
-- The former is considered toplevel case for which the function returns 'True',
1579+
-- the latter is not toplevel and the returned value is 'False'.
1580+
--
1581+
-- When type hole is at toplevel then there’s a line starting with
1582+
-- "• In the type signature" which ends with " :: _" like in the
1583+
-- following snippet:
1584+
--
1585+
-- source/library/Language/Haskell/Brittany/Internal.hs:131:13: error:
1586+
-- • Found type wildcard ‘_’ standing for ‘HsDecl GhcPs’
1587+
-- To use the inferred type, enable PartialTypeSignatures
1588+
-- • In the type signature: decl :: _
1589+
-- In an equation for ‘splitAnnots’:
1590+
-- splitAnnots m@HsModule {hsmodAnn, hsmodDecls}
1591+
-- = undefined
1592+
-- where
1593+
-- ann :: SrcSpanAnnA
1594+
-- decl :: _
1595+
-- L ann decl = head hsmodDecls
1596+
-- • Relevant bindings include
1597+
-- [REDACTED]
1598+
--
1599+
-- When type hole is not at toplevel there’s a stack of where
1600+
-- the hole was located ending with "In the type signature":
1601+
--
1602+
-- source/library/Language/Haskell/Brittany/Internal.hs:130:20: error:
1603+
-- • Found type wildcard ‘_’ standing for ‘GhcPs’
1604+
-- To use the inferred type, enable PartialTypeSignatures
1605+
-- • In the first argument of ‘HsDecl’, namely ‘_’
1606+
-- In the type ‘HsDecl _’
1607+
-- In the type signature: decl :: HsDecl _
1608+
-- • Relevant bindings include
1609+
-- [REDACTED]
1610+
errorMessageRefersToToplevelHole :: T.Text -> Bool
1611+
errorMessageRefersToToplevelHole msg =
1612+
not (T.null prefix) && " :: _" `T.isSuffixOf` T.takeWhile (/= '\n') rest
1613+
where
1614+
(prefix, rest) = T.breakOn "• In the type signature:" msg
15731615

15741616
extractRenamableTerms :: T.Text -> [T.Text]
15751617
extractRenamableTerms msg

ghcide/test/exe/Main.hs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,7 +1196,7 @@ typeWildCardActionTests = testGroup "type wildcard actions"
11961196
[ "func :: _"
11971197
, "func x = x"
11981198
]
1199-
[ "func :: (p -> p)"
1199+
[ "func :: p -> p"
12001200
, "func x = x"
12011201
]
12021202
, testUseTypeSignature "local signature"
@@ -1212,11 +1212,11 @@ typeWildCardActionTests = testGroup "type wildcard actions"
12121212
, " y = x * 2"
12131213
, " in y"
12141214
]
1215-
, testUseTypeSignature "multi-line message"
1215+
, testUseTypeSignature "multi-line message 1"
12161216
[ "func :: _"
12171217
, "func x y = x + y"
12181218
]
1219-
[ "func :: (Integer -> Integer -> Integer)"
1219+
[ "func :: Integer -> Integer -> Integer"
12201220
, "func x y = x + y"
12211221
]
12221222
, testUseTypeSignature "type in parentheses"
@@ -1240,6 +1240,43 @@ typeWildCardActionTests = testGroup "type wildcard actions"
12401240
[ "func :: IO ()"
12411241
, "func = putChar 'H'"
12421242
]
1243+
, testUseTypeSignature "no spaces around '::'"
1244+
[ "func::_"
1245+
, "func x y = x + y"
1246+
]
1247+
[ "func::Integer -> Integer -> Integer"
1248+
, "func x y = x + y"
1249+
]
1250+
, testGroup "add parens if hole is part of bigger type"
1251+
[ testUseTypeSignature "subtype 1"
1252+
[ "func :: _ -> Integer -> Integer"
1253+
, "func x y = x + y"
1254+
]
1255+
[ "func :: Integer -> Integer -> Integer"
1256+
, "func x y = x + y"
1257+
]
1258+
, testUseTypeSignature "subtype 2"
1259+
[ "func :: Integer -> _ -> Integer"
1260+
, "func x y = x + y"
1261+
]
1262+
[ "func :: Integer -> Integer -> Integer"
1263+
, "func x y = x + y"
1264+
]
1265+
, testUseTypeSignature "subtype 3"
1266+
[ "func :: Integer -> Integer -> _"
1267+
, "func x y = x + y"
1268+
]
1269+
[ "func :: Integer -> Integer -> Integer"
1270+
, "func x y = x + y"
1271+
]
1272+
, testUseTypeSignature "subtype 4"
1273+
[ "func :: Integer -> _"
1274+
, "func x y = x + y"
1275+
]
1276+
[ "func :: Integer -> (Integer -> Integer)"
1277+
, "func x y = x + y"
1278+
]
1279+
]
12431280
]
12441281
where
12451282
-- | Test session of given name, checking action "Use type signature..."

haskell-language-server.cabal

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,11 @@ flag changeTypeSignature
186186
default: True
187187
manual: True
188188

189+
flag gadt
190+
description: Enable gadt plugin
191+
default: True
192+
manual: True
193+
189194
-- formatters
190195

191196
flag floskell
@@ -308,6 +313,11 @@ common changeTypeSignature
308313
build-depends: hls-change-type-signature-plugin ^>= 1.0
309314
cpp-options: -DchangeTypeSignature
310315

316+
common gadt
317+
if flag(gadt)
318+
build-depends: hls-gadt-plugin ^>= 1.0
319+
cpp-options: -Dgadt
320+
311321
-- formatters
312322

313323
common floskell
@@ -359,6 +369,7 @@ executable haskell-language-server
359369
, alternateNumberFormat
360370
, qualifyImportedNames
361371
, selectionRange
372+
, gadt
362373
, floskell
363374
, fourmolu
364375
, ormolu

hls-plugin-api/src/Ide/PluginUtils.hs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ import Language.LSP.Types hiding
5656
SemanticTokensEdit (_start))
5757
import qualified Language.LSP.Types as J
5858
import Language.LSP.Types.Capabilities
59-
import Language.LSP.Types.Lens (uri)
6059

6160
-- ---------------------------------------------------------------------
6261

hls-test-utils/src/Test/Hls/Util.hs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ module Test.Hls.Util
4040
, waitForDiagnosticsFromSourceWithTimeout
4141
, withCurrentDirectoryInTmp
4242
, withCurrentDirectoryInTmp'
43+
, withCanonicalTempDir
4344
)
4445
where
4546

@@ -54,16 +55,17 @@ import Data.Default
5455
import Data.List.Extra (find)
5556
import qualified Data.Set as Set
5657
import qualified Data.Text as T
57-
import Development.IDE (GhcVersion(..), ghcVersion)
58+
import Development.IDE (GhcVersion (..), ghcVersion)
5859
import qualified Language.LSP.Test as Test
5960
import Language.LSP.Types hiding (Reason (..))
6061
import qualified Language.LSP.Types.Capabilities as C
6162
import qualified Language.LSP.Types.Lens as L
6263
import System.Directory
6364
import System.Environment
6465
import System.FilePath
65-
import System.IO.Temp
6666
import System.Info.Extra (isMac, isWindows)
67+
import qualified System.IO.Extra
68+
import System.IO.Temp
6769
import System.Time.Extra (Seconds, sleep)
6870
import Test.Tasty (TestTree)
6971
import Test.Tasty.ExpectedFailure (expectFailBecause,
@@ -253,7 +255,7 @@ onMatch :: [a] -> (a -> Bool) -> String -> IO a
253255
onMatch as predicate err = maybe (fail err) return (find predicate as)
254256

255257
noMatch :: [a] -> (a -> Bool) -> String -> IO ()
256-
noMatch [] _ _ = pure ()
258+
noMatch [] _ _ = pure ()
257259
noMatch as predicate err = bool (pure ()) (fail err) (any predicate as)
258260

259261
inspectDiagnostic :: [Diagnostic] -> [T.Text] -> IO Diagnostic
@@ -384,3 +386,10 @@ getCompletionByLabel desiredLabel compls =
384386
Nothing -> liftIO . assertFailure $
385387
"Completion with label " <> show desiredLabel
386388
<> " not found in " <> show (fmap (^. L.label) compls)
389+
390+
-- ---------------------------------------------------------------------
391+
-- Run with a canonicalized temp dir
392+
withCanonicalTempDir :: (FilePath -> IO a) -> IO a
393+
withCanonicalTempDir f = System.IO.Extra.withTempDir $ \dir -> do
394+
dir' <- canonicalizePath dir
395+
f dir'

plugins/hls-call-hierarchy-plugin/test/Main.hs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import System.Directory.Extra
1919
import System.FilePath
2020
import qualified System.IO.Extra
2121
import Test.Hls
22+
import Test.Hls.Util (withCanonicalTempDir)
2223

2324
plugin :: PluginDescriptor IdeState
2425
plugin = descriptor "callHierarchy"
@@ -319,7 +320,7 @@ outgoingCallsTests =
319320
testGroup "Outgoing Calls"
320321
[ testGroup "single file"
321322
[
322-
testCase "xdata unavailable" $ withTempDir $ \dir ->
323+
testCase "xdata unavailable" $ withCanonicalTempDir $ \dir ->
323324
runSessionWithServer plugin dir $ do
324325
doc <- createDoc "A.hs" "haskell" $ T.unlines ["a=3", "b=a"]
325326
waitForKickDone
@@ -423,7 +424,7 @@ deriving instance Ord CallHierarchyIncomingCall
423424
deriving instance Ord CallHierarchyOutgoingCall
424425

425426
incomingCallTestCase :: T.Text -> Int -> Int -> [(Int, Int)] -> [Range] -> Assertion
426-
incomingCallTestCase contents queryX queryY positions ranges = withTempDir $ \dir ->
427+
incomingCallTestCase contents queryX queryY positions ranges = withCanonicalTempDir $ \dir ->
427428
runSessionWithServer plugin dir $ do
428429
doc <- createDoc "A.hs" "haskell" contents
429430
waitForKickDone
@@ -465,7 +466,7 @@ incomingCallMultiFileTestCase filepath queryX queryY mp =
465466
closeDoc doc
466467

467468
outgoingCallTestCase :: T.Text -> Int -> Int -> [(Int, Int)] -> [Range] -> Assertion
468-
outgoingCallTestCase contents queryX queryY positions ranges = withTempDir $ \dir ->
469+
outgoingCallTestCase contents queryX queryY positions ranges = withCanonicalTempDir $ \dir ->
469470
runSessionWithServer plugin dir $ do
470471
doc <- createDoc "A.hs" "haskell" contents
471472
waitForKickDone
@@ -505,7 +506,7 @@ outgoingCallMultiFileTestCase filepath queryX queryY mp =
505506
closeDoc doc
506507

507508
oneCaseWithCreate :: T.Text -> Int -> Int -> (Uri -> CallHierarchyItem) -> Assertion
508-
oneCaseWithCreate contents queryX queryY expected = withTempDir $ \dir ->
509+
oneCaseWithCreate contents queryX queryY expected = withCanonicalTempDir $ \dir ->
509510
runSessionWithServer plugin dir $ do
510511
doc <- createDoc "A.hs" "haskell" contents
511512
waitForKickDone
@@ -544,8 +545,3 @@ mkIncomingCallsParam = CallHierarchyIncomingCallsParams Nothing Nothing
544545

545546
mkOutgoingCallsParam :: CallHierarchyItem -> CallHierarchyOutgoingCallsParams
546547
mkOutgoingCallsParam = CallHierarchyOutgoingCallsParams Nothing Nothing
547-
548-
withTempDir :: (FilePath -> IO a) -> IO a
549-
withTempDir f = System.IO.Extra.withTempDir $ \dir -> do
550-
dir' <- canonicalizePath dir
551-
f dir'

0 commit comments

Comments
 (0)