2026-03-03 14:26:56 +00:00
|
|
|
module Datalog.LSP.Highlight where
|
|
|
|
|
|
2026-03-03 16:00:36 +00:00
|
|
|
import Control.Lens (Lens', (^.))
|
2026-03-03 14:26:56 +00:00
|
|
|
import Data.Either (fromRight)
|
|
|
|
|
import Data.Maybe (fromJust)
|
2026-03-03 16:00:36 +00:00
|
|
|
import Datalog.Parser (SrcLoc (..))
|
|
|
|
|
import Datalog.Syntax (Atom' (Atom), ConId (..), Program' (..), RelId (RelId), Rule' (..), Term' (..))
|
|
|
|
|
import Language.LSP.Protocol.Lens (HasParams, HasTextDocument, HasUri, params, textDocument, uri)
|
2026-03-03 14:26:56 +00:00
|
|
|
import Language.LSP.Protocol.Message
|
|
|
|
|
import Language.LSP.Protocol.Types
|
|
|
|
|
import Language.LSP.Server
|
2026-03-03 16:00:36 +00:00
|
|
|
import Text.Megaparsec
|
|
|
|
|
import Language.LSP.VFS (virtualFileText)
|
|
|
|
|
import Datalog.Parser (parseProgram)
|
2026-03-03 16:31:44 +00:00
|
|
|
import qualified Data.Text as T
|
2026-03-03 14:26:56 +00:00
|
|
|
|
|
|
|
|
tokenHandler :: Handlers (LspM ())
|
|
|
|
|
tokenHandler = requestHandler SMethod_TextDocumentSemanticTokensFull $ \req responder -> do
|
2026-03-03 16:00:36 +00:00
|
|
|
c <- virtualFileText . fromJust <$> getVirtualFile (toNormalizedUri $ req ^. docUri)
|
|
|
|
|
let
|
2026-03-03 16:42:20 +00:00
|
|
|
absTokens = case runParser parseProgram "" c of
|
|
|
|
|
Left _ -> []
|
|
|
|
|
Right prog -> highlightProg prog
|
|
|
|
|
tokens = fromRight (error "") $ makeSemanticTokens defaultSemanticTokensLegend absTokens
|
2026-03-03 16:00:36 +00:00
|
|
|
|
2026-03-03 14:26:56 +00:00
|
|
|
responder (Right $ InL tokens)
|
|
|
|
|
|
2026-03-03 16:00:36 +00:00
|
|
|
docUri :: (HasParams s s1, HasTextDocument s1 s2, HasUri s2 a) => Lens' s a
|
2026-03-03 14:26:56 +00:00
|
|
|
docUri = params . textDocument . uri
|
2026-03-03 16:00:36 +00:00
|
|
|
|
|
|
|
|
highlightProg :: Program' SrcLoc -> [SemanticTokenAbsolute]
|
|
|
|
|
highlightProg (Program _ rs) = rs >>= highlightRule
|
|
|
|
|
|
|
|
|
|
highlightRule :: Rule' SrcLoc -> [SemanticTokenAbsolute]
|
|
|
|
|
highlightRule (Rule _ a as) = a : as >>= highlightAtom
|
|
|
|
|
|
|
|
|
|
highlightAtom :: Atom' SrcLoc -> [SemanticTokenAbsolute]
|
|
|
|
|
highlightAtom (Atom loc (RelId relId) ts) = highlightRel ++ (ts >>= highlightTerm) where
|
2026-03-03 16:31:44 +00:00
|
|
|
highlightRel =
|
|
|
|
|
[ SemanticTokenAbsolute
|
|
|
|
|
{ _line = unPos' startLine - 1
|
|
|
|
|
, _startChar = unPos' startCol - 1
|
|
|
|
|
, _length = fromIntegral . length . T.unpack $ relId
|
|
|
|
|
, _tokenType = SemanticTokenTypes_Interface
|
|
|
|
|
, _tokenModifiers = []
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
where
|
|
|
|
|
unPos' = fromIntegral . unPos
|
|
|
|
|
startLine = sourceLine . start $ loc
|
|
|
|
|
startCol = sourceColumn . start $ loc
|
|
|
|
|
stopCol = sourceColumn . end $ loc
|
2026-03-03 16:00:36 +00:00
|
|
|
|
|
|
|
|
getConLoc :: Term' SrcLoc -> SrcLoc
|
|
|
|
|
getConLoc (Con loc _) = loc
|
|
|
|
|
getConLoc (Var loc _) = loc
|
|
|
|
|
|
|
|
|
|
highlightTerm :: Term' SrcLoc -> [SemanticTokenAbsolute]
|
|
|
|
|
highlightTerm t =
|
|
|
|
|
[ SemanticTokenAbsolute
|
2026-03-03 16:31:44 +00:00
|
|
|
{ _line = unPos' startLine - 1
|
|
|
|
|
, _startChar = unPos' startCol - 1
|
2026-03-03 16:00:36 +00:00
|
|
|
, _length = fromIntegral $ unPos stopCol - unPos startCol
|
|
|
|
|
, _tokenType = case t of
|
|
|
|
|
Con _ _ -> SemanticTokenTypes_Number
|
2026-03-03 16:31:44 +00:00
|
|
|
Var _ _ -> SemanticTokenTypes_Keyword
|
2026-03-03 16:00:36 +00:00
|
|
|
, _tokenModifiers = []
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
where
|
|
|
|
|
loc = getConLoc t
|
|
|
|
|
unPos' = fromIntegral . unPos
|
|
|
|
|
startLine = sourceLine . start $ loc
|
|
|
|
|
startCol = sourceColumn . start $ loc
|
|
|
|
|
stopCol = sourceColumn . end $ loc
|