76 lines
2.7 KiB
Haskell
Raw Normal View History

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
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