diff --git a/haskell-language-server.cabal b/haskell-language-server.cabal index cccc36168c..bb56964268 100644 --- a/haskell-language-server.cabal +++ b/haskell-language-server.cabal @@ -2260,3 +2260,55 @@ test-suite ghcide-bench-test OverloadedStrings RecordWildCards ViewPatterns + +flag cabalProject + description: Enable cabal project plugin + default: True + manual: True + +common cabalProject + if flag(cabalProject) + build-depends: haskell-language-server:hls-cabal-project-plugin + cpp-options: -Dhls_cabalProject + +library hls-cabal-project-plugin + import: defaults, pedantic, warnings + if !flag(cabalProject) + buildable: False + exposed-modules: Ide.Plugin.CabalProject + hs-source-dirs: plugins/hls-cabal-project-plugin/src + build-depends: + , base + , bytestring + , containers + , deepseq + , directory + , filepath + , ghcide == 2.10.0.0 + , hls-plugin-api == 2.10.0.0 + , lens + , lsp ^>=2.7 + , lsp-types ^>=2.3 + , text + , text-rope + , transformers + , unordered-containers >=0.2.10.0 + + default-extensions: + DataKinds + OverloadedStrings + RecordWildCards + +test-suite hls-cabal-project-plugin-tests + import: defaults, pedantic, test-defaults, warnings + if !flag(cabalProject) + buildable: False + type: exitcode-stdio-1.0 + hs-source-dirs: plugins/hls-cabal-project-plugin/test + main-is: Main.hs + build-depends: + , base + , filepath + , haskell-language-server:hls-cabal-project-plugin + , hls-test-utils == 2.10.0.0 + , text diff --git a/plugins/hls-cabal-project-plugin/hls-cabal-project-plugin.cabal b/plugins/hls-cabal-project-plugin/hls-cabal-project-plugin.cabal new file mode 100644 index 0000000000..898bbd41a0 --- /dev/null +++ b/plugins/hls-cabal-project-plugin/hls-cabal-project-plugin.cabal @@ -0,0 +1,51 @@ +cabal-version: 3.0 +name: hls-cabal-project-plugin +version: 2.10.0.0 +synopsis: Cabal project file support for Haskell Language Server +description: Please see the README on GitHub at +category: Development +homepage: https://github.com/haskell/haskell-language-server#readme +bug-reports: https://github.com/haskell/haskell-language-server/issues +author: The Haskell IDE Team +maintainer: https://github.com/haskell/haskell-language-server/graphs/contributors +license: Apache-2.0 +license-file: LICENSE +build-type: Simple + +library + import: defaults, pedantic, warnings + exposed-modules: Ide.Plugin.CabalProject + hs-source-dirs: src + build-depends: + , base + , bytestring + , containers + , deepseq + , directory + , filepath + , ghcide == 2.10.0.0 + , hls-plugin-api == 2.10.0.0 + , lens + , lsp ^>=2.7 + , lsp-types ^>=2.3 + , text + , text-rope + , transformers + , unordered-containers >=0.2.10.0 + + default-extensions: + DataKinds + OverloadedStrings + RecordWildCards + +test-suite hls-cabal-project-plugin-tests + import: defaults, pedantic, test-defaults, warnings + type: exitcode-stdio-1.0 + hs-source-dirs: test + main-is: Main.hs + build-depends: + , base + , filepath + , haskell-language-server:hls-cabal-project-plugin + , hls-test-utils == 2.10.0.0 + , text \ No newline at end of file diff --git a/plugins/hls-cabal-project-plugin/src/Ide/Plugin/CabalProject.hs b/plugins/hls-cabal-project-plugin/src/Ide/Plugin/CabalProject.hs new file mode 100644 index 0000000000..1653a689b1 --- /dev/null +++ b/plugins/hls-cabal-project-plugin/src/Ide/Plugin/CabalProject.hs @@ -0,0 +1,69 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DuplicateRecordFields #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeFamilies #-} + +module Ide.Plugin.CabalProject (descriptor, Log (..)) where + +import Control.DeepSeq +import Control.Lens ((^.)) +import Control.Monad.Extra +import Control.Monad.IO.Class +import qualified Data.ByteString as BS +import qualified Data.Text as T +import qualified Data.Text.Encoding as Encoding +import Data.Text.Utf16.Rope.Mixed as Rope +import Development.IDE as D +import Development.IDE.Core.PluginUtils +import qualified Development.IDE.Core.Shake as Shake +import Development.IDE.Graph (Key, alwaysRerun) +import Ide.Types +import qualified Language.LSP.Protocol.Lens as JL +import qualified Language.LSP.Protocol.Message as LSP +import Language.LSP.Protocol.Types +import qualified Language.LSP.VFS as VFS + +data Log + = LogModificationTime NormalizedFilePath FileVersion + | LogShake Shake.Log + | LogDocOpened Uri + | LogDocModified Uri + deriving (Show) + +instance Pretty Log where + pretty = \case + LogShake log' -> pretty log' + LogModificationTime nfp modTime -> + "Modified:" <+> pretty (fromNormalizedFilePath nfp) <+> pretty (show modTime) + LogDocOpened uri -> + "Opened text document:" <+> pretty (getUri uri) + LogDocModified uri -> + "Modified text document:" <+> pretty (getUri uri) + +descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState +descriptor recorder plId = (defaultPluginDescriptor plId "Cabal Project File Support") + { pluginHandlers = mkPluginHandler LSP.SMethod_TextDocumentDidOpen $ + \ideState _ vfs (DidOpenTextDocumentParams TextDocumentItem{_uri,_version,_text}) -> do + let filePath = toNormalizedUri _uri + logWith recorder Debug $ LogDocOpened _uri + when (isCabalProjectFile filePath) $ do + -- TODO: Initialize project file handling + pure () + , pluginHandlers = mkPluginHandler LSP.SMethod_TextDocumentDidChange $ + \ideState _ vfs (DidChangeTextDocumentParams TextDocumentIdentifier{_uri} _ _) -> do + let filePath = toNormalizedUri _uri + logWith recorder Debug $ LogDocModified _uri + when (isCabalProjectFile filePath) $ do + -- TODO: Handle file changes + pure () + , pluginRules = cabalProjectRules recorder plId + } + +isCabalProjectFile :: NormalizedFilePath -> Bool +isCabalProjectFile filePath = "cabal.project" `T.isSuffixOf` T.pack (fromNormalizedFilePath filePath) + +cabalProjectRules :: Recorder (WithPriority Log) -> PluginId -> Rules () +cabalProjectRules recorder plId = do + -- TODO: Add rules for parsing and validating cabal.project files + pure () \ No newline at end of file diff --git a/src/HlsPlugins.hs b/src/HlsPlugins.hs index 87a1af7392..ef52550e15 100644 --- a/src/HlsPlugins.hs +++ b/src/HlsPlugins.hs @@ -97,6 +97,10 @@ import qualified Ide.Plugin.OverloadedRecordDot as OverloadedRecordDot import qualified Ide.Plugin.Notes as Notes #endif +#if hls_cabalProject +import qualified Ide.Plugin.CabalProject as CabalProject +#endif + -- formatters #if hls_floskell @@ -247,6 +251,9 @@ idePlugins recorder = pluginDescToIdePlugins allPlugins #endif #if hls_notes let pId = "notes" in Notes.descriptor (pluginRecorder pId) pId : +#endif +#if hls_cabalProject + let pId = "cabal-project" in CabalProject.descriptor (pluginRecorder pId) pId : #endif GhcIde.descriptors (pluginRecorder "ghcide")