Skip to content

Commit

Permalink
move dependents implementation into its own module
Browse files Browse the repository at this point in the history
  • Loading branch information
mitchellwrosen committed Oct 16, 2024
1 parent e2c42ca commit f068357
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 62 deletions.
41 changes: 41 additions & 0 deletions unison-cli/src/Unison/Cli/NameResolutionUtils.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
-- | Utilities related to resolving names to things.
module Unison.Cli.NameResolutionUtils
( resolveHQToLabeledDependencies,
)
where

import Control.Monad.Reader (ask)
import Data.Set qualified as Set
import Unison.Cli.Monad (Cli)
import Unison.Cli.Monad qualified as Cli
import Unison.Cli.NamesUtils qualified as Cli
import Unison.HashQualified qualified as HQ
import Unison.LabeledDependency (LabeledDependency)
import Unison.LabeledDependency qualified as LD
import Unison.Name (Name)
import Unison.Name qualified as Name
import Unison.Names qualified as Names
import Unison.Prelude
import Unison.Server.NameSearch.Sqlite qualified as Sqlite

-- todo: compare to `getHQTerms` / `getHQTypes`. Is one universally better?
resolveHQToLabeledDependencies :: HQ.HashQualified Name -> Cli (Set LabeledDependency)
resolveHQToLabeledDependencies = \case
HQ.NameOnly n -> do
names <- Cli.currentNames
let terms, types :: Set LabeledDependency
terms = Set.map LD.referent . Name.searchBySuffix n $ Names.terms names
types = Set.map LD.typeRef . Name.searchBySuffix n $ Names.types names
pure $ terms <> types
-- rationale: the hash should be unique enough that the name never helps
HQ.HashQualified _n sh -> resolveHashOnly sh
HQ.HashOnly sh -> resolveHashOnly sh
where
resolveHashOnly sh = do
Cli.Env {codebase} <- ask
(terms, types) <-
Cli.runTransaction do
terms <- Sqlite.termReferentsByShortHash codebase sh
types <- Sqlite.typeReferencesByShortHash sh
pure (terms, types)
pure $ Set.map LD.referent terms <> Set.map LD.typeRef types
66 changes: 4 additions & 62 deletions unison-cli/src/Unison/Codebase/Editor/HandleInput.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import Unison.Cli.Monad (Cli)
import Unison.Cli.Monad qualified as Cli
import Unison.Cli.MonadUtils (getCurrentProjectBranch)
import Unison.Cli.MonadUtils qualified as Cli
import Unison.Cli.NameResolutionUtils (resolveHQToLabeledDependencies)
import Unison.Cli.NamesUtils qualified as Cli
import Unison.Cli.ProjectUtils qualified as ProjectUtils
import Unison.Codebase qualified as Codebase
Expand All @@ -59,6 +60,7 @@ import Unison.Codebase.Editor.HandleInput.DebugFoldRanges qualified as DebugFold
import Unison.Codebase.Editor.HandleInput.DebugSynhashTerm (handleDebugSynhashTerm)
import Unison.Codebase.Editor.HandleInput.DeleteBranch (handleDeleteBranch)
import Unison.Codebase.Editor.HandleInput.DeleteProject (handleDeleteProject)
import Unison.Codebase.Editor.HandleInput.Dependents (handleDependents)
import Unison.Codebase.Editor.HandleInput.EditNamespace (handleEditNamespace)
import Unison.Codebase.Editor.HandleInput.FindAndReplace (handleStructuredFindI, handleStructuredFindReplaceI, handleTextFindI)
import Unison.Codebase.Editor.HandleInput.FormatFile qualified as Format
Expand Down Expand Up @@ -771,7 +773,7 @@ loop e = do
names <- lift Cli.currentNames
let buildPPED uf tf =
let names' = (fromMaybe mempty $ (UF.typecheckedToNames <$> tf) <|> (UF.toNames <$> uf)) `Names.shadowing` names
in pure (PPED.makePPED (PPE.hqNamer 10 names') (PPE.suffixifyByHashName names'))
in pure (PPED.makePPED (PPE.hqNamer 10 names') (PPE.suffixifyByHashName names'))
let formatWidth = 80
currentPath <- lift $ Cli.getCurrentPath
updates <- MaybeT $ Format.formatFile buildPPED formatWidth currentPath pf tf Nothing
Expand Down Expand Up @@ -1226,44 +1228,6 @@ handleDependencies hq = do
Cli.setNumberedArgs . map SA.HashQualified $ types <> terms
Cli.respond $ ListDependencies suffixifiedPPE lds types terms

handleDependents :: HQ.HashQualified Name -> Cli ()
handleDependents hq = do
-- todo: add flag to handle transitive efficiently
lds <- resolveHQToLabeledDependencies hq
-- Use an unsuffixified PPE here, so we display full names (relative to the current path),
-- rather than the shortest possible unambiguous name.
names <- Cli.currentNames
let pped = PPED.makePPED (PPE.hqNamer 10 names) (PPE.suffixifyByHash names)
let fqppe = PPE.unsuffixifiedPPE pped
let ppe = PPE.suffixifiedPPE pped
when (null lds) do
Cli.returnEarly (LabeledReferenceNotFound hq)

results <- for (toList lds) \ld -> do
-- The full set of dependent references, any number of which may not have names in the current namespace.
dependents <-
let tp = Codebase.dependents Queries.ExcludeOwnComponent
tm = \case
Referent.Ref r -> Codebase.dependents Queries.ExcludeOwnComponent r
Referent.Con (ConstructorReference r _cid) _ct ->
Codebase.dependents Queries.ExcludeOwnComponent r
in Cli.runTransaction (LD.fold tp tm ld)
let -- True is term names, False is type names
results :: [(Bool, HQ.HashQualified Name, Reference)]
results = do
r <- Set.toList dependents
Just (isTerm, hq) <- [(True,) <$> PPE.terms fqppe (Referent.Ref r), (False,) <$> PPE.types fqppe r]
fullName <- [HQ'.toName hq]
guard (not (Name.beginsWithSegment fullName NameSegment.libSegment))
Just shortName <- pure $ PPE.terms ppe (Referent.Ref r) <|> PPE.types ppe r
pure (isTerm, HQ'.toHQ shortName, r)
pure results
let sort = fmap fst . nubOrdOn snd . Name.sortByText (HQ.toText . fst)
let types = sort [(n, r) | (False, n, r) <- join results]
let terms = sort [(n, r) | (True, n, r) <- join results]
Cli.setNumberedArgs . map SA.HashQualified $ types <> terms
Cli.respond (ListDependents ppe lds types terms)

-- | Handle a @ShowDefinitionI@ input command, i.e. `view` or `edit`.
handleShowDefinition :: OutputLocation -> ShowDefinitionScope -> NonEmpty (HQ.HashQualified Name) -> Cli ()
handleShowDefinition outputLoc showDefinitionScope query = do
Expand Down Expand Up @@ -1308,28 +1272,6 @@ handleShowDefinition outputLoc showDefinitionScope query = do
FileLocation _ -> Backend.IncludeCycles
LatestFileLocation -> Backend.IncludeCycles

-- todo: compare to `getHQTerms` / `getHQTypes`. Is one universally better?
resolveHQToLabeledDependencies :: HQ.HashQualified Name -> Cli (Set LabeledDependency)
resolveHQToLabeledDependencies = \case
HQ.NameOnly n -> do
names <- Cli.currentNames
let terms, types :: Set LabeledDependency
terms = Set.map LD.referent . Name.searchBySuffix n $ Names.terms names
types = Set.map LD.typeRef . Name.searchBySuffix n $ Names.types names
pure $ terms <> types
-- rationale: the hash should be unique enough that the name never helps
HQ.HashQualified _n sh -> resolveHashOnly sh
HQ.HashOnly sh -> resolveHashOnly sh
where
resolveHashOnly sh = do
Cli.Env {codebase} <- ask
(terms, types) <-
Cli.runTransaction do
terms <- Backend.termReferentsByShortHash codebase sh
types <- Backend.typeReferencesByShortHash sh
pure (terms, types)
pure $ Set.map LD.referent terms <> Set.map LD.typeRef types

doDisplay :: OutputLocation -> Names -> Term Symbol () -> Cli ()
doDisplay outputLoc names tm = do
Cli.Env {codebase} <- ask
Expand Down Expand Up @@ -1475,7 +1417,7 @@ doCompile profile native output main = do
outf
| native = output
| otherwise = output <> ".uc"
copts = Runtime.defaultCompileOpts { Runtime.profile = profile }
copts = Runtime.defaultCompileOpts {Runtime.profile = profile}
whenJustM
( liftIO $
Runtime.compileTo theRuntime copts codeLookup ppe ref outf
Expand Down
68 changes: 68 additions & 0 deletions unison-cli/src/Unison/Codebase/Editor/HandleInput/Dependents.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
module Unison.Codebase.Editor.HandleInput.Dependents
( handleDependents,
)
where

import Data.Set qualified as Set
import U.Codebase.Sqlite.Queries qualified as Queries
import Unison.Cli.Monad (Cli)
import Unison.Cli.Monad qualified as Cli
import Unison.Cli.NameResolutionUtils (resolveHQToLabeledDependencies)
import Unison.Cli.NamesUtils qualified as Cli
import Unison.Codebase qualified as Codebase
import Unison.Codebase.Editor.Output
import Unison.Codebase.Editor.StructuredArgument qualified as SA
import Unison.ConstructorReference (GConstructorReference (..))
import Unison.HashQualified qualified as HQ
import Unison.HashQualifiedPrime qualified as HQ'
import Unison.LabeledDependency qualified as LD
import Unison.Name (Name)
import Unison.Name qualified as Name
import Unison.NameSegment qualified as NameSegment
import Unison.Prelude
import Unison.PrettyPrintEnv qualified as PPE
import Unison.PrettyPrintEnv.Names qualified as PPE
import Unison.PrettyPrintEnvDecl qualified as PPE hiding (biasTo, empty)
import Unison.PrettyPrintEnvDecl.Names qualified as PPED
import Unison.Reference (Reference)
import Unison.Referent qualified as Referent
import Unison.Syntax.HashQualified qualified as HQ (toText)
import Unison.Util.List (nubOrdOn)

handleDependents :: HQ.HashQualified Name -> Cli ()
handleDependents hq = do
-- todo: add flag to handle transitive efficiently
lds <- resolveHQToLabeledDependencies hq
-- Use an unsuffixified PPE here, so we display full names (relative to the current path),
-- rather than the shortest possible unambiguous name.
names <- Cli.currentNames
let pped = PPED.makePPED (PPE.hqNamer 10 names) (PPE.suffixifyByHash names)
let fqppe = PPE.unsuffixifiedPPE pped
let ppe = PPE.suffixifiedPPE pped
when (null lds) do
Cli.returnEarly (LabeledReferenceNotFound hq)

results <- for (toList lds) \ld -> do
-- The full set of dependent references, any number of which may not have names in the current namespace.
dependents <-
let tp = Codebase.dependents Queries.ExcludeOwnComponent
tm = \case
Referent.Ref r -> Codebase.dependents Queries.ExcludeOwnComponent r
Referent.Con (ConstructorReference r _cid) _ct ->
Codebase.dependents Queries.ExcludeOwnComponent r
in Cli.runTransaction (LD.fold tp tm ld)
let -- True is term names, False is type names
results :: [(Bool, HQ.HashQualified Name, Reference)]
results = do
r <- Set.toList dependents
Just (isTerm, hq) <- [(True,) <$> PPE.terms fqppe (Referent.Ref r), (False,) <$> PPE.types fqppe r]
fullName <- [HQ'.toName hq]
guard (not (Name.beginsWithSegment fullName NameSegment.libSegment))
Just shortName <- pure $ PPE.terms ppe (Referent.Ref r) <|> PPE.types ppe r
pure (isTerm, HQ'.toHQ shortName, r)
pure results
let sort = fmap fst . nubOrdOn snd . Name.sortByText (HQ.toText . fst)
let types = sort [(n, r) | (False, n, r) <- join results]
let terms = sort [(n, r) | (True, n, r) <- join results]
Cli.setNumberedArgs . map SA.HashQualified $ types <> terms
Cli.respond (ListDependents ppe lds types terms)
2 changes: 2 additions & 0 deletions unison-cli/unison-cli.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ library
Unison.Cli.MergeTypes
Unison.Cli.Monad
Unison.Cli.MonadUtils
Unison.Cli.NameResolutionUtils
Unison.Cli.NamesUtils
Unison.Cli.Pretty
Unison.Cli.ProjectUtils
Expand All @@ -61,6 +62,7 @@ library
Unison.Codebase.Editor.HandleInput.DebugSynhashTerm
Unison.Codebase.Editor.HandleInput.DeleteBranch
Unison.Codebase.Editor.HandleInput.DeleteProject
Unison.Codebase.Editor.HandleInput.Dependents
Unison.Codebase.Editor.HandleInput.EditNamespace
Unison.Codebase.Editor.HandleInput.FindAndReplace
Unison.Codebase.Editor.HandleInput.FormatFile
Expand Down

0 comments on commit f068357

Please sign in to comment.