packages feed

hspretty-0.1.0.0: src/Formatters/Ormolu.hs

{-# LANGUAGE OverloadedStrings #-}

-- |
-- Description : Ormolu formatter.
--
-- Applies the Ormolu formatter.
module Formatters.Ormolu (formatter) where

import qualified Data.Text as Text
import qualified Data.Text.Short as ShortText
import Formatter (FileContent, Formatter, FormattingResult)
import qualified Formatter
import qualified Ormolu
import Path (File, Path, Rel)
import qualified Path
import PathFilter (PathFilter)
import qualified PathFilter
import qualified System.IO.Unsafe (unsafePerformIO)
import qualified UnliftIO

-- | Ormolu formatter.
formatter :: Formatter
formatter = Formatter.Formatter $ \path ->
  case PathFilter.unPathFilter pfHs path of
    PathFilter.Reject -> Formatter.DoNotFormat
    PathFilter.Accept ->
      Formatter.Format $ formatAction Ormolu.defaultConfig path

-- | Formatting action; defers to a 'System.IO.Unsafe.unsafePerformIO' action.
formatAction ::
  Ormolu.Config Ormolu.RegionIndices ->
  Path Rel File ->
  FileContent ->
  FormattingResult FileContent
formatAction config filePathForMessages content =
  System.IO.Unsafe.unsafePerformIO $
    formatActionIO config filePathForMessages content

-- | Formatting action in 'IO'.
formatActionIO ::
  Ormolu.Config Ormolu.RegionIndices ->
  Path Rel File ->
  FileContent ->
  IO (FormattingResult FileContent)
formatActionIO config filePathForMessages content = do
  case Formatter.fileContentToUtf8 content (Just filePathForMessages) of
    Left errorMessage -> pure $ Formatter.Error errorMessage
    Right txtContent -> do
      let strContent = Text.unpack txtContent
          strFileName = Path.fromRelFile filePathForMessages

          fmtAction :: IO FileContent
          fmtAction =
            Formatter.utf8TextToFileContent
              <$> Ormolu.ormolu config strFileName strContent

          recovery :: Ormolu.OrmoluException -> IO (FormattingResult FileContent)
          recovery e =
            pure . Formatter.Error . Formatter.ErrorMessage . ShortText.pack $
              "hspretty: Ormolu error when formatting file \""
                <> Path.fromRelFile filePathForMessages
                <> "\": "
                <> UnliftIO.displayException e

      result <- UnliftIO.catch (Right <$> fmtAction) (fmap Left <$> recovery)

      case result of
        Left err -> pure err
        Right outFileContent ->
          pure $
            if outFileContent == content
              then Formatter.Unchanged
              else Formatter.Changed outFileContent

-- | A 'PathFilter' for @.hs@ files.
pfHs :: PathFilter
pfHs = PathFilter.pfExtension ".hs"