content: {-
    Copyright (c) Meta Platforms, Inc. and affiliates.
    All rights reserved.
  
    This source code is licensed under the BSD-style license found in the
    LICENSE file in the root directory of this source tree.
  -}
  
  {-# LANGUAGE ApplicativeDo, TypeApplications #-}
  {-# OPTIONS_GHC -Wno-name-shadowing #-}
  
  {-
  Example client for Glean to provide a basic "jump to
  definition". Given a file name and a byte offset into the file,
  returns the target of the identifier at that position, if any.
  
  $ ./example --service localhost:25052 some/File.h 11007
  [XRefTarget_unknown (SrcLoc {srcLoc_file = File {file_id = 2718, file_key = Nothing}, srcLoc_line = Nat {unNat = 23}, srcLoc_column = Nat {unNat = 1}})]
  -}
  
  module Example where
  
  import Data.HashMap.Strict (toList)
  import qualified Data.Set as Set
  import Data.String
  import Options.Applicative
  
  import Util.EventBase
  
  import qualified Glean
  import qualified Glean.Remote
  import Glean.Angle as Angle
  import Glean.Impl.ConfigProvider
  import Glean.Repo (getSCMrevisions)
  import Glean.Schema.Builtin.Types (schema_id)
  import qualified Glean.Schema.Cxx1.Types as Cxx
  import Glean.Util.ConfigProvider
  import Glean.Util.Range
  import Glean.Util.XRefs
  
  
  data Config = Config
    { cfgService :: Glean.ThriftSource Glean.ClientConfig
    , cfgFile :: FilePath
    , cfgOffset :: Int
    }
  
  options :: ParserInfo Config
  options = info (helper <*> parser) fullDesc
    where
      parser :: Parser Config
      parser = do
        cfgService <- Glean.Remote.options
        cfgFile <- strArgument (metavar "FILE")
        cfgOffset <- argument auto (metavar "OFFSET")
        return Config{..}
  
  main :: IO ()
  main =
    withConfigOptions options $ \(cfg, cfgOpts) ->
    withEventBaseDataplane $ \evb ->
    withConfigProvider cfgOpts $ \(cfgAPI :: ConfigAPI) ->
    Glean.Remote.withRemoteBackend evb cfgAPI (cfgService cfg) (Just schema_id)
      $ \backend -> do
        repo <- Glean.getLatestRepo backend "fbsource"
        doQuery backend cfg repo
        scmRevisions <- getSCMrevisions backend repo
        putStrLn $ "SCM revisions: " <> show (toList scmRevisions)
  
  doQuery :: Glean.Backend b => b -> Config -> Glean.Repo -> IO ()
  doQuery backend Config{..} repo = do
    let
      printResults results = print
        [ target
        | (ByteRange{..}, target) <- Set.toList $ collectXRefTargets results
        , byteRange_begin == fromIntegral cfgOffset ]
  
    -- Query using Angle syntax
    --   [+] Concise
    --   [+] Supports arbitrary Angle queries
    --   [-] Not typechecked at compile time
    --   [-] Hard to build queries programmatically
    --   [?] May break if the schema changes
    results <- Glean.runQuery_ backend repo $ Glean.recursive $ Glean.angle $
      "cxx1.FileXRefs { xmap = { file = \"" <> fromString cfgFile <> "\" }}"
    printResults results
  
    -- Query using Angle combinators
    --   [-] More verbose than Angle syntax
    --   [+] Supports arbitrary Angle queries
    --   [+] Typechecked at compile time
    --   [+] Easy to build queries programmatically
    --   [+] Does not break when the schema changes
    results <- Glean.runQuery_ backend repo $ Glean.recursive $ Angle.query $
      predicate @Cxx.FileXRefs $
        rec $
          field @"xmap" (rec (field @"file" (fromString cfgFile) end))
        end
    printResults results
  