From ea86e5dcb4e1314856f311cc181bd12ffe9f822d Mon Sep 17 00:00:00 2001 From: Julian Kalema Lukwata Date: Sat, 12 Oct 2024 15:11:47 +0200 Subject: [PATCH 1/5] Safely handle linenumbering for errors in the first line of cabal files --- plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Diagnostics.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Diagnostics.hs b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Diagnostics.hs index 26156c5131..dc36a43482 100644 --- a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Diagnostics.hs +++ b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Diagnostics.hs @@ -63,8 +63,9 @@ positionFromCabalPosition :: Syntax.Position -> Position positionFromCabalPosition (Syntax.Position line column) = Position (fromIntegral line') (fromIntegral col') where -- LSP is zero-based, Cabal is one-based - line' = line-1 - col' = column-1 + -- Cabal can return line 0 for errors in the first line + line' = if line <= 0 then 0 else line-1 + col' = if column <= 0 then 0 else column-1 -- | Create a 'FileDiagnostic' mkDiag From 6d1c04c2d7ede9a7669b7727c09b8791138536aa Mon Sep 17 00:00:00 2001 From: Julian Kalema Lukwata Date: Sat, 12 Oct 2024 15:33:28 +0200 Subject: [PATCH 2/5] add integration test for unsupported cabal version Signed-off-by: Julian Kalema Lukwata --- plugins/hls-cabal-plugin/test/Main.hs | 8 ++++++++ .../test/testdata/unsupportedVersion.cabal | 3 +++ 2 files changed, 11 insertions(+) create mode 100644 plugins/hls-cabal-plugin/test/testdata/unsupportedVersion.cabal diff --git a/plugins/hls-cabal-plugin/test/Main.hs b/plugins/hls-cabal-plugin/test/Main.hs index 499d4aa569..09949f840f 100644 --- a/plugins/hls-cabal-plugin/test/Main.hs +++ b/plugins/hls-cabal-plugin/test/Main.hs @@ -107,6 +107,14 @@ pluginTests = length diags @?= 1 unknownLicenseDiag ^. L.range @?= Range (Position 3 24) (Position 4 0) unknownLicenseDiag ^. L.severity @?= Just DiagnosticSeverity_Error + , runCabalTestCaseSession "Publishes Diagnostics on Error in the first line" "" $ do + _ <- openDoc "unsupportedVersion.cabal" "cabal" + diags <- cabalCaptureKick + unknownVersionDiag <- liftIO $ inspectDiagnostic diags ["Unsupported cabal-version 99999.0"] + liftIO $ do + length diags @?= 1 + unknownVersionDiag ^. L.range @?= Range (Position 0 0) (Position 1 0) + unknownVersionDiag ^. L.severity @?= Just DiagnosticSeverity_Error , runCabalTestCaseSession "Clears diagnostics" "" $ do doc <- openDoc "invalid.cabal" "cabal" diags <- cabalCaptureKick diff --git a/plugins/hls-cabal-plugin/test/testdata/unsupportedVersion.cabal b/plugins/hls-cabal-plugin/test/testdata/unsupportedVersion.cabal new file mode 100644 index 0000000000..328d373cd8 --- /dev/null +++ b/plugins/hls-cabal-plugin/test/testdata/unsupportedVersion.cabal @@ -0,0 +1,3 @@ +cabal-version: 99999.0 +name: invalid +version: 0.1.0.0 \ No newline at end of file From 4dcb7ba7b5ba834ec10431018b0d4e8f7798a92c Mon Sep 17 00:00:00 2001 From: Julian Kalema Lukwata Date: Sun, 13 Oct 2024 13:39:00 +0200 Subject: [PATCH 3/5] cast unsupported cabal version as warning --- plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs | 15 ++++++++++++++- plugins/hls-cabal-plugin/test/Main.hs | 4 ++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs index d68f61639a..662b2984bc 100644 --- a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs +++ b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs @@ -65,6 +65,7 @@ import Text.Regex.TDFA import qualified Data.Text () +import Distribution.Parsec.Error import qualified Ide.Plugin.Cabal.CabalAdd as CabalAdd data Log @@ -247,7 +248,19 @@ cabalRules recorder plId = do let warningDiags = fmap (Diagnostics.warningDiagnostic file) pWarnings case pm of Left (_cabalVersion, pErrorNE) -> do - let errorDiags = NE.toList $ NE.map (Diagnostics.errorDiagnostic file) pErrorNE + let regex :: T.Text + -- We don't support the cabal version, this should not be an error, as the + -- user did not do anything wrong. Instead we cast it to a warning + regex = "Unsupported cabal-version [0-9]+.[0-9]*" + errorDiags = + NE.toList $ + NE.map + ( \pe@(PError pos text) -> + if text =~ regex + then Diagnostics.warningDiagnostic file (Syntax.PWarning Syntax.PWTOther pos text) + else Diagnostics.errorDiagnostic file pe + ) + pErrorNE allDiags = errorDiags <> warningDiags pure (allDiags, Nothing) Right gpd -> do diff --git a/plugins/hls-cabal-plugin/test/Main.hs b/plugins/hls-cabal-plugin/test/Main.hs index 09949f840f..cec2d36a53 100644 --- a/plugins/hls-cabal-plugin/test/Main.hs +++ b/plugins/hls-cabal-plugin/test/Main.hs @@ -107,14 +107,14 @@ pluginTests = length diags @?= 1 unknownLicenseDiag ^. L.range @?= Range (Position 3 24) (Position 4 0) unknownLicenseDiag ^. L.severity @?= Just DiagnosticSeverity_Error - , runCabalTestCaseSession "Publishes Diagnostics on Error in the first line" "" $ do + , runCabalTestCaseSession "Publishes Diagnostics on unsupported cabal version as Warning" "" $ do _ <- openDoc "unsupportedVersion.cabal" "cabal" diags <- cabalCaptureKick unknownVersionDiag <- liftIO $ inspectDiagnostic diags ["Unsupported cabal-version 99999.0"] liftIO $ do length diags @?= 1 unknownVersionDiag ^. L.range @?= Range (Position 0 0) (Position 1 0) - unknownVersionDiag ^. L.severity @?= Just DiagnosticSeverity_Error + unknownVersionDiag ^. L.severity @?= Just DiagnosticSeverity_Warning , runCabalTestCaseSession "Clears diagnostics" "" $ do doc <- openDoc "invalid.cabal" "cabal" diags <- cabalCaptureKick From 688c575cb81eab6fc7eceb9f5453763767da5535 Mon Sep 17 00:00:00 2001 From: Julian Kalema Lukwata Date: Sun, 13 Oct 2024 15:26:18 +0200 Subject: [PATCH 4/5] add better warning text --- plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs index 662b2984bc..47febea84a 100644 --- a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs +++ b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs @@ -252,12 +252,13 @@ cabalRules recorder plId = do -- We don't support the cabal version, this should not be an error, as the -- user did not do anything wrong. Instead we cast it to a warning regex = "Unsupported cabal-version [0-9]+.[0-9]*" + unsupportedCabalHelpText = "\nThe used cabal version is not fully supported by hls. This means that some functionallity might not work as expected.\nIf you face any issues try to downgrade to a supported cabal version." errorDiags = NE.toList $ NE.map ( \pe@(PError pos text) -> if text =~ regex - then Diagnostics.warningDiagnostic file (Syntax.PWarning Syntax.PWTOther pos text) + then Diagnostics.warningDiagnostic file (Syntax.PWarning Syntax.PWTOther pos (text <> unsupportedCabalHelpText)) else Diagnostics.errorDiagnostic file pe ) pErrorNE From 869e8a3aad001d2e06e4740f9872f533abada4d2 Mon Sep 17 00:00:00 2001 From: Fendor Date: Sun, 20 Oct 2024 21:15:12 +0200 Subject: [PATCH 5/5] Add supported cabal-versions to the error message --- .../hls-cabal-plugin/src/Ide/Plugin/Cabal.hs | 26 ++++++++++++++----- .../src/Ide/Plugin/Cabal/Completion/Data.hs | 5 +++- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs index 47febea84a..8202d7c1e0 100644 --- a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs +++ b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs @@ -17,8 +17,10 @@ import qualified Data.ByteString as BS import Data.Hashable import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HashMap +import qualified Data.List as List import qualified Data.List.NonEmpty as NE import qualified Data.Maybe as Maybe +import qualified Data.Text () import qualified Data.Text as T import qualified Data.Text.Encoding as Encoding import Data.Text.Utf16.Rope.Mixed as Rope @@ -33,17 +35,21 @@ import Development.IDE.Graph (Key, import Development.IDE.LSP.HoverDefinition (foundHover) import qualified Development.IDE.Plugin.Completions.Logic as Ghcide import Development.IDE.Types.Shake (toKey) +import qualified Distribution.CabalSpecVersion as Cabal import qualified Distribution.Fields as Syntax import Distribution.Package (Dependency) import Distribution.PackageDescription (allBuildDepends, depPkgName, unPackageName) import Distribution.PackageDescription.Configuration (flattenPackageDescription) +import Distribution.Parsec.Error import qualified Distribution.Parsec.Position as Syntax import GHC.Generics +import qualified Ide.Plugin.Cabal.CabalAdd as CabalAdd import Ide.Plugin.Cabal.Completion.CabalFields as CabalFields import qualified Ide.Plugin.Cabal.Completion.Completer.Types as CompleterTypes import qualified Ide.Plugin.Cabal.Completion.Completions as Completions +import qualified Ide.Plugin.Cabal.Completion.Data as Data import Ide.Plugin.Cabal.Completion.Types (ParseCabalCommonSections (ParseCabalCommonSections), ParseCabalFields (..), ParseCabalFile (..)) @@ -63,11 +69,6 @@ import Language.LSP.Protocol.Types import qualified Language.LSP.VFS as VFS import Text.Regex.TDFA - -import qualified Data.Text () -import Distribution.Parsec.Error -import qualified Ide.Plugin.Cabal.CabalAdd as CabalAdd - data Log = LogModificationTime NormalizedFilePath FileVersion | LogShake Shake.Log @@ -252,13 +253,24 @@ cabalRules recorder plId = do -- We don't support the cabal version, this should not be an error, as the -- user did not do anything wrong. Instead we cast it to a warning regex = "Unsupported cabal-version [0-9]+.[0-9]*" - unsupportedCabalHelpText = "\nThe used cabal version is not fully supported by hls. This means that some functionallity might not work as expected.\nIf you face any issues try to downgrade to a supported cabal version." + unsupportedCabalHelpText = unlines + [ "The used cabal version is not fully supported by HLS. This means that some functionality might not work as expected." + , "If you face any issues try to downgrade to a supported cabal version." + , "" + , "Supported versions are: " <> + List.intercalate ", " + (fmap Cabal.showCabalSpecVersion Data.supportedCabalVersions) + ] errorDiags = NE.toList $ NE.map ( \pe@(PError pos text) -> if text =~ regex - then Diagnostics.warningDiagnostic file (Syntax.PWarning Syntax.PWTOther pos (text <> unsupportedCabalHelpText)) + then Diagnostics.warningDiagnostic file (Syntax.PWarning Syntax.PWTOther pos $ + unlines + [ text + , unsupportedCabalHelpText + ]) else Diagnostics.errorDiagnostic file pe ) pErrorNE diff --git a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Completion/Data.hs b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Completion/Data.hs index 44535607ab..c27568d692 100644 --- a/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Completion/Data.hs +++ b/plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal/Completion/Data.hs @@ -23,6 +23,9 @@ import Ide.Plugin.Cabal.LicenseSuggest (licenseNames) -- Completion Data -- ---------------------------------------------------------------- +supportedCabalVersions :: [CabalSpecVersion] +supportedCabalVersions = [CabalSpecV2_2 .. maxBound] + -- | Keyword for cabal version; required to be the top line in a cabal file cabalVersionKeyword :: Map KeyWordName Completer cabalVersionKeyword = @@ -30,7 +33,7 @@ cabalVersionKeyword = constantCompleter $ -- We only suggest cabal versions newer than 2.2 -- since we don't recommend using older ones. - map (T.pack . showCabalSpecVersion) [CabalSpecV2_2 .. maxBound] + map (T.pack . showCabalSpecVersion) supportedCabalVersions -- | Top level keywords of a cabal file. --