Skip to content

Commit ea8dc5d

Browse files
committed
init hls-explicit-fixity-plugin
1 parent 140f904 commit ea8dc5d

File tree

12 files changed

+230
-2
lines changed

12 files changed

+230
-2
lines changed

cabal.project

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ packages:
2929
./plugins/hls-selection-range-plugin
3030
./plugins/hls-change-type-signature-plugin
3131
./plugins/hls-gadt-plugin
32+
./plugins/hls-explicit-fixity-plugin
3233

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

exe/Plugins.hs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ import Ide.Plugin.ChangeTypeSignature as ChangeTypeSignature
8686
#if gadt
8787
import Ide.Plugin.GADT as GADT
8888
#endif
89+
90+
#if explicitFixity
91+
import Ide.Plugin.ExplicitFixity as ExplicitFixity
92+
#endif
93+
8994
-- formatters
9095

9196
#if floskell
@@ -201,7 +206,11 @@ idePlugins recorder includeExamples = pluginDescToIdePlugins allPlugins
201206
-- The ghcide descriptors should come last so that the notification handlers
202207
-- (which restart the Shake build) run after everything else
203208
GhcIde.descriptors pluginRecorder
209+
#if explicitFixity
210+
++ [ExplicitFixity.descriptor "explicitFixity"]
211+
#endif
204212
examplePlugins =
205213
[Example.descriptor pluginRecorder "eg"
206214
,Example2.descriptor pluginRecorder "eg2"
207215
]
216+

ghcide/src/Development/IDE/GHC/Compat/Core.hs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ module Development.IDE.GHC.Compat.Core (
102102
#endif
103103
-- * Fixity
104104
LexicalFixity(..),
105+
Fixity (..),
106+
mi_fix,
107+
defaultFixity,
108+
lookupFixityRn,
105109
-- * ModSummary
106110
ModSummary(..),
107111
-- * HomeModInfo
@@ -551,6 +555,7 @@ import GHC.Runtime.Context (InteractiveImport (..))
551555
import GHC.Parser.Lexer
552556
import qualified GHC.Runtime.Linker as Linker
553557
#endif
558+
import GHC.Rename.Fixity (lookupFixityRn)
554559
import GHC.Rename.Names
555560
import GHC.Rename.Splice
556561
import qualified GHC.Runtime.Interpreter as GHCi
@@ -567,7 +572,7 @@ import GHC.Tc.Utils.TcType as TcType
567572
import qualified GHC.Types.Avail as Avail
568573
#if MIN_VERSION_ghc(9,2,0)
569574
import GHC.Types.Avail (greNamePrintableName)
570-
import GHC.Types.Fixity (LexicalFixity (..))
575+
import GHC.Types.Fixity (LexicalFixity (..), Fixity (..), defaultFixity)
571576
#endif
572577
#if MIN_VERSION_ghc(9,2,0)
573578
import GHC.Types.Meta
@@ -612,7 +617,7 @@ import GHC.Unit.Module.Imported
612617
import GHC.Unit.Module.ModDetails
613618
import GHC.Unit.Module.ModGuts
614619
import GHC.Unit.Module.ModIface (IfaceExport, ModIface (..),
615-
ModIface_ (..))
620+
ModIface_ (..), mi_fix)
616621
import GHC.Unit.Module.ModSummary (ModSummary (..))
617622
#endif
618623
import GHC.Unit.State (ModuleOrigin (..))
@@ -687,6 +692,7 @@ import qualified Panic as Plain
687692
#endif
688693
import Parser
689694
import PatSyn
695+
import RnFixity
690696
#if MIN_VERSION_ghc(8,8,0)
691697
import Plugins
692698
#endif

haskell-language-server.cabal

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ flag gadt
191191
default: True
192192
manual: True
193193

194+
flag explicitFixity
195+
description: Enable explicitFixity plugin
196+
default: True
197+
manual: True
198+
194199
-- formatters
195200

196201
flag floskell
@@ -318,6 +323,11 @@ common gadt
318323
build-depends: hls-gadt-plugin ^>= 1.0
319324
cpp-options: -Dgadt
320325

326+
common explicitFixity
327+
if flag(explicitFixity)
328+
build-depends: hls-explicit-fixity-plugin ^>= 1.0
329+
cpp-options: -DexplicitFixity
330+
321331
-- formatters
322332

323333
common floskell
@@ -370,6 +380,7 @@ executable haskell-language-server
370380
, qualifyImportedNames
371381
, selectionRange
372382
, gadt
383+
, explicitFixity
373384
, floskell
374385
, fourmolu
375386
, ormolu
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
cabal-version: 2.4
2+
name: hls-explicit-fixity-plugin
3+
version: 1.0.0.0
4+
synopsis: Show fixity explicitly
5+
description:
6+
Please see the README on GitHub at <https://github.com/haskell/haskell-language-server/tree/master/plugins/hls-explicit-fixity-plugin#readme>
7+
8+
license: Apache-2.0
9+
license-file: LICENSE
10+
author: Lei Zhu
11+
maintainer: [email protected]
12+
category: Development
13+
build-type: Simple
14+
extra-source-files:
15+
LICENSE
16+
test/testdata/*.hs
17+
18+
library
19+
exposed-modules: Ide.Plugin.ExplicitFixity
20+
21+
hs-source-dirs: src
22+
build-depends:
23+
, aeson
24+
, base >=4.12 && <5
25+
, containers
26+
, extra
27+
, ghc
28+
, ghcide ^>= 1.7
29+
, ghc-boot-th
30+
, ghc-exactprint
31+
, hls-plugin-api ^>= 1.4
32+
, lens
33+
, lsp >=1.2.0.1
34+
, mtl
35+
, text
36+
, transformers
37+
, unordered-containers
38+
39+
ghc-options:
40+
-Wall
41+
-Wno-name-shadowing
42+
-Wno-unticked-promoted-constructors
43+
default-language: Haskell2010
44+
default-extensions: DataKinds
45+
46+
test-suite tests
47+
type: exitcode-stdio-1.0
48+
default-language: Haskell2010
49+
hs-source-dirs: test
50+
main-is: Main.hs
51+
ghc-options: -threaded -rtsopts -with-rtsopts=-N
52+
build-depends:
53+
, base
54+
, filepath
55+
, hls-explicit-fixity-plugin
56+
, hls-test-utils ^>=1.3
57+
, lens
58+
, lsp
59+
, lsp-test
60+
, text
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
{-# OPTIONS_GHC -Wall #-}
3+
{-# OPTIONS_GHC -Wno-deprecations #-}
4+
{-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-}
5+
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
6+
{-# HLINT ignore "Functor law" #-}
7+
8+
module Ide.Plugin.ExplicitFixity where
9+
import Control.Monad (forM)
10+
import Control.Monad.IO.Class (liftIO)
11+
import Data.Bifunctor
12+
import Data.List.Extra (nubOn)
13+
import qualified Data.Map as M
14+
import Data.Maybe
15+
import qualified Data.Text as T
16+
import Development.IDE hiding (pluginHandlers)
17+
import Development.IDE.GHC.Compat
18+
import Development.IDE.Spans.AtPoint (pointCommand)
19+
import Ide.PluginUtils (getNormalizedFilePath,
20+
handleMaybeM, pluginResponse)
21+
import Ide.Types
22+
import Language.LSP.Types
23+
24+
descriptor :: PluginId -> PluginDescriptor IdeState
25+
descriptor plId = (defaultPluginDescriptor plId)
26+
{ pluginHandlers = mkPluginHandler STextDocumentHover hover
27+
}
28+
29+
hover :: PluginMethodHandler IdeState TextDocumentHover
30+
hover state plId (HoverParams (TextDocumentIdentifier uri) pos _) = pluginResponse $ do
31+
nfp <- getNormalizedFilePath plId uri
32+
har <- handleMaybeM "Unable to get HieResult"
33+
$ liftIO
34+
$ runAction "ExplicitFixity.HieResult" state
35+
$ use GetHieAst nfp
36+
37+
-- Names at the position
38+
let names = case har of
39+
HAR _ asts _ _ _ -> concat
40+
$ pointCommand asts pos
41+
$ \ast -> mapMaybe (either (const Nothing) Just) $ M.keys $ getNodeIds ast
42+
43+
-- Get fixity from HscEnv for local defined operator will crash the plugin,
44+
-- we first try to use ModIface to get fixities, and then use
45+
-- HscEnv if ModIface doesn't available.
46+
fixities <- getFixityFromModIface nfp names
47+
48+
if isJust fixities then pure fixities else getFixityFromEnv nfp names
49+
where
50+
-- | For local definition
51+
getFixityFromModIface nfp names = do
52+
hi <- handleMaybeM "Unable to get ModIface"
53+
$ liftIO
54+
$ runAction "ExplicitFixity.GetModIface" state
55+
$ use GetModIface nfp
56+
let iface = hirModIface hi
57+
fixities = filter (\(_, fixity) -> fixity /= defaultFixity)
58+
$ map (\name -> (name, mi_fix iface (occName name))) names
59+
-- We don't have much fixities on one position,
60+
-- so `nubOn` is acceptable.
61+
pure $ toHover $ nubOn snd fixities
62+
63+
-- | Get fixity from HscEnv
64+
getFixityFromEnv nfp names = do
65+
env <- fmap hscEnv
66+
$ handleMaybeM "Unable to get GhcSession"
67+
$ liftIO
68+
$ runAction "ExplicitFixity.GhcSession" state
69+
$ use GhcSession nfp
70+
fixities <- liftIO
71+
$ fmap (map (second fromJust))
72+
-- Ignore all default fixity
73+
$ fmap (filter (\(_, fixity) -> isJust fixity && fromJust fixity /= defaultFixity))
74+
$ forM names $ \name ->
75+
(\(_, fixity) -> (name, fixity)) <$> runTcInteractive env (lookupFixityRn name)
76+
pure $ toHover $ nubOn snd fixities
77+
78+
toHover [] = Nothing
79+
toHover fixities =
80+
let contents = T.intercalate "\n\n" $ fixityText <$> fixities
81+
contents' = "\n" <> sectionSeparator <> contents
82+
in Just $ Hover (HoverContents $ unmarkedUpContent contents') Nothing
83+
84+
fixityText (name, Fixity _ precedence direction) =
85+
printOutputable direction <> " " <> printOutputable precedence <> " `" <> printOutputable name <> "`"
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
module Main where
3+
import Test.Hls
4+
import Ide.Plugin.ExplicitFixity (descriptor)
5+
import qualified Data.Text as T
6+
import System.FilePath
7+
8+
9+
plugin :: PluginDescriptor IdeState
10+
plugin = descriptor "ExplicitFixity"
11+
12+
main :: IO ()
13+
main = defaultTestRunner test
14+
15+
test = testCase "" $ runSessionWithServer plugin testDataDir $ do
16+
doc <- openDoc "B.hs" "haskell"
17+
waitForProgressDone
18+
d <- getHover doc (Position 6 8)
19+
liftIO $ print d
20+
21+
testDataDir :: FilePath
22+
testDataDir = "test" </> "testdata"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module A where
2+
import Control.Monad
3+
import Data.Function (on)
4+
5+
f1 = (++)
6+
f2 = ($)
7+
f3 = (.)
8+
f4 = (-)
9+
f5 = 1 - 2
10+
f6 = (<>)
11+
f7 = (>>=)
12+
f8 = (>=>)
13+
f9 = elem
14+
f10 = on
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{-# LANGUAGE RecordWildCards #-}
2+
module C where
3+
infixr 7 >>:
4+
infix 9 >>::
5+
data F = G
6+
{ (>>:) :: Int -> Int -> Int
7+
, c :: Int
8+
, (>>::) :: Char
9+
}
10+
f G{..} = undefined
11+
12+
infixr 9 >>>:
13+
(>>>:) :: Int -> Int
14+
(>>>:) x = 3
15+
16+
infixl 3 ~\:
17+
(~\:) x y = 3

stack-lts16.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ packages:
3131
- ./plugins/hls-selection-range-plugin
3232
- ./plugins/hls-change-type-signature-plugin
3333
- ./plugins/hls-gadt-plugin
34+
- ./plugins/hls-explicit-fixity-plugin
3435

3536
ghc-options:
3637
"$everything": -haddock

stack-lts19.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ packages:
3131
- ./plugins/hls-selection-range-plugin
3232
- ./plugins/hls-change-type-signature-plugin
3333
- ./plugins/hls-gadt-plugin
34+
- ./plugins/hls-explicit-fixity-plugin
3435

3536
ghc-options:
3637
"$everything": -haddock

stack.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ packages:
3232
- ./plugins/hls-selection-range-plugin
3333
- ./plugins/hls-change-type-signature-plugin
3434
- ./plugins/hls-gadt-plugin
35+
- ./plugins/hls-explicit-fixity-plugin
3536

3637
extra-deps:
3738
- Chart-1.9.3@sha256:640a38463318b070d80a049577e4f0b3322df98290abb7afcf0cb74a4ad5b512,2948

0 commit comments

Comments
 (0)