-- Copyright (c) 2019 The DAML Authors. All rights reserved. -- SPDX-License-Identifier: Apache-2.0 module Development.IDE.Types.Diagnostics ( LSP.Diagnostic(..), ShowDiagnostic(..), FileDiagnostic, IdeResult, LSP.DiagnosticSeverity(..), DiagnosticStore, List(..), ideErrorText, ideErrorWithSource, showDiagnostics, showDiagnosticsColored, IdeResultNoDiagnosticsEarlyCutoff) where import Control.DeepSeq import Data.Maybe as Maybe import qualified Data.Text as T import Data.Text.Prettyprint.Doc import Data.Text.Prettyprint.Doc.Render.Terminal (Color (..), color) import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Terminal import Data.Text.Prettyprint.Doc.Render.Text import Language.LSP.Diagnostics import Language.LSP.Types as LSP (Diagnostic (..), DiagnosticSeverity (..), DiagnosticSource, List (..)) import Data.ByteString (ByteString) import Development.IDE.Types.Location -- | The result of an IDE operation. Warnings and errors are in the Diagnostic, -- and a value is in the Maybe. For operations that throw an error you -- expect a non-empty list of diagnostics, at least one of which is an error, -- and a Nothing. For operations that succeed you expect perhaps some warnings -- and a Just. For operations that depend on other failing operations you may -- get empty diagnostics and a Nothing, to indicate this phase throws no fresh -- errors but still failed. -- -- A rule on a file should only return diagnostics for that given file. It should -- not propagate diagnostic errors through multiple phases. type IdeResult v = ([FileDiagnostic], Maybe v) -- | an IdeResult with a fingerprint type IdeResultNoDiagnosticsEarlyCutoff v = (Maybe ByteString, Maybe v) ideErrorText :: NormalizedFilePath -> T.Text -> FileDiagnostic ideErrorText = ideErrorWithSource (Just "compiler") (Just DsError) ideErrorWithSource :: Maybe DiagnosticSource -> Maybe DiagnosticSeverity -> a -> T.Text -> (a, ShowDiagnostic, Diagnostic) ideErrorWithSource source sev fp msg = (fp, ShowDiag, LSP.Diagnostic { _range = noRange, _severity = sev, _code = Nothing, _source = source, _message = msg, _relatedInformation = Nothing, _tags = Nothing }) -- | Defines whether a particular diagnostic should be reported -- back to the user. -- -- One important use case is "missing signature" code lenses, -- for which we need to enable the corresponding warning during -- type checking. However, we do not want to show the warning -- unless the programmer asks for it (#261). data ShowDiagnostic = ShowDiag -- ^ Report back to the user | HideDiag -- ^ Hide from user deriving (Eq, Ord, Show) instance NFData ShowDiagnostic where rnf = rwhnf -- | Human readable diagnostics for a specific file. -- -- This type packages a pretty printed, human readable error message -- along with the related source location so that we can display the error -- on either the console or in the IDE at the right source location. -- type FileDiagnostic = (NormalizedFilePath, ShowDiagnostic, Diagnostic) prettyRange :: Range -> Doc Terminal.AnsiStyle prettyRange Range{..} = f _start <> "-" <> f _end where f Position{..} = pretty (show $ _line+1) <> colon <> pretty (show $ _character+1) stringParagraphs :: T.Text -> Doc a stringParagraphs = vcat . map (fillSep . map pretty . T.words) . T.lines showDiagnostics :: [FileDiagnostic] -> T.Text showDiagnostics = srenderPlain . prettyDiagnostics showDiagnosticsColored :: [FileDiagnostic] -> T.Text showDiagnosticsColored = srenderColored . prettyDiagnostics prettyDiagnostics :: [FileDiagnostic] -> Doc Terminal.AnsiStyle prettyDiagnostics = vcat . map prettyDiagnostic prettyDiagnostic :: FileDiagnostic -> Doc Terminal.AnsiStyle prettyDiagnostic (fp, sh, LSP.Diagnostic{..}) = vcat [ slabel_ "File: " $ pretty (fromNormalizedFilePath fp) , slabel_ "Hidden: " $ if sh == ShowDiag then "no" else "yes" , slabel_ "Range: " $ prettyRange _range , slabel_ "Source: " $ pretty _source , slabel_ "Severity:" $ pretty $ show sev , slabel_ "Message: " $ case sev of LSP.DsError -> annotate $ color Red LSP.DsWarning -> annotate $ color Yellow LSP.DsInfo -> annotate $ color Blue LSP.DsHint -> annotate $ color Magenta $ stringParagraphs _message ] where sev = fromMaybe LSP.DsError _severity -- | Label a document. slabel_ :: String -> Doc a -> Doc a slabel_ t d = nest 2 $ sep [pretty t, d] -- | The layout options used for the SDK assistant. cliLayout :: Int -- ^ Rendering width of the pretty printer. -> LayoutOptions cliLayout renderWidth = LayoutOptions { layoutPageWidth = AvailablePerLine renderWidth 0.9 } -- | Render without any syntax annotations srenderPlain :: Doc ann -> T.Text srenderPlain = renderStrict . layoutSmart (cliLayout defaultTermWidth) -- | Render a 'Document' as an ANSII colored string. srenderColored :: Doc Terminal.AnsiStyle -> T.Text srenderColored = Terminal.renderStrict . layoutSmart defaultLayoutOptions { layoutPageWidth = AvailablePerLine 100 1.0 } defaultTermWidth :: Int defaultTermWidth = 80