-
-
Notifications
You must be signed in to change notification settings - Fork 373
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #42 from alanz/add-floskell-formatter
Generalize formatter plugin support, add Floskell
- Loading branch information
Showing
15 changed files
with
425 additions
and
170 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
{-# LANGUAGE RecordWildCards #-} | ||
{-# LANGUAGE DeriveGeneric #-} | ||
{-# LANGUAGE FlexibleInstances #-} | ||
{-# LANGUAGE OverloadedStrings #-} | ||
{-# LANGUAGE TypeFamilies #-} | ||
module Ide.Plugin.Config | ||
( | ||
getInitialConfig | ||
, getConfigFromNotification | ||
, Config(..) | ||
) where | ||
|
||
import qualified Data.Aeson as A | ||
import Data.Aeson hiding ( Error ) | ||
import Data.Default | ||
import qualified Data.Text as T | ||
import Language.Haskell.LSP.Types | ||
|
||
-- --------------------------------------------------------------------- | ||
|
||
-- | Given a DidChangeConfigurationNotification message, this function returns the parsed | ||
-- Config object if possible. | ||
getConfigFromNotification :: DidChangeConfigurationNotification -> Either T.Text Config | ||
getConfigFromNotification (NotificationMessage _ _ (DidChangeConfigurationParams p)) = | ||
case fromJSON p of | ||
A.Success c -> Right c | ||
A.Error err -> Left $ T.pack err | ||
|
||
-- | Given an InitializeRequest message, this function returns the parsed | ||
-- Config object if possible. Otherwise, it returns the default configuration | ||
getInitialConfig :: InitializeRequest -> Either T.Text Config | ||
getInitialConfig (RequestMessage _ _ _ InitializeParams{_initializationOptions = Nothing }) = Right def | ||
getInitialConfig (RequestMessage _ _ _ InitializeParams{_initializationOptions = Just opts}) = | ||
case fromJSON opts of | ||
A.Success c -> Right c | ||
A.Error err -> Left $ T.pack err | ||
|
||
-- --------------------------------------------------------------------- | ||
|
||
-- | We (initially anyway) mirror the hie configuration, so that existing | ||
-- clients can simply switch executable and not have any nasty surprises. There | ||
-- will be surprises relating to config options being ignored, initially though. | ||
data Config = | ||
Config | ||
{ hlintOn :: Bool | ||
, diagnosticsOnChange :: Bool | ||
, maxNumberOfProblems :: Int | ||
, diagnosticsDebounceDuration :: Int | ||
, liquidOn :: Bool | ||
, completionSnippetsOn :: Bool | ||
, formatOnImportOn :: Bool | ||
, formattingProvider :: T.Text | ||
} deriving (Show,Eq) | ||
|
||
instance Default Config where | ||
def = Config | ||
{ hlintOn = True | ||
, diagnosticsOnChange = True | ||
, maxNumberOfProblems = 100 | ||
, diagnosticsDebounceDuration = 350000 | ||
, liquidOn = False | ||
, completionSnippetsOn = True | ||
, formatOnImportOn = True | ||
-- , formattingProvider = "brittany" | ||
, formattingProvider = "ormolu" | ||
-- , formattingProvider = "floskell" | ||
} | ||
|
||
-- TODO: Add API for plugins to expose their own LSP config options | ||
instance A.FromJSON Config where | ||
parseJSON = A.withObject "Config" $ \v -> do | ||
s <- v .: "languageServerHaskell" | ||
flip (A.withObject "Config.settings") s $ \o -> Config | ||
<$> o .:? "hlintOn" .!= hlintOn def | ||
<*> o .:? "diagnosticsOnChange" .!= diagnosticsOnChange def | ||
<*> o .:? "maxNumberOfProblems" .!= maxNumberOfProblems def | ||
<*> o .:? "diagnosticsDebounceDuration" .!= diagnosticsDebounceDuration def | ||
<*> o .:? "liquidOn" .!= liquidOn def | ||
<*> o .:? "completionSnippetsOn" .!= completionSnippetsOn def | ||
<*> o .:? "formatOnImportOn" .!= formatOnImportOn def | ||
<*> o .:? "formattingProvider" .!= formattingProvider def | ||
|
||
-- 2017-10-09 23:22:00.710515298 [ThreadId 11] - ---> {"jsonrpc":"2.0","method":"workspace/didChangeConfiguration","params":{"settings":{"languageServerHaskell":{"maxNumberOfProblems":100,"hlintOn":true}}}} | ||
-- 2017-10-09 23:22:00.710667381 [ThreadId 15] - reactor:got didChangeConfiguration notification: | ||
-- NotificationMessage | ||
-- {_jsonrpc = "2.0" | ||
-- , _method = WorkspaceDidChangeConfiguration | ||
-- , _params = DidChangeConfigurationParams | ||
-- {_settings = Object (fromList [("languageServerHaskell",Object (fromList [("hlintOn",Bool True) | ||
-- ,("maxNumberOfProblems",Number 100.0)]))])}} | ||
|
||
instance A.ToJSON Config where | ||
toJSON (Config h diag m d l c f fp) = object [ "languageServerHaskell" .= r ] | ||
where | ||
r = object [ "hlintOn" .= h | ||
, "diagnosticsOnChange" .= diag | ||
, "maxNumberOfProblems" .= m | ||
, "diagnosticsDebounceDuration" .= d | ||
, "liquidOn" .= l | ||
, "completionSnippetsOn" .= c | ||
, "formatOnImportOn" .= f | ||
, "formattingProvider" .= fp | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
{-# LANGUAGE RecordWildCards #-} | ||
{-# LANGUAGE CPP #-} | ||
{-# LANGUAGE OverloadedStrings #-} | ||
{-# LANGUAGE ScopedTypeVariables #-} | ||
{-# LANGUAGE TypeApplications #-} | ||
{-# LANGUAGE ViewPatterns #-} | ||
|
||
module Ide.Plugin.Floskell | ||
( | ||
provider | ||
) | ||
where | ||
|
||
import qualified Data.ByteString.Lazy as BS | ||
import qualified Data.Text as T | ||
import qualified Data.Text.Encoding as T | ||
import Development.IDE.Types.Diagnostics as D | ||
import Development.IDE.Types.Location | ||
import Floskell | ||
import Ide.Plugin.Formatter | ||
import Language.Haskell.LSP.Types | ||
import Text.Regex.TDFA.Text() | ||
|
||
-- --------------------------------------------------------------------- | ||
|
||
-- | Format provider of Floskell. | ||
-- Formats the given source in either a given Range or the whole Document. | ||
-- If the provider fails an error is returned that can be displayed to the user. | ||
provider :: FormattingProvider IO | ||
provider _ideState typ contents fp _ = do | ||
let file = fromNormalizedFilePath fp | ||
config <- findConfigOrDefault file | ||
let (range, selectedContents) = case typ of | ||
FormatText -> (fullRange contents, contents) | ||
FormatRange r -> (r, extractRange r contents) | ||
result = reformat config (Just file) (BS.fromStrict (T.encodeUtf8 selectedContents)) | ||
case result of | ||
Left err -> return $ Left $ responseError (T.pack $ "floskellCmd: " ++ err) | ||
Right new -> return $ Right $ List [TextEdit range (T.decodeUtf8 (BS.toStrict new))] | ||
|
||
-- | Find Floskell Config, user and system wide or provides a default style. | ||
-- Every directory of the filepath will be searched to find a user configuration. | ||
-- Also looks into places such as XDG_CONFIG_DIRECTORY<https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html>. | ||
-- This function may not throw an exception and returns a default config. | ||
findConfigOrDefault :: FilePath -> IO AppConfig | ||
findConfigOrDefault file = do | ||
mbConf <- findAppConfigIn file | ||
case mbConf of | ||
Just confFile -> readAppConfig confFile | ||
Nothing -> | ||
let gibiansky = head (filter (\s -> styleName s == "gibiansky") styles) | ||
in return $ defaultAppConfig { appStyle = gibiansky } | ||
|
||
-- --------------------------------------------------------------------- |
Oops, something went wrong.