nvim-hs-2.3.2.4: src/Neovim/Quickfix.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Neovim.Quickfix
Description : API for interacting with the quickfix list
Copyright : (c) Sebastian Witte
License : Apache-2.0
Maintainer : woozletoff@gmail.com
Stability : experimental
Portability : GHC
-}
module Neovim.Quickfix where
import Neovim.API.String ( vim_call_function )
import Neovim.Classes
( Generic,
NFData,
(<+>),
Doc,
AnsiStyle,
NvimObject(toObject, fromObject),
(+:) )
import Neovim.Context ( throwError, Neovim )
import Control.Monad (void)
import Data.ByteString as BS (ByteString, all, elem)
import qualified Data.Map as Map
import Data.Maybe ( fromMaybe )
import Data.MessagePack ( Object(ObjectBinary, ObjectMap) )
import Prettyprinter (viaShow)
import Prelude
{- | This is a wrapper around neovim's @setqflist()@. @strType@ can be any
string that you can append to (hence 'Monoid') that is also an instance
of 'NvimObject'. You can e.g. use the plain old 'String'.
-}
setqflist ::
(Monoid strType, NvimObject strType) =>
[QuickfixListItem strType] ->
QuickfixAction ->
Neovim env ()
setqflist qs a =
void $ vim_call_function "setqflist" $ qs +: a +: []
data ColumnNumber
= VisualColumn Int
| ByteIndexColumn Int
| NoColumn
deriving (Eq, Ord, Show, Generic)
instance NFData ColumnNumber
data SignLocation strType
= LineNumber Int
| SearchPattern strType
deriving (Eq, Ord, Show, Generic)
instance (NFData strType) => NFData (SignLocation strType)
{- | Quickfix list item. The parameter names should mostly conform to those in
@:h setqflist()@. Some fields are merged to explicitly state mutually
exclusive elements or some other behavior of the fields.
see 'quickfixListItem' for creating a value of this type without typing too
much.
-}
data QuickfixListItem strType = QFItem
{ -- | Since the filename is only used if no buffer can be specified, this
-- field is a merge of @bufnr@ and @filename@.
bufOrFile :: Either Int strType
, -- | Line number or search pattern to locate the error.
lnumOrPattern :: Either Int strType
, -- | A tuple of a column number and a boolean indicating which kind of
-- indexing should be used. 'True' means that the visual column should be
-- used. 'False' means to use the byte index.
col :: ColumnNumber
, -- | Error number.
nr :: Maybe Int
, -- | Description of the error.
text :: strType
, -- | Type of error.
errorType :: QuickfixErrorType
}
deriving (Eq, Show, Generic)
instance (NFData strType) => NFData (QuickfixListItem strType)
-- | Simple error type enum.
data QuickfixErrorType = Warning | Error
deriving (Eq, Ord, Show, Read, Enum, Bounded, Generic)
instance NFData QuickfixErrorType
instance NvimObject QuickfixErrorType where
toObject = \case
Warning -> ObjectBinary "W"
Error -> ObjectBinary "E"
fromObject o = case fromObject o :: Either (Doc AnsiStyle) String of
Right "W" -> return Warning
Right "E" -> return Error
_ -> return Error
{- | Create a 'QuickfixListItem' by providing the minimal amount of arguments
needed.
-}
quickfixListItem ::
(Monoid strType) =>
-- | buffer of file name
Either Int strType ->
-- | line number or pattern
Either Int strType ->
QuickfixListItem strType
quickfixListItem bufferOrFile lineOrPattern =
QFItem
{ bufOrFile = bufferOrFile
, lnumOrPattern = lineOrPattern
, col = NoColumn
, nr = Nothing
, text = mempty
, errorType = Error
}
instance
(Monoid strType, NvimObject strType) =>
NvimObject (QuickfixListItem strType)
where
toObject QFItem{..} =
(toObject :: Map.Map ByteString Object -> Object) . Map.fromList $
[ either
(\b -> ("bufnr", toObject b))
(\f -> ("filename", toObject f))
bufOrFile
, either
(\l -> ("lnum", toObject l))
(\p -> ("pattern", toObject p))
lnumOrPattern
, ("type", toObject errorType)
, ("text", toObject text)
]
++ case col of
NoColumn -> []
ByteIndexColumn i -> [("col", toObject i), ("vcol", toObject False)]
VisualColumn i -> [("col", toObject i), ("vcol", toObject True)]
fromObject objectMap@(ObjectMap _) = do
m <- fromObject objectMap
let l :: NvimObject o => ByteString -> Either (Doc AnsiStyle) o
l key = case Map.lookup key m of
Just o -> fromObject o
Nothing -> throwError $ "Key not found."
bufOrFile <- case (l "bufnr", l "filename") of
(Right b, _) -> return $ Left b
(_, Right f) -> return $ Right f
_ -> throwError $ "No buffer number or file name inside quickfix list item."
lnumOrPattern <- case (l "lnum", l "pattern") of
(Right lnum, _) -> return $ Left lnum
(_, Right pat) -> return $ Right pat
_ -> throwError $ "No line number or search pattern inside quickfix list item."
let l' :: NvimObject o => ByteString -> Either (Doc AnsiStyle) (Maybe o)
l' key = case Map.lookup key m of
Just o -> Just <$> fromObject o
Nothing -> return Nothing
nr <-
l' "nr" >>= \case
Just 0 -> return Nothing
nr' -> return nr'
c <- l' "col"
v <- l' "vcol"
let col = fromMaybe NoColumn $ do
c' <- c
v' <- v
case (c', v') of
(0, _) -> return NoColumn
(_, True) -> return $ VisualColumn c'
(_, False) -> return $ ByteIndexColumn c'
text <- fromMaybe mempty <$> l' "text"
errorType <- fromMaybe Error <$> l' "type"
return QFItem{..}
fromObject o =
throwError $
"Could not deserialize QuickfixListItem,"
<+> "expected a map but received:"
<+> viaShow o
data QuickfixAction
= -- | Add items to the current list (or create a new one if none exists).
Append
| -- | Replace current list (or create a new one if none exists).
Replace
| -- | Create a new list.
New
deriving (Eq, Ord, Enum, Bounded, Show, Generic)
instance NFData QuickfixAction
instance NvimObject QuickfixAction where
toObject = \case
Append -> ObjectBinary "a"
Replace -> ObjectBinary "r"
New -> ObjectBinary ""
fromObject o = case fromObject o of
Right "a" -> return Append
Right "r" -> return Replace
Right s | BS.all (`BS.elem` " \t\n\r") s -> return New
_ -> Left "Could not convert to QuickfixAction"