-
-
Notifications
You must be signed in to change notification settings - Fork 355
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
hls-notes-plugin: Find notes at index time and cache
- Loading branch information
1 parent
029303b
commit 505ee39
Showing
6 changed files
with
115 additions
and
108 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,104 @@ | ||
module Ide.Plugin.Notes (descriptor) where | ||
module Ide.Plugin.Notes (descriptor, Log) where | ||
|
||
import Development.IDE | ||
import qualified Ide.Plugin.Notes.Internal as X | ||
import Control.Lens (ix, (^.), (^?)) | ||
import Control.Monad.IO.Class (liftIO) | ||
import Control.Monad.Trans.Class (lift) | ||
import qualified Data.Array as A | ||
import Data.HashMap.Strict (HashMap) | ||
import qualified Data.HashMap.Strict as HM | ||
import Data.Maybe (listToMaybe, mapMaybe) | ||
import Data.Text (Text, intercalate) | ||
import qualified Data.Text as T | ||
import qualified Data.Text.Utf16.Rope as Rope | ||
import Data.Typeable (Typeable) | ||
import Development.IDE hiding (line) | ||
import qualified Development.IDE.Core.Shake as Shake | ||
import Development.IDE.Graph.Classes (Hashable, NFData) | ||
import GHC.Generics (Generic) | ||
import Ide.PluginUtils (getNormalizedFilePath, | ||
pluginResponse, | ||
throwPluginError) | ||
import Ide.Types | ||
import qualified Language.LSP.Server as LSP | ||
import Language.LSP.Types | ||
import qualified Language.LSP.Types.Lens as L | ||
import Language.LSP.VFS (VirtualFile (..)) | ||
import Text.Regex.TDFA (Regex, caseSensitive, | ||
defaultCompOpt, defaultExecOpt, | ||
makeRegexOpts, matchAllText) | ||
|
||
descriptor :: PluginId -> PluginDescriptor IdeState | ||
descriptor plId = (defaultPluginDescriptor plId) | ||
{ Ide.Types.pluginHandlers = | ||
mkPluginHandler STextDocumentDefinition X.jumpToNote | ||
data Log | ||
= LogShake Shake.Log | ||
| LogNotesFound [Text] | ||
deriving Show | ||
|
||
instance Pretty Log where | ||
pretty = \case | ||
LogShake l -> pretty l | ||
LogNotesFound notes -> | ||
"Found notes: [" | ||
<> pretty (intercalate ", " (fmap (\s -> "\"" <> s <> "\"") notes)) <> "]" | ||
|
||
descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState | ||
descriptor recorder plId = (defaultPluginDescriptor plId) | ||
{ Ide.Types.pluginHandlers = mkPluginHandler STextDocumentDefinition jumpToNote | ||
, Ide.Types.pluginRules = findNotesRules recorder | ||
} | ||
|
||
jumpToNote :: PluginMethodHandler IdeState TextDocumentDefinition | ||
jumpToNote state _ param = pluginResponse $ do | ||
let uriOrig = param ^. (L.textDocument . L.uri) | ||
Position l c = param ^. L.position | ||
nfp <- getNormalizedFilePath uriOrig | ||
contents <- fmap _file_text . err "Error getting file contents" | ||
=<< lift (LSP.getVirtualFile (toNormalizedUri uriOrig)) | ||
line <- err "Line not found in file" (Rope.lines contents ^? ix (fromIntegral l)) | ||
note <- err "No note at this position" $ listToMaybe $ | ||
mapMaybe (atPos $ fromIntegral c) $ matchAllText noteRefRegex line | ||
allNotes <- err "No notes found in file" =<< | ||
liftIO (runAction "Notes.getNotes" state $ use MkNoteDefinitions nfp) | ||
pos <- err "Note not found" (HM.lookup note allNotes) | ||
pure $ InL (Location uriOrig (Range pos pos)) | ||
where | ||
err s = maybe (throwPluginError s) pure | ||
atPos c arr = case arr A.! 0 of | ||
(_, (c', len)) -> if c' <= c && c <= c' + len | ||
then Just (fst (arr A.! 1)) else Nothing | ||
|
||
data NoteDefinitions = MkNoteDefinitions | ||
deriving (Eq, Show, Typeable, Generic) | ||
instance Hashable NoteDefinitions | ||
instance NFData NoteDefinitions | ||
|
||
type instance RuleResult NoteDefinitions = HashMap Text Position | ||
|
||
findNotesRules :: Recorder (WithPriority Log) -> Rules () | ||
findNotesRules recorder = do | ||
defineNoDiagnostics (cmapWithPrio LogShake recorder) $ \MkNoteDefinitions file -> do | ||
content <- snd <$> use_ GetFileContents file | ||
let m = do | ||
c <- content | ||
let matches = (A.! 1) <$> matchAllText noteRegex c | ||
pure $ toPositions matches c | ||
logWith recorder Debug $ LogNotesFound (maybe [] HM.keys m) | ||
pure m | ||
where | ||
uint = fromIntegral . toInteger | ||
toPositions matches = snd . fst . T.foldl' (\case | ||
(([], m), _) -> const (([], m), (0, 0, 0)) | ||
((x@(name, (char, _)):xs, m), (n, nc, c)) -> \char' -> | ||
let !c' = c + 1 | ||
(!n', !nc') = if char' == '\n' then (n + 1, c') else (n, nc) | ||
p = if char == c then | ||
(xs, HM.insert name (Position (uint n') (uint (char - nc'))) m) | ||
else (x:xs, m) | ||
in (p, (n', nc', c')) | ||
) ((matches, HM.empty), (0, 0, 0)) | ||
|
||
noteRefRegex, noteRegex :: Regex | ||
(noteRefRegex, noteRegex) = | ||
( mkReg ("note \\[(.+)\\]( in (([A-Za-z0-9]+\\.)*[A-Za-z0-9]+))?" :: String) | ||
, mkReg ("note \\[([[:print:]]+)\\][[:blank:]]*[[:space:]][[:space:]]?~~~" :: String) | ||
) | ||
where | ||
mkReg = makeRegexOpts (defaultCompOpt { caseSensitive = False }) defaultExecOpt |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters