From bfc40e027a31c7e2c2aabd4a43abd69d6eb619c7 Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Sat, 7 May 2022 22:39:48 +0300 Subject: [PATCH 01/16] Initial HIndent support --- cabal.project | 6 + exe/Plugins.hs | 8 + haskell-language-server.cabal | 12 ++ plugins/hls-hident-plugin/LICENSE | 201 ++++++++++++++++++ .../hls-hident-plugin/hls-hident-plugin.cabal | 53 +++++ .../src/Ide/Plugin/HIndent.hs | 67 ++++++ plugins/hls-hident-plugin/src/Path/Find.hs | 98 +++++++++ plugins/hls-hident-plugin/test/Main.hs | 41 ++++ .../test/testdata/.hindent.yaml | 1 + .../testdata/HIndent.formatted_document.hs | 7 + .../test/testdata/HIndent.formatted_range.hs | 5 + .../test/testdata/HIndent.hs | 3 + .../hls-hident-plugin/test/testdata/hie.yaml | 3 + 13 files changed, 505 insertions(+) create mode 100644 plugins/hls-hident-plugin/LICENSE create mode 100644 plugins/hls-hident-plugin/hls-hident-plugin.cabal create mode 100644 plugins/hls-hident-plugin/src/Ide/Plugin/HIndent.hs create mode 100644 plugins/hls-hident-plugin/src/Path/Find.hs create mode 100644 plugins/hls-hident-plugin/test/Main.hs create mode 100644 plugins/hls-hident-plugin/test/testdata/.hindent.yaml create mode 100644 plugins/hls-hident-plugin/test/testdata/HIndent.formatted_document.hs create mode 100644 plugins/hls-hident-plugin/test/testdata/HIndent.formatted_range.hs create mode 100644 plugins/hls-hident-plugin/test/testdata/HIndent.hs create mode 100644 plugins/hls-hident-plugin/test/testdata/hie.yaml diff --git a/cabal.project b/cabal.project index eb5147ba70..f5565e7e91 100644 --- a/cabal.project +++ b/cabal.project @@ -29,6 +29,12 @@ packages: ./plugins/hls-selection-range-plugin ./plugins/hls-change-type-signature-plugin ./plugins/hls-gadt-plugin + ./plugins/hls-hident-plugin + +source-repository-package + type: git + location: https://github.com/uhbif19/hindent.git + tag: dda88a4ab9fefbd07ba2614c02fecf73b20fe9d5 -- Standard location for temporary packages needed for particular environments -- For example it is used in the project gitlab mirror to help in the MAcOS M1 build script diff --git a/exe/Plugins.hs b/exe/Plugins.hs index 5a5f59d467..255361d22e 100644 --- a/exe/Plugins.hs +++ b/exe/Plugins.hs @@ -108,6 +108,11 @@ import qualified Ide.Plugin.StylishHaskell as StylishHaskell import qualified Ide.Plugin.Brittany as Brittany #endif +#if hindent +import qualified Ide.Plugin.HIndent as HIndent +#endif + + data Log = forall a. (Pretty a) => Log a instance Pretty Log where @@ -156,6 +161,9 @@ idePlugins recorder includeExamples = pluginDescToIdePlugins allPlugins #if brittany Brittany.descriptor "brittany" : #endif +#if hindent + HIndent.descriptor "hindent" : +#endif #if callHierarchy CallHierarchy.descriptor : #endif diff --git a/haskell-language-server.cabal b/haskell-language-server.cabal index 97ecfa8269..306cacfd32 100644 --- a/haskell-language-server.cabal +++ b/haskell-language-server.cabal @@ -218,6 +218,12 @@ flag brittany default: True manual: True +flag hindent + description: Enable hindent plugin + default: True + manual: True + + flag dynamic description: Build with the dyn rts default: True @@ -340,6 +346,11 @@ common stylishHaskell build-depends: hls-stylish-haskell-plugin ^>= 1.0 cpp-options: -DstylishHaskell +common hindent + if flag(hindent) + build-depends: hls-hindent-plugin ^>= 1.0 + cpp-options: -Dhindent + common brittany if flag(brittany) && (impl(ghc < 9.0.2) || flag(ignore-plugins-ghc-bounds)) build-depends: hls-brittany-plugin ^>= 1.0 @@ -375,6 +386,7 @@ executable haskell-language-server , ormolu , stylishHaskell , brittany + , hindent main-is: Main.hs hs-source-dirs: exe diff --git a/plugins/hls-hident-plugin/LICENSE b/plugins/hls-hident-plugin/LICENSE new file mode 100644 index 0000000000..16502c47e2 --- /dev/null +++ b/plugins/hls-hident-plugin/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 The Haskell IDE team + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/plugins/hls-hident-plugin/hls-hident-plugin.cabal b/plugins/hls-hident-plugin/hls-hident-plugin.cabal new file mode 100644 index 0000000000..61b8a10b0e --- /dev/null +++ b/plugins/hls-hident-plugin/hls-hident-plugin.cabal @@ -0,0 +1,53 @@ +cabal-version: 2.4 +name: hls-hindent-plugin +version: 1.0.0.0 +synopsis: Integration with the HIndent code formatter +description: + Please see the README on GitHub at +license: Apache-2.0 +license-file: LICENSE +author: The Haskell IDE Team +copyright: The Haskell IDE Team +maintainer: uhbif19@gmail.com +category: Development +build-type: Simple +extra-source-files: + LICENSE + test/testdata/*.hs + +library + exposed-modules: + Ide.Plugin.HIndent + other-modules: + Path.Find + hs-source-dirs: src + build-depends: + , base >=4.12 && <5 + , binary + , bytestring + , deepseq + , exceptions + , filepath + , ghcide ^>=1.7 + , hindent ^>=5.3.2 + , hls-plugin-api ^>=1.4 + , lsp-types + , path + , path-io + , text + , unix-compat + , yaml + + default-language: Haskell2010 + +test-suite tests + type: exitcode-stdio-1.0 + default-language: Haskell2010 + hs-source-dirs: test + main-is: Main.hs + ghc-options: -threaded -rtsopts -with-rtsopts=-N + build-depends: + , base + , filepath + , hls-hindent-plugin + , hls-test-utils ^>=1.3 diff --git a/plugins/hls-hident-plugin/src/Ide/Plugin/HIndent.hs b/plugins/hls-hident-plugin/src/Ide/Plugin/HIndent.hs new file mode 100644 index 0000000000..64660844a1 --- /dev/null +++ b/plugins/hls-hident-plugin/src/Ide/Plugin/HIndent.hs @@ -0,0 +1,67 @@ +{-# LANGUAGE OverloadedStrings #-} +module Ide.Plugin.HIndent + ( + descriptor + , provider + ) +where + +import Control.Monad.IO.Class (liftIO) +import Data.Binary.Builder (toLazyByteString) +import qualified Data.ByteString as B (concat) +import qualified Data.ByteString.Lazy as BL (toChunks) +import qualified Data.Text as T +import qualified Data.Text.Encoding as TE +import qualified Data.Yaml +import Development.IDE (IdeState, fromNormalizedFilePath) +import HIndent (reformat) +import HIndent.Types (Config, defaultConfig) +import Ide.PluginUtils (extractRange, fullRange, normalize, + responseError) +import Ide.Types (FormattingHandler, + FormattingType (FormatRange, FormatText), + PluginDescriptor (pluginHandlers), + PluginId, defaultPluginDescriptor, + mkFormattingHandlers) +import Language.LSP.Types as J (List (List), TextEdit (TextEdit)) +import Path (filename, toFilePath) +import qualified Path.Find as Path +import qualified Path.IO as Path + +descriptor :: PluginId -> PluginDescriptor IdeState +descriptor plId = (defaultPluginDescriptor plId) + { pluginHandlers = mkFormattingHandlers provider + } + +provider :: FormattingHandler IdeState +provider ide typ contents fp _opts = do + let file = fromNormalizedFilePath fp + let (range, selectedContents) = case typ of + FormatText -> (fullRange contents, contents) + FormatRange r -> (normalize r, extractRange r contents) + let extensions = Nothing -- Extensions should be covered by Config + config <- liftIO getHIndentConfig + let result = HIndent.reformat config extensions (Just file) (TE.encodeUtf8 selectedContents) + convertToTextEdit result range + where + builderToText = TE.decodeUtf8 . B.concat . BL.toChunks . toLazyByteString + convertToTextEdit result range = case result of + Left err -> return $ Left $ responseError $ T.pack $ "hident: " ++ err + Right new -> return $ Right $ J.List [TextEdit range (builderToText new)] + +-- Copied from +-- https://github.com/mihaimaruseac/hindent/blob/master/src/main/Main.hs#L77 + +getHIndentConfig :: IO Config +getHIndentConfig = do + cur <- Path.getCurrentDir + homeDir <- Path.getHomeDir + mfile <- + Path.findFileUp cur ((== ".hindent.yaml") . toFilePath . filename) (Just homeDir) + case mfile of + Nothing -> return defaultConfig + Just file -> do + result <- Data.Yaml.decodeFileEither (toFilePath file) + case result of + Left e -> error (show e) + Right config -> return config diff --git a/plugins/hls-hident-plugin/src/Path/Find.hs b/plugins/hls-hident-plugin/src/Path/Find.hs new file mode 100644 index 0000000000..dae21190ca --- /dev/null +++ b/plugins/hls-hident-plugin/src/Path/Find.hs @@ -0,0 +1,98 @@ +{-# LANGUAGE DataKinds #-} + +-- | Finding files. + +-- Copied from HIndent, where it was lifted from Stack. + +module Path.Find + (findFileUp + ,findDirUp + ,findFiles + ,findInParents) + where + +import Control.Exception (evaluate) +import Control.DeepSeq (force) +import Control.Monad +import Control.Monad.Catch +import Control.Monad.IO.Class +import System.IO.Error (isPermissionError) +import Data.List +import Path +import Path.IO hiding (findFiles) +import System.PosixCompat.Files (getSymbolicLinkStatus, isSymbolicLink) + +-- | Find the location of a file matching the given predicate. +findFileUp :: (MonadIO m,MonadThrow m) + => Path Abs Dir -- ^ Start here. + -> (Path Abs File -> Bool) -- ^ Predicate to match the file. + -> Maybe (Path Abs Dir) -- ^ Do not ascend above this directory. + -> m (Maybe (Path Abs File)) -- ^ Absolute file path. +findFileUp = findPathUp snd + +-- | Find the location of a directory matching the given predicate. +findDirUp :: (MonadIO m,MonadThrow m) + => Path Abs Dir -- ^ Start here. + -> (Path Abs Dir -> Bool) -- ^ Predicate to match the directory. + -> Maybe (Path Abs Dir) -- ^ Do not ascend above this directory. + -> m (Maybe (Path Abs Dir)) -- ^ Absolute directory path. +findDirUp = findPathUp fst + +-- | Find the location of a path matching the given predicate. +findPathUp :: (MonadIO m,MonadThrow m) + => (([Path Abs Dir],[Path Abs File]) -> [Path Abs t]) + -- ^ Choose path type from pair. + -> Path Abs Dir -- ^ Start here. + -> (Path Abs t -> Bool) -- ^ Predicate to match the path. + -> Maybe (Path Abs Dir) -- ^ Do not ascend above this directory. + -> m (Maybe (Path Abs t)) -- ^ Absolute path. +findPathUp pathType dir p upperBound = + do entries <- listDir dir + case find p (pathType entries) of + Just path -> return (Just path) + Nothing | Just dir == upperBound -> return Nothing + | parent dir == dir -> return Nothing + | otherwise -> findPathUp pathType (parent dir) p upperBound + +-- | Find files matching predicate below a root directory. +-- +-- NOTE: this skips symbolic directory links, to avoid loops. This may +-- not make sense for all uses of file finding. +-- +-- TODO: write one of these that traverses symbolic links but +-- efficiently ignores loops. +findFiles :: Path Abs Dir -- ^ Root directory to begin with. + -> (Path Abs File -> Bool) -- ^ Predicate to match files. + -> (Path Abs Dir -> Bool) -- ^ Predicate for which directories to traverse. + -> IO [Path Abs File] -- ^ List of matching files. +findFiles dir p traversep = + do (dirs,files) <- catchJust (\ e -> if isPermissionError e + then Just () + else Nothing) + (listDir dir) + (\ _ -> return ([], [])) + filteredFiles <- evaluate $ force (filter p files) + filteredDirs <- filterM (fmap not . isSymLink) dirs + subResults <- + forM filteredDirs + (\entry -> + if traversep entry + then findFiles entry p traversep + else return []) + return (concat (filteredFiles : subResults)) + +isSymLink :: Path Abs t -> IO Bool +isSymLink = fmap isSymbolicLink . getSymbolicLinkStatus . toFilePath + +-- | @findInParents f path@ applies @f@ to @path@ and its 'parent's until +-- it finds a 'Just' or reaches the root directory. +findInParents :: MonadIO m => (Path Abs Dir -> m (Maybe a)) -> Path Abs Dir -> m (Maybe a) +findInParents f path = do + mres <- f path + case mres of + Just res -> return (Just res) + Nothing -> do + let next = parent path + if next == path + then return Nothing + else findInParents f next \ No newline at end of file diff --git a/plugins/hls-hident-plugin/test/Main.hs b/plugins/hls-hident-plugin/test/Main.hs new file mode 100644 index 0000000000..3148ea72c4 --- /dev/null +++ b/plugins/hls-hident-plugin/test/Main.hs @@ -0,0 +1,41 @@ +{-# LANGUAGE OverloadedStrings #-} +module Main + ( main + ) where + +import qualified Ide.Plugin.HIndent as HIndent +import System.FilePath ( () ) +import Test.Hls + ( testGroup, + defaultTestRunner, + TestName, + TestTree, + goldenWithHaskellDocFormatter, + def, + Session, + TextDocumentIdentifier, + formatDoc, + formatRange, + Position (..), + Range (..), + FormattingOptions (..), + ) + +main :: IO () +main = defaultTestRunner tests + +tests :: TestTree +tests = testGroup "hindent" [ + goldenWithHIndent "formats a document" "HIndent" "formatted_document" $ \doc -> do + formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing) + -- formatting only first line + , goldenWithHIndent "formats a range" "HIndent" "formatted_range" $ \doc -> do + formatRange doc (FormattingOptions 2 True Nothing Nothing Nothing) (Range (Position 0 0) (Position 0 20)) + ] + + +goldenWithHIndent :: TestName -> FilePath -> FilePath -> (TextDocumentIdentifier -> Session ()) -> TestTree +goldenWithHIndent title fp desc = goldenWithHaskellDocFormatter (HIndent.descriptor "hindent") "hindent" def title testDataDir fp desc "hs" + +testDataDir :: FilePath +testDataDir = "test" "testdata" diff --git a/plugins/hls-hident-plugin/test/testdata/.hindent.yaml b/plugins/hls-hident-plugin/test/testdata/.hindent.yaml new file mode 100644 index 0000000000..44959972e8 --- /dev/null +++ b/plugins/hls-hident-plugin/test/testdata/.hindent.yaml @@ -0,0 +1 @@ +indent-size: 4 \ No newline at end of file diff --git a/plugins/hls-hident-plugin/test/testdata/HIndent.formatted_document.hs b/plugins/hls-hident-plugin/test/testdata/HIndent.formatted_document.hs new file mode 100644 index 0000000000..63b8eb3ce5 --- /dev/null +++ b/plugins/hls-hident-plugin/test/testdata/HIndent.formatted_document.hs @@ -0,0 +1,7 @@ +example1 = + case x of + Just p -> foo bar' + +example2 = + case x of + Just p -> foo bar' diff --git a/plugins/hls-hident-plugin/test/testdata/HIndent.formatted_range.hs b/plugins/hls-hident-plugin/test/testdata/HIndent.formatted_range.hs new file mode 100644 index 0000000000..7046a35a17 --- /dev/null +++ b/plugins/hls-hident-plugin/test/testdata/HIndent.formatted_range.hs @@ -0,0 +1,5 @@ +example1 = + case x of + Just p -> foo bar' + +example2 = case x of Just p -> foo bar' \ No newline at end of file diff --git a/plugins/hls-hident-plugin/test/testdata/HIndent.hs b/plugins/hls-hident-plugin/test/testdata/HIndent.hs new file mode 100644 index 0000000000..9eda43b80f --- /dev/null +++ b/plugins/hls-hident-plugin/test/testdata/HIndent.hs @@ -0,0 +1,3 @@ +example1 = case x of Just p -> foo bar' + +example2 = case x of Just p -> foo bar' \ No newline at end of file diff --git a/plugins/hls-hident-plugin/test/testdata/hie.yaml b/plugins/hls-hident-plugin/test/testdata/hie.yaml new file mode 100644 index 0000000000..824558147d --- /dev/null +++ b/plugins/hls-hident-plugin/test/testdata/hie.yaml @@ -0,0 +1,3 @@ +cradle: + direct: + arguments: [] From 02c4c9683485dfced4f0102a10da7add7164185a Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Fri, 17 Jun 2022 23:31:33 +0300 Subject: [PATCH 02/16] Add comments on hacks which could be thrown out in the future --- cabal.project | 2 ++ plugins/hls-hident-plugin/src/Ide/Plugin/HIndent.hs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/cabal.project b/cabal.project index f5565e7e91..1a39a5463e 100644 --- a/cabal.project +++ b/cabal.project @@ -31,6 +31,8 @@ packages: ./plugins/hls-gadt-plugin ./plugins/hls-hident-plugin +-- Can be removed when new release of HIndent is out +-- https://github.com/mihaimaruseac/hindent/issues/583#issuecomment-1158054210 source-repository-package type: git location: https://github.com/uhbif19/hindent.git diff --git a/plugins/hls-hident-plugin/src/Ide/Plugin/HIndent.hs b/plugins/hls-hident-plugin/src/Ide/Plugin/HIndent.hs index 64660844a1..2637f3a214 100644 --- a/plugins/hls-hident-plugin/src/Ide/Plugin/HIndent.hs +++ b/plugins/hls-hident-plugin/src/Ide/Plugin/HIndent.hs @@ -51,6 +51,9 @@ provider ide typ contents fp _opts = do -- Copied from -- https://github.com/mihaimaruseac/hindent/blob/master/src/main/Main.hs#L77 +-- Can be removed with Path.Find and it dependences, once this issue got closed: +-- https://github.com/mihaimaruseac/hindent/issues/585 + getHIndentConfig :: IO Config getHIndentConfig = do From 7eea1e8be6a79d90b9ce2d93b78889db5f1014e3 Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Sat, 18 Jun 2022 01:12:41 +0300 Subject: [PATCH 03/16] Add docs --- docs/features.md | 1 + docs/supported-versions.md | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/features.md b/docs/features.md index 0bf1d16487..c521499a11 100644 --- a/docs/features.md +++ b/docs/features.md @@ -94,6 +94,7 @@ Format your code with various Haskell code formatters. | Fourmolu | `hls-fourmolu-plugin` | | Ormolu | `hls-ormolu-plugin` | | Stylish Haskell | `hls-stylish-haskell-plugin` | +| HIndent | `hls-hindent-plugin` | ## Document symbols diff --git a/docs/supported-versions.md b/docs/supported-versions.md index 21341049df..d7f6e3f829 100644 --- a/docs/supported-versions.md +++ b/docs/supported-versions.md @@ -56,6 +56,7 @@ Sometimes a plugin will be supported in the prebuilt binaries but not in a HLS b | `hls-tactics-plugin` | 9.2 | | `hls-selection-range-plugin` | | | `hls-gadt-plugin` | | +| `hls-hindent-plugin` | | ### Using deprecated GHC versions From fde6233895ebb7393218798d92b78f7fb7e9b641 Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Sun, 19 Jun 2022 21:50:54 +0300 Subject: [PATCH 04/16] To trigger CI From 88dc03879ccceb92dfe8e34f947460376ae20e16 Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Thu, 7 Jul 2022 10:34:54 +0300 Subject: [PATCH 05/16] Bump HIndent version --- cabal.project | 7 ------- plugins/hls-hident-plugin/hls-hident-plugin.cabal | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/cabal.project b/cabal.project index 1a39a5463e..0e71ac1e45 100644 --- a/cabal.project +++ b/cabal.project @@ -31,13 +31,6 @@ packages: ./plugins/hls-gadt-plugin ./plugins/hls-hident-plugin --- Can be removed when new release of HIndent is out --- https://github.com/mihaimaruseac/hindent/issues/583#issuecomment-1158054210 -source-repository-package - type: git - location: https://github.com/uhbif19/hindent.git - tag: dda88a4ab9fefbd07ba2614c02fecf73b20fe9d5 - -- Standard location for temporary packages needed for particular environments -- For example it is used in the project gitlab mirror to help in the MAcOS M1 build script -- See https://github.com/haskell/haskell-language-server/blob/master/.gitlab-ci.yml diff --git a/plugins/hls-hident-plugin/hls-hident-plugin.cabal b/plugins/hls-hident-plugin/hls-hident-plugin.cabal index 61b8a10b0e..edf1fba6c3 100644 --- a/plugins/hls-hident-plugin/hls-hident-plugin.cabal +++ b/plugins/hls-hident-plugin/hls-hident-plugin.cabal @@ -29,7 +29,7 @@ library , exceptions , filepath , ghcide ^>=1.7 - , hindent ^>=5.3.2 + , hindent ^>=5.3.3 , hls-plugin-api ^>=1.4 , lsp-types , path From 65ffab73073f5e8859a5587d27fdda63e6474b1c Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Thu, 7 Jul 2022 10:38:28 +0300 Subject: [PATCH 06/16] Fix typo --- cabal.project | 2 +- plugins/{hls-hident-plugin => hls-hindent-plugin}/LICENSE | 0 .../hls-hindent-plugin.cabal} | 0 .../src/Ide/Plugin/HIndent.hs | 2 +- .../{hls-hident-plugin => hls-hindent-plugin}/src/Path/Find.hs | 0 plugins/{hls-hident-plugin => hls-hindent-plugin}/test/Main.hs | 0 .../test/testdata/.hindent.yaml | 0 .../test/testdata/HIndent.formatted_document.hs | 0 .../test/testdata/HIndent.formatted_range.hs | 0 .../test/testdata/HIndent.hs | 0 .../test/testdata/hie.yaml | 0 11 files changed, 2 insertions(+), 2 deletions(-) rename plugins/{hls-hident-plugin => hls-hindent-plugin}/LICENSE (100%) rename plugins/{hls-hident-plugin/hls-hident-plugin.cabal => hls-hindent-plugin/hls-hindent-plugin.cabal} (100%) rename plugins/{hls-hident-plugin => hls-hindent-plugin}/src/Ide/Plugin/HIndent.hs (99%) rename plugins/{hls-hident-plugin => hls-hindent-plugin}/src/Path/Find.hs (100%) rename plugins/{hls-hident-plugin => hls-hindent-plugin}/test/Main.hs (100%) rename plugins/{hls-hident-plugin => hls-hindent-plugin}/test/testdata/.hindent.yaml (100%) rename plugins/{hls-hident-plugin => hls-hindent-plugin}/test/testdata/HIndent.formatted_document.hs (100%) rename plugins/{hls-hident-plugin => hls-hindent-plugin}/test/testdata/HIndent.formatted_range.hs (100%) rename plugins/{hls-hident-plugin => hls-hindent-plugin}/test/testdata/HIndent.hs (100%) rename plugins/{hls-hident-plugin => hls-hindent-plugin}/test/testdata/hie.yaml (100%) diff --git a/cabal.project b/cabal.project index 0e71ac1e45..91532f9f6f 100644 --- a/cabal.project +++ b/cabal.project @@ -29,7 +29,7 @@ packages: ./plugins/hls-selection-range-plugin ./plugins/hls-change-type-signature-plugin ./plugins/hls-gadt-plugin - ./plugins/hls-hident-plugin + ./plugins/hls-hindent-plugin -- Standard location for temporary packages needed for particular environments -- For example it is used in the project gitlab mirror to help in the MAcOS M1 build script diff --git a/plugins/hls-hident-plugin/LICENSE b/plugins/hls-hindent-plugin/LICENSE similarity index 100% rename from plugins/hls-hident-plugin/LICENSE rename to plugins/hls-hindent-plugin/LICENSE diff --git a/plugins/hls-hident-plugin/hls-hident-plugin.cabal b/plugins/hls-hindent-plugin/hls-hindent-plugin.cabal similarity index 100% rename from plugins/hls-hident-plugin/hls-hident-plugin.cabal rename to plugins/hls-hindent-plugin/hls-hindent-plugin.cabal diff --git a/plugins/hls-hident-plugin/src/Ide/Plugin/HIndent.hs b/plugins/hls-hindent-plugin/src/Ide/Plugin/HIndent.hs similarity index 99% rename from plugins/hls-hident-plugin/src/Ide/Plugin/HIndent.hs rename to plugins/hls-hindent-plugin/src/Ide/Plugin/HIndent.hs index 2637f3a214..80987ab757 100644 --- a/plugins/hls-hident-plugin/src/Ide/Plugin/HIndent.hs +++ b/plugins/hls-hindent-plugin/src/Ide/Plugin/HIndent.hs @@ -46,7 +46,7 @@ provider ide typ contents fp _opts = do where builderToText = TE.decodeUtf8 . B.concat . BL.toChunks . toLazyByteString convertToTextEdit result range = case result of - Left err -> return $ Left $ responseError $ T.pack $ "hident: " ++ err + Left err -> return $ Left $ responseError $ T.pack $ "hindent: " ++ err Right new -> return $ Right $ J.List [TextEdit range (builderToText new)] -- Copied from diff --git a/plugins/hls-hident-plugin/src/Path/Find.hs b/plugins/hls-hindent-plugin/src/Path/Find.hs similarity index 100% rename from plugins/hls-hident-plugin/src/Path/Find.hs rename to plugins/hls-hindent-plugin/src/Path/Find.hs diff --git a/plugins/hls-hident-plugin/test/Main.hs b/plugins/hls-hindent-plugin/test/Main.hs similarity index 100% rename from plugins/hls-hident-plugin/test/Main.hs rename to plugins/hls-hindent-plugin/test/Main.hs diff --git a/plugins/hls-hident-plugin/test/testdata/.hindent.yaml b/plugins/hls-hindent-plugin/test/testdata/.hindent.yaml similarity index 100% rename from plugins/hls-hident-plugin/test/testdata/.hindent.yaml rename to plugins/hls-hindent-plugin/test/testdata/.hindent.yaml diff --git a/plugins/hls-hident-plugin/test/testdata/HIndent.formatted_document.hs b/plugins/hls-hindent-plugin/test/testdata/HIndent.formatted_document.hs similarity index 100% rename from plugins/hls-hident-plugin/test/testdata/HIndent.formatted_document.hs rename to plugins/hls-hindent-plugin/test/testdata/HIndent.formatted_document.hs diff --git a/plugins/hls-hident-plugin/test/testdata/HIndent.formatted_range.hs b/plugins/hls-hindent-plugin/test/testdata/HIndent.formatted_range.hs similarity index 100% rename from plugins/hls-hident-plugin/test/testdata/HIndent.formatted_range.hs rename to plugins/hls-hindent-plugin/test/testdata/HIndent.formatted_range.hs diff --git a/plugins/hls-hident-plugin/test/testdata/HIndent.hs b/plugins/hls-hindent-plugin/test/testdata/HIndent.hs similarity index 100% rename from plugins/hls-hident-plugin/test/testdata/HIndent.hs rename to plugins/hls-hindent-plugin/test/testdata/HIndent.hs diff --git a/plugins/hls-hident-plugin/test/testdata/hie.yaml b/plugins/hls-hindent-plugin/test/testdata/hie.yaml similarity index 100% rename from plugins/hls-hident-plugin/test/testdata/hie.yaml rename to plugins/hls-hindent-plugin/test/testdata/hie.yaml From 099f15a6bf1311329246fced0d0de34f8734ba77 Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Sun, 10 Jul 2022 23:31:36 +0300 Subject: [PATCH 07/16] Update index-state --- cabal.project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cabal.project b/cabal.project index 91532f9f6f..9b6cd19b0e 100644 --- a/cabal.project +++ b/cabal.project @@ -45,7 +45,7 @@ package * write-ghc-environment-files: never -index-state: 2022-06-12T00:00:00Z +index-state: 2022-07-08T03:47:21Z constraints: hyphenation +embed, From 6232fb72bad94ee8121c2286f89477789037234c Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Tue, 16 Aug 2022 01:58:28 +0300 Subject: [PATCH 08/16] Fix stylish-haskell linting --- exe/Plugins.hs | 2 +- plugins/hls-hindent-plugin/src/Path/Find.hs | 23 +++++++++++---------- plugins/hls-hindent-plugin/test/Main.hs | 22 ++++++-------------- 3 files changed, 19 insertions(+), 28 deletions(-) diff --git a/exe/Plugins.hs b/exe/Plugins.hs index 332b4c92f0..d108ed7194 100644 --- a/exe/Plugins.hs +++ b/exe/Plugins.hs @@ -119,7 +119,7 @@ import qualified Ide.Plugin.Brittany as Brittany #endif #if hindent -import qualified Ide.Plugin.HIndent as HIndent +import qualified Ide.Plugin.HIndent as HIndent #endif diff --git a/plugins/hls-hindent-plugin/src/Path/Find.hs b/plugins/hls-hindent-plugin/src/Path/Find.hs index dae21190ca..662695ffe5 100644 --- a/plugins/hls-hindent-plugin/src/Path/Find.hs +++ b/plugins/hls-hindent-plugin/src/Path/Find.hs @@ -11,16 +11,17 @@ module Path.Find ,findInParents) where -import Control.Exception (evaluate) -import Control.DeepSeq (force) -import Control.Monad -import Control.Monad.Catch -import Control.Monad.IO.Class -import System.IO.Error (isPermissionError) -import Data.List -import Path -import Path.IO hiding (findFiles) -import System.PosixCompat.Files (getSymbolicLinkStatus, isSymbolicLink) +import Control.DeepSeq (force) +import Control.Exception (evaluate) +import Control.Monad +import Control.Monad.Catch +import Control.Monad.IO.Class +import Data.List +import Path +import Path.IO hiding (findFiles) +import System.IO.Error (isPermissionError) +import System.PosixCompat.Files (getSymbolicLinkStatus, + isSymbolicLink) -- | Find the location of a file matching the given predicate. findFileUp :: (MonadIO m,MonadThrow m) @@ -95,4 +96,4 @@ findInParents f path = do let next = parent path if next == path then return Nothing - else findInParents f next \ No newline at end of file + else findInParents f next diff --git a/plugins/hls-hindent-plugin/test/Main.hs b/plugins/hls-hindent-plugin/test/Main.hs index 3148ea72c4..72c8eb3ca1 100644 --- a/plugins/hls-hindent-plugin/test/Main.hs +++ b/plugins/hls-hindent-plugin/test/Main.hs @@ -4,22 +4,12 @@ module Main ) where import qualified Ide.Plugin.HIndent as HIndent -import System.FilePath ( () ) -import Test.Hls - ( testGroup, - defaultTestRunner, - TestName, - TestTree, - goldenWithHaskellDocFormatter, - def, - Session, - TextDocumentIdentifier, - formatDoc, - formatRange, - Position (..), - Range (..), - FormattingOptions (..), - ) +import System.FilePath (()) +import Test.Hls (FormattingOptions (..), Position (..), + Range (..), Session, TestName, TestTree, + TextDocumentIdentifier, def, + defaultTestRunner, formatDoc, formatRange, + goldenWithHaskellDocFormatter, testGroup) main :: IO () main = defaultTestRunner tests From 880a803abd51cb737576bfb395297cbba2b828f6 Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Tue, 16 Aug 2022 01:58:42 +0300 Subject: [PATCH 09/16] Make test more robust --- test/functional/Format.hs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/functional/Format.hs b/test/functional/Format.hs index af90fc7a9c..224128cdf9 100644 --- a/test/functional/Format.hs +++ b/test/functional/Format.hs @@ -6,6 +6,7 @@ import Control.Lens ((^.)) import Control.Monad.IO.Class import Data.Aeson import qualified Data.ByteString.Lazy as BS +import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.Text.IO as T import Language.LSP.Test @@ -47,8 +48,7 @@ providerTests = testGroup "formatting provider" [ testCase "respects none" $ runSessionWithConfig (formatConfig "none") hlsCommand fullCaps "test/testdata/format" $ do doc <- openDoc "Format.hs" "haskell" resp <- request STextDocumentFormatting $ DocumentFormattingParams Nothing doc (FormattingOptions 2 True Nothing Nothing Nothing) - liftIO $ resp ^. LSP.result @?= Left (ResponseError InvalidRequest "No plugin enabled for STextDocumentFormatting, available:\nPluginId \"floskell\"\nPluginId \"fourmolu\"\nPluginId \"ormolu\"\nPluginId \"stylish-haskell\"\nPluginId \"brittany\"\n" Nothing) - + liftIO $ foramattingNoneResultCorrect (resp ^. LSP.result) @? "Result incorrect" , requiresOrmoluPlugin . requiresFloskellPlugin $ testCase "can change on the fly" $ runSession hlsCommand fullCaps "test/testdata/format" $ do formattedOrmolu <- liftIO $ T.readFile "test/testdata/format/Format.ormolu.formatted.hs" formattedFloskell <- liftIO $ T.readFile "test/testdata/format/Format.floskell.formatted.hs" @@ -81,6 +81,10 @@ providerTests = testGroup "formatting provider" [ formatDoc doc (FormattingOptions 2 True Nothing Nothing Nothing) documentContents doc >>= liftIO . (@?= formattedFloskell) ] + where + foramattingNoneResultCorrect (Left (ResponseError InvalidRequest text Nothing)) = + T.isPrefixOf "No plugin enabled for STextDocumentFormatting" text + foramattingNoneResultCorrect _ = False formatLspConfig :: Value -> Value formatLspConfig provider = object [ "haskell" .= object ["formattingProvider" .= (provider :: Value)] ] From 9561d0e292b39a4a944026618945c48fa6c8e766 Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Tue, 16 Aug 2022 01:58:51 +0300 Subject: [PATCH 10/16] Fix stack build --- stack-lts16.yaml | 1 + stack-lts19.yaml | 1 + stack.yaml | 1 + 3 files changed, 3 insertions(+) diff --git a/stack-lts16.yaml b/stack-lts16.yaml index 5460e8940f..f3d28c9793 100644 --- a/stack-lts16.yaml +++ b/stack-lts16.yaml @@ -33,6 +33,7 @@ packages: - ./plugins/hls-change-type-signature-plugin - ./plugins/hls-gadt-plugin - ./plugins/hls-explicit-fixity-plugin + - ./plugins/hls-hindent-plugin ghc-options: "$everything": -haddock diff --git a/stack-lts19.yaml b/stack-lts19.yaml index 219dc7e820..cd57ec8fc5 100644 --- a/stack-lts19.yaml +++ b/stack-lts19.yaml @@ -32,6 +32,7 @@ packages: - ./plugins/hls-change-type-signature-plugin - ./plugins/hls-gadt-plugin - ./plugins/hls-explicit-fixity-plugin + - ./plugins/hls-hindent-plugin ghc-options: "$everything": -haddock diff --git a/stack.yaml b/stack.yaml index 6ea299746c..6cba14e071 100644 --- a/stack.yaml +++ b/stack.yaml @@ -32,6 +32,7 @@ packages: - ./plugins/hls-change-type-signature-plugin - ./plugins/hls-gadt-plugin - ./plugins/hls-explicit-fixity-plugin +- ./plugins/hls-hindent-plugin extra-deps: - floskell-0.10.6@sha256:e77d194189e8540abe2ace2c7cb8efafc747ca35881a2fefcbd2d40a1292e036,3819 From 63cf0275dd8488e7b75e6cffa2eff6e99ef63ee7 Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Tue, 16 Aug 2022 19:10:43 +0300 Subject: [PATCH 11/16] Fix stack once again --- stack-lts16.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/stack-lts16.yaml b/stack-lts16.yaml index f3d28c9793..c2fe0f8708 100644 --- a/stack-lts16.yaml +++ b/stack-lts16.yaml @@ -103,6 +103,7 @@ extra-deps: - trial-tomland-0.0.0.0@sha256:743a9baaa36891ed3a44618fdfd5bc4ed9afc39cf9b9fa23ea1b96f3787f5ec0,2526 - text-rope-0.2 - co-log-core-0.3.1.0 + - hindent-5.3.4 configure-options: ghcide: From 0ef676f75a24c0b9df81ca6aa419b1eed8735cb9 Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Wed, 17 Aug 2022 00:34:19 +0300 Subject: [PATCH 12/16] Trigger CI From e390d16788aca3e781c06219f5abb986b9fa8a18 Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Wed, 17 Aug 2022 18:00:32 +0300 Subject: [PATCH 13/16] Bump haskell-src-exts version for lts16 to fix hindent building bug --- stack-lts16.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/stack-lts16.yaml b/stack-lts16.yaml index c2fe0f8708..ae4eacad08 100644 --- a/stack-lts16.yaml +++ b/stack-lts16.yaml @@ -104,6 +104,7 @@ extra-deps: - text-rope-0.2 - co-log-core-0.3.1.0 - hindent-5.3.4 + - haskell-src-exts-1.23.1 configure-options: ghcide: From b380410a0a29d2146705d2db74a92afe5a4c3eea Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Thu, 18 Aug 2022 14:59:11 +0300 Subject: [PATCH 14/16] Trigger CI From d7b11980995c519447df08d4a4a04a9463a3a05a Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Sat, 20 Aug 2022 02:52:39 +0300 Subject: [PATCH 15/16] Trigger CI From 1ff0e6e6c28c1178f95161d9ad119131347e1884 Mon Sep 17 00:00:00 2001 From: uhbif19 Date: Mon, 22 Aug 2022 01:01:45 +0300 Subject: [PATCH 16/16] Trigger CI