packages feed

futhark-0.28.2: src/Futhark/LSP/State.hs

-- | The language server state definition.
module Futhark.LSP.State
  ( State (..),
    emptyState,
    getStaleContent,
    getStaleMapping,
    updateStaleContent,
    updateStaleMapping,
  )
where

import Data.Int (Int32)
import Data.Map qualified as M
import Data.Set qualified as S
import Futhark.Compiler.Program (LoadedProg)
import Futhark.LSP.PositionMapping (PositionMapping, StaleFile (..))
import Language.LSP.Protocol.Types (NormalizedUri)
import Language.LSP.VFS (VirtualFile)

-- | The state of the language server.
data State = State
  { -- | The loaded program.
    stateProgram :: Maybe LoadedProg,
    -- | The stale data, stored to provide PositionMapping when requested.
    -- All files that have been opened have an entry.
    staleData :: M.Map FilePath StaleFile,
    -- | The file and version of the most recent compilation, if it
    -- failed.  Used to avoid recompiling unchanged files.
    stateFailed :: Maybe (FilePath, Int32),
    -- | The files for which the most recent compilation published
    -- diagnostics.  These must be cleared by the next compilation.
    stateDiagnosed :: S.Set NormalizedUri
  }

-- | Initial state.
emptyState :: State
emptyState = State Nothing M.empty Nothing S.empty

-- | Get the contents of a stale (last successfully complied) file's contents.
getStaleContent :: State -> FilePath -> Maybe VirtualFile
getStaleContent state file_path = (Just . staleContent) =<< M.lookup file_path (staleData state)

-- | Get the PositionMapping for a file.
getStaleMapping :: State -> FilePath -> Maybe PositionMapping
getStaleMapping state file_path = staleMapping =<< M.lookup file_path (staleData state)

-- | Update the state with another pair of file_path and contents.
-- Could do a clean up becausae there is no need to store files that are not in lpFilePaths prog.
updateStaleContent :: FilePath -> VirtualFile -> LoadedProg -> State -> State
updateStaleContent file_path file_content loadedProg state =
  -- NOTE: insert will replace the old value if the key already exists.
  -- updateStaleContent is only called after a successful type-check,
  -- so the PositionsMapping should be Nothing here, it's calculated after failed type-check.
  state
    { stateProgram = Just loadedProg,
      staleData = M.insert file_path (StaleFile file_content Nothing) (staleData state)
    }

-- | Update the state with another pair of file_path and PositionMapping.
updateStaleMapping :: Maybe FilePath -> Maybe PositionMapping -> State -> State
updateStaleMapping (Just file_path) mapping state = do
  case M.lookup file_path (staleData state) of
    Nothing -> state -- Only happends when the file have never been successfully type-checked before.
    Just (StaleFile file_content _mapping) ->
      state {staleData = M.insert file_path (StaleFile file_content mapping) (staleData state)}
updateStaleMapping _ _ state = state