mirror of
https://github.com/unisonweb/unison.git
synced 2024-09-23 16:28:02 +03:00
Merge branch 'master' into CompilerBug
This commit is contained in:
commit
f9a348dbce
9
parser-typechecker/src/Unison/Codebase/BranchLoadMode.hs
Normal file
9
parser-typechecker/src/Unison/Codebase/BranchLoadMode.hs
Normal file
@ -0,0 +1,9 @@
|
||||
module Unison.Codebase.BranchLoadMode where
|
||||
|
||||
-- When loading a nonexistent branch, what should happen?
|
||||
-- Could bomb (`FailIfMissing`) or return the empty branch (`EmptyIfMissing`).
|
||||
--
|
||||
-- `EmptyIfMissing` mode is used when attempting to load a user-specified
|
||||
-- branch. `FailIfMissing` is used when loading the root branch - if the root
|
||||
-- does not exist, that's a serious problem.
|
||||
data BranchLoadMode = FailIfMissing | EmptyIfMissing deriving (Eq, Show)
|
@ -38,6 +38,7 @@ import Unison.ShortHash ( ShortHash )
|
||||
import Unison.Type ( Type )
|
||||
import Unison.Codebase.ShortBranchHash
|
||||
( ShortBranchHash )
|
||||
import Unison.Codebase.BranchLoadMode (BranchLoadMode)
|
||||
|
||||
|
||||
type AmbientAbilities v = [Type v Ann]
|
||||
@ -127,7 +128,7 @@ data Command m i v a where
|
||||
LoadLocalBranch :: Branch.Hash -> Command m i v (Branch m)
|
||||
|
||||
LoadRemoteRootBranch ::
|
||||
RemoteRepo -> Command m i v (Either GitError (Branch m))
|
||||
BranchLoadMode -> RemoteRepo -> Command m i v (Either GitError (Branch m))
|
||||
|
||||
-- returns NoRemoteNamespaceWithHash or RemoteNamespaceHashAmbiguous
|
||||
-- if no exact match.
|
||||
|
@ -74,27 +74,30 @@ shallowPullFromGit localPath url gitBranch = do
|
||||
pullGitRootBranch
|
||||
:: MonadIO m
|
||||
=> FilePath
|
||||
-> BranchLoadMode
|
||||
-> Codebase m v a
|
||||
-> Text
|
||||
-> Maybe Text
|
||||
-> ExceptT GitError m (Branch m)
|
||||
pullGitRootBranch localPath codebase url treeish =
|
||||
pullGitBranch localPath codebase url treeish Nothing
|
||||
pullGitRootBranch localPath loadMode codebase url treeish =
|
||||
pullGitBranch localPath codebase url treeish (Left loadMode)
|
||||
|
||||
-- pull repo & load arbitrary branch
|
||||
-- if `loadInfo` is Left, we try to load the root branch;
|
||||
-- if Right, we try to load the specified hash
|
||||
pullGitBranch
|
||||
:: MonadIO m
|
||||
=> FilePath
|
||||
-> Codebase m v a
|
||||
-> Text
|
||||
-> Maybe Text
|
||||
-> Maybe ShortBranchHash
|
||||
-> Either BranchLoadMode ShortBranchHash
|
||||
-> ExceptT GitError m (Branch m)
|
||||
pullGitBranch localPath codebase url treeish sbh = do
|
||||
pullGitBranch localPath codebase url treeish loadInfo = do
|
||||
pullFromGit localPath url treeish
|
||||
branch <- case sbh of
|
||||
Nothing -> lift $ FC.getRootBranch (localPath </> codebasePath)
|
||||
Just sbh -> do
|
||||
branch <- case loadInfo of
|
||||
Left loadMode -> lift $ FC.getRootBranch loadMode gitCodebasePath
|
||||
Right sbh -> do
|
||||
branchCompletions <- lift $ FC.branchHashesByPrefix gitCodebasePath sbh
|
||||
case toList branchCompletions of
|
||||
[] -> throwError $ NoRemoteNamespaceWithHash url treeish sbh
|
||||
@ -122,15 +125,8 @@ clone :: MonadError GitError m => MonadIO m => Text -> FilePath -> m ()
|
||||
clone uri localPath = "git" ["clone", uri, Text.pack localPath]
|
||||
`onError` throwError (NoRemoteRepoAt uri)
|
||||
|
||||
shallowClone :: MonadError GitError m => MonadIO m => Text -> FilePath -> m ()
|
||||
shallowClone uri localPath =
|
||||
"git" ["clone", "--depth=1", uri, Text.pack localPath]
|
||||
`onError` throwError (NoRemoteRepoAt uri)
|
||||
|
||||
pull :: MonadError GitError m => MonadIO m => FilePath -> Text -> Maybe Text -> m ()
|
||||
pull localPath uri treeish = do
|
||||
gitIn localPath (["fetch", uri] ++ toList treeish)
|
||||
`onError` throwError (NoRemoteRepoAt uri)
|
||||
pull localPath _uri treeish = do
|
||||
for_ treeish $ \treeish ->
|
||||
liftIO $ gitIn localPath ["checkout", treeish]
|
||||
|
||||
|
@ -122,9 +122,9 @@ commandLine config awaitInput setBranchRef rt notifyUser codebase =
|
||||
SyncLocalRootBranch branch -> do
|
||||
setBranchRef branch
|
||||
Codebase.putRootBranch codebase branch
|
||||
LoadRemoteRootBranch GitRepo {..} -> do
|
||||
LoadRemoteRootBranch loadMode GitRepo {..} -> do
|
||||
tmp <- tempGitDir url commit
|
||||
runExceptT $ Git.pullGitRootBranch tmp codebase url commit
|
||||
runExceptT $ Git.pullGitRootBranch tmp loadMode codebase url commit
|
||||
SyncRemoteRootBranch GitRepo {..} branch -> do
|
||||
tmp <- tempGitDir url commit
|
||||
runExceptT
|
||||
@ -152,7 +152,7 @@ commandLine config awaitInput setBranchRef rt notifyUser codebase =
|
||||
BranchHashesByPrefix h -> Codebase.branchHashesByPrefix codebase h
|
||||
LoadRemoteShortBranch GitRepo{..} sbh -> do
|
||||
tmp <- tempGitDir url commit
|
||||
runExceptT $ Git.pullGitBranch tmp codebase url commit (Just sbh)
|
||||
runExceptT $ Git.pullGitBranch tmp codebase url commit (Right sbh)
|
||||
ParseType names (src, _) -> pure $
|
||||
Parsers.parseType (Text.unpack src) (Parser.ParsingEnv mempty names)
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
|
||||
--{-# OPTIONS_GHC -Wno-unused-imports #-} -- todo: delete
|
||||
{-# OPTIONS_GHC -Wno-unused-top-binds #-} -- todo: delete
|
||||
{-# OPTIONS_GHC -Wno-unused-local-binds #-} -- todo: delete
|
||||
--{-# OPTIONS_GHC -Wno-unused-matches #-} -- todo: delete
|
||||
|
||||
{-# LANGUAGE ApplicativeDo #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
@ -54,6 +52,7 @@ import Unison.Codebase.Branch ( Branch(..)
|
||||
, Branch0(..)
|
||||
)
|
||||
import qualified Unison.Codebase.Branch as Branch
|
||||
import Unison.Codebase.BranchLoadMode ( BranchLoadMode(FailIfMissing, EmptyIfMissing) )
|
||||
import qualified Unison.Codebase.BranchUtil as BranchUtil
|
||||
import qualified Unison.Codebase.Causal as Causal
|
||||
import qualified Unison.Codebase.Metadata as Metadata
|
||||
@ -245,10 +244,10 @@ loop = do
|
||||
let lexed = L.lexer (Text.unpack sourceName) (Text.unpack text)
|
||||
withFile [] sourceName (text, lexed) $ \unisonFile -> do
|
||||
sr <- toSlurpResult unisonFile <$> slurpResultNames0
|
||||
hnames <- makeShadowedPrintNamesFromLabeled
|
||||
names <- makeShadowedPrintNamesFromLabeled
|
||||
(UF.termSignatureExternalLabeledDependencies unisonFile)
|
||||
(UF.typecheckedToNames0 unisonFile)
|
||||
ppe <- prettyPrintEnv hnames
|
||||
ppe <- PPE.suffixifiedPPE <$> prettyPrintEnvDecl names
|
||||
eval (Notify $ Typechecked sourceName ppe sr unisonFile)
|
||||
r <- eval . Evaluate ppe $ unisonFile
|
||||
case r of
|
||||
@ -586,7 +585,7 @@ loop = do
|
||||
|
||||
NamesI thing -> do
|
||||
len <- eval CodebaseHashLength
|
||||
parseNames0 <- basicParseNames0
|
||||
parseNames0 <- Names3.suffixify0 <$> basicParseNames0
|
||||
let filtered = case thing of
|
||||
HQ.HashOnly shortHash ->
|
||||
Names.filterBySHs (Set.singleton shortHash) parseNames0
|
||||
@ -829,7 +828,7 @@ loop = do
|
||||
-- We might like to make sure that the user search terms get used as
|
||||
-- the names in the pretty-printer, but the current implementation
|
||||
-- doesn't.
|
||||
ppe <- prettyPrintEnv printNames
|
||||
ppe <- prettyPrintEnvDecl printNames
|
||||
let loc = case outputLoc of
|
||||
ConsoleLocation -> Nothing
|
||||
FileLocation path -> Just path
|
||||
@ -855,7 +854,7 @@ loop = do
|
||||
|
||||
FindShallowI pathArg -> do
|
||||
prettyPrintNames0 <- basicPrettyPrintNames0
|
||||
ppe <- prettyPrintEnv $ Names prettyPrintNames0 mempty
|
||||
ppe <- fmap PPE.suffixifiedPPE . prettyPrintEnvDecl $ Names prettyPrintNames0 mempty
|
||||
hashLen <- eval CodebaseHashLength
|
||||
let pathArgAbs = Path.toAbsolutePath currentPath' pathArg
|
||||
b0 <- Branch.head <$> getAt pathArgAbs
|
||||
@ -944,7 +943,7 @@ loop = do
|
||||
Right results -> do
|
||||
numberedArgs .= fmap searchResultToHQString results
|
||||
results' <- loadSearchResults results
|
||||
ppe <- prettyPrintEnv =<<
|
||||
ppe <- prettyPrintEnv . Names3.suffixify =<<
|
||||
makePrintNamesFromLabeled'
|
||||
(foldMap SR'.labeledDependencies results')
|
||||
respond $ ListOfDefinitions ppe isVerbose results'
|
||||
@ -1057,11 +1056,11 @@ loop = do
|
||||
stepAt ( Path.unabsolute currentPath'
|
||||
, doSlurpAdds (Slurp.adds sr) uf)
|
||||
eval . AddDefsToCodebase . filterBySlurpResult sr $ uf
|
||||
ppe <- prettyPrintEnv =<<
|
||||
ppe <- prettyPrintEnvDecl =<<
|
||||
makeShadowedPrintNamesFromLabeled
|
||||
(UF.termSignatureExternalLabeledDependencies uf)
|
||||
(UF.typecheckedToNames0 uf)
|
||||
respond $ SlurpOutput input ppe sr
|
||||
respond $ SlurpOutput input (PPE.suffixifiedPPE ppe) sr
|
||||
|
||||
UpdateI maybePatchPath hqs -> case uf of
|
||||
Nothing -> respond $ NoUnisonFile input
|
||||
@ -1161,7 +1160,7 @@ loop = do
|
||||
TodoI patchPath branchPath' -> do
|
||||
patch <- getPatchAt (fromMaybe defaultPatchPath patchPath)
|
||||
names <- makePrintNamesFromLabeled' $ Patch.labeledDependencies patch
|
||||
ppe <- prettyPrintEnv names
|
||||
ppe <- prettyPrintEnvDecl names
|
||||
branch <- getAt $ Path.toAbsolutePath currentPath' branchPath'
|
||||
let names0 = Branch.toNames0 (Branch.head branch)
|
||||
-- showTodoOutput only needs the local references
|
||||
@ -1278,7 +1277,7 @@ loop = do
|
||||
Left e -> eval . Notify $ e
|
||||
Right (repo, Nothing, remotePath) -> do
|
||||
-- push from srcb to repo's remotePath
|
||||
eval (LoadRemoteRootBranch repo) >>= \case
|
||||
eval (LoadRemoteRootBranch EmptyIfMissing repo) >>= \case
|
||||
Left e -> eval . Notify $ GitError input e
|
||||
Right remoteRoot -> do
|
||||
newRemoteRoot <- eval . Eval $
|
||||
@ -1360,14 +1359,15 @@ loop = do
|
||||
doDisplay :: Var v => OutputLocation -> Names -> Referent -> Action' m v ()
|
||||
doDisplay outputLoc names r = do
|
||||
let tm = Term.fromReferent External r
|
||||
ppe <- prettyPrintEnv names
|
||||
ppe <- prettyPrintEnvDecl names
|
||||
latestFile' <- use latestFile
|
||||
let
|
||||
loc = case outputLoc of
|
||||
ConsoleLocation -> Nothing
|
||||
FileLocation path -> Just path
|
||||
LatestFileLocation -> fmap fst latestFile' <|> Just "scratch.u"
|
||||
evalTerm r = fmap ErrorUtil.hush . eval $ Evaluate1 ppe (Term.ref External r)
|
||||
evalTerm r = fmap ErrorUtil.hush . eval $
|
||||
Evaluate1 (PPE.suffixifiedPPE ppe) (Term.ref External r)
|
||||
loadTerm (Reference.DerivedId r) = eval $ LoadTerm r
|
||||
loadTerm _ = pure Nothing
|
||||
loadDecl (Reference.DerivedId r) = eval $ LoadType r
|
||||
@ -1416,10 +1416,11 @@ getLinks input src mdTypeStr = do
|
||||
\r -> loadTypeOfTerm (Referent.Ref r)
|
||||
let deps = Set.map LD.termRef results <>
|
||||
Set.unions [ Set.map LD.typeRef . Type.dependencies $ t | Just t <- sigs ]
|
||||
ppe <- prettyPrintEnv =<< makePrintNamesFromLabeled' deps
|
||||
let sortedSigs = sortOn snd (toList results `zip` sigs)
|
||||
let out = [(PPE.termName ppe (Referent.Ref r), r, t) | (r, t) <- sortedSigs ]
|
||||
pure (Right (ppe, out))
|
||||
ppe <- prettyPrintEnvDecl =<< makePrintNamesFromLabeled' deps
|
||||
let ppeDecl = PPE.unsuffixifiedPPE ppe
|
||||
let sortedSigs = sortOn snd (toList results `zip` sigs)
|
||||
let out = [(PPE.termName ppeDecl (Referent.Ref r), r, t) | (r, t) <- sortedSigs ]
|
||||
pure (Right (PPE.suffixifiedPPE ppe, out))
|
||||
|
||||
resolveShortBranchHash ::
|
||||
Input -> ShortBranchHash -> Action' m v (Either (Output v) (Branch m))
|
||||
@ -1444,11 +1445,11 @@ propagatePatch inputDescription patch scopePath = do
|
||||
let names0 = Branch.toNames0 (Branch.head scope)
|
||||
-- this will be different AFTER the update succeeds
|
||||
names <- makePrintNamesFromLabeled' (Patch.labeledDependencies patch)
|
||||
ppe <- prettyPrintEnv names
|
||||
ppe <- prettyPrintEnvDecl names
|
||||
showTodoOutput ppe patch names0
|
||||
pure changed
|
||||
|
||||
showTodoOutput :: PPE.PrettyPrintEnv -> Patch -> Names0 -> Action' m v ()
|
||||
showTodoOutput :: PPE.PrettyPrintEnvDecl -> Patch -> Names0 -> Action' m v ()
|
||||
showTodoOutput ppe patch names0 = do
|
||||
todo <- checkTodo patch names0
|
||||
numberedArgs .=
|
||||
@ -1648,7 +1649,8 @@ searchBranchExact len names queries = let
|
||||
respond :: Output v -> Action m i v ()
|
||||
respond output = eval $ Notify output
|
||||
|
||||
-- merges the specified remote branch into the specified local absolute path
|
||||
-- Merges the specified remote branch into the specified local absolute path.
|
||||
-- Implementation detail of PullRemoteBranchI
|
||||
loadRemoteBranchAt
|
||||
:: Var v
|
||||
=> Monad m
|
||||
@ -1658,7 +1660,7 @@ loadRemoteBranchAt
|
||||
-> Path.Absolute
|
||||
-> Action' m v ()
|
||||
loadRemoteBranchAt input inputDescription (repo, sbh, remotePath) p = do
|
||||
b <- eval $ maybe (LoadRemoteRootBranch repo)
|
||||
b <- eval $ maybe (LoadRemoteRootBranch FailIfMissing repo)
|
||||
(LoadRemoteShortBranch repo) sbh
|
||||
case b of
|
||||
Left e -> eval . Notify $ GitError input e
|
||||
@ -2053,6 +2055,9 @@ lexedSource name src = do
|
||||
prettyPrintEnv :: Names -> Action' m v PPE.PrettyPrintEnv
|
||||
prettyPrintEnv ns = eval CodebaseHashLength <&> (`PPE.fromNames` ns)
|
||||
|
||||
prettyPrintEnvDecl :: Names -> Action' m v PPE.PrettyPrintEnvDecl
|
||||
prettyPrintEnvDecl ns = eval CodebaseHashLength <&> (`PPE.fromNamesDecl` ns)
|
||||
|
||||
parseSearchType :: (Monad m, Var v)
|
||||
=> Input -> String -> Action' m v (Either (Output v) (Type v Ann))
|
||||
parseSearchType input typ = fmap Type.removeAllEffectVars <$> parseType input typ
|
||||
@ -2061,7 +2066,10 @@ parseType :: (Monad m, Var v)
|
||||
=> Input -> String -> Action' m v (Either (Output v) (Type v Ann))
|
||||
parseType input src = do
|
||||
-- `show Input` is the name of the "file" being lexed
|
||||
(names, lexed) <- lexedSource (Text.pack $ show input) (Text.pack src)
|
||||
(names0, lexed) <- lexedSource (Text.pack $ show input) (Text.pack src)
|
||||
parseNames <- Names3.suffixify0 <$> basicParseNames0
|
||||
let names = Names3.push (Names3.currentNames names0)
|
||||
(Names3.Names parseNames (Names3.oldNames names0))
|
||||
e <- eval $ ParseType names lexed
|
||||
pure $ case e of
|
||||
Left err -> Left $ TypeParseError input src err
|
||||
|
@ -125,10 +125,10 @@ data Output v
|
||||
| DisplayRendered (Maybe FilePath) (P.Pretty P.ColorText)
|
||||
-- "display" definitions, possibly to a FilePath on disk (e.g. editing)
|
||||
| DisplayDefinitions (Maybe FilePath)
|
||||
PPE.PrettyPrintEnv
|
||||
PPE.PrettyPrintEnvDecl
|
||||
(Map Reference (DisplayThing (Decl v Ann)))
|
||||
(Map Reference (DisplayThing (Term v Ann)))
|
||||
| TodoOutput PPE.PrettyPrintEnv (TO.TodoOutput v Ann)
|
||||
| TodoOutput PPE.PrettyPrintEnvDecl (TO.TodoOutput v Ann)
|
||||
| TestIncrementalOutputStart PPE.PrettyPrintEnv (Int,Int) Reference (Term v Ann)
|
||||
| TestIncrementalOutputEnd PPE.PrettyPrintEnv (Int,Int) Reference (Term v Ann)
|
||||
| TestResults TestReportStats
|
||||
@ -147,7 +147,7 @@ data Output v
|
||||
| NoConfiguredGitUrl PushPull Path'
|
||||
| ConfiguredGitUrlParseError PushPull Path' Text String
|
||||
| ConfiguredGitUrlIncludesShortBranchHash PushPull RemoteRepo ShortBranchHash Path
|
||||
| DisplayLinks PPE.PrettyPrintEnv Metadata.Metadata
|
||||
| DisplayLinks PPE.PrettyPrintEnvDecl Metadata.Metadata
|
||||
(Map Reference (DisplayThing (Decl v Ann)))
|
||||
(Map Reference (DisplayThing (Term v Ann)))
|
||||
| LinkFailure Input
|
||||
|
@ -70,6 +70,7 @@ import Unison.Codebase.Causal ( Causal
|
||||
import qualified Unison.Codebase.Causal as Causal
|
||||
import Unison.Codebase.Branch ( Branch )
|
||||
import qualified Unison.Codebase.Branch as Branch
|
||||
import Unison.Codebase.BranchLoadMode ( BranchLoadMode(FailIfMissing, EmptyIfMissing) )
|
||||
import qualified Unison.Codebase.Reflog as Reflog
|
||||
import qualified Unison.Codebase.Serialization as S
|
||||
import qualified Unison.Codebase.Serialization.V1
|
||||
@ -274,16 +275,10 @@ touchReferentFile id fp = do
|
||||
|
||||
-- checks if `path` looks like a unison codebase
|
||||
minimalCodebaseStructure :: CodebasePath -> [FilePath]
|
||||
minimalCodebaseStructure root =
|
||||
[ termsDir root
|
||||
, typesDir root
|
||||
, branchesDir root
|
||||
, branchHeadDir root
|
||||
, editsDir root
|
||||
]
|
||||
minimalCodebaseStructure root = [ branchHeadDir root ]
|
||||
|
||||
-- checks if a minimal codebase structure exists at `path`
|
||||
exists :: CodebasePath -> IO Bool
|
||||
exists :: MonadIO m => CodebasePath -> m Bool
|
||||
exists root =
|
||||
and <$> traverse doesDirectoryExist (minimalCodebaseStructure root)
|
||||
|
||||
@ -292,14 +287,6 @@ initialize :: CodebasePath -> IO ()
|
||||
initialize path =
|
||||
traverse_ (createDirectoryIfMissing True) (minimalCodebaseStructure path)
|
||||
|
||||
-- When loading a nonexistent branch, what should happen?
|
||||
-- Could bomb (`FailIfMissing`) or return the empty branch (`EmptyIfMissing`).
|
||||
--
|
||||
-- `EmptyIfMissing` mode is used when attempting to load a user-specified
|
||||
-- branch. `FailIfMissing` is used when loading the root branch - if the root
|
||||
-- does not exist, that's a serious problem.
|
||||
data BranchLoadMode = FailIfMissing | EmptyIfMissing deriving Eq
|
||||
|
||||
branchFromFiles :: MonadIO m => BranchLoadMode -> FilePath -> Branch.Hash -> m (Branch m)
|
||||
branchFromFiles loadMode rootDir h@(RawHash h') = do
|
||||
fileExists <- doesFileExist (branchPath rootDir h')
|
||||
@ -324,20 +311,26 @@ branchFromFiles loadMode rootDir h@(RawHash h') = do
|
||||
Left err -> failWith $ InvalidEditsFile file err
|
||||
Right edits -> pure edits
|
||||
|
||||
getRootBranch :: MonadIO m => CodebasePath -> m (Branch m)
|
||||
getRootBranch root = do
|
||||
unlessM (doesDirectoryExist $ branchHeadDir root)
|
||||
(failWith . NoBranchHead $ branchHeadDir root)
|
||||
liftIO (listDirectory $ branchHeadDir root) >>= \case
|
||||
[] -> failWith . NoBranchHead $ branchHeadDir root
|
||||
[single] -> go single
|
||||
conflict -> traverse go conflict >>= \case
|
||||
x : xs -> foldM Branch.merge x xs
|
||||
[] -> failWith . NoBranchHead $ branchHeadDir root
|
||||
-- returns Nothing if `root` has no root branch (in `branchHeadDir root`)
|
||||
getRootBranch ::
|
||||
MonadIO m => BranchLoadMode -> CodebasePath -> m (Branch m)
|
||||
getRootBranch loadMode root = do
|
||||
ifM (exists root)
|
||||
(liftIO (listDirectory $ branchHeadDir root) >>= \case
|
||||
[] -> missing
|
||||
[single] -> go single
|
||||
conflict -> traverse go conflict >>= \case
|
||||
x : xs -> foldM Branch.merge x xs
|
||||
[] -> missing
|
||||
)
|
||||
missing
|
||||
where
|
||||
go single = case hashFromString single of
|
||||
Nothing -> failWith $ CantParseBranchHead single
|
||||
Just h -> branchFromFiles FailIfMissing root (RawHash h)
|
||||
missing = case loadMode of
|
||||
FailIfMissing -> failWith . NoBranchHead $ branchHeadDir root
|
||||
EmptyIfMissing -> pure $ Branch.empty
|
||||
|
||||
putRootBranch :: MonadIO m => CodebasePath -> Branch m -> m ()
|
||||
putRootBranch root b = do
|
||||
@ -409,6 +402,9 @@ referentToString = Text.unpack . Referent.toText
|
||||
copyDir :: (FilePath -> Bool) -> FilePath -> FilePath -> IO ()
|
||||
copyDir predicate from to = do
|
||||
createDirectoryIfMissing True to
|
||||
-- createDir doesn't create a new directory on disk,
|
||||
-- it creates a description of an existing directory,
|
||||
-- and it crashes if `from` doesn't exist.
|
||||
d <- createDir from
|
||||
when (predicate $ dirPath d) $ do
|
||||
forM_ (subDirs d)
|
||||
@ -418,10 +414,13 @@ copyDir predicate from to = do
|
||||
unless exists . copyFile path $ replaceRoot from to path
|
||||
|
||||
copyFromGit :: MonadIO m => FilePath -> FilePath -> m ()
|
||||
copyFromGit = (liftIO .) . flip
|
||||
(copyDir (\x -> not ((".git" `isSuffixOf` x) || ("_head" `isSuffixOf` x))))
|
||||
copyFromGit to from = liftIO . whenM (doesDirectoryExist from) $
|
||||
copyDir (\x -> not ((".git" `isSuffixOf` x) || ("_head" `isSuffixOf` x)))
|
||||
from to
|
||||
|
||||
writeAllTermsAndTypes
|
||||
-- Create a codebase structure at `localPath` if none exists, and
|
||||
-- copy (merge) all codebase elements from the current codebase into it.
|
||||
syncToDirectory
|
||||
:: forall m v a
|
||||
. (MonadUnliftIO m)
|
||||
=> Var v
|
||||
@ -432,8 +431,8 @@ writeAllTermsAndTypes
|
||||
-> FilePath
|
||||
-> Branch m
|
||||
-> m (Branch m)
|
||||
writeAllTermsAndTypes fmtV fmtA codebase localPath branch = do
|
||||
b <- doesDirectoryExist localPath
|
||||
syncToDirectory fmtV fmtA codebase localPath branch = do
|
||||
b <- (liftIO . exists) localPath
|
||||
if b then do
|
||||
let code = codebase1 fmtV fmtA localPath
|
||||
remoteRoot <- Codebase.getRootBranch code
|
||||
@ -584,7 +583,7 @@ codebase1 fmtV@(S.Format getV putV) fmtA@(S.Format getA putA) path =
|
||||
getDecl
|
||||
(putTerm putV putA path)
|
||||
(putDecl putV putA path)
|
||||
(getRootBranch path)
|
||||
(getRootBranch FailIfMissing path)
|
||||
(putRootBranch path)
|
||||
(branchHeadUpdates path)
|
||||
(branchFromFiles EmptyIfMissing path)
|
||||
@ -593,7 +592,7 @@ codebase1 fmtV@(S.Format getV putV) fmtA@(S.Format getA putA) path =
|
||||
(copyFromGit path)
|
||||
-- This is fine as long as watat doesn't call
|
||||
-- syncToDirectory c
|
||||
(writeAllTermsAndTypes fmtV fmtA c)
|
||||
(syncToDirectory fmtV fmtA c)
|
||||
watches
|
||||
getWatch
|
||||
(putWatch putV putA path)
|
||||
|
@ -24,49 +24,54 @@ import qualified Unison.Util.SyntaxText as S
|
||||
type Pretty = P.Pretty P.ColorText
|
||||
|
||||
displayTerm :: (Var v, Monad m)
|
||||
=> PPE.PrettyPrintEnv
|
||||
=> PPE.PrettyPrintEnvDecl
|
||||
-> (Reference -> m (Maybe (AnnotatedTerm v a)))
|
||||
-> (Referent -> m (Maybe (Type v a)))
|
||||
-> (Reference -> m (Maybe (AnnotatedTerm v a)))
|
||||
-> (Reference -> m (Maybe (DD.Decl v a)))
|
||||
-> AnnotatedTerm v a
|
||||
-> m Pretty
|
||||
displayTerm ppe terms typeOf eval types tm = case tm of
|
||||
displayTerm pped terms typeOf eval types tm = case tm of
|
||||
-- todo: can dispatch on other things with special rendering
|
||||
Term.Ref' r -> eval r >>= \case
|
||||
Nothing -> pure $ termName ppe (Referent.Ref r)
|
||||
Just tm -> displayDoc ppe terms typeOf eval types tm
|
||||
_ -> displayDoc ppe terms typeOf eval types tm
|
||||
Nothing -> pure $ termName (PPE.suffixifiedPPE pped) (Referent.Ref r)
|
||||
Just tm -> displayDoc pped terms typeOf eval types tm
|
||||
_ -> displayDoc pped terms typeOf eval types tm
|
||||
|
||||
displayDoc :: (Var v, Monad m)
|
||||
=> PPE.PrettyPrintEnv
|
||||
=> PPE.PrettyPrintEnvDecl
|
||||
-> (Reference -> m (Maybe (AnnotatedTerm v a)))
|
||||
-> (Referent -> m (Maybe (Type v a)))
|
||||
-> (Reference -> m (Maybe (AnnotatedTerm v a)))
|
||||
-> (Reference -> m (Maybe (DD.Decl v a)))
|
||||
-> AnnotatedTerm v a
|
||||
-> m Pretty
|
||||
displayDoc ppe terms typeOf evaluated types t = go t
|
||||
displayDoc pped terms typeOf evaluated types t = go t
|
||||
where
|
||||
go (DD.DocJoin docs) = foldMap id <$> traverse go docs
|
||||
go (DD.DocBlob txt) = pure $ P.paragraphyText txt
|
||||
go (DD.DocLink (DD.LinkTerm (Term.TermLink' r))) = pure $ P.underline (termName ppe r)
|
||||
go (DD.DocLink (DD.LinkType (Term.TypeLink' r))) = pure $ P.underline (typeName ppe r)
|
||||
go (DD.DocLink (DD.LinkTerm (Term.TermLink' r))) =
|
||||
pure $ P.underline (termName (PPE.suffixifiedPPE pped) r)
|
||||
go (DD.DocLink (DD.LinkType (Term.TypeLink' r))) =
|
||||
pure $ P.underline (typeName (PPE.suffixifiedPPE pped) r)
|
||||
go (DD.DocSource (DD.LinkTerm (Term.TermLink' r))) = prettyTerm terms r
|
||||
go (DD.DocSource (DD.LinkType (Term.TypeLink' r))) = prettyType r
|
||||
go (DD.DocSignature (Term.TermLink' r)) = prettySignature r
|
||||
go (DD.DocEvaluate (Term.TermLink' r)) = prettyTerm evaluated r
|
||||
go tm = pure $ TP.pretty ppe tm
|
||||
go tm = pure $ TP.pretty (PPE.suffixifiedPPE pped) tm
|
||||
prettySignature r = typeOf r >>= \case
|
||||
Nothing -> pure $ termName ppe r
|
||||
Just typ -> pure $ P.group $ TypePrinter.prettySignatures ppe [(PPE.termName ppe r, typ)]
|
||||
Nothing -> pure $ termName (PPE.unsuffixifiedPPE pped) r
|
||||
Just typ -> pure . P.group $
|
||||
TypePrinter.prettySignatures
|
||||
(PPE.suffixifiedPPE pped)
|
||||
[(PPE.termName (PPE.unsuffixifiedPPE pped) r, typ)]
|
||||
prettyTerm terms r = case r of
|
||||
Referent.Ref (Reference.Builtin _) -> prettySignature r
|
||||
Referent.Ref ref -> terms ref >>= \case
|
||||
Referent.Ref ref -> let ppe = PPE.declarationPPE pped ref in terms ref >>= \case
|
||||
Nothing -> pure $ "😶 Missing term source for: " <> termName ppe r
|
||||
Just tm -> pure . P.syntaxToColor $ P.group $ TP.prettyBinding ppe (PPE.termName ppe r) tm
|
||||
Referent.Con r _ _ -> prettyType r
|
||||
prettyType r = types r >>= \case
|
||||
prettyType r = let ppe = PPE.declarationPPE pped r in types r >>= \case
|
||||
Nothing -> pure $ "😶 Missing type source for: " <> typeName ppe r
|
||||
Just ty -> pure . P.syntaxToColor $ P.group $ DP.prettyDecl ppe r (PPE.typeName ppe r) ty
|
||||
|
||||
|
@ -832,29 +832,31 @@ formatMissingStuff terms types =
|
||||
<> P.column2 [ (P.syntaxToColor $ prettyHashQualified name, fromString (show ref)) | (name, ref) <- types ])
|
||||
|
||||
displayDefinitions' :: Var v => Ord a1
|
||||
=> PPE.PrettyPrintEnv
|
||||
=> PPE.PrettyPrintEnvDecl
|
||||
-> Map Reference.Reference (DisplayThing (DD.Decl v a1))
|
||||
-> Map Reference.Reference (DisplayThing (Unison.Term.AnnotatedTerm v a1))
|
||||
-> Pretty
|
||||
displayDefinitions' ppe types terms = P.syntaxToColor $ P.sep "\n\n" (prettyTypes <> prettyTerms)
|
||||
displayDefinitions' ppe0 types terms = P.syntaxToColor $ P.sep "\n\n" (prettyTypes <> prettyTerms)
|
||||
where
|
||||
ppeBody r = PPE.declarationPPE ppe0 r
|
||||
ppeDecl = PPE.unsuffixifiedPPE ppe0
|
||||
prettyTerms = map go . Map.toList
|
||||
-- sort by name
|
||||
$ Map.mapKeys (first (PPE.termName ppe . Referent.Ref) . dupe) terms
|
||||
$ Map.mapKeys (first (PPE.termName ppeDecl . Referent.Ref) . dupe) terms
|
||||
prettyTypes = map go2 . Map.toList
|
||||
$ Map.mapKeys (first (PPE.typeName ppe) . dupe) types
|
||||
$ Map.mapKeys (first (PPE.typeName ppeDecl) . dupe) types
|
||||
go ((n, r), dt) =
|
||||
case dt of
|
||||
MissingThing r -> missing n r
|
||||
BuiltinThing -> builtin n
|
||||
RegularThing tm -> TermPrinter.prettyBinding ppe n tm
|
||||
RegularThing tm -> TermPrinter.prettyBinding (ppeBody r) n tm
|
||||
go2 ((n, r), dt) =
|
||||
case dt of
|
||||
MissingThing r -> missing n r
|
||||
BuiltinThing -> builtin n
|
||||
RegularThing decl -> case decl of
|
||||
Left d -> DeclPrinter.prettyEffectDecl ppe r n d
|
||||
Right d -> DeclPrinter.prettyDataDecl ppe r n d
|
||||
Left d -> DeclPrinter.prettyEffectDecl (ppeBody r) r n d
|
||||
Right d -> DeclPrinter.prettyDataDecl (ppeBody r) r n d
|
||||
builtin n = P.wrap $ "--" <> prettyHashQualified n <> " is built-in."
|
||||
missing n r = P.wrap (
|
||||
"-- The name " <> prettyHashQualified n <> " is assigned to the "
|
||||
@ -888,7 +890,7 @@ displayRendered outputLoc pp =
|
||||
|
||||
displayDefinitions :: Var v => Ord a1 =>
|
||||
Maybe FilePath
|
||||
-> PPE.PrettyPrintEnv
|
||||
-> PPE.PrettyPrintEnvDecl
|
||||
-> Map Reference.Reference (DisplayThing (DD.Decl v a1))
|
||||
-> Map Reference.Reference (DisplayThing (Unison.Term.AnnotatedTerm v a1))
|
||||
-> IO Pretty
|
||||
@ -1067,7 +1069,7 @@ renderEditConflicts ppe Patch{..} =
|
||||
P.oxfordCommas [ termName r | TermEdit.Replace r _ <- es ]
|
||||
formatConflict = either formatTypeEdits formatTermEdits
|
||||
|
||||
todoOutput :: Var v => PPE.PrettyPrintEnv -> TO.TodoOutput v a -> IO Pretty
|
||||
todoOutput :: Var v => PPE.PrettyPrintEnvDecl -> TO.TodoOutput v a -> IO Pretty
|
||||
todoOutput ppe todo =
|
||||
if noConflicts && noEdits
|
||||
then pure $ P.okCallout "No conflicts or edits in progress."
|
||||
@ -1076,16 +1078,18 @@ todoOutput ppe todo =
|
||||
noConflicts = TO.nameConflicts todo == mempty
|
||||
&& TO.editConflicts todo == Patch.empty
|
||||
noEdits = TO.todoScore todo == 0
|
||||
ppeu = PPE.unsuffixifiedPPE ppe
|
||||
ppes = PPE.suffixifiedPPE ppe
|
||||
(frontierTerms, frontierTypes) = TO.todoFrontier todo
|
||||
(dirtyTerms, dirtyTypes) = TO.todoFrontierDependents todo
|
||||
corruptTerms =
|
||||
[ (PPE.termName ppe (Referent.Ref r), r) | (r, Nothing) <- frontierTerms ]
|
||||
[ (PPE.termName ppeu (Referent.Ref r), r) | (r, Nothing) <- frontierTerms ]
|
||||
corruptTypes =
|
||||
[ (PPE.typeName ppe r, r) | (r, MissingThing _) <- frontierTypes ]
|
||||
[ (PPE.typeName ppeu r, r) | (r, MissingThing _) <- frontierTypes ]
|
||||
goodTerms ts =
|
||||
[ (PPE.termName ppe (Referent.Ref r), typ) | (r, Just typ) <- ts ]
|
||||
[ (PPE.termName ppeu (Referent.Ref r), typ) | (r, Just typ) <- ts ]
|
||||
todoConflicts = if noConflicts then mempty else P.lines . P.nonEmpty $
|
||||
[ renderEditConflicts ppe (TO.editConflicts todo)
|
||||
[ renderEditConflicts ppeu (TO.editConflicts todo)
|
||||
, renderNameConflicts conflictedTypeNames conflictedTermNames ]
|
||||
where
|
||||
-- If a conflict is both an edit and a name conflict, we show it in the edit
|
||||
@ -1125,15 +1129,15 @@ todoOutput ppe todo =
|
||||
<> "transitive dependent(s) left to upgrade."
|
||||
<> "Your edit frontier is the dependents of these definitions:")
|
||||
, P.indentN 2 . P.lines $ (
|
||||
(prettyDeclPair ppe <$> toList frontierTypes) ++
|
||||
TypePrinter.prettySignatures' ppe (goodTerms frontierTerms)
|
||||
(prettyDeclPair ppeu <$> toList frontierTypes) ++
|
||||
TypePrinter.prettySignatures' ppes (goodTerms frontierTerms)
|
||||
)
|
||||
, P.wrap "I recommend working on them in the following order:"
|
||||
, P.numberedList $
|
||||
let unscore (_score,a,b) = (a,b)
|
||||
in (prettyDeclPair ppe . unscore <$> toList dirtyTypes) ++
|
||||
in (prettyDeclPair ppeu . unscore <$> toList dirtyTypes) ++
|
||||
TypePrinter.prettySignatures'
|
||||
ppe
|
||||
ppes
|
||||
(goodTerms $ unscore <$> dirtyTerms)
|
||||
, formatMissingStuff corruptTerms corruptTypes
|
||||
]
|
||||
|
@ -4,6 +4,7 @@ module Unison.HashQualified where
|
||||
|
||||
import Unison.Prelude hiding (fromString)
|
||||
|
||||
import Data.List ( sortOn )
|
||||
import Data.Maybe ( fromJust
|
||||
)
|
||||
import qualified Data.Text as Text
|
||||
@ -40,6 +41,21 @@ toName = \case
|
||||
HashQualified name _ -> Just name
|
||||
HashOnly _ -> Nothing
|
||||
|
||||
-- Sort the list of names by length of segments: smaller number of
|
||||
-- segments is listed first. NameOnly < Hash qualified < Hash only
|
||||
--
|
||||
-- Examples:
|
||||
-- [foo.bar.baz, bar.baz] -> [bar.baz, foo.bar.baz]
|
||||
-- [#a29dj2k91, foo.bar.baz] -> [foo.bar.baz, #a29dj2k91]
|
||||
-- [foo.bar#abc, foo.bar] -> [foo.bar, foo.bar#abc]
|
||||
-- [.foo.bar, foo.bar] -> [foo.bar, .foo.bar]
|
||||
sortByLength :: [HashQualified' Name] -> [HashQualified' Name]
|
||||
sortByLength hs = sortOn f hs where
|
||||
f (NameOnly n) = (countDots n, 0, Left n)
|
||||
f (HashQualified n _h) = (countDots n, 1, Left n)
|
||||
f (HashOnly h) = (maxBound, 0, Right h)
|
||||
countDots n = Text.count "." (Text.dropEnd 1 (Name.toText n))
|
||||
|
||||
hasName, hasHash :: HashQualified -> Bool
|
||||
hasName = isJust . toName
|
||||
hasHash = isJust . toHash
|
||||
|
@ -11,6 +11,7 @@ module Unison.Name
|
||||
, sortNamed
|
||||
, stripNamePrefix
|
||||
, stripPrefixes
|
||||
, suffixes
|
||||
, toString
|
||||
, toVar
|
||||
, unqualified
|
||||
@ -29,7 +30,7 @@ import qualified Unison.Hashable as H
|
||||
import Unison.Var ( Var )
|
||||
import qualified Unison.Var as Var
|
||||
import qualified Data.RFC5051 as RFC5051
|
||||
import Data.List ( sortBy )
|
||||
import Data.List ( sortBy, tails )
|
||||
|
||||
newtype Name = Name { toText :: Text } deriving (Eq, Ord)
|
||||
|
||||
@ -103,6 +104,12 @@ parent (Name txt) = case unsnoc (Text.splitOn "." txt) of
|
||||
Just ([],_) -> Nothing
|
||||
Just (init,_) -> Just $ Name (Text.intercalate "." init)
|
||||
|
||||
suffixes :: Name -> [Name]
|
||||
suffixes (Name n) =
|
||||
fmap up . tails . dropWhile (== "") $ Text.splitOn "." n
|
||||
where
|
||||
up ns = Name (Text.intercalate "." ns)
|
||||
|
||||
unqualified' :: Text -> Text
|
||||
unqualified' = last . Text.splitOn "."
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE PatternSynonyms #-}
|
||||
{-# LANGUAGE ViewPatterns #-}
|
||||
|
||||
module Unison.Names3 where
|
||||
|
||||
import Unison.Prelude
|
||||
|
||||
import Data.List.Extra (nubOrd)
|
||||
import Unison.HashQualified (HashQualified)
|
||||
import qualified Unison.HashQualified as HQ
|
||||
import qualified Unison.HashQualified' as HQ'
|
||||
@ -15,9 +17,11 @@ import Unison.Referent (Referent)
|
||||
import Unison.Referent as Referent
|
||||
import Unison.Util.Relation (Relation)
|
||||
import qualified Data.Set as Set
|
||||
import qualified Data.Map as Map
|
||||
import qualified Unison.Name as Name
|
||||
import qualified Unison.Names2
|
||||
import qualified Unison.Names2 as Names
|
||||
import qualified Unison.Util.List as List
|
||||
import qualified Unison.Util.Relation as R
|
||||
import qualified Unison.ConstructorType as CT
|
||||
|
||||
@ -33,6 +37,22 @@ data ResolutionFailure v a
|
||||
|
||||
type ResolutionResult v a r = Either (Seq (ResolutionFailure v a)) r
|
||||
|
||||
-- For all names in `ns`, (ex: foo.bar.baz), generate the list of suffixes
|
||||
-- of that name [[foo.bar.baz], [bar.baz], [baz]]. Insert these suffixes
|
||||
-- into a multimap map along with their corresponding refs. Any suffix
|
||||
-- which is unique is added as an entry to `ns`.
|
||||
suffixify0 :: Names0 -> Names0
|
||||
suffixify0 ns = ns <> suffixNs
|
||||
where
|
||||
suffixNs = names0 (R.fromList uniqueTerms) (R.fromList uniqueTypes)
|
||||
terms = List.multimap [ (n,ref) | (n0,ref) <- R.toList (terms0 ns), n <- Name.suffixes n0 ]
|
||||
types = List.multimap [ (n,ref) | (n0,ref) <- R.toList (types0 ns), n <- Name.suffixes n0 ]
|
||||
uniqueTerms = [ (n,ref) | (n, nubOrd -> [ref]) <- Map.toList terms ]
|
||||
uniqueTypes = [ (n,ref) | (n, nubOrd -> [ref]) <- Map.toList types ]
|
||||
|
||||
suffixify :: Names -> Names
|
||||
suffixify ns = Names (suffixify0 (currentNames ns)) (oldNames ns)
|
||||
|
||||
filterTypes :: (Name -> Bool) -> Names0 -> Names0
|
||||
filterTypes = Unison.Names2.filterTypes
|
||||
|
||||
|
@ -240,12 +240,13 @@ rootFile :: Ord v => P v a -> P v a
|
||||
rootFile p = p <* P.eof
|
||||
|
||||
run' :: Ord v => P v a -> String -> String -> ParsingEnv -> Either (Err v) a
|
||||
run' p s name =
|
||||
run' p s name env =
|
||||
let lex = if debug
|
||||
then L.lexer name (trace (L.debugLex''' "lexer receives" s) s)
|
||||
else L.lexer name s
|
||||
pTraced = traceRemainingTokens "parser receives" *> p
|
||||
in runParserT pTraced name (Input lex)
|
||||
env' = env { names = Names.suffixify (names env) }
|
||||
in runParserT pTraced name (Input lex) env'
|
||||
|
||||
run :: Ord v => P v a -> String -> ParsingEnv -> Either (Err v) a
|
||||
run p s = run' p s ""
|
||||
|
@ -15,6 +15,7 @@ import qualified Data.Map as Map
|
||||
import qualified Unison.HashQualified as HQ
|
||||
import qualified Unison.Name as Name
|
||||
import qualified Unison.Names3 as Names
|
||||
import qualified Unison.Reference as Reference
|
||||
import qualified Unison.Referent as Referent
|
||||
import qualified Unison.ConstructorType as CT
|
||||
import qualified Unison.HashQualified' as HQ'
|
||||
@ -34,10 +35,48 @@ instance Show PrettyPrintEnv where
|
||||
show _ = "PrettyPrintEnv"
|
||||
|
||||
fromNames :: Int -> Names -> PrettyPrintEnv
|
||||
fromNames length names = PrettyPrintEnv terms' types' where
|
||||
terms' r = safeHead . Set.map HQ'.toHQ $ (Names.termName length r names)
|
||||
types' r = safeHead . Set.map HQ'.toHQ $ (Names.typeName length r names)
|
||||
fromNames len names = PrettyPrintEnv terms' types' where
|
||||
terms' r = shortestName . Set.map HQ'.toHQ $ (Names.termName len r names)
|
||||
types' r = shortestName . Set.map HQ'.toHQ $ (Names.typeName len r names)
|
||||
shortestName ns = safeHead $ HQ.sortByLength (toList ns)
|
||||
|
||||
fromSuffixNames :: Int -> Names -> PrettyPrintEnv
|
||||
fromSuffixNames len names = fromNames len (Names.suffixify names)
|
||||
|
||||
fromNamesDecl :: Int -> Names -> PrettyPrintEnvDecl
|
||||
fromNamesDecl len names =
|
||||
PrettyPrintEnvDecl (fromNames len names) (fromSuffixNames len names)
|
||||
|
||||
-- A pair of PrettyPrintEnvs:
|
||||
-- - suffixifiedPPE uses the shortest unique suffix
|
||||
-- - unsuffixifiedPPE uses the shortest full name
|
||||
--
|
||||
-- Generally, we want declarations LHS (the `x` in `x = 23`) to use the
|
||||
-- unsuffixified names, so the LHS is an accurate description of where in the
|
||||
-- namespace the definition lives. For everywhere else, we can use the
|
||||
-- suffixified version.
|
||||
data PrettyPrintEnvDecl = PrettyPrintEnvDecl {
|
||||
unsuffixifiedPPE :: PrettyPrintEnv,
|
||||
suffixifiedPPE :: PrettyPrintEnv
|
||||
} deriving Show
|
||||
|
||||
-- declarationPPE uses the full name for references that are
|
||||
-- part the same cycle as the input reference, used to ensures
|
||||
-- recursive definitions are printed properly, for instance:
|
||||
--
|
||||
-- foo.bar x = foo.bar x
|
||||
-- and not
|
||||
-- foo.bar x = bar x
|
||||
declarationPPE :: PrettyPrintEnvDecl -> Reference -> PrettyPrintEnv
|
||||
declarationPPE ppe rd = PrettyPrintEnv tm ty where
|
||||
comp = Reference.members (Reference.componentFor rd)
|
||||
tm r0@(Referent.Ref r) = if Set.member r comp
|
||||
then terms (unsuffixifiedPPE ppe) r0
|
||||
else terms (suffixifiedPPE ppe) r0
|
||||
tm r = terms (suffixifiedPPE ppe) r
|
||||
ty r = if Set.member r comp then types (unsuffixifiedPPE ppe) r
|
||||
else types (suffixifiedPPE ppe) r
|
||||
|
||||
-- Left-biased union of environments
|
||||
unionLeft :: PrettyPrintEnv -> PrettyPrintEnv -> PrettyPrintEnv
|
||||
unionLeft e1 e2 = PrettyPrintEnv
|
||||
|
@ -28,6 +28,7 @@ import qualified Unison.Test.Var as Var
|
||||
import qualified Unison.Test.Codebase as Codebase
|
||||
import qualified Unison.Test.Codebase.FileCodebase as FileCodebase
|
||||
import qualified Unison.Test.UriParser as UriParser
|
||||
import qualified Unison.Test.Git as Git
|
||||
|
||||
test :: Test ()
|
||||
test = tests
|
||||
@ -54,6 +55,7 @@ test = tests
|
||||
, Typechecker.test
|
||||
, UriParser.test
|
||||
, Context.test
|
||||
, Git.test
|
||||
]
|
||||
|
||||
main :: IO ()
|
||||
|
56
parser-typechecker/tests/Unison/Test/Git.hs
Normal file
56
parser-typechecker/tests/Unison/Test/Git.hs
Normal file
@ -0,0 +1,56 @@
|
||||
{-# Language OverloadedStrings #-}
|
||||
{-# Language QuasiQuotes #-}
|
||||
|
||||
module Unison.Test.Git where
|
||||
|
||||
import EasyTest
|
||||
import Data.String.Here (iTrim)
|
||||
import Unison.Prelude
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as Text
|
||||
import qualified System.IO.Temp as Temp
|
||||
import Shellmet ()
|
||||
import System.FilePath ((</>))
|
||||
import System.Directory (getCurrentDirectory)
|
||||
|
||||
import Unison.Codebase.FileCodebase as FC
|
||||
import qualified Unison.Codebase.TranscriptParser as TR
|
||||
|
||||
test :: Test ()
|
||||
test = scope "git" . tests $ [testBareRepo]
|
||||
|
||||
testBareRepo :: Test ()
|
||||
testBareRepo = scope "testBareRepo" $ do
|
||||
io . Temp.withSystemTempDirectory "testBareRepo" $ \tmp -> do
|
||||
-- create a git repo and a transcript that references it
|
||||
let repo = tmp </> "repo.git"
|
||||
"git" ["init", "--bare", Text.pack repo]
|
||||
let transcript = makeTranscript repo
|
||||
|
||||
-- initialize an fresh codebase
|
||||
let codebase = tmp </> "codebase"
|
||||
FC.initCodebase codebase
|
||||
|
||||
case TR.parse "transcript" transcript of
|
||||
Left err -> error $ "Parse error: \n" <> show err
|
||||
Right stanzas -> void $ do
|
||||
currentDir <- getCurrentDirectory
|
||||
theCodebase <- FC.getCodebaseOrExit $ Just codebase
|
||||
TR.run currentDir stanzas theCodebase
|
||||
ok
|
||||
|
||||
makeTranscript :: FilePath -> Text
|
||||
makeTranscript repoPath = Text.pack $ [iTrim|
|
||||
```unison
|
||||
x = 3
|
||||
```
|
||||
```ucm
|
||||
.foo> add
|
||||
.foo> push ${repoPath}
|
||||
```
|
||||
Now we pull what we pushed
|
||||
```ucm
|
||||
.foo2> pull ${repoPath}
|
||||
.foo2> ls
|
||||
```
|
||||
|]
|
@ -40,6 +40,7 @@ library
|
||||
Unison.Codecs
|
||||
Unison.Codebase
|
||||
Unison.Codebase.Branch
|
||||
Unison.Codebase.BranchLoadMode
|
||||
Unison.Codebase.BranchUtil
|
||||
Unison.Codebase.Causal
|
||||
Unison.Codebase.Classes
|
||||
@ -290,6 +291,7 @@ executable tests
|
||||
Unison.Test.Common
|
||||
Unison.Test.DataDeclaration
|
||||
Unison.Test.FileParser
|
||||
Unison.Test.Git
|
||||
Unison.Test.Lexer
|
||||
Unison.Test.Range
|
||||
Unison.Test.Referent
|
||||
@ -317,10 +319,13 @@ executable tests
|
||||
extra,
|
||||
filepath,
|
||||
filemanip,
|
||||
here,
|
||||
lens,
|
||||
megaparsec,
|
||||
mtl,
|
||||
raw-strings-qq,
|
||||
shellmet,
|
||||
temporary,
|
||||
text,
|
||||
transformers,
|
||||
unison-parser-typechecker
|
||||
|
23
unison-src/tests/suffix-resolve.u
Normal file
23
unison-src/tests/suffix-resolve.u
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
-- This file shows that any unique suffix can be used to refer
|
||||
-- to a definition.
|
||||
|
||||
-- no imports needed here, even though FQN is builtin.Int
|
||||
foo : Int
|
||||
foo = +1
|
||||
|
||||
-- no imports needed here, even though FQNs are builtin.Optional.{None,Some}
|
||||
ex1 o = case o of
|
||||
None -> 0
|
||||
Some a -> a + 1
|
||||
|
||||
-- you can still use the
|
||||
ex2 o = case o of
|
||||
Optional.None -> 99
|
||||
Optional.Some _ -> 0
|
||||
|
||||
ex3 = builtin.Optional.None
|
||||
|
||||
-- TDNR would have handled this one before, but TDNR can't do
|
||||
-- type resolution or pattern resolution
|
||||
zoink = Some 42
|
@ -12,7 +12,7 @@ See [this ticket](https://github.com/unisonweb/unison/issues/873); the point bei
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
- : builtin.Nat -> builtin.Nat -> builtin.Int
|
||||
- : Nat -> Nat -> Int
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -23,7 +23,7 @@ See [this ticket](https://github.com/unisonweb/unison/issues/873); the point bei
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
- : builtin.Nat -> builtin.Nat -> builtin.Int
|
||||
- : Nat -> Nat -> Int
|
||||
|
||||
```
|
||||
```unison
|
||||
@ -38,7 +38,7 @@ baz x = x - 1
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
baz : builtin.Nat -> builtin.Int
|
||||
baz : Nat -> Int
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
|
@ -6,12 +6,12 @@ Unison documentation is written in Unison. Documentation is a value of the follo
|
||||
.> view builtin.Doc
|
||||
|
||||
unique type builtin.Doc
|
||||
= Link builtin.Link
|
||||
| Source builtin.Link
|
||||
| Blob builtin.Text
|
||||
= Link Link
|
||||
| Source Link
|
||||
| Blob Text
|
||||
| Join [builtin.Doc]
|
||||
| Signature builtin.Link.Term
|
||||
| Evaluate builtin.Link.Term
|
||||
| Signature Term
|
||||
| Evaluate Term
|
||||
|
||||
```
|
||||
You can create these `Doc` values with ordinary code, or you can use the special syntax. A value of type `Doc` can be created via syntax like:
|
||||
@ -36,7 +36,7 @@ Can link to definitions like @List.drop or @List
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
doc1 : builtin.Doc
|
||||
doc1 : Doc
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -69,8 +69,8 @@ List.take.ex2 = take 2 [1,2,3,4,5]
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
List.take.ex1 : [builtin.Nat]
|
||||
List.take.ex2 : [builtin.Nat]
|
||||
List.take.ex1 : [Nat]
|
||||
List.take.ex2 : [Nat]
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -81,8 +81,8 @@ List.take.ex2 = take 2 [1,2,3,4,5]
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
List.take.ex1 : [builtin.Nat]
|
||||
List.take.ex2 : [builtin.Nat]
|
||||
List.take.ex1 : [Nat]
|
||||
List.take.ex2 : [Nat]
|
||||
|
||||
```
|
||||
And now let's write our docs and reference these examples:
|
||||
@ -115,7 +115,7 @@ docs.List.take = [:
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
docs.List.take : builtin.Doc
|
||||
docs.List.take : Doc
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -128,7 +128,7 @@ Let's add it to the codebase, and link it to the definition:
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
docs.List.take : builtin.Doc
|
||||
docs.List.take : Doc
|
||||
|
||||
.> link builtin.List.take docs.List.take
|
||||
|
||||
@ -140,7 +140,7 @@ Now that documentation is linked to the definition. We can view it if we like:
|
||||
```ucm
|
||||
.> links builtin.List.take builtin.Doc
|
||||
|
||||
1. docs.List.take : builtin.Doc
|
||||
1. docs.List.take : Doc
|
||||
|
||||
Tip: Try using `display 1` to display the first result or
|
||||
`view 1` to view its source.
|
||||
|
@ -16,7 +16,7 @@ hey = "yello"
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
hey : builtin.Text
|
||||
hey : Text
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -27,7 +27,7 @@ hey = "yello"
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
hey : builtin.Text
|
||||
hey : Text
|
||||
|
||||
```
|
||||
Update
|
||||
@ -49,7 +49,7 @@ hey = "hello"
|
||||
⍟ These new definitions will replace existing ones of the
|
||||
same name and are ok to `update`:
|
||||
|
||||
hey : builtin.Text
|
||||
hey : Text
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
|
@ -15,7 +15,7 @@ x = 42
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
x : builtin.Nat
|
||||
x : Nat
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
|
@ -14,9 +14,9 @@ z = y + 2
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
x : builtin.Nat
|
||||
y : builtin.Nat
|
||||
z : builtin.Nat
|
||||
x : Nat
|
||||
y : Nat
|
||||
z : Nat
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -27,9 +27,9 @@ z = y + 2
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
x : builtin.Nat
|
||||
y : builtin.Nat
|
||||
z : builtin.Nat
|
||||
x : Nat
|
||||
y : Nat
|
||||
z : Nat
|
||||
|
||||
```
|
||||
Now we edit `x` to be `7`, which should make `z` equal `10`:
|
||||
@ -47,7 +47,7 @@ x = 7
|
||||
⍟ These new definitions will replace existing ones of the
|
||||
same name and are ok to `update`:
|
||||
|
||||
x : builtin.Nat
|
||||
x : Nat
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -66,17 +66,17 @@ x = 7
|
||||
|
||||
.> view x y z
|
||||
|
||||
x : builtin.Nat
|
||||
x : Nat
|
||||
x = 7
|
||||
|
||||
y : builtin.Nat
|
||||
y : Nat
|
||||
y =
|
||||
use builtin.Nat +
|
||||
use Nat +
|
||||
x + 1
|
||||
|
||||
z : builtin.Nat
|
||||
z : Nat
|
||||
z =
|
||||
use builtin.Nat +
|
||||
use Nat +
|
||||
y + 2
|
||||
|
||||
```
|
||||
@ -94,7 +94,7 @@ test> t1 = if z == 3 then [Fail "nooo!!!"] else [Ok "great"]
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
t1 : [builtin.Test.Result]
|
||||
t1 : [Result]
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -109,7 +109,7 @@ test> t1 = if z == 3 then [Fail "nooo!!!"] else [Ok "great"]
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
t1 : [builtin.Test.Result]
|
||||
t1 : [Result]
|
||||
|
||||
.> test
|
||||
|
||||
|
@ -38,7 +38,7 @@ x = 42
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
x : builtin.Nat
|
||||
x : Nat
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -51,11 +51,11 @@ Let's go ahead and add that to the codebase, then make sure it's there:
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
x : builtin.Nat
|
||||
x : Nat
|
||||
|
||||
.> view x
|
||||
|
||||
x : builtin.Nat
|
||||
x : Nat
|
||||
x = 42
|
||||
|
||||
```
|
||||
|
@ -14,7 +14,7 @@ x = 42
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
x : builtin.Nat
|
||||
x : Nat
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -25,7 +25,7 @@ x = 42
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
x : builtin.Nat
|
||||
x : Nat
|
||||
|
||||
```
|
||||
Let's move `x` into a new namespace, `master`:
|
||||
@ -63,7 +63,7 @@ y = "hello"
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
y : builtin.Text
|
||||
y : Text
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -76,7 +76,7 @@ y = "hello"
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
y : .builtin.Text
|
||||
y : Text
|
||||
|
||||
.master> merge .feature1
|
||||
|
||||
@ -92,7 +92,7 @@ y = "hello"
|
||||
|
||||
.master> view y
|
||||
|
||||
y : .builtin.Text
|
||||
y : Text
|
||||
y = "hello"
|
||||
|
||||
```
|
||||
@ -189,7 +189,7 @@ z = 99
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
z : builtin.Nat
|
||||
z : Nat
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -200,7 +200,7 @@ z = 99
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
z : .builtin.Nat
|
||||
z : Nat
|
||||
|
||||
.feature2> delete.term x
|
||||
|
||||
@ -220,8 +220,8 @@ master.frobnicate n = n + 1
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
master.frobnicate : .builtin.Nat -> .builtin.Nat
|
||||
master.y : .builtin.Text
|
||||
master.frobnicate : Nat -> Nat
|
||||
master.y : Text
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -244,14 +244,14 @@ master.frobnicate n = n + 1
|
||||
|
||||
.> view master.y
|
||||
|
||||
feature2.y : builtin.Text
|
||||
feature2.y : Text
|
||||
feature2.y = "updated y"
|
||||
|
||||
.> view master.frobnicate
|
||||
|
||||
master.frobnicate : builtin.Nat -> builtin.Nat
|
||||
master.frobnicate : Nat -> Nat
|
||||
master.frobnicate n =
|
||||
use builtin.Nat +
|
||||
use Nat +
|
||||
n + 1
|
||||
|
||||
```
|
||||
@ -291,19 +291,19 @@ And notice that `y` has the most recent value, and that `z` and `frobnicate` bot
|
||||
```ucm
|
||||
.> view master.y
|
||||
|
||||
feature2.y : builtin.Text
|
||||
feature2.y : Text
|
||||
feature2.y = "updated y"
|
||||
|
||||
.> view master.z
|
||||
|
||||
feature2.z : builtin.Nat
|
||||
feature2.z : Nat
|
||||
feature2.z = 99
|
||||
|
||||
.> view master.frobnicate
|
||||
|
||||
master.frobnicate : builtin.Nat -> builtin.Nat
|
||||
master.frobnicate : Nat -> Nat
|
||||
master.frobnicate n =
|
||||
use builtin.Nat +
|
||||
use Nat +
|
||||
n + 1
|
||||
|
||||
```
|
||||
|
@ -19,12 +19,12 @@ corge = "corge"
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
bar : builtin.Text
|
||||
baz : builtin.Text
|
||||
corge : builtin.Text
|
||||
foo : builtin.Text
|
||||
quux : builtin.Text
|
||||
qux : builtin.Text
|
||||
bar : Text
|
||||
baz : Text
|
||||
corge : Text
|
||||
foo : Text
|
||||
quux : Text
|
||||
qux : Text
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -37,12 +37,12 @@ corge = "corge"
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
bar : .builtin.Text
|
||||
baz : .builtin.Text
|
||||
corge : .builtin.Text
|
||||
foo : .builtin.Text
|
||||
quux : .builtin.Text
|
||||
qux : .builtin.Text
|
||||
bar : Text
|
||||
baz : Text
|
||||
corge : Text
|
||||
foo : Text
|
||||
quux : Text
|
||||
qux : Text
|
||||
|
||||
```
|
||||
We can get the list of things in the namespace, and UCM will give us a numbered
|
||||
@ -51,12 +51,12 @@ list:
|
||||
```ucm
|
||||
.temp> find
|
||||
|
||||
1. bar : .builtin.Text
|
||||
2. baz : .builtin.Text
|
||||
3. corge : .builtin.Text
|
||||
4. foo : .builtin.Text
|
||||
5. quux : .builtin.Text
|
||||
6. qux : .builtin.Text
|
||||
1. bar : Text
|
||||
2. baz : Text
|
||||
3. corge : Text
|
||||
4. foo : Text
|
||||
5. quux : Text
|
||||
6. qux : Text
|
||||
|
||||
|
||||
```
|
||||
@ -65,17 +65,17 @@ We can ask to `view` the second element of this list:
|
||||
```ucm
|
||||
.temp> find
|
||||
|
||||
1. bar : .builtin.Text
|
||||
2. baz : .builtin.Text
|
||||
3. corge : .builtin.Text
|
||||
4. foo : .builtin.Text
|
||||
5. quux : .builtin.Text
|
||||
6. qux : .builtin.Text
|
||||
1. bar : Text
|
||||
2. baz : Text
|
||||
3. corge : Text
|
||||
4. foo : Text
|
||||
5. quux : Text
|
||||
6. qux : Text
|
||||
|
||||
|
||||
.temp> view 2
|
||||
|
||||
baz : .builtin.Text
|
||||
baz : Text
|
||||
baz = "baz"
|
||||
|
||||
```
|
||||
@ -84,23 +84,23 @@ And we can `view` multiple elements by separating with spaces:
|
||||
```ucm
|
||||
.temp> find
|
||||
|
||||
1. bar : .builtin.Text
|
||||
2. baz : .builtin.Text
|
||||
3. corge : .builtin.Text
|
||||
4. foo : .builtin.Text
|
||||
5. quux : .builtin.Text
|
||||
6. qux : .builtin.Text
|
||||
1. bar : Text
|
||||
2. baz : Text
|
||||
3. corge : Text
|
||||
4. foo : Text
|
||||
5. quux : Text
|
||||
6. qux : Text
|
||||
|
||||
|
||||
.temp> view 2 3 5
|
||||
|
||||
baz : .builtin.Text
|
||||
baz : Text
|
||||
baz = "baz"
|
||||
|
||||
corge : .builtin.Text
|
||||
corge : Text
|
||||
corge = "corge"
|
||||
|
||||
quux : .builtin.Text
|
||||
quux : Text
|
||||
quux = "quux"
|
||||
|
||||
```
|
||||
@ -109,23 +109,23 @@ We can also ask for a range:
|
||||
```ucm
|
||||
.temp> find
|
||||
|
||||
1. bar : .builtin.Text
|
||||
2. baz : .builtin.Text
|
||||
3. corge : .builtin.Text
|
||||
4. foo : .builtin.Text
|
||||
5. quux : .builtin.Text
|
||||
6. qux : .builtin.Text
|
||||
1. bar : Text
|
||||
2. baz : Text
|
||||
3. corge : Text
|
||||
4. foo : Text
|
||||
5. quux : Text
|
||||
6. qux : Text
|
||||
|
||||
|
||||
.temp> view 2-4
|
||||
|
||||
baz : .builtin.Text
|
||||
baz : Text
|
||||
baz = "baz"
|
||||
|
||||
corge : .builtin.Text
|
||||
corge : Text
|
||||
corge = "corge"
|
||||
|
||||
foo : .builtin.Text
|
||||
foo : Text
|
||||
foo = "foo"
|
||||
|
||||
```
|
||||
@ -134,32 +134,32 @@ And we can ask for multiple ranges and use mix of ranges and numbers:
|
||||
```ucm
|
||||
.temp> find
|
||||
|
||||
1. bar : .builtin.Text
|
||||
2. baz : .builtin.Text
|
||||
3. corge : .builtin.Text
|
||||
4. foo : .builtin.Text
|
||||
5. quux : .builtin.Text
|
||||
6. qux : .builtin.Text
|
||||
1. bar : Text
|
||||
2. baz : Text
|
||||
3. corge : Text
|
||||
4. foo : Text
|
||||
5. quux : Text
|
||||
6. qux : Text
|
||||
|
||||
|
||||
.temp> view 1-3 4 5-6
|
||||
|
||||
bar : .builtin.Text
|
||||
bar : Text
|
||||
bar = "bar"
|
||||
|
||||
baz : .builtin.Text
|
||||
baz : Text
|
||||
baz = "baz"
|
||||
|
||||
corge : .builtin.Text
|
||||
corge : Text
|
||||
corge = "corge"
|
||||
|
||||
foo : .builtin.Text
|
||||
foo : Text
|
||||
foo = "foo"
|
||||
|
||||
quux : .builtin.Text
|
||||
quux : Text
|
||||
quux = "quux"
|
||||
|
||||
qux : .builtin.Text
|
||||
qux : Text
|
||||
qux = "qux"
|
||||
|
||||
```
|
||||
|
@ -20,7 +20,7 @@ fooToInt _ = +42
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
unique type Foo
|
||||
fooToInt : Foo -> builtin.Int
|
||||
fooToInt : Foo -> Int
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -36,7 +36,7 @@ And then we add it.
|
||||
⍟ I've added these definitions:
|
||||
|
||||
unique type Foo
|
||||
fooToInt : Foo -> .builtin.Int
|
||||
fooToInt : Foo -> Int
|
||||
|
||||
.subpath> find.verbose
|
||||
|
||||
@ -47,13 +47,13 @@ And then we add it.
|
||||
Foo.Foo : Foo
|
||||
|
||||
3. -- #o9q6anf4873hbnsaiifh5b46q8fdli18cu8cudu0ti8ort1gm253120uq8ijk24l52ecf62bm1rmq4tgnu7ip8apireh1oq97e042jg
|
||||
fooToInt : Foo -> .builtin.Int
|
||||
fooToInt : Foo -> Int
|
||||
|
||||
|
||||
|
||||
.subpath> view fooToInt
|
||||
|
||||
fooToInt : Foo -> .builtin.Int
|
||||
fooToInt : Foo -> Int
|
||||
fooToInt _ = +42
|
||||
|
||||
```
|
||||
@ -97,7 +97,7 @@ and update the codebase to use the new type `Foo`...
|
||||
```ucm
|
||||
.subpath> view fooToInt
|
||||
|
||||
fooToInt : Foo -> .builtin.Int
|
||||
fooToInt : Foo -> Int
|
||||
fooToInt _ = +42
|
||||
|
||||
```
|
||||
@ -124,8 +124,8 @@ otherTerm y = someTerm y
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
otherTerm : .builtin.Optional baz -> .builtin.Optional baz
|
||||
someTerm : .builtin.Optional foo -> .builtin.Optional foo
|
||||
otherTerm : Optional baz -> Optional baz
|
||||
someTerm : Optional foo -> Optional foo
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -140,8 +140,8 @@ Add that to the codebase:
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
otherTerm : .builtin.Optional baz -> .builtin.Optional baz
|
||||
someTerm : .builtin.Optional foo -> .builtin.Optional foo
|
||||
otherTerm : Optional baz -> Optional baz
|
||||
someTerm : Optional foo -> Optional foo
|
||||
|
||||
```
|
||||
Let's now edit the dependency:
|
||||
@ -162,7 +162,7 @@ someTerm _ = None
|
||||
⍟ These new definitions will replace existing ones of the
|
||||
same name and are ok to `update`:
|
||||
|
||||
someTerm : .builtin.Optional x -> .builtin.Optional x
|
||||
someTerm : Optional x -> Optional x
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -188,12 +188,12 @@ type of `otherTerm` should remain the same.
|
||||
```ucm
|
||||
.subpath.preserve> view someTerm
|
||||
|
||||
someTerm : .builtin.Optional x -> .builtin.Optional x
|
||||
someTerm _ = .builtin.Optional.None
|
||||
someTerm : Optional x -> Optional x
|
||||
someTerm _ = None
|
||||
|
||||
.subpath.preserve> view otherTerm
|
||||
|
||||
otherTerm : .builtin.Optional baz -> .builtin.Optional baz
|
||||
otherTerm : Optional baz -> Optional baz
|
||||
otherTerm y = someTerm y
|
||||
|
||||
```
|
||||
@ -236,8 +236,8 @@ otherTerm y = someTerm y
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
otherTerm : builtin.Optional baz -> builtin.Optional baz
|
||||
someTerm : builtin.Optional foo -> builtin.Optional foo
|
||||
otherTerm : Optional baz -> Optional baz
|
||||
someTerm : Optional foo -> Optional foo
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -252,8 +252,8 @@ We'll make two copies of this namespace.
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
otherTerm : .builtin.Optional baz -> .builtin.Optional baz
|
||||
someTerm : .builtin.Optional foo -> .builtin.Optional foo
|
||||
otherTerm : Optional baz -> Optional baz
|
||||
someTerm : Optional foo -> Optional foo
|
||||
|
||||
.subpath> fork one two
|
||||
|
||||
@ -277,7 +277,7 @@ someTerm _ = None
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
someTerm : .builtin.Optional x -> .builtin.Optional x
|
||||
someTerm : Optional x -> Optional x
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -302,7 +302,7 @@ The other namespace should be left alone.
|
||||
```ucm
|
||||
.subpath.two> view someTerm
|
||||
|
||||
someTerm : .builtin.Optional foo -> .builtin.Optional foo
|
||||
someTerm : Optional foo -> Optional foo
|
||||
someTerm x = x
|
||||
|
||||
```
|
||||
|
@ -13,7 +13,7 @@ x = 1
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
x : builtin.Nat
|
||||
x : Nat
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -24,7 +24,7 @@ x = 1
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
x : builtin.Nat
|
||||
x : Nat
|
||||
|
||||
```
|
||||
```unison
|
||||
@ -39,7 +39,7 @@ y = 2
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
y : builtin.Nat
|
||||
y : Nat
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -50,11 +50,11 @@ y = 2
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
y : builtin.Nat
|
||||
y : Nat
|
||||
|
||||
.> view y
|
||||
|
||||
y : builtin.Nat
|
||||
y : Nat
|
||||
y = 2
|
||||
|
||||
```
|
||||
|
@ -24,7 +24,7 @@ a.foo = 42
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
a.foo : .builtin.Nat
|
||||
a.foo : Nat
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -35,7 +35,7 @@ a.foo = 42
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
a.foo : .builtin.Nat
|
||||
a.foo : Nat
|
||||
|
||||
```
|
||||
We'll fork the namespace `a` into a new namespace `b`, so we can edit the two concurrently.
|
||||
@ -73,7 +73,7 @@ foo = 43
|
||||
⍟ These new definitions will replace existing ones of the
|
||||
same name and are ok to `update`:
|
||||
|
||||
foo : .builtin.Nat
|
||||
foo : Nat
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
@ -106,7 +106,7 @@ foo = 44
|
||||
⍟ These new definitions will replace existing ones of the
|
||||
same name and are ok to `update`:
|
||||
|
||||
foo : .builtin.Nat
|
||||
foo : Nat
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
|
28
unison-src/transcripts/suffixes.md
Normal file
28
unison-src/transcripts/suffixes.md
Normal file
@ -0,0 +1,28 @@
|
||||
# Suffix-based resolution of names
|
||||
|
||||
Any unique name suffix can be used to refer to a definition. For instance:
|
||||
|
||||
```unison
|
||||
-- No imports needed even though FQN is `builtin.{Int,Nat}`
|
||||
foo.bar.a : Int
|
||||
foo.bar.a = +99
|
||||
|
||||
-- No imports needed even though FQN is `builtin.Optional.{None,Some}`
|
||||
optional.isNone o = case o of
|
||||
None -> true
|
||||
Some _ -> false
|
||||
```
|
||||
|
||||
This also affects commands like find. Notice lack of qualified names in output:
|
||||
|
||||
```ucm
|
||||
.> find take
|
||||
```
|
||||
|
||||
In the signature, we don't see `base.Nat`, just `Nat`. The full declaration name is still shown for each search result though.
|
||||
|
||||
Type-based search also benefits from this, we can just say `Nat` rather than `.base.Nat`:
|
||||
|
||||
```ucm
|
||||
.> find : Nat -> [a] -> [a]
|
||||
```
|
53
unison-src/transcripts/suffixes.output.md
Normal file
53
unison-src/transcripts/suffixes.output.md
Normal file
@ -0,0 +1,53 @@
|
||||
# Suffix-based resolution of names
|
||||
|
||||
Any unique name suffix can be used to refer to a definition. For instance:
|
||||
|
||||
```unison
|
||||
-- No imports needed even though FQN is `builtin.{Int,Nat}`
|
||||
foo.bar.a : Int
|
||||
foo.bar.a = +99
|
||||
|
||||
-- No imports needed even though FQN is `builtin.Optional.{None,Some}`
|
||||
optional.isNone o = case o of
|
||||
None -> true
|
||||
Some _ -> false
|
||||
```
|
||||
|
||||
```ucm
|
||||
|
||||
I found and typechecked these definitions in scratch.u. If you
|
||||
do an `add` or `update`, here's how your codebase would
|
||||
change:
|
||||
|
||||
⍟ These new definitions are ok to `add`:
|
||||
|
||||
foo.bar.a : Int
|
||||
optional.isNone : Optional a -> Boolean
|
||||
|
||||
Now evaluating any watch expressions (lines starting with
|
||||
`>`)... Ctrl+C cancels.
|
||||
|
||||
```
|
||||
This also affects commands like find. Notice lack of qualified names in output:
|
||||
|
||||
```ucm
|
||||
.> find take
|
||||
|
||||
1. builtin.Bytes.take : Nat -> Bytes -> Bytes
|
||||
2. builtin.List.take : Nat -> [a] -> [a]
|
||||
3. builtin.Text.take : Nat -> Text -> Text
|
||||
|
||||
|
||||
```
|
||||
In the signature, we don't see `base.Nat`, just `Nat`. The full declaration name is still shown for each search result though.
|
||||
|
||||
Type-based search also benefits from this, we can just say `Nat` rather than `.base.Nat`:
|
||||
|
||||
```ucm
|
||||
.> find : Nat -> [a] -> [a]
|
||||
|
||||
1. builtin.List.drop : Nat -> [a] -> [a]
|
||||
2. builtin.List.take : Nat -> [a] -> [a]
|
||||
|
||||
|
||||
```
|
Loading…
Reference in New Issue
Block a user