Add diagnostics for Megaparsec parsing
This commit is contained in:
parent
dedc72789b
commit
7ac8aef519
@ -6,10 +6,8 @@ import Language.LSP.Protocol.Types
|
|||||||
import Language.LSP.Server
|
import Language.LSP.Server
|
||||||
import Datalog.LSP.Hover (hoverHandler)
|
import Datalog.LSP.Hover (hoverHandler)
|
||||||
import Datalog.LSP.Highlight (tokenHandler)
|
import Datalog.LSP.Highlight (tokenHandler)
|
||||||
import Datalog.LSP.Types (DLogLspM, LSPContext (LSPContext))
|
import Datalog.LSP.Types (DLogLspM, LSPState)
|
||||||
import Datalog.LSP.DocChange (docChangeHandler, docOpenHandler)
|
import Datalog.LSP.DocChange (docChangeHandler, docOpenHandler)
|
||||||
import qualified Data.Map as M
|
|
||||||
import Control.Concurrent.STM
|
|
||||||
|
|
||||||
handlers :: Handlers DLogLspM
|
handlers :: Handlers DLogLspM
|
||||||
handlers =
|
handlers =
|
||||||
@ -24,13 +22,12 @@ handlers =
|
|||||||
initHandler :: Handlers DLogLspM
|
initHandler :: Handlers DLogLspM
|
||||||
initHandler = notificationHandler SMethod_Initialized $ \_ -> pure ()
|
initHandler = notificationHandler SMethod_Initialized $ \_ -> pure ()
|
||||||
|
|
||||||
serverDefinition :: IO (ServerDefinition LSPContext)
|
serverDefinition :: LSPState -> ServerDefinition LSPState
|
||||||
serverDefinition = do
|
serverDefinition context =
|
||||||
ref <- newTVarIO M.empty
|
ServerDefinition
|
||||||
pure $ ServerDefinition
|
|
||||||
{ parseConfig = \c v -> Right c
|
{ parseConfig = \c v -> Right c
|
||||||
, onConfigChange = const $ pure ()
|
, onConfigChange = const $ pure ()
|
||||||
, defaultConfig = LSPContext ref
|
, defaultConfig = context
|
||||||
, configSection = "demo"
|
, configSection = "demo"
|
||||||
, doInitialize = \env _req -> pure $ Right env
|
, doInitialize = \env _req -> pure $ Right env
|
||||||
, staticHandlers = const handlers
|
, staticHandlers = const handlers
|
||||||
|
|||||||
@ -3,15 +3,18 @@
|
|||||||
module Datalog.LSP.DocChange (docChangeHandler, docOpenHandler) where
|
module Datalog.LSP.DocChange (docChangeHandler, docOpenHandler) where
|
||||||
|
|
||||||
import Control.Concurrent.STM
|
import Control.Concurrent.STM
|
||||||
|
import Control.Lens ((^.))
|
||||||
import Control.Monad.Trans
|
import Control.Monad.Trans
|
||||||
|
import Data.List.NonEmpty qualified as NE
|
||||||
import Data.Map qualified as M
|
import Data.Map qualified as M
|
||||||
|
import Data.Text qualified as T
|
||||||
import Datalog.LSP.Types
|
import Datalog.LSP.Types
|
||||||
import Datalog.LSP.Utils (currentBufferText, currentBufferUri)
|
import Datalog.LSP.Utils (currentBufferText, currentBufferUri, currentBufferUriUnNormalized)
|
||||||
import Datalog.Parser (parseProgram)
|
import Datalog.Parser (parseProgram)
|
||||||
import Language.LSP.Protocol.Lens (HasParams, HasTextDocument, HasUri)
|
import Language.LSP.Protocol.Lens (HasParams, HasTextDocument, HasUri)
|
||||||
import Language.LSP.Protocol.Message (SMethod (SMethod_TextDocumentDidChange, SMethod_TextDocumentDidOpen))
|
import Language.LSP.Protocol.Message (SMethod (SMethod_TextDocumentDidChange, SMethod_TextDocumentDidOpen, SMethod_TextDocumentPublishDiagnostics))
|
||||||
import Language.LSP.Protocol.Types (Uri)
|
import Language.LSP.Protocol.Types (Diagnostic (..), DiagnosticSeverity (DiagnosticSeverity_Error), Position (..), PublishDiagnosticsParams (..), Range (Range), Uri)
|
||||||
import Language.LSP.Server (Handlers, MonadLsp, getConfig, notificationHandler)
|
import Language.LSP.Server (Handlers, MonadLsp, getConfig, notificationHandler, sendNotification)
|
||||||
import Text.Megaparsec
|
import Text.Megaparsec
|
||||||
|
|
||||||
docOpenHandler :: Handlers DLogLspM
|
docOpenHandler :: Handlers DLogLspM
|
||||||
@ -20,12 +23,45 @@ docOpenHandler = notificationHandler SMethod_TextDocumentDidOpen updateState
|
|||||||
docChangeHandler :: Handlers DLogLspM
|
docChangeHandler :: Handlers DLogLspM
|
||||||
docChangeHandler = notificationHandler SMethod_TextDocumentDidChange updateState
|
docChangeHandler = notificationHandler SMethod_TextDocumentDidChange updateState
|
||||||
|
|
||||||
updateState :: (HasParams s a1, MonadLsp LSPContext (t IO), HasUri a2 Uri, HasTextDocument a1 a2, MonadTrans t) => s -> t IO ()
|
updateState :: (HasParams s a1, MonadLsp LSPState (t IO), HasUri a2 Uri, HasTextDocument a1 a2, MonadTrans t) => s -> t IO ()
|
||||||
updateState req = do
|
updateState req = do
|
||||||
let uri = currentBufferUri req
|
let uri = currentBufferUri req
|
||||||
LSPContext parseStateRef <- getConfig
|
|
||||||
text <- currentBufferText req
|
parseRef <- parseState <$> getConfig
|
||||||
lift . atomically $ do
|
bufferText <- currentBufferText req
|
||||||
v <- readTVar parseStateRef
|
parseResult <- lift . atomically $ do
|
||||||
writeTVar parseStateRef $
|
v <- readTVar parseRef
|
||||||
M.insert uri (runParser parseProgram (show uri) text) v
|
|
||||||
|
let parsedBuffer = runParser parseProgram (show uri) bufferText
|
||||||
|
|
||||||
|
writeTVar parseRef $
|
||||||
|
M.insert uri parsedBuffer v
|
||||||
|
|
||||||
|
pure parsedBuffer
|
||||||
|
|
||||||
|
sendNotification
|
||||||
|
SMethod_TextDocumentPublishDiagnostics
|
||||||
|
PublishDiagnosticsParams
|
||||||
|
{ _uri = req ^. currentBufferUriUnNormalized
|
||||||
|
, _version = Nothing
|
||||||
|
, _diagnostics = case parseResult of
|
||||||
|
Right _ -> []
|
||||||
|
Left (ParseErrorBundle errs position) ->
|
||||||
|
NE.toList . flip fmap (fst $ attachSourcePos errorOffset errs position) $ \(err, pos) ->
|
||||||
|
Diagnostic
|
||||||
|
{ _range = let p = sourcePosToPosition pos in Range p p
|
||||||
|
, _severity = Just DiagnosticSeverity_Error
|
||||||
|
, _code = Nothing
|
||||||
|
, _codeDescription = Nothing
|
||||||
|
, _source = Nothing
|
||||||
|
, _message = T.pack . parseErrorTextPretty $ err
|
||||||
|
, _tags = Nothing
|
||||||
|
, _relatedInformation = Nothing
|
||||||
|
, _data_ = Nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcePosToPosition :: SourcePos -> Position
|
||||||
|
sourcePosToPosition (SourcePos _ line column) = Position (unPos' line) (unPos' column)
|
||||||
|
where
|
||||||
|
unPos' = fromIntegral . (\x -> x - 1) . unPos
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import Control.Monad.Trans
|
|||||||
import Data.Either (fromRight)
|
import Data.Either (fromRight)
|
||||||
import Data.Map qualified as M
|
import Data.Map qualified as M
|
||||||
import Data.Text qualified as T
|
import Data.Text qualified as T
|
||||||
import Datalog.LSP.Types (DLogLspM, LSPContext (..))
|
import Datalog.LSP.Types (DLogLspM, LSPState (..))
|
||||||
import Datalog.LSP.Utils (currentBufferUri)
|
import Datalog.LSP.Utils (currentBufferUri)
|
||||||
import Datalog.Parser (SrcLoc (..))
|
import Datalog.Parser (SrcLoc (..))
|
||||||
import Datalog.Syntax (Atom' (Atom), Program' (..), RelId (RelId), Rule' (..), Term' (..))
|
import Datalog.Syntax (Atom' (Atom), Program' (..), RelId (RelId), Rule' (..), Term' (..))
|
||||||
@ -15,7 +15,7 @@ import Language.LSP.Server
|
|||||||
|
|
||||||
tokenHandler :: Handlers DLogLspM
|
tokenHandler :: Handlers DLogLspM
|
||||||
tokenHandler = requestHandler SMethod_TextDocumentSemanticTokensFull $ \req responder -> do
|
tokenHandler = requestHandler SMethod_TextDocumentSemanticTokensFull $ \req responder -> do
|
||||||
LSPContext parseRef <- getConfig
|
LSPState parseRef <- getConfig
|
||||||
p <- lift . readTVarIO $ parseRef
|
p <- lift . readTVarIO $ parseRef
|
||||||
case M.lookup (currentBufferUri req) p of
|
case M.lookup (currentBufferUri req) p of
|
||||||
Nothing ->
|
Nothing ->
|
||||||
@ -26,7 +26,7 @@ tokenHandler = requestHandler SMethod_TextDocumentSemanticTokensFull $ \req resp
|
|||||||
responder
|
responder
|
||||||
( Right
|
( Right
|
||||||
. InL
|
. InL
|
||||||
. fromRight (error "")
|
. fromRight (SemanticTokens Nothing [])
|
||||||
. makeSemanticTokens defaultSemanticTokensLegend
|
. makeSemanticTokens defaultSemanticTokensLegend
|
||||||
$ highlightProg prog
|
$ highlightProg prog
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,24 +1,19 @@
|
|||||||
module Datalog.LSP.Hover where
|
module Datalog.LSP.Hover where
|
||||||
|
|
||||||
import Control.Lens ((^.), Lens')
|
import Datalog.LSP.Types (DLogLspM)
|
||||||
import Data.Maybe (fromJust)
|
import Datalog.LSP.Utils (currentBufferText)
|
||||||
import Language.LSP.Protocol.Lens (params, textDocument, uri, HasTextDocument, HasParams, HasUri)
|
|
||||||
import Language.LSP.Protocol.Message
|
import Language.LSP.Protocol.Message
|
||||||
import Language.LSP.Protocol.Types
|
import Language.LSP.Protocol.Types
|
||||||
import Language.LSP.Server
|
import Language.LSP.Server
|
||||||
import Language.LSP.VFS (virtualFileText)
|
|
||||||
import Datalog.LSP.Types (DLogLspM)
|
|
||||||
|
|
||||||
hoverHandler :: Handlers DLogLspM
|
hoverHandler :: Handlers DLogLspM
|
||||||
hoverHandler = requestHandler SMethod_TextDocumentHover $ \req responder -> do
|
hoverHandler = requestHandler SMethod_TextDocumentHover $ \req responder -> do
|
||||||
let
|
text <- currentBufferText req
|
||||||
openUri = toNormalizedUri $ req ^. docUri
|
responder
|
||||||
TRequestMessage _ _ _ (HoverParams _doc pos _workDone) = req
|
( Right
|
||||||
Position _l _c' = pos
|
. InL
|
||||||
rsp txt = Hover (InL . mkMarkdown $ txt) (Just range)
|
$ Hover
|
||||||
range = Range pos pos
|
{ _contents = InL . mkMarkdown $ text
|
||||||
c <- fromJust <$> getVirtualFile openUri
|
, _range = Nothing
|
||||||
responder (Right . InL . rsp . virtualFileText $ c)
|
}
|
||||||
|
)
|
||||||
docUri :: (HasParams s s1, HasTextDocument s1 s2, HasUri s2 a) => Lens' s a
|
|
||||||
docUri = params . textDocument . uri
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
module Datalog.LSP.Types (DLogLspM, LSPContext(..)) where
|
module Datalog.LSP.Types (DLogLspM, LSPState(..)) where
|
||||||
|
|
||||||
import Control.Monad.Reader (ReaderT)
|
|
||||||
import Language.LSP.Server (LspM)
|
import Language.LSP.Server (LspM)
|
||||||
import Control.Concurrent.STM (TVar)
|
import Control.Concurrent.STM (TVar)
|
||||||
import Text.Megaparsec
|
import Text.Megaparsec
|
||||||
@ -11,10 +10,10 @@ import Language.LSP.Protocol.Types qualified as J
|
|||||||
import Datalog.Syntax (Program')
|
import Datalog.Syntax (Program')
|
||||||
import Datalog.Parser (SrcLoc)
|
import Datalog.Parser (SrcLoc)
|
||||||
|
|
||||||
type DLogLspM = LspM LSPContext
|
type DLogLspM = LspM LSPState
|
||||||
|
|
||||||
type UriBundle a = Map J.NormalizedUri a
|
type UriBundle a = Map J.NormalizedUri a
|
||||||
|
|
||||||
data LSPContext = LSPContext
|
data LSPState = LSPState
|
||||||
{ parseState :: TVar (UriBundle (Either (ParseErrorBundle Text Void) (Program' SrcLoc)))
|
{ parseState :: TVar (UriBundle (Either (ParseErrorBundle Text Void) (Program' SrcLoc)))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,12 @@ import Language.LSP.Protocol.Types
|
|||||||
import Language.LSP.Server
|
import Language.LSP.Server
|
||||||
import Language.LSP.VFS
|
import Language.LSP.VFS
|
||||||
|
|
||||||
currentBufferText :: (MonadLsp config f, HasParams s a1, HasTextDocument a1 a2, HasUri a2 Uri) => s -> f T.Text
|
currentBufferText :: (MonadLsp config m, HasParams s a1, HasTextDocument a1 a2, HasUri a2 Uri) => s -> m T.Text
|
||||||
currentBufferText req = virtualFileText . fromJust <$> getVirtualFile (currentBufferUri req)
|
currentBufferText = fmap (virtualFileText . fromJust) . (getVirtualFile . currentBufferUri)
|
||||||
|
|
||||||
currentBufferUri :: (HasParams s a1, HasTextDocument a1 a2, HasUri a2 Uri) => s -> NormalizedUri
|
currentBufferUri :: (HasParams s a1, HasTextDocument a1 a2, HasUri a2 Uri) => s -> NormalizedUri
|
||||||
currentBufferUri req = toNormalizedUri $ req ^. (params . textDocument . uri)
|
currentBufferUri = toNormalizedUri . view currentBufferUriUnNormalized
|
||||||
|
|
||||||
|
currentBufferUriUnNormalized :: (HasParams s a1, HasTextDocument a1 a2, HasUri a2 a3) => Lens' s a3
|
||||||
|
currentBufferUriUnNormalized = params . textDocument . uri
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,14 @@
|
|||||||
|
import Control.Concurrent.STM (newTVarIO)
|
||||||
import Datalog.LSP (serverDefinition)
|
import Datalog.LSP (serverDefinition)
|
||||||
|
import Datalog.LSP.Types (LSPState (..))
|
||||||
import Language.LSP.Server (runServer)
|
import Language.LSP.Server (runServer)
|
||||||
|
|
||||||
main :: IO Int
|
main :: IO Int
|
||||||
main = serverDefinition >>= runServer
|
main = do
|
||||||
|
ref <- newTVarIO mempty
|
||||||
|
runServer $
|
||||||
|
serverDefinition
|
||||||
|
( LSPState
|
||||||
|
{ parseState = ref
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
vim.filetype.add({
|
vim.filetype.add({
|
||||||
extension = {
|
extension = {
|
||||||
lsptest = "lsptest"
|
mydatalog = "dl"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
vim.lsp.config['geolog'] = {
|
vim.lsp.config['mydatalog'] = {
|
||||||
cmd = { './result/bin/geolog-lsp' },
|
cmd = { './result/bin/datalog-lsp' },
|
||||||
filetypes = { 'lsptest'}
|
filetypes = { 'mydatalog' }
|
||||||
}
|
}
|
||||||
vim.lsp.enable('geolog')
|
vim.lsp.enable('mydatalog')
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user