{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-} -- | Functions for performing code completion. -- -- To get started with code completion, it's enough to parse a file with -- 'Clang.parseSourceFile' and pass the 'FFI.TranslationUnit' to 'codeCompleteAt'. -- This will return a 'FFI.CodeCompleteResults' value, from which you can -- retrieve a list of completion strings using 'getResults'. Each completion -- string in turn consists of a series of chunks, which you can retrieve using -- 'getChunks'. -- -- This module is intended to be imported qualified. module Clang.Completion ( -- * Code completion codeCompleteAt , FFI.CodeCompleteFlags(..) , FFI.CodeCompleteResults -- * Completion results , getResults , FFI.CompletionString , sortResults , getDiagnostics , getContexts , FFI.CompletionContext(..) , getContainerKind , getContainerUSR , getObjCSelector -- * Completion strings , getChunks , Chunk(..) , FFI.ChunkKind(..) , getPriority , getAvailability , getAnnotations , getParent , getBriefComment ) where import Control.Applicative import Control.Monad import Control.Monad.IO.Class import Data.Typeable import qualified Data.Vector as DV import Clang.Internal.BitFlags import qualified Clang.Internal.FFI as FFI import Clang.Internal.Monad -- | Perform code completion at a given location in a translation unit. -- -- This function performs code completion at a particular file, line, and -- column within source code, providing results that suggest potential -- code snippets based on the context of the completion. The basic model -- for code completion is that Clang will parse a complete source file, -- performing syntax checking up to the location where code completion has -- been requested. At that point, a special code completion token is passed -- to the parser, which recognizes this token and determines, based on the -- current location in the C \/ Objective-C \/ C++ grammar and the state of -- semantic analysis, what completions to provide. These completions are -- returned via a 'FFI.CodeCompleteResults' value. -- -- Code completion itself is meant to be triggered by the client when the -- user types punctuation characters or whitespace, at which point the -- code completion location will coincide with the cursor. For example, if \'p\' -- is a pointer, code completion might be triggered after the \'-\' and then -- after the \'>\' in \'p->\'. When the code completion location is after the \'>\', -- the completion results will provide, e.g., the members of the struct that -- \'p\' points to. The client is responsible for placing the cursor at the -- beginning of the token currently being typed, then filtering the results -- based on the contents of the token. For example, when code-completing for -- the expression \'p->get\', the client should provide the location just after -- the \'>\' (e.g., pointing at the \'g\') to this code completion hook. Then, the -- client can filter the results based on the current token text (\'get\'), only -- showing those results that start with \'get\'. The intent of this interface -- is to separate the relatively high-latency acquisition of code completion -- results from the filtering of results on a per-character basis, which must -- have a lower latency. codeCompleteAt :: ClangBase m => FFI.TranslationUnit s' -- ^ The translation unit in which code completion should occur. -- The source files for this translation unit need not be -- completely up-to-date (and the contents of those source files -- may be overridden via the 'FFI.UnsavedFile' vector). Cursors -- referring into the translation unit may be invalidated by -- this invocation. -> FilePath -- ^ The name of the source file where code -- completion should be performed. This filename may be any file -- included in the translation unit. -> Int -- ^ The line at which code completion should occur. -> Int -- ^ The column at which code completion should occur. -- Note that the column should point just after the syntactic construct that -- initiated code completion, and not in the middle of a lexical token. -> DV.Vector FFI.UnsavedFile -- ^ Files that have not yet been saved to disk -- but may be required for parsing or code completion, including -- the contents of those files. The contents and name of these -- files (as specified by 'FFI.UnsavedFile') are copied when -- necessary, so the client only needs to guarantee their -- validity until the call to this function returns. -> Maybe [FFI.CodeCompleteFlags] -- ^ Extra options that control the behavior of code -- completion, or 'Nothing' to use the default set. -> ClangT s m (FFI.CodeCompleteResults s) codeCompleteAt t fname l c ufs mayOpts = do opts <- case mayOpts of Just os -> return os Nothing -> unFlags <$> liftIO FFI.defaultCodeCompleteOptions FFI.codeCompleteAt t fname l c ufs (orFlags opts) -- | Retrieves a list of code completion results. -- -- The first element of each tuple is the completion string, which describes how to insert -- this result into the editing buffer. Use 'getChunks' to analyze it further. -- -- The second element of each tuple is the kind of entity that this completion refers to. -- It will be a macro, keyword, or declaration describing the entity that the completion -- is referring to. getResults :: ClangBase m => FFI.CodeCompleteResults s' -> ClangT s m [(FFI.CompletionString s, FFI.CursorKind)] getResults rs = do numS <- liftIO $ FFI.codeCompleteGetNumResults rs forM [0..(numS - 1)] $ \i -> FFI.codeCompleteGetResult rs i -- | Sort the provided code completion results in case-insensitive alphabetical order. sortResults :: ClangBase m => FFI.CodeCompleteResults s' -> ClangT s m () sortResults c = liftIO $ FFI.sortCodeCompletionResults c -- | Retrieves the diagnostics associated with the given code completion. getDiagnostics :: ClangBase m => FFI.CodeCompleteResults s' -> ClangT s m [FFI.Diagnostic s] getDiagnostics c = do numD <- liftIO $ FFI.codeCompleteGetNumDiagnostics c mapM (FFI.codeCompleteGetDiagnostic c) [0..(numD - 1)] -- | Determines which kinds of completions are appropriate for the context -- of the given code completion. getContexts :: ClangBase m => FFI.CodeCompleteResults s' -> ClangT s m [FFI.CompletionContext] getContexts rs = unFlags <$> liftIO (FFI.codeCompleteGetContexts rs) -- | Returns a cursor kind for the container associated with the given code -- completion. Only contexts like member accesses and Objective-C message sends -- have containers; for other kinds of contexts, a cursor kind of -- 'FFI.InvalidCodeCursor' is returned. -- -- The second element of the result tuple is a boolean indicating whether libclang -- has incomplete information about the container. A 'True' value indicates that -- information about the container is incomplete. getContainerKind :: ClangBase m => FFI.CodeCompleteResults s' -> ClangT s m (FFI.CursorKind, Bool) getContainerKind rs = liftIO $ FFI.codeCompleteGetContainerKind rs -- | Given a code completion context, returns a "Clang.USR" for the appropriate -- container. Only contexts like member accesses and Objective-C message sends -- have containers; for other kinds of contexts, the empty string is returned. getContainerUSR :: ClangBase m => FFI.CodeCompleteResults s' -> ClangT s m (FFI.ClangString s) getContainerUSR = FFI.codeCompleteGetContainerUSR -- | Returns the currently-entered selector for an Objective-C message -- send, formatted like \"initWithFoo:bar:\". This function is only guaranteed -- to return a non-empty string if the completion context is an Objective-C -- instance message or class message send, which you can check with 'getContexts'. getObjCSelector :: ClangBase m => FFI.CodeCompleteResults s' -> ClangT s m (FFI.ClangString s) getObjCSelector = FFI.codeCompleteGetObjCSelector -- | The completion string is a template that describes not only the completion itself, -- but also information about how it should be presented to the user. It is divided into -- a list of chunks, with each kind of chunk playing a different role in the template. data Chunk s = TextChunk FFI.ChunkKind (FFI.ClangString s) | OptionalChunk (FFI.CompletionString s) deriving (Eq, Ord, Typeable) -- | Retrieves the chunks within a completion string. -- -- Each \"chunk\" contains either a piece of text with a specific \"kind\" -- that describes how that text should be interpreted by the client, or -- another completion string. getChunks :: ClangBase m => FFI.CompletionString s' -> ClangT s m [Chunk s] getChunks cs = do numC <- liftIO $ FFI.getNumCompletionChunks cs forM [0..(numC - 1)] $ \i -> do kind <- liftIO $ FFI.getCompletionChunkKind cs i case kind of FFI.OptionalChunkKind -> OptionalChunk <$> (liftIO $ FFI.getCompletionChunkCompletionString cs i) _ -> TextChunk kind <$> FFI.getCompletionChunkText cs i -- | Determines the priority of this code completion string. -- -- The priority of a code completion indicates how likely it is that this -- particular completion is the completion that the user will select. The -- priority is selected by various internal heuristics. Smaller values -- indicate more likely completions. getPriority :: ClangBase m => FFI.CompletionString s' -> ClangT s m Int getPriority cs = liftIO $ FFI.getCompletionPriority cs -- | Determines the availability of the entity that this code completion -- string refers to. getAvailability :: ClangBase m => FFI.CompletionString s' -> ClangT s m FFI.AvailabilityKind getAvailability cs = liftIO $ FFI.getCompletionAvailability cs -- | Retrieves the annotations associated with the given completion string. getAnnotations :: ClangBase m => FFI.CompletionString s' -> ClangT s m [FFI.ClangString s] getAnnotations cs = do numA <- liftIO $ FFI.getCompletionNumAnnotations cs mapM (FFI.getCompletionAnnotation cs) [0..(numA - 1)] -- | Retrieves the parent context of the given completion string. -- -- The parent context of a completion string is the semantic parent of -- the declaration (if any) that the code completion represents. For example, -- a code completion for an Objective-C method would have the method's class -- or protocol as its context. A completion string representing a method on -- the NSObject class might have a parent context of \"NSObject\". getParent :: ClangBase m => FFI.CompletionString s' -> ClangT s m (FFI.ClangString s) getParent = FFI.getCompletionParent -- | Retrieves the brief documentation comment attached to the declaration -- that corresponds to the given completion string. getBriefComment :: ClangBase m => FFI.CompletionString s' -> ClangT s m (FFI.ClangString s) getBriefComment = FFI.getCompletionBriefComment