Merge branch 'trunk' into topic/rehash-codebase

This commit is contained in:
Chris Penner 2022-02-14 13:31:57 -06:00
commit 3e3b44d1d1
45 changed files with 1465 additions and 617 deletions

View File

@ -36,3 +36,78 @@ jobs:
with:
files: /tmp/ucm/**/*.tar.gz
build_linux:
name: "build_linux"
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: install stack
run: |
curl -L https://github.com/commercialhaskell/stack/releases/download/v2.5.1/stack-2.5.1-linux-x86_64.tar.gz | tar -xz
echo "$HOME/stack-2.5.1-linux-x86_64/" >> $GITHUB_PATH
# One of the transcripts fails if the user's git name hasn't been set.
- name: set git user info
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
- name: build
run: stack --no-terminal build --flag unison-parser-typechecker:optimized
- name: fetch latest codebase-ui and package with ucm
run: |
mkdir -p /tmp/ucm/ui
UCM=$(stack path | awk '/local-install-root/{print $2}')/bin/unison
cp $UCM /tmp/ucm/ucm
wget -O/tmp/unisonLocal.zip https://github.com/unisonweb/codebase-ui/releases/download/latest/unisonLocal.zip
unzip -d /tmp/ucm/ui /tmp/unisonLocal.zip
tar -c -z -f ucm-linux.tar.gz -C /tmp/ucm .
- name: Upload linux artifact
uses: actions/upload-artifact@v2
with:
if-no-files-found: error
name: build-linux
path: ucm-linux.tar.gz
build_macos:
name: "build_macos"
runs-on: macos-10.15
steps:
- uses: actions/checkout@v2
- name: install stack
run: |
curl -L https://github.com/commercialhaskell/stack/releases/download/v2.5.1/stack-2.5.1-osx-x86_64.tar.gz | tar -xz
echo "$HOME/stack-2.5.1-osx-x86_64/" >> $GITHUB_PATH
# One of the transcripts fails if the user's git name hasn't been set.
- name: set git user info
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
- name: remove ~/.stack/setup-exe-cache on macOS
run: rm -rf ~/.stack/setup-exe-cache
- name: build
run: stack --no-terminal build --flag unison-parser-typechecker:optimized
- name: fetch latest codebase-ui and package with ucm
run: |
mkdir -p /tmp/ucm/ui
UCM=$(stack path | awk '/local-install-root/{print $2}')/bin/unison
cp $UCM /tmp/ucm/ucm
wget -O/tmp/unisonLocal.zip https://github.com/unisonweb/codebase-ui/releases/download/latest/unisonLocal.zip
unzip -d /tmp/ucm/ui /tmp/unisonLocal.zip
tar -c -z -f ucm-macos.tar.gz -C /tmp/ucm .
- name: Upload macos artifact
uses: actions/upload-artifact@v2
with:
if-no-files-found: error
name: build-macos
path: ucm-macos.tar.gz

View File

@ -66,3 +66,4 @@ The format for this list: name, GitHub handle, and then optional blurb about wha
* Sameer Kolhar (@kolharsam)
* Nicole Prindle (@nprindle)
* Harald Gliebe (@hagl)
* Phil de Joux (@philderbeast)

View File

@ -193,10 +193,7 @@ withRepo repo@(ReadGitRepo {url = uri, ref = mayGitRef}) branchBehavior action =
"--force", -- force updating local refs even if not fast-forward
-- update local refs with the same name they have on the remote.
"--refmap", "*:*",
-- Note: a shallow fetch saves time initially, but prevents
-- 'local' clones from using hard-links, so doing a normal fetch saves the most time
-- in the long run.
-- "--depth", "1",
"--depth", "1",
uri, -- The repo to fetch from
gitRef -- The specific reference to fetch
] ++ gitVerbosity
@ -221,10 +218,7 @@ cloneIfMissing repo@(ReadGitRepo {url=uri}) localPath = do
gitGlobal
(["clone"]
++ ["--bare"]
-- Note: a shallow clone saves time on the initial clone, but prevents all future
-- 'local' clones from using hard-links, so doing a full clone saves the most time
-- in the long run.
-- ++ ["--depth", "1"]
++ ["--depth", "1"]
++ [uri, Text.pack localPath]))
`withIOError` (throwError . GitError.CloneException repo . show)
isGitDir <- liftIO $ isGitRepo (Bare localPath)

View File

@ -397,7 +397,7 @@ lexemes' eof = P.optional space >> do
pure s
typeLink = wrap "syntax.docEmbedTypeLink" $ do
_ <- typeOrAbilityAlt lit <* CP.space
_ <- typeOrAbilityAlt wordyKw <* CP.space
tok (symbolyId <|> wordyId) <* CP.space
termLink = wrap "syntax.docEmbedTermLink" $

View File

@ -192,16 +192,19 @@ enclose keep rec (Let1NamedTop' top v b@(unAnn -> LamsNamed' vs bd) e)
| Ann' _ ty <- b = ann a tm ty
| otherwise = tm
lamb = lam' a evs (annotate $ lam' a vs lbody)
enclose keep rec t@(LamsNamed' vs body)
enclose keep rec t@(unLamsAnnot -> Just (vs0, mty, vs1, body))
= Just $ if null evs then lamb else apps' lamb $ map (var a) evs
where
-- remove shadowed variables
keep' = Set.difference keep $ Set.fromList vs
keep' = Set.difference keep $ Set.fromList (vs0 ++ vs1)
fvs = ABT.freeVars t
evs = Set.toList $ Set.difference fvs keep
a = ABT.annotation t
lbody = rec keep' body
lamb = lam' a (evs ++ vs) lbody
annotate tm
| Just ty <- mty = ann a tm ty
| otherwise = tm
lamb = lam' a (evs ++ vs0) . annotate . lam' a vs1 $ lbody
enclose keep rec t@(Handle' h body)
| isStructured body
= Just . handle (ABT.annotation t) (rec keep h) $ apps' lamb args
@ -267,10 +270,11 @@ letFloater rec vbs e = do
modify (\(vs,ctx,dcmp) -> (vs, ctx ++ fvbs, dcmp))
pure $ ABT.renames shadowMap e
where
rec' b@(Ann' (LamsNamed' vs bd) _ty)
= lam' a vs <$> rec bd
where a = ABT.annotation b
rec' b@(LamsNamed' vs bd) = lam' (ABT.annotation b) vs <$> rec bd
rec' b
| Just (vs0, mty, vs1, bd) <- unLamsAnnot b
= lam' a vs0 . maybe id (flip $ ann a) mty . lam' a vs1 <$> rec bd
where
a = ABT.annotation b
rec' b = rec b
lamFloater

View File

@ -166,10 +166,6 @@ fresh4 :: Var v => (v, v, v, v)
fresh4 = (v1, v2, v3, v4) where
[v1, v2, v3, v4] = freshes 4
fresh5 :: Var v => (v, v, v, v, v)
fresh5 = (v1, v2, v3, v4, v5) where
[v1, v2, v3, v4, v5] = freshes 5
fresh6 :: Var v => (v, v, v, v, v, v)
fresh6 = (v1, v2, v3, v4, v5, v6) where
[v1, v2, v3, v4, v5, v6] = freshes 6
@ -1055,12 +1051,12 @@ outIoFailNat stack1 stack2 stack3 fail nat result =
$ right nat)
]
outIoFailBox :: forall v. Var v => v -> v -> v -> v -> ANormal v
outIoFailBox stack1 stack2 fail result =
outIoFailBox :: forall v. Var v => v -> v -> v -> v -> v -> ANormal v
outIoFailBox stack1 stack2 stack3 fail result =
TMatch result . MatchSum $ mapFromList
[ (0, ([BX, BX],)
. TAbss [stack1, stack2]
. TLetD fail BX (TCon Ty.failureRef 0 [stack1, stack2])
[ (0, ([BX, BX, BX],)
. TAbss [stack1, stack2, stack3]
. TLetD fail BX (TCon Ty.failureRef 0 [stack1, stack2, stack3])
$ left fail)
, (1, ([BX],)
. TAbs stack1
@ -1148,14 +1144,14 @@ unitToInt = inUnit unit result
-- () -> Either Failure a
unitToEFBox :: ForeignOp
unitToEFBox = inUnit unit result
$ outIoFailBox stack1 stack2 fail result
where (unit, stack1, stack2, fail, result) = fresh5
$ outIoFailBox stack1 stack2 stack3 fail result
where (unit, stack1, stack2, stack3, fail, result) = fresh6
boxIomrToEFBox :: ForeignOp
boxIomrToEFBox = inBxIomr arg1 arg2 enum result
$ outIoFailBox stack1 stack2 fail result
$ outIoFailBox stack1 stack2 stack3 fail result
where
(arg1, arg2, enum, stack1, stack2, fail, result) = fresh7
(arg1, arg2, enum, stack1, stack2, stack3, fail, result) = fresh8
-- a -> ()
boxTo0 :: ForeignOp
@ -1235,9 +1231,9 @@ boxBoxBoxDirect instr
boxToEFBox :: ForeignOp
boxToEFBox =
inBx arg result $
outIoFail stack1 stack2 fail result
outIoFailBox stack1 stack2 stack3 fail result
where
(arg, result, stack1, stack2, fail) = fresh5
(arg, result, stack1, stack2, stack3, fail) = fresh6
-- a -> Either Failure (Maybe b)
boxToEFMBox :: ForeignOp
@ -1592,9 +1588,24 @@ mkForeignTls f = mkForeign $ \a -> fmap flatten (tryIO2 (tryIO1 (f a)))
tryIO2 = try
flatten :: Either IOException (Either TLS.TLSException r) -> Either (Failure ) r
flatten (Left e) = Left (Failure Ty.ioFailureRef (Util.Text.pack (show e)) unitValue)
flatten (Right (Left e)) = Left (Failure Ty.tlsFailureRef (Util.Text.pack (show e)) (unitValue))
flatten (Right (Left e)) = Left (Failure Ty.tlsFailureRef (Util.Text.pack (show e)) unitValue)
flatten (Right (Right a)) = Right a
mkForeignTlsE
:: forall a r.(ForeignConvention a, ForeignConvention r)
=> (a -> IO (Either Failure r)) -> ForeignFunc
mkForeignTlsE f = mkForeign $ \a -> fmap flatten (tryIO2 (tryIO1 (f a)))
where
tryIO1 :: IO (Either Failure r) -> IO (Either TLS.TLSException (Either Failure r))
tryIO1 = try
tryIO2 :: IO (Either TLS.TLSException (Either Failure r)) -> IO (Either IOException (Either TLS.TLSException (Either Failure r)))
tryIO2 = try
flatten :: Either IOException (Either TLS.TLSException (Either Failure r)) -> Either Failure r
flatten (Left e) = Left (Failure Ty.ioFailureRef (Util.Text.pack (show e)) unitValue)
flatten (Right (Left e)) = Left (Failure Ty.tlsFailureRef (Util.Text.pack (show e)) unitValue)
flatten (Right (Right (Left e))) = Left e
flatten (Right (Right (Right a))) = Right a
declareForeigns :: FDecl Symbol ()
declareForeigns = do
declareForeign Tracked "IO.openFile.impl.v3" boxIomrToEFBox $
@ -1852,9 +1863,7 @@ declareForeigns = do
socket :: SYS.Socket) -> TLS.contextNew socket config
declareForeign Tracked "Tls.handshake.impl.v3" boxToEF0 . mkForeignTls $
\(tls :: TLS.Context) -> do
i <- contextGetInformation tls
traceShow i $ TLS.handshake tls
\(tls :: TLS.Context) -> TLS.handshake tls
declareForeign Tracked "Tls.send.impl.v3" boxBoxToEFBox . mkForeignTls $
\(tls :: TLS.Context,
@ -1864,12 +1873,12 @@ declareForeigns = do
decoded :: Bytes.Bytes -> Either String PEM
decoded bytes = case pemParseLBS $ Bytes.toLazyByteString bytes of
Right (pem : _) -> Right pem
Right _ -> Left "no PEM found"
Right [] -> Left "no PEM found"
Left l -> Left l
asCert :: PEM -> Either String X.SignedCertificate
asCert pem = X.decodeSignedCertificate $ pemContent pem
in
declareForeign Tracked "Tls.decodeCert.impl.v3" boxToEFBox . mkForeignTls $
declareForeign Tracked "Tls.decodeCert.impl.v3" boxToEFBox . mkForeignTlsE $
\(bytes :: Bytes.Bytes) -> pure $ mapLeft wrapFailure $ (decoded >=> asCert) bytes
declareForeign Tracked "Tls.encodeCert" boxDirect . mkForeign $

View File

@ -192,7 +192,7 @@ toHtml docNamesByRef document =
content
div_ [class_ "tooltips", style_ "display: none;"] $ sequence_ tooltips
where
(content, (_, tooltips)) =
(_ :: Html (), (content, tooltips) :: (Html (), Seq (Html ()))) =
runWriterT (evalStateT (toHtml_ 1 document) 0)
toHtml_ ::
@ -249,10 +249,10 @@ toHtml docNamesByRef document =
in case doc of
Tooltip triggerContent tooltipContent -> do
tooltipNo <- State.get
let tooltipId = Text.pack . show $ tooltipId
let tooltipId = "tooltip-" <> (Text.pack . show $ tooltipNo)
State.put (tooltipNo + 1)
tooltip <-
div_ [class_ "tooltip-content", id_ ("tooltip-" <> tooltipId)]
div_ [class_ "tooltip-content", id_ tooltipId]
<$> currentSectionLevelToHtml tooltipContent
Writer.tell (pure tooltip)
@ -274,7 +274,7 @@ toHtml docNamesByRef document =
Strikethrough d ->
span_ [class_ "strikethrough"] <$> currentSectionLevelToHtml d
Style cssclass_ d ->
span_ [class_ $ textToClass cssclass_] <$> currentSectionLevelToHtml d
div_ [class_ $ textToClass cssclass_] <$> currentSectionLevelToHtml d
Anchor id' d ->
a_ [id_ id', href_ $ "#" <> id'] <$> currentSectionLevelToHtml d
Blockquote d ->
@ -294,18 +294,21 @@ toHtml docNamesByRef document =
[class_ "aside-anchor"]
. aside_ []
<$> currentSectionLevelToHtml d
Callout icon content ->
let (cls :: Attribute, ico :: Html ()) =
case icon of
Just emoji ->
( class_ "callout callout-with-icon",
div_ [class_ "callout-icon"] $ L.toHtml . toText "" $ emoji
)
Nothing ->
(class_ "callout", "")
in div_ [cls] <$> do
_ <- pure ico
div_ [class_ "callout-content"] <$> currentSectionLevelToHtml content
Callout icon content -> do
callout <- currentSectionLevelToHtml content
pure $
div_ [cls] $ do
ico
div_ [class_ "callout-content"] callout
where
(cls :: Attribute, ico :: Html ()) =
case icon of
Just emoji ->
( class_ "callout callout-with-icon",
div_ [class_ "callout-icon"] $ L.toHtml . toText "" $ emoji
)
Nothing ->
(class_ "callout", "")
Table rows ->
let cellToHtml c =
td_ [] <$> currentSectionLevelToHtml c

View File

@ -1408,16 +1408,16 @@ prettyDoc2 ppe ac tm = case tm of
S.DocDelimiter
"}}"
bail tm = brace (pretty0 ppe ac tm)
-- Finds the longest run of a character and return a run one longer than that
oneMore c inner = replicate num c
where
num =
case
filter (\s -> take 2 s == "__")
$ group (PP.toPlainUnbroken $ PP.syntaxToColor inner)
of
[] -> 2
x -> 1 + (maximum $ map length x)
-- Finds the longest run of a character and return one bigger than that
longestRun c s =
case
filter (\s -> take 2 s == [c,c])
$ group (PP.toPlainUnbroken $ PP.syntaxToColor s)
of
[] -> 2
x -> 1 + (maximum $ map length x)
oneMore c inner = replicate (longestRun c inner) c
makeFence inner = PP.string $ replicate (max 3 $ longestRun '`' inner) '`'
go :: Width -> Term3 v PrintAnnotation -> Pretty SyntaxText
go hdr = \case
(toDocTransclude ppe -> Just d) ->
@ -1444,22 +1444,22 @@ prettyDoc2 ppe ac tm = case tm of
PP.text t
(toDocCode ppe -> Just d) ->
let inner = rec d
quotes = oneMore '\'' inner
in PP.group $ PP.string quotes <> inner <> PP.string quotes
quotes = PP.string $ oneMore '\'' inner
in PP.group $ quotes <> inner <> quotes
(toDocJoin ppe -> Just ds) ->
foldMap rec ds
(toDocItalic ppe -> Just d) ->
let inner = rec d
underscores = oneMore '_' inner
in PP.group $ PP.string underscores <> inner <> PP.string underscores
underscores = PP.string $ oneMore '_' inner
in PP.group $ underscores <> inner <> underscores
(toDocBold ppe -> Just d) ->
let inner = rec d
stars = oneMore '*' inner
in PP.group $ PP.string stars <> inner <> PP.string stars
stars = PP.string $ oneMore '*' inner
in PP.group $ stars <> inner <> stars
(toDocStrikethrough ppe -> Just d) ->
let inner = rec d
quotes = oneMore '~' inner
in PP.group $ PP.string quotes <> inner <> PP.string quotes
quotes = PP.string $ oneMore '~' inner
in PP.group $ quotes <> inner <> quotes
(toDocGroup ppe -> Just d) ->
PP.group $ rec d
(toDocColumn ppe -> Just ds) ->
@ -1470,13 +1470,17 @@ prettyDoc2 ppe ac tm = case tm of
Left r -> "{type " <> tyName r <> "}"
Right r -> "{" <> tmName r <> "}"
(toDocEval ppe -> Just tm) ->
PP.lines ["```", pretty0 ppe ac tm, "```"]
let inner = pretty0 ppe ac tm
fence = makeFence inner
in PP.lines [fence, inner, fence]
(toDocEvalInline ppe -> Just tm) ->
"@eval{" <> pretty0 ppe ac tm <> "}"
(toDocExample ppe -> Just tm) ->
PP.group $ "``" <> pretty0 ppe ac tm <> "``"
(toDocExampleBlock ppe -> Just tm) ->
PP.lines ["@typecheck ```", pretty0 ppe ac' tm, "```"]
let inner = pretty0 ppe ac' tm
fence = makeFence inner
in PP.lines ["@typecheck " <> fence, inner, fence]
where ac' = ac { elideUnit = True }
(toDocSource ppe -> Just es) ->
PP.group $ " @source{" <> intercalateMap ", " go es <> "}"
@ -1494,18 +1498,20 @@ prettyDoc2 ppe ac tm = case tm of
let name = if length tms == 1 then "@signature" else "@signatures"
in PP.group $ " " <> name <> "{" <> intercalateMap ", " tmName tms <> "}"
(toDocCodeBlock ppe -> Just (typ, txt)) ->
PP.group $
PP.lines
[ "``` " <> PP.text typ,
PP.group $ PP.text txt,
"```"
]
let txt' = PP.text txt
fence = makeFence txt'
in PP.group $
PP.lines
[ fence <> " " <> PP.text typ
, PP.group txt'
, fence
]
(toDocVerbatim ppe -> Just txt) ->
PP.group $
PP.lines
[ "'''",
PP.group $ PP.text txt,
"'''"
[ "'''"
, PP.group $ PP.text txt
, "'''"
]
-- todo : emit fewer gratuitous columns, maybe a wrapIfMany combinator
tm -> bail tm

View File

@ -1513,13 +1513,83 @@ ungeneralize :: (Var v, Ord loc) => Type v loc -> M v loc (Type v loc)
ungeneralize t = snd <$> ungeneralize' t
ungeneralize' :: (Var v, Ord loc) => Type v loc -> M v loc ([v], Type v loc)
ungeneralize' (Type.Forall' t) = do
v <- ABT.freshen t freshenTypeVar
appendContext [existential v]
t <- pure $ ABT.bindInheritAnnotation t (existential' () B.Blank v)
first (v:) <$> ungeneralize' t
ungeneralize' (Type.ForallNamed' v t) = do
(vs, t) <- tweakEffects v t
first (vs++) <$> ungeneralize' t
ungeneralize' t = pure ([], t)
-- Tries to massage types like:
--
-- (a ->{e} b ->{e} c) ->{e} d
--
-- by rewriting them into:
--
-- (a ->{e1} b ->{e2} c) ->{e1,e2} d
--
-- The strategy is to find all negative occurrences of `e` and
-- introduce a new variable for each, and then replace any
-- non-negative occurrences with the row of all negative
-- variables. The reason this is valid is that `e` can be
-- instantiated with the entire row, and then all the negative
-- rows can be pared down to the single variable via subtyping.
--
-- This is meant to occur when a polymorphic type is
-- de-generalized, and replaces simple freshening of the
-- polymorphic variable.
tweakEffects
:: Var v
=> Ord loc
=> TypeVar v loc
-> Type v loc
-> M v loc ([v], Type v loc)
tweakEffects v0 t0
| isEffectVar v0 t0 = rewrite (Just False) t0 >>= \case
([], ty) ->
freshenTypeVar v0 >>= \out -> finish [out] ty
(vs, ty) -> finish vs ty
| otherwise
= freshenTypeVar v0 >>= \out -> finish [out] t0
where
negative = fromMaybe False
typ [v] = existential' () B.Blank v
typ vs = Type.effects () $ existential' () B.Blank <$> vs
finish vs ty = do
appendContext (existential <$> vs)
pure (vs, ABT.substInheritAnnotation v0 (typ vs) ty)
rewrite p ty@(Type.ForallNamed' v t)
| v0 /= v = second (Type.forall a v) <$> rewrite p t
where a = loc ty
rewrite p ty@(Type.Arrow'' i es o) = do
(vis, i) <- rewrite (not <$> p) i
(vos, o) <- rewrite p o
ess <- traverse (rewrite p) es
let es = snd <$> ess ; ves = fst =<< ess
pure (vis ++ ves ++ vos, Type.arrow a i (Type.effect a es o))
where a = loc ty
rewrite p ty@(Type.Var' v)
| v0 == v && negative p = do
u <- freshenTypeVar v0
pure ([u], existential' (loc ty) B.Blank u)
rewrite p ty@(Type.App' f x) = do
(vfs, f) <- rewrite p f
(vxs, x) <- rewrite Nothing x
pure (vfs ++ vxs, Type.app (loc ty) f x)
rewrite _ ty = pure ([], ty)
isEffectVar :: Var v => TypeVar v loc -> Type v loc -> Bool
isEffectVar u (Type.ForallNamed' v t)
| u == v = False
| otherwise = isEffectVar u t
isEffectVar u (Type.Arrow'' i es o) =
any p es || isEffectVar u i || isEffectVar u o
where
p (Type.Var' v) = v == u
p _ = False
isEffectVar _ _ = False
skolemize
:: Var v
=> Ord loc

View File

@ -178,7 +178,6 @@ loop = do
sbhLength <- eval BranchHashLength
let currentPath'' = Path.unabsolute currentPath'
hqNameQuery q = eval $ HQNameQuery (Just currentPath'') root' q
sbh = SBH.fromHash sbhLength
root0 = Branch.head root'
currentBranch0 = Branch.head currentBranch'
defaultPatchPath :: PatchPath
@ -809,15 +808,15 @@ loop = do
where
doHistory !n b acc =
if maybe False (n >=) resultsCap
then respond $ History diffCap acc (PageEnd (sbh $ Branch.headHash b) n)
then respondNumbered $ History diffCap sbhLength acc (PageEnd (Branch.headHash b) n)
else case Branch._history b of
Causal.One {} ->
respond $ History diffCap acc (EndOfLog . sbh $ Branch.headHash b)
respondNumbered $ History diffCap sbhLength acc (EndOfLog $ Branch.headHash b)
Causal.Merge _ _ tails ->
respond $ History diffCap acc (MergeTail (sbh $ Branch.headHash b) . map sbh $ Map.keys tails)
respondNumbered $ History diffCap sbhLength acc (MergeTail (Branch.headHash b) $ Map.keys tails)
Causal.Cons _ _ tail -> do
b' <- fmap Branch.Branch . eval . Eval $ snd tail
let elem = (sbh $ Branch.headHash b, Branch.namesDiff b' b)
let elem = (Branch.headHash b, Branch.namesDiff b' b)
doHistory (n + 1) b' (elem : acc)
UndoI -> do
prev <- eval . Eval $ Branch.uncons root'
@ -1475,7 +1474,7 @@ loop = do
ppe <-
suffixifiedPPE
=<< makePrintNamesFromLabeled' (Patch.labeledDependencies patch)
respond $ ListEdits patch ppe
respondNumbered $ ListEdits patch ppe
PullRemoteBranchI mayRepo path syncMode pullMode verbosity -> unlessError do
let preprocess = case pullMode of
Input.PullWithHistory -> Unmodified
@ -2270,7 +2269,7 @@ showTodoOutput getPpe patch names0 = do
<$> fst (TO.todoFrontierDependents todo)
)
ppe <- getPpe
respond $ TodoOutput ppe todo
respondNumbered $ TodoOutput ppe todo
checkTodo :: Patch -> Names -> Action m i v (TO.TodoOutput v Ann)
checkTodo patch names0 = do

View File

@ -71,6 +71,8 @@ type SourceName = Text
type NumberedArgs = [String]
type HashLength = Int
data PushPull = Push | Pull deriving (Eq, Ord, Show)
pushPull :: a -> a -> PushPull -> a
@ -91,12 +93,21 @@ data NumberedOutput v
| ShowDiffAfterCreatePR ReadRemoteNamespace ReadRemoteNamespace PPE.PrettyPrintEnv (BranchDiffOutput v Ann)
| -- <authorIdentifier> <authorPath> <relativeBase>
ShowDiffAfterCreateAuthor NameSegment Path.Path' Path.Absolute PPE.PrettyPrintEnv (BranchDiffOutput v Ann)
| -- | Invariant: there's at least one conflict or edit in the TodoOutput.
TodoOutput PPE.PrettyPrintEnvDecl (TO.TodoOutput v Ann)
| -- | CantDeleteDefinitions ppe couldntDelete becauseTheseStillReferenceThem
CantDeleteDefinitions PPE.PrettyPrintEnvDecl (Map LabeledDependency (NESet LabeledDependency))
| -- | CantDeleteNamespace ppe couldntDelete becauseTheseStillReferenceThem
CantDeleteNamespace PPE.PrettyPrintEnvDecl (Map LabeledDependency (NESet LabeledDependency))
| -- | DeletedDespiteDependents ppe deletedThings thingsWhichNowHaveUnnamedReferences
DeletedDespiteDependents PPE.PrettyPrintEnvDecl (Map LabeledDependency (NESet LabeledDependency))
-- | size limit, history , how the history ends
| History
(Maybe Int) -- Amount of history to print
HashLength
[(Branch.Hash, Names.Diff)]
HistoryTail -- 'origin point' of this view of history.
| ListEdits Patch PPE.PrettyPrintEnv
-- | ShowDiff
@ -178,8 +189,6 @@ data Output v
PPE.PrettyPrintEnvDecl
(Map Reference (DisplayObject () (Decl v Ann)))
(Map Reference (DisplayObject (Type v Ann) (Term v Ann)))
| -- | Invariant: there's at least one conflict or edit in the TodoOutput.
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
@ -190,7 +199,6 @@ data Output v
[(Reference, Text)] -- oks
[(Reference, Text)] -- fails
| CantUndo UndoFailureReason
| ListEdits Patch PPE.PrettyPrintEnv
| -- new/unrepresented references followed by old/removed
-- todo: eventually replace these sets with [SearchResult' v Ann]
-- and a nicer render.
@ -208,7 +216,6 @@ data Output v
| PatchInvolvesExternalDependents PPE.PrettyPrintEnv (Set Reference)
| WarnIncomingRootBranch ShortBranchHash (Set ShortBranchHash)
| StartOfCurrentPathHistory
| History (Maybe Int) [(ShortBranchHash, Names.Diff)] HistoryTail
| ShowReflog [ReflogEntry]
| PullAlreadyUpToDate ReadRemoteNamespace Path'
| PullSuccessful ReadRemoteNamespace Path'
@ -247,9 +254,9 @@ data ReflogEntry = ReflogEntry {hash :: ShortBranchHash, reason :: Text}
deriving (Show)
data HistoryTail
= EndOfLog ShortBranchHash
| MergeTail ShortBranchHash [ShortBranchHash]
| PageEnd ShortBranchHash Int -- PageEnd nextHash nextIndex
= EndOfLog Branch.Hash
| MergeTail Branch.Hash [Branch.Hash]
| PageEnd Branch.Hash Int -- PageEnd nextHash nextIndex
deriving (Show)
data TestReportStats
@ -323,12 +330,10 @@ isFailure o = case o of
Typechecked {} -> False
DisplayDefinitions _ _ m1 m2 -> null m1 && null m2
DisplayRendered {} -> False
TodoOutput _ todo -> TO.todoScore todo > 0 || not (TO.noConflicts todo)
TestIncrementalOutputStart {} -> False
TestIncrementalOutputEnd {} -> False
TestResults _ _ _ _ _ fails -> not (null fails)
CantUndo {} -> True
ListEdits {} -> False
GitError {} -> True
BustedBuiltins {} -> True
ConfiguredMetadataParseError {} -> True
@ -340,7 +345,6 @@ isFailure o = case o of
PatchInvolvesExternalDependents {} -> True
NothingToPatch {} -> False
WarnIncomingRootBranch {} -> False
History {} -> False
StartOfCurrentPathHistory -> True
NotImplemented -> True
DumpNumberedArgs {} -> False
@ -381,6 +385,9 @@ isNumberedFailure = \case
ShowDiffAfterPull {} -> False
ShowDiffAfterCreatePR {} -> False
ShowDiffAfterCreateAuthor {} -> False
TodoOutput _ todo -> TO.todoScore todo > 0 || not (TO.noConflicts todo)
CantDeleteDefinitions {} -> True
CantDeleteNamespace {} -> True
History {} -> False
DeletedDespiteDependents {} -> False
ListEdits {} -> False

View File

@ -61,7 +61,7 @@ import qualified Unison.Codebase.TermEdit as TermEdit
import Unison.Codebase.Type (GitError (GitCodebaseError, GitProtocolError, GitSqliteCodebaseError))
import qualified Unison.Codebase.TypeEdit as TypeEdit
import Unison.CommandLine (bigproblem, note, tip)
import Unison.CommandLine.InputPatterns (makeExample, makeExample')
import Unison.CommandLine.InputPatterns (makeExample')
import qualified Unison.CommandLine.InputPatterns as IP
import Unison.ConstructorReference (GConstructorReference(..))
import qualified Unison.DataDeclaration as DD
@ -89,7 +89,7 @@ import Unison.Names (Names (..))
import qualified Unison.Names as Names
import qualified Unison.NamesWithHistory as Names
import Unison.Parser.Ann (Ann, startingLine)
import Unison.Prelude hiding (unlessM)
import Unison.Prelude
import qualified Unison.PrettyPrintEnv as PPE
import qualified Unison.PrettyPrintEnv.Util as PPE
import qualified Unison.PrettyPrintEnvDecl as PPE
@ -119,10 +119,7 @@ import Unison.Type (Type)
import qualified Unison.TypePrinter as TypePrinter
import qualified Unison.UnisonFile as UF
import qualified Unison.Util.List as List
import Unison.Util.Monoid
( intercalateMap,
unlessM,
)
import Unison.Util.Monoid (intercalateMap)
import qualified Unison.Util.Pretty as P
import qualified Unison.Util.Relation as R
import Unison.Var (Var)
@ -130,6 +127,12 @@ import qualified Unison.Var as Var
import qualified Unison.WatchKind as WK
import Prelude hiding (readFile, writeFile)
import qualified Data.List.NonEmpty as NEList
import qualified U.Util.Monoid as Monoid
import qualified Data.Foldable as Foldable
import qualified Unison.Codebase.Branch as Branch
import Control.Monad.State
import Control.Monad.Trans.Writer.CPS
import qualified Unison.ShortHash as ShortHash
type Pretty = P.Pretty P.ColorText
@ -309,6 +312,7 @@ notifyNumbered o = case o of
]
)
(showDiffNamespace ShowNumbers ppe (absPathToBranchId bAbs) (absPathToBranchId bAbs) diff)
TodoOutput names todo -> todoOutput names todo
CantDeleteDefinitions ppeDecl endangerments ->
(P.warnCallout $
P.lines
@ -328,6 +332,63 @@ notifyNumbered o = case o of
<> IP.patternName IP.deleteNamespaceForce
]
, numberedArgsForEndangerments ppeDecl endangerments)
History _cap sbhLength history tail ->
let (tailMsg, tailHashes) = handleTail (length history + 1)
msg :: Pretty
msg = P.lines
[ note $ "The most recent namespace hash is immediately below this message.",
"",
P.sep "\n\n" [go i (toSBH h) diff | (i, (h, diff)) <- zip [1..] reversedHistory],
"",
tailMsg
]
branchHashes :: [Branch.Hash]
branchHashes = (fst <$> reversedHistory) <> tailHashes
in (msg, displayBranchHash <$> branchHashes)
where
toSBH :: Branch.Hash -> ShortBranchHash
toSBH h = SBH.fromHash sbhLength h
reversedHistory = reverse history
showNum n = P.shown n <> ". "
handleTail :: Int -> (Pretty, [Branch.Hash])
handleTail n = case tail of
E.EndOfLog h ->
(P.lines
[ "" <> showNum n <> prettySBH (toSBH h) <> " (start of history)"
]
, [h]
)
E.MergeTail h hs ->
(P.lines
[ P.wrap $ "This segment of history starts with a merge." <> ex,
"",
"" <> showNum n <> prettySBH (toSBH h),
"",
P.lines (hs & imap \i h -> showNum (n + 1 + i) <> prettySBH (toSBH h))
]
, h : hs
)
E.PageEnd h _n ->
(P.lines
[ P.wrap $ "There's more history before the versions shown here." <> ex,
"",
dots,
"",
"" <> showNum n <> prettySBH (toSBH h),
""
]
, [h]
)
dots = ""
go i sbh diff =
P.lines
[ "" <> showNum i <> prettySBH sbh,
"",
P.indentN 2 $ prettyDiff diff
]
ex =
"Use" <> IP.makeExample IP.history ["#som3n4m3space"]
<> "to view history starting from a given namespace hash."
DeletedDespiteDependents ppeDecl endangerments ->
(P.warnCallout $
P.lines
@ -336,6 +397,7 @@ notifyNumbered o = case o of
endangeredDependentsTable ppeDecl endangerments
]
, numberedArgsForEndangerments ppeDecl endangerments)
ListEdits patch ppe -> showListEdits patch ppe
where
absPathToBranchId = Right
undoTip =
@ -345,6 +407,99 @@ notifyNumbered o = case o of
<> IP.makeExample' IP.viewReflog
<> "to undo this change."
showListEdits :: Patch -> PPE.PrettyPrintEnv -> (P.Pretty P.ColorText, NumberedArgs)
showListEdits patch ppe =
( P.sepNonEmpty
"\n\n"
[ if null types
then mempty
else
"Edited Types:"
`P.hang` P.column2 typeOutputs,
if null terms
then mempty
else
"Edited Terms:"
`P.hang` P.column2 termOutputs,
if null types && null terms
then "This patch is empty."
else
tip . P.string $
"To remove entries from a patch, use "
<> IP.deleteTermReplacementCommand
<> " or "
<> IP.deleteTypeReplacementCommand
<> ", as appropriate."
],
numberedArgsCol1 <> numberedArgsCol2
)
where
typeOutputs, termOutputs :: [(Pretty, Pretty)]
numberedArgsCol1, numberedArgsCol2 :: NumberedArgs
-- We use the output of the first column's count as the first number in the second
-- column's count. Laziness allows this since they're used independently of one another.
(((typeOutputs, termOutputs), (lastNumberInFirstColumn, _)), (numberedArgsCol1, numberedArgsCol2)) =
runWriter . flip runStateT (1, lastNumberInFirstColumn) $ do
typeOutputs <- traverse prettyTypeEdit types
termOutputs <- traverse prettyTermEdit terms
pure (typeOutputs, termOutputs)
types :: [(Reference, TypeEdit.TypeEdit)]
types = R.toList $ Patch._typeEdits patch
terms :: [(Reference, TermEdit.TermEdit)]
terms = R.toList $ Patch._termEdits patch
showNum :: Int -> Pretty
showNum n = P.hiBlack (P.shown n <> ". ")
prettyTermEdit ::
(Reference.TermReference, TermEdit.TermEdit) ->
StateT (Int, Int) (Writer (NumberedArgs, NumberedArgs)) (Pretty, Pretty)
prettyTermEdit (lhsRef, termEdit) = do
n1 <- gets fst <* modify (first succ)
let lhsTermName = PPE.termName ppe (Referent.Ref lhsRef)
-- We use the shortHash of the lhs rather than its name for numbered args,
-- since its name is likely to be "historical", and won't work if passed to a ucm command.
let lhsHash = ShortHash.toString . Reference.toShortHash $ lhsRef
case termEdit of
TermEdit.Deprecate -> do
lift $ tell ([lhsHash], [])
pure
( showNum n1 <> (P.syntaxToColor . prettyHashQualified $ lhsTermName),
"-> (deprecated)"
)
TermEdit.Replace rhsRef _typing -> do
n2 <- gets snd <* modify (second succ)
let rhsTermName = PPE.termName ppe (Referent.Ref rhsRef)
lift $ tell ([lhsHash], [HQ.toString rhsTermName])
pure
( showNum n1 <> (P.syntaxToColor . prettyHashQualified $ lhsTermName),
"-> " <> showNum n2 <> (P.syntaxToColor . prettyHashQualified $ rhsTermName)
)
prettyTypeEdit ::
(Reference, TypeEdit.TypeEdit) ->
StateT (Int, Int) (Writer (NumberedArgs, NumberedArgs)) (Pretty, Pretty)
prettyTypeEdit (lhsRef, typeEdit) = do
n1 <- gets fst <* modify (first succ)
let lhsTypeName = PPE.typeName ppe lhsRef
-- We use the shortHash of the lhs rather than its name for numbered args,
-- since its name is likely to be "historical", and won't work if passed to a ucm command.
let lhsHash = ShortHash.toString . Reference.toShortHash $ lhsRef
case typeEdit of
TypeEdit.Deprecate -> do
lift $ tell ([lhsHash], [])
pure
( showNum n1 <> (P.syntaxToColor . prettyHashQualified $ lhsTypeName),
"-> (deprecated)"
)
TypeEdit.Replace rhsRef -> do
n2 <- gets snd <* modify (second succ)
let rhsTypeName = PPE.typeName ppe rhsRef
lift $ tell ([lhsHash], [HQ.toString rhsTypeName])
pure
( showNum n1 <> (P.syntaxToColor . prettyHashQualified $ lhsTypeName),
"-> " <> showNum n2 <> (P.syntaxToColor . prettyHashQualified $ rhsTypeName)
)
prettyRemoteNamespace ::
ReadRemoteNamespace ->
Pretty
@ -881,7 +1036,6 @@ notifyUser dir o = case o of
pure . P.wrap $
"I loaded " <> P.text sourceName <> " and didn't find anything."
else pure mempty
TodoOutput names todo -> pure (todoOutput names todo)
GitError e -> pure $ case e of
GitSqliteCodebaseError e -> case e of
NoDatabaseFile repo localPath ->
@ -1000,49 +1154,6 @@ notifyUser dir o = case o of
"",
P.wrap "Try again with a few more hash characters to disambiguate."
]
ListEdits patch ppe -> do
let types = Patch._typeEdits patch
terms = Patch._termEdits patch
prettyTermEdit (r, TermEdit.Deprecate) =
( P.syntaxToColor . prettyHashQualified . PPE.termName ppe . Referent.Ref $ r,
"-> (deprecated)"
)
prettyTermEdit (r, TermEdit.Replace r' _typing) =
( P.syntaxToColor . prettyHashQualified . PPE.termName ppe . Referent.Ref $ r,
"-> " <> (P.syntaxToColor . prettyHashQualified . PPE.termName ppe . Referent.Ref $ r')
)
prettyTypeEdit (r, TypeEdit.Deprecate) =
( P.syntaxToColor . prettyHashQualified $ PPE.typeName ppe r,
"-> (deprecated)"
)
prettyTypeEdit (r, TypeEdit.Replace r') =
( P.syntaxToColor . prettyHashQualified $ PPE.typeName ppe r,
"-> " <> (P.syntaxToColor . prettyHashQualified . PPE.typeName ppe $ r')
)
pure $
P.sepNonEmpty
"\n\n"
[ if R.null types
then mempty
else
"Edited Types:"
`P.hang` P.column2 (prettyTypeEdit <$> R.toList types),
if R.null terms
then mempty
else
"Edited Terms:"
`P.hang` P.column2 (prettyTermEdit <$> R.toList terms),
if R.null types && R.null terms
then "This patch is empty."
else
tip . P.string $
"To remove entries from a patch, use "
<> IP.deleteTermReplacementCommand
<> " or "
<> IP.deleteTypeReplacementCommand
<> ", as appropriate."
]
BustedBuiltins (Set.toList -> new) (Set.toList -> old) ->
-- todo: this could be prettier! Have a nice list like `find` gives, but
-- that requires querying the codebase to determine term types. Probably
@ -1250,48 +1361,6 @@ notifyUser dir o = case o of
renderEntry (Output.ReflogEntry hash reason) =
P.wrap $
P.blue (prettySBH hash) <> " : " <> P.text reason
History _cap history tail ->
pure $
P.lines
[ note $ "The most recent namespace hash is immediately below this message.",
"",
P.sep "\n\n" [go h diff | (h, diff) <- reverse history],
"",
tailMsg
]
where
tailMsg = case tail of
E.EndOfLog h ->
P.lines
[ "" <> prettySBH h <> " (start of history)"
]
E.MergeTail h hs ->
P.lines
[ P.wrap $ "This segment of history starts with a merge." <> ex,
"",
"" <> prettySBH h,
"",
P.lines (prettySBH <$> hs)
]
E.PageEnd h _n ->
P.lines
[ P.wrap $ "There's more history before the versions shown here." <> ex,
"",
dots,
"",
"" <> prettySBH h,
""
]
dots = ""
go hash diff =
P.lines
[ "" <> prettySBH hash,
"",
P.indentN 2 $ prettyDiff diff
]
ex =
"Use" <> IP.makeExample IP.history ["#som3n4m3space"]
<> "to view history starting from a given namespace hash."
StartOfCurrentPathHistory ->
pure $
P.wrap "You're already at the very beginning! 🙂"
@ -1509,12 +1578,12 @@ formatMissingStuff ::
[(HQ.HashQualified Name, typ)] ->
Pretty
formatMissingStuff terms types =
( unlessM (null terms) . P.fatalCallout $
( Monoid.unlessM (null terms) . P.fatalCallout $
P.wrap "The following terms have a missing or corrupted type signature:"
<> "\n\n"
<> P.column2 [(P.syntaxToColor $ prettyHashQualified name, fromString (show ref)) | (name, ref) <- terms]
)
<> ( unlessM (null types) . P.fatalCallout $
<> ( Monoid.unlessM (null types) . P.fatalCallout $
P.wrap "The following types weren't found in the codebase:"
<> "\n\n"
<> P.column2 [(P.syntaxToColor $ prettyHashQualified name, fromString (show ref)) | (name, ref) <- types]
@ -1779,72 +1848,128 @@ prettyDeclPair ::
Pretty
prettyDeclPair ppe (r, dt) = prettyDeclTriple (PPE.typeName ppe r, r, dt)
renderNameConflicts :: Set.Set Name -> Set.Set Name -> Pretty
renderNameConflicts conflictedTypeNames conflictedTermNames =
unlessM (null allNames) $
P.callout "" . P.sep "\n\n" . P.nonEmpty $
[ showConflictedNames "types" conflictedTypeNames,
showConflictedNames "terms" conflictedTermNames,
tip $
"This occurs when merging branches that both independently introduce the same name. Use "
<> makeExample IP.view (prettyName <$> take 3 allNames)
<> "to see the conflicting definitions, then use "
<> makeExample'
( if (not . null) conflictedTypeNames
then IP.renameType
else IP.renameTerm
)
<> "to resolve the conflicts."
]
renderNameConflicts :: PPE.PrettyPrintEnv -> Names -> Numbered Pretty
renderNameConflicts ppe conflictedNames = do
let conflictedTypeNames :: Map Name [HQ.HashQualified Name]
conflictedTypeNames = conflictedNames
& Names.types
& R.domain
& fmap (foldMap (pure @[] . PPE.typeName ppe))
let conflictedTermNames :: Map Name [HQ.HashQualified Name]
conflictedTermNames = conflictedNames
& Names.terms
& R.domain
& fmap (foldMap (pure @[] . PPE.termName ppe))
let allConflictedNames :: [Name]
allConflictedNames = Set.toList (Map.keysSet conflictedTermNames <> Map.keysSet conflictedTypeNames)
prettyConflictedTypes <- showConflictedNames "type" conflictedTypeNames
prettyConflictedTerms <- showConflictedNames "term" conflictedTermNames
pure $ Monoid.unlessM (null allConflictedNames) $
P.callout "" . P.sep "\n\n" . P.nonEmpty $
[ prettyConflictedTypes,
prettyConflictedTerms,
tip $
"This occurs when merging branches that both independently introduce the same name."
<> "Use "
<> makeExample'
( if (not . null) conflictedTypeNames
then IP.renameType
else IP.renameTerm
)
<> " or "
<> makeExample'
( if (not . null) conflictedTypeNames
then IP.deleteType
else IP.deleteTerm
)
<> "to resolve the conflicts."
]
where
allNames = toList (conflictedTermNames <> conflictedTypeNames)
showConflictedNames things conflictedNames =
unlessM (Set.null conflictedNames) $
P.wrap ("These" <> P.bold (things <> "have conflicting definitions:"))
`P.hang` P.commas (P.blue . prettyName <$> toList conflictedNames)
showConflictedNames :: Pretty -> Map Name [HQ.HashQualified Name] -> Numbered Pretty
showConflictedNames thingKind conflictedNames = P.lines <$> do
for (Map.toList conflictedNames) $ \(name, hashes) -> do
prettyConflicts <- for hashes \hash -> do
n <- addNumberedArg (HQ.toString hash)
pure $ formatNum n <> (P.blue . P.syntaxToColor . prettyHashQualified $ hash)
pure . P.wrap $
("The " <> thingKind <> " " <> P.green (prettyName name)
<> " has conflicting definitions:"
) `P.hang` P.lines prettyConflicts
renderEditConflicts ::
PPE.PrettyPrintEnv -> Patch -> Pretty
renderEditConflicts ppe Patch {..} =
unlessM (null editConflicts) . P.callout "" . P.sep "\n\n" $
[ P.wrap $
"These" <> P.bold "definitions were edited differently"
<> "in namespaces that have been merged into this one."
<> "You'll have to tell me what to use as the new definition:",
P.indentN 2 (P.lines (formatConflict <$> editConflicts))
-- , tip $ "Use " <> makeExample IP.resolve [name (head editConflicts), " <replacement>"] <> " to pick a replacement." -- todo: eventually something with `edit`
]
PPE.PrettyPrintEnv -> Patch -> Numbered Pretty
renderEditConflicts ppe Patch {..} = do
formattedConflicts <- for editConflicts formatConflict
pure . Monoid.unlessM (null editConflicts) . P.callout "" . P.sep "\n\n" $
[ P.wrap $
"These" <> P.bold "definitions were edited differently"
<> "in namespaces that have been merged into this one."
<> "You'll have to tell me what to use as the new definition:",
P.indentN 2 (P.lines formattedConflicts)
-- , tip $ "Use " <> makeExample IP.resolve [name (head editConflicts), " <replacement>"] <> " to pick a replacement." -- todo: eventually something with `edit`
]
where
-- todo: could possibly simplify all of this, but today is a copy/paste day.
editConflicts :: [Either (Reference, Set TypeEdit.TypeEdit) (Reference, Set TermEdit.TermEdit)]
editConflicts =
(fmap Left . Map.toList . R.toMultimap . R.filterManyDom $ _typeEdits)
<> (fmap Right . Map.toList . R.toMultimap . R.filterManyDom $ _termEdits)
typeName r = styleHashQualified P.bold (PPE.typeName ppe r)
termName r = styleHashQualified P.bold (PPE.termName ppe (Referent.Ref r))
formatTypeEdits (r, toList -> es) =
P.wrap $
"The type" <> typeName r <> "was"
numberedHQName :: HQ.HashQualified Name -> Numbered Pretty
numberedHQName hqName = do
n <- addNumberedArg (HQ.toString hqName)
pure $ formatNum n <> styleHashQualified P.bold hqName
formatTypeEdits :: (Reference, Set TypeEdit.TypeEdit)
-> Numbered Pretty
formatTypeEdits (r, toList -> es) = do
replacedType <- numberedHQName (PPE.typeName ppe r)
replacements <- for [PPE.typeName ppe r | TypeEdit.Replace r <- es] numberedHQName
pure . P.wrap $
"The type" <> replacedType <> "was"
<> ( if TypeEdit.Deprecate `elem` es
then "deprecated and also replaced with"
else "replaced with"
)
<> P.oxfordCommas [typeName r | TypeEdit.Replace r <- es]
formatTermEdits (r, toList -> es) =
P.wrap $
"The term" <> termName r <> "was"
`P.hang` P.lines replacements
formatTermEdits :: (Reference.TermReference, Set TermEdit.TermEdit)
-> Numbered Pretty
formatTermEdits (r, toList -> es) = do
replacedTerm <- numberedHQName (PPE.termName ppe (Referent.Ref r))
replacements <- for [PPE.termName ppe (Referent.Ref r) | TermEdit.Replace r _ <- es] numberedHQName
pure . P.wrap $
"The term" <> replacedTerm <> "was"
<> ( if TermEdit.Deprecate `elem` es
then "deprecated and also replaced with"
else "replaced with"
)
<> P.oxfordCommas [termName r | TermEdit.Replace r _ <- es]
`P.hang` P.lines replacements
formatConflict :: Either
(Reference, Set TypeEdit.TypeEdit)
(Reference.TermReference, Set TermEdit.TermEdit)
-> Numbered Pretty
formatConflict = either formatTypeEdits formatTermEdits
type Numbered = State.State (Int, Seq.Seq String)
todoOutput :: Var v => PPE.PrettyPrintEnvDecl -> TO.TodoOutput v a -> Pretty
todoOutput ppe todo =
todoConflicts <> todoEdits
addNumberedArg :: String -> Numbered Int
addNumberedArg s = do
(n, args) <- State.get
State.put (n + 1, args Seq.|> s)
pure $ (n + 1)
formatNum :: Int -> Pretty
formatNum n = P.string (show n <> ". ")
runNumbered :: Numbered a -> (a, NumberedArgs)
runNumbered m =
let (a, (_, args)) = State.runState m (0, mempty)
in (a, Foldable.toList args)
todoOutput :: Var v => PPE.PrettyPrintEnvDecl -> TO.TodoOutput v a -> (Pretty, NumberedArgs)
todoOutput ppe todo = runNumbered do
conflicts <- todoConflicts
edits <- todoEdits
pure (conflicts <> edits)
where
ppeu = PPE.unsuffixifiedPPE ppe
ppes = PPE.suffixifiedPPE ppe
@ -1856,21 +1981,19 @@ todoOutput ppe todo =
[(PPE.typeName ppeu r, r) | (r, MissingObject _) <- frontierTypes]
goodTerms ts =
[(Referent.Ref r, PPE.termName ppeu (Referent.Ref r), typ) | (r, Just typ) <- ts]
todoConflicts =
todoConflicts :: Numbered Pretty
todoConflicts = do
if TO.noConflicts todo
then mempty
else
P.lines . P.nonEmpty $
[ renderEditConflicts ppeu (TO.editConflicts todo),
renderNameConflicts conflictedTypeNames conflictedTermNames
]
then pure mempty
else do
editConflicts <- renderEditConflicts ppeu (TO.editConflicts todo)
nameConflicts <- renderNameConflicts ppeu conflictedNames
pure $ P.lines . P.nonEmpty $ [editConflicts, nameConflicts]
where
-- If a conflict is both an edit and a name conflict, we show it in the edit
-- conflicts section
c :: Names
c = removeEditConflicts (TO.editConflicts todo) (TO.nameConflicts todo)
conflictedTypeNames = (R.dom . Names.types) c
conflictedTermNames = (R.dom . Names.terms) c
conflictedNames :: Names
conflictedNames = removeEditConflicts (TO.editConflicts todo) (TO.nameConflicts todo)
-- e.g. `foo#a` has been independently updated to `foo#b` and `foo#c`.
-- This means there will be a name conflict:
-- foo -> #b
@ -1897,26 +2020,33 @@ todoOutput ppe todo =
typeEditConflicts = R.filterDom (`R.manyDom` _typeEdits) _typeEdits
termEditConflicts = R.filterDom (`R.manyDom` _termEdits) _termEdits
todoEdits =
unlessM (TO.noEdits todo) . P.callout "🚧" . P.sep "\n\n" . P.nonEmpty $
[ P.wrap
( "The namespace has" <> fromString (show (TO.todoScore todo))
<> "transitive dependent(s) left to upgrade."
<> "Your edit frontier is the dependents of these definitions:"
),
P.indentN 2 . P.lines $
( (prettyDeclPair ppeu <$> toList frontierTypes)
++ TypePrinter.prettySignaturesCT 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 ppeu . unscore <$> toList dirtyTypes)
++ TypePrinter.prettySignaturesCT
ppes
(goodTerms $ unscore <$> dirtyTerms),
formatMissingStuff corruptTerms corruptTypes
]
todoEdits :: Numbered Pretty
todoEdits = do
numberedTypes <- for (unscore <$> dirtyTypes) \(ref, displayObj) -> do
n <- addNumberedArg (HQ.toString $ PPE.typeName ppeu ref)
pure $ formatNum n <> prettyDeclPair ppeu (ref, displayObj)
let filteredTerms = goodTerms (unscore <$> dirtyTerms)
termNumbers <- for filteredTerms \(ref, _, _) -> do
n <- addNumberedArg (HQ.toString $ PPE.termName ppeu ref)
pure $ formatNum n
let formattedTerms = TypePrinter.prettySignaturesCT ppes filteredTerms
numberedTerms = zipWith (<>) termNumbers formattedTerms
pure $ Monoid.unlessM (TO.noEdits todo) . P.callout "🚧" . P.sep "\n\n" . P.nonEmpty $
[ P.wrap
( "The namespace has" <> fromString (show (TO.todoScore todo))
<> "transitive dependent(s) left to upgrade."
<> "Your edit frontier is the dependents of these definitions:"
),
P.indentN 2 . P.lines $
( (prettyDeclPair ppeu <$> toList frontierTypes)
++ TypePrinter.prettySignaturesCT ppes (goodTerms frontierTerms)
),
P.wrap "I recommend working on them in the following order:",
P.lines $ numberedTypes ++ numberedTerms,
formatMissingStuff corruptTerms corruptTypes
]
unscore :: (a, b, c) -> (b, c)
unscore (_score, b, c) = (b, c)
listOfDefinitions ::
Var v => PPE.PrettyPrintEnv -> E.ListDetailed -> [SR'.SearchResult' v a] -> IO Pretty
@ -2350,15 +2480,15 @@ showDiffNamespace sn ppe oldPath newPath OBD.BranchDiffOutput {..} =
-- DeclPrinter.prettyDeclHeader : HQ -> Either
numPatch :: Input.AbsBranchId -> Name -> Numbered Pretty
numPatch prefix name =
addNumberedArg $ prefixBranchId prefix name
addNumberedArg' $ prefixBranchId prefix name
numHQ :: Input.AbsBranchId -> HQ.HashQualified Name -> Referent -> Numbered Pretty
numHQ prefix hq r =
addNumberedArg . HQ.toStringWith (prefixBranchId prefix) . HQ.requalify hq $ r
addNumberedArg' . HQ.toStringWith (prefixBranchId prefix) . HQ.requalify hq $ r
numHQ' :: Input.AbsBranchId -> HQ'.HashQualified Name -> Referent -> Numbered Pretty
numHQ' prefix hq r =
addNumberedArg . HQ'.toStringWith (prefixBranchId prefix) . HQ'.requalify hq $ r
addNumberedArg' . HQ'.toStringWith (prefixBranchId prefix) . HQ'.requalify hq $ r
-- E.g.
-- prefixBranchId "#abcdef" "base.List.map" -> "#abcdef.base.List.map"
@ -2368,12 +2498,11 @@ showDiffNamespace sn ppe oldPath newPath OBD.BranchDiffOutput {..} =
Left sbh -> "#" <> SBH.toString sbh <> ":" <> Name.toString (Name.makeAbsolute name)
Right pathPrefix -> Name.toString (Name.makeAbsolute . Path.prefixName pathPrefix $ name)
addNumberedArg :: String -> Numbered Pretty
addNumberedArg s = case sn of
addNumberedArg' :: String -> Numbered Pretty
addNumberedArg' s = case sn of
ShowNumbers -> do
(n, args) <- State.get
State.put (n + 1, args Seq.|> s)
pure $ padNumber (n + 1)
n <- addNumberedArg s
pure $ padNumber n
HideNumbers -> pure mempty
padNumber :: Int -> Pretty
@ -2402,7 +2531,7 @@ listOfDefinitions' ppe detailed results =
. P.nonEmpty
$ prettyNumberedResults :
[ formatMissingStuff termsWithMissingTypes missingTypes,
unlessM (null missingBuiltins)
Monoid.unlessM (null missingBuiltins)
. bigproblem
$ P.wrap
"I encountered an inconsistency in the codebase; these definitions refer to built-ins that this version of unison doesn't know about:"
@ -2678,3 +2807,7 @@ endangeredDependentsTable ppeDecl m =
refs
& fmap (\(n, dep) -> numArg n <> prettyLabeled fqnEnv dep)
& P.lines
-- | Displays a full, non-truncated Branch Hash to a string, e.g. #abcdef
displayBranchHash :: Branch.Hash -> String
displayBranchHash = ("#" <>) . Text.unpack . Hash.base32Hex . Causal.unRawHash

View File

@ -338,3 +338,19 @@ foo = let
.> load scratch.u
```
## Nested fences
```ucm
.> load unison-src/transcripts-round-trip/nested.u
.> add
```
```ucm
.> edit nested
.> undo
```
```ucm
.> load unison-src/transcripts-round-trip/nested.u
```

View File

@ -34,15 +34,15 @@ x = 1 + 1
most recent, along with the command that got us there. Try:
`fork 2 .old`
`fork #ehfimtkqge .old` to make an old namespace
`fork #3c9e0ekrve .old` to make an old namespace
accessible again,
`reset-root #ehfimtkqge` to reset the root namespace and
`reset-root #3c9e0ekrve` to reset the root namespace and
its history to that of the
specified namespace.
1. #edkeq4dlqo : add
2. #ehfimtkqge : builtins.mergeio
1. #2l4u38r8o4 : add
2. #3c9e0ekrve : builtins.mergeio
3. #sjg2v58vn2 : (initial reflogged namespace)
.> reset-root 2
@ -116,17 +116,17 @@ Without the above stanza, the `edit` will send the definition to the most recent
most recent, along with the command that got us there. Try:
`fork 2 .old`
`fork #ehfimtkqge .old` to make an old namespace
`fork #3c9e0ekrve .old` to make an old namespace
accessible again,
`reset-root #ehfimtkqge` to reset the root namespace and
`reset-root #3c9e0ekrve` to reset the root namespace and
its history to that of the
specified namespace.
1. #dne7ugdlmg : add
2. #ehfimtkqge : reset-root #ehfimtkqge
3. #edkeq4dlqo : add
4. #ehfimtkqge : builtins.mergeio
1. #il1nrbvapm : add
2. #3c9e0ekrve : reset-root #3c9e0ekrve
3. #2l4u38r8o4 : add
4. #3c9e0ekrve : builtins.mergeio
5. #sjg2v58vn2 : (initial reflogged namespace)
.> reset-root 2
@ -191,19 +191,19 @@ f x = let
most recent, along with the command that got us there. Try:
`fork 2 .old`
`fork #ehfimtkqge .old` to make an old namespace
`fork #3c9e0ekrve .old` to make an old namespace
accessible again,
`reset-root #ehfimtkqge` to reset the root namespace and
`reset-root #3c9e0ekrve` to reset the root namespace and
its history to that of the
specified namespace.
1. #ps96u84es8 : add
2. #ehfimtkqge : reset-root #ehfimtkqge
3. #dne7ugdlmg : add
4. #ehfimtkqge : reset-root #ehfimtkqge
5. #edkeq4dlqo : add
6. #ehfimtkqge : builtins.mergeio
1. #ujscu5crkl : add
2. #3c9e0ekrve : reset-root #3c9e0ekrve
3. #il1nrbvapm : add
4. #3c9e0ekrve : reset-root #3c9e0ekrve
5. #2l4u38r8o4 : add
6. #3c9e0ekrve : builtins.mergeio
7. #sjg2v58vn2 : (initial reflogged namespace)
.> reset-root 2
@ -273,21 +273,21 @@ h xs = match xs with
most recent, along with the command that got us there. Try:
`fork 2 .old`
`fork #ehfimtkqge .old` to make an old namespace
`fork #3c9e0ekrve .old` to make an old namespace
accessible again,
`reset-root #ehfimtkqge` to reset the root namespace and
`reset-root #3c9e0ekrve` to reset the root namespace and
its history to that of the
specified namespace.
1. #13i3s2120q : add
2. #ehfimtkqge : reset-root #ehfimtkqge
3. #ps96u84es8 : add
4. #ehfimtkqge : reset-root #ehfimtkqge
5. #dne7ugdlmg : add
6. #ehfimtkqge : reset-root #ehfimtkqge
7. #edkeq4dlqo : add
8. #ehfimtkqge : builtins.mergeio
1. #nidbht5ocv : add
2. #3c9e0ekrve : reset-root #3c9e0ekrve
3. #ujscu5crkl : add
4. #3c9e0ekrve : reset-root #3c9e0ekrve
5. #il1nrbvapm : add
6. #3c9e0ekrve : reset-root #3c9e0ekrve
7. #2l4u38r8o4 : add
8. #3c9e0ekrve : builtins.mergeio
9. #sjg2v58vn2 : (initial reflogged namespace)
.> reset-root 2
@ -353,23 +353,23 @@ foo n _ = n
most recent, along with the command that got us there. Try:
`fork 2 .old`
`fork #ehfimtkqge .old` to make an old namespace
`fork #3c9e0ekrve .old` to make an old namespace
accessible again,
`reset-root #ehfimtkqge` to reset the root namespace and
`reset-root #3c9e0ekrve` to reset the root namespace and
its history to that of the
specified namespace.
1. #29at46a9as : add
2. #ehfimtkqge : reset-root #ehfimtkqge
3. #13i3s2120q : add
4. #ehfimtkqge : reset-root #ehfimtkqge
5. #ps96u84es8 : add
6. #ehfimtkqge : reset-root #ehfimtkqge
7. #dne7ugdlmg : add
8. #ehfimtkqge : reset-root #ehfimtkqge
9. #edkeq4dlqo : add
10. #ehfimtkqge : builtins.mergeio
1. #rrjp642tnp : add
2. #3c9e0ekrve : reset-root #3c9e0ekrve
3. #nidbht5ocv : add
4. #3c9e0ekrve : reset-root #3c9e0ekrve
5. #ujscu5crkl : add
6. #3c9e0ekrve : reset-root #3c9e0ekrve
7. #il1nrbvapm : add
8. #3c9e0ekrve : reset-root #3c9e0ekrve
9. #2l4u38r8o4 : add
10. #3c9e0ekrve : builtins.mergeio
11. #sjg2v58vn2 : (initial reflogged namespace)
.> reset-root 2
@ -432,25 +432,25 @@ foo =
most recent, along with the command that got us there. Try:
`fork 2 .old`
`fork #ehfimtkqge .old` to make an old namespace
`fork #3c9e0ekrve .old` to make an old namespace
accessible again,
`reset-root #ehfimtkqge` to reset the root namespace and
`reset-root #3c9e0ekrve` to reset the root namespace and
its history to that of the
specified namespace.
1. #7b35f5f5ue : add
2. #ehfimtkqge : reset-root #ehfimtkqge
3. #29at46a9as : add
4. #ehfimtkqge : reset-root #ehfimtkqge
5. #13i3s2120q : add
6. #ehfimtkqge : reset-root #ehfimtkqge
7. #ps96u84es8 : add
8. #ehfimtkqge : reset-root #ehfimtkqge
9. #dne7ugdlmg : add
10. #ehfimtkqge : reset-root #ehfimtkqge
11. #edkeq4dlqo : add
12. #ehfimtkqge : builtins.mergeio
1. #876bkg1cir : add
2. #3c9e0ekrve : reset-root #3c9e0ekrve
3. #rrjp642tnp : add
4. #3c9e0ekrve : reset-root #3c9e0ekrve
5. #nidbht5ocv : add
6. #3c9e0ekrve : reset-root #3c9e0ekrve
7. #ujscu5crkl : add
8. #3c9e0ekrve : reset-root #3c9e0ekrve
9. #il1nrbvapm : add
10. #3c9e0ekrve : reset-root #3c9e0ekrve
11. #2l4u38r8o4 : add
12. #3c9e0ekrve : builtins.mergeio
13. #sjg2v58vn2 : (initial reflogged namespace)
.> reset-root 2
@ -1005,3 +1005,63 @@ foo = let
foo : 'Nat
```
## Nested fences
```ucm
.> load unison-src/transcripts-round-trip/nested.u
I found and typechecked these definitions in
unison-src/transcripts-round-trip/nested.u. If you do an `add`
or `update`, here's how your codebase would change:
⍟ These new definitions are ok to `add`:
nested : Doc2
.> add
⍟ I've added these definitions:
nested : Doc2
```
```ucm
.> edit nested
☝️
I added these definitions to the top of
/Users/runar/work/unison/unison-src/transcripts-round-trip/nested.u
nested : Doc2
nested =
{{ ```` raw
```unison
r = "boopydoo"
```
```` }}
You can edit them there, then do `update` to replace the
definitions currently in this namespace.
.> undo
Here are the changes I undid
Added definitions:
1. nested : Doc2
```
```ucm
.> load unison-src/transcripts-round-trip/nested.u
I found and typechecked these definitions in
unison-src/transcripts-round-trip/nested.u. If you do an `add`
or `update`, here's how your codebase would change:
⍟ These new definitions are ok to `add`:
nested : Doc2
```

View File

@ -0,0 +1,10 @@
nested = {{
````raw
```unison
r = "boopydoo"
```
````
}}

View File

@ -12,31 +12,11 @@
-- generated with:
-- openssl req -newkey rsa:2048 -subj '/CN=test.unison.cloud/O=Unison/C=US' -nodes -keyout key.pem -x509 -days 3650 -out cert.pem
join strs = List.foldLeft (a -> b -> b ++ a ++ "\n") "" strs
self_signed_key_pem="-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDtV0Lqk9i5DKJG\ne5zwDFuxHxSxhOygCuq6Jl4xonsjl4hdvXxUUiuqxGGbv4x9HSvavpHwyriGiIRQ\noIjanWiNK9Jp6VDYWOvErnTG/+Rfm1vCoUKQvn8lDrD9knSPUoTz3Cz7JS8FE/rr\nFR3IRyXa0gpXmvIwX16SeCS/Lb/Le9o1HJh9DrkxVyoFq3zlX1OE0AVV0a014IDB\nNprqLITwiVzyDPQkP8rbJF9WPI5afzW8+3+v5UanIFknOOPaJl8pf3gmqI5g8fxk\n/SSMlPgnLd1Fi7h90gBygdpJw3do3/ZA1IOvmFQ+LXE1xtqU1Ay3f3At3DiJgTxP\n8mwBYdtdAgMBAAECggEBAMo85QRF3xIvtcchZeUWYrtWpKdvgMIPC1x7fSAGN69o\nXAakg+DF8/ebRyET435o8QmAAZOQ6hOZGEYrxPGj14cTpEQjT4RKoPwDO/al7c+Z\n7mK2TqZP7L+C+UXZGgFWa3vwTVPjp2FIWTMf1zTli1geSjnECkM1wLxGK+nL7fZQ\nesHXPkJJG5AqzA84bJ/fY5OQ/dfcCxnHEv5XpHPq6VFgXg7jtcNbr1R9EBiQfreN\nU7Hd38R77jYjL1fT71HwEUQ0cwavfxTu0jZFXJxEC7CC1J65QXUguZXLf9vwgSB0\nm0gZgeJlQ905bDJrxUcqCFxdROy/SndP6qFnJSCsfwECgYEA+2cld/WCieUGstJd\njsIrJ6f/e+uuOSTnGTtnsBX6KoiHdcg3sVVVK18xI9El9V+YX9SjN37XeGFe/Wzu\ngE3M4A3Jqz7cgdNj/PaKjqQwJWNbcJnL5ku6eQvcAIpc5gAZxXVCPIbY1ZpeYcsh\nMwr3cOEpQu8UVFBbn/OeJ1r07dECgYEA8a5J3Ls5PSxXq8NDrkAxt3vUJIWLGQQJ\nbV2aGDI2XP2N+vh2WML9rlFeyyBOeRxK9TsErVOaEeOcQZV97//fzIGxCU+SXyiC\nnVMXT2U1mzOu5qPfzLO5Ga4sunxqKDman6NM2IPw2NPA7zMWNQMEIHAerwYZzjm5\nB5tFcMA8e80CgYBgF8rwkTz2LD5lN5dfK8SHAeXbnfgYC4zxzg0R9zSJ8WmlkYQI\nGk/VpisIP7c8lO+PIZ3JZohBkSZXw71d+V7n/R0qgXqTfRNo62uGnidxAws+fOq8\n+hEql2feJQThPQScvvc0X26eJsUQqC3mbripwsacuPmSSKzc9Kds741TIQKBgQCd\nXnG2CytATAliTKlbY218HmOKzHJAfcJttk9KhhekAW5cB0F4lq98vHtPJOA0OFoO\nyLlI63EdSOpMQj1Y83IUxjYy699Rmx1BuAMrral0P/kZMYfe0QAsWp/BZpXxT2EB\npeG58l/3sBqnJsrFBgu/24H/UaeoAyoaa96Rhntb2QKBgQCSEkcUnzTvoUyMFN14\n8NttxOUZiSsCmgoXk6Rk2QKyCPsJocGS4BffGt3kOMcotz/0YsvM1TBBLB7vIaAy\nE1eWLBxK4yYeS8dKXwiCZn170yaJyjoBwZC1RgqQiKa5Y22Di7KjJoMa4Da8Tk4z\nFbE5dBApbLhvNTyQ7BHZxlfmdg==\n-----END PRIVATE KEY-----"
self_signed_cert_pem2 = join [
"-----BEGIN CERTIFICATE-----",
"MIIDVTCCAj2gAwIBAgIUdMNT5sYMfDJYH48Rh8LrlN+5wwgwDQYJKoZIhvcNAQEL",
"BQAwOjEaMBgGA1UEAwwRdGVzdC51bmlzb24uY2xvdWQxDzANBgNVBAoMBlVuaXNv",
"bjELMAkGA1UEBhMCVVMwHhcNMjIwMTI0MjAxNzQ2WhcNMzIwMTIyMjAxNzQ2WjA6",
"MRowGAYDVQQDDBF0ZXN0LnVuaXNvbi5jbG91ZDEPMA0GA1UECgwGVW5pc29uMQsw",
"CQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO1XQuqT",
"2LkMokZ7nPAMW7EfFLGE7KAK6romXjGieyOXiF29fFRSK6rEYZu/jH0dK9q+kfDK",
"uIaIhFCgiNqdaI0r0mnpUNhY68SudMb/5F+bW8KhQpC+fyUOsP2SdI9ShPPcLPsl",
"LwUT+usVHchHJdrSClea8jBfXpJ4JL8tv8t72jUcmH0OuTFXKgWrfOVfU4TQBVXR",
"rTXggME2muoshPCJXPIM9CQ/ytskX1Y8jlp/Nbz7f6/lRqcgWSc449omXyl/eCao",
"jmDx/GT9JIyU+Cct3UWLuH3SAHKB2knDd2jf9kDUg6+YVD4tcTXG2pTUDLd/cC3c",
"OImBPE/ybAFh210CAwEAAaNTMFEwHQYDVR0OBBYEFIfwxpuqtqxfCpaJGW32jH2J",
"NbnYMB8GA1UdIwQYMBaAFIfwxpuqtqxfCpaJGW32jH2JNbnYMA8GA1UdEwEB/wQF",
"MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKh7EDo5XjSd6J190WGH3V8v49J0Sh8M",
"P7APe1eL8eTkW1Vh7/QCOhRpkSnyCz2OxJjjeFVAsCO3aLxlRM6wQZQKXu45iM2U",
"iPmv7ECS5xUn7LqRZd/JG1P6jvRPtBC1+oqA+NNDe27wzQp3rWyDG3pWZga8jJfW",
"q+2xQ+s6GfzszxYZ/8MLn4zaUSymnOA+70yQ8czXkSO7MT2jJ7QDX8jxuJPZZARW",
"uXeAYPRqD+b4MjdBATEtxgPTDWEi8gtfHFGUgInFhD4hOu+D3NLiE6lfR5brUqpQ",
"Z4v8prCI8OjGSUx1dIJhqQHB5O0vdaxO0hkVdfqDVE93UrGBPwBRDlo=",
"-----END CERTIFICATE-----"]
self_signed_cert_pem2 = "-----BEGIN CERTIFICATE-----\nMIIDVTCCAj2gAwIBAgIUdMNT5sYMfDJYH48Rh8LrlN+5wwgwDQYJKoZIhvcNAQEL\nBQAwOjEaMBgGA1UEAwwRdGVzdC51bmlzb24uY2xvdWQxDzANBgNVBAoMBlVuaXNv\nbjELMAkGA1UEBhMCVVMwHhcNMjIwMTI0MjAxNzQ2WhcNMzIwMTIyMjAxNzQ2WjA6\nMRowGAYDVQQDDBF0ZXN0LnVuaXNvbi5jbG91ZDEPMA0GA1UECgwGVW5pc29uMQsw\nCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO1XQuqT\n2LkMokZ7nPAMW7EfFLGE7KAK6romXjGieyOXiF29fFRSK6rEYZu/jH0dK9q+kfDK\nuIaIhFCgiNqdaI0r0mnpUNhY68SudMb/5F+bW8KhQpC+fyUOsP2SdI9ShPPcLPsl\nLwUT+usVHchHJdrSClea8jBfXpJ4JL8tv8t72jUcmH0OuTFXKgWrfOVfU4TQBVXR\nrTXggME2muoshPCJXPIM9CQ/ytskX1Y8jlp/Nbz7f6/lRqcgWSc449omXyl/eCao\njmDx/GT9JIyU+Cct3UWLuH3SAHKB2knDd2jf9kDUg6+YVD4tcTXG2pTUDLd/cC3c\nOImBPE/ybAFh210CAwEAAaNTMFEwHQYDVR0OBBYEFIfwxpuqtqxfCpaJGW32jH2J\nNbnYMB8GA1UdIwQYMBaAFIfwxpuqtqxfCpaJGW32jH2JNbnYMA8GA1UdEwEB/wQF\nMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKh7EDo5XjSd6J190WGH3V8v49J0Sh8M\nP7APe1eL8eTkW1Vh7/QCOhRpkSnyCz2OxJjjeFVAsCO3aLxlRM6wQZQKXu45iM2U\niPmv7ECS5xUn7LqRZd/JG1P6jvRPtBC1+oqA+NNDe27wzQp3rWyDG3pWZga8jJfW\nq+2xQ+s6GfzszxYZ/8MLn4zaUSymnOA+70yQ8czXkSO7MT2jJ7QDX8jxuJPZZARW\nuXeAYPRqD+b4MjdBATEtxgPTDWEi8gtfHFGUgInFhD4hOu+D3NLiE6lfR5brUqpQ\nZ4v8prCI8OjGSUx1dIJhqQHB5O0vdaxO0hkVdfqDVE93UrGBPwBRDlo=\n-----END CERTIFICATE-----"
not_a_cert = "-----BEGIN SCHERMIFICATE-----\n-----END SCHERMIFICATE-----"
```
```ucm:hide
@ -48,10 +28,14 @@ self_signed_cert_pem2 = join [
First lets make sure we can load our cert and private key
```unison
test> match (decodeCert.impl (toUtf8 self_signed_cert_pem2) with
test> this_should_work=match (decodeCert.impl (toUtf8 self_signed_cert_pem2) with
Left (Failure _ t _) -> [Fail t]
Right _ -> [Ok "succesfully decoded self_signed_pem"]
test> this_should_not_work=match (decodeCert.impl (toUtf8 not_a_cert) with
Left _ -> [Ok "failed"]
Right _ -> [Fail "um, that was a schmificate"]
```
Test handshaking a client/server a local TCP connection using our
@ -89,21 +73,15 @@ serverThread portVar toSend = 'let
-- start listening to the socket so that it starts accepting connections
listen sock
watch ("server listening on port: " ++ (toText port)) ()
-- accept a single connection on this socket
sock' = socketAccept sock
-- attach TLS to our TCP connection
tls = newServer tlsconfig sock'
printLine "oooooooooooooooo"
-- try to handshake the TLS connection with the client
match handshake.impl tls with
Right _ -> printLine "no error on server side"
Left (Failure _ t _) -> printLine ("error " ++ t)
reraise (handshake.impl tls)
printLine "iiiiiiiiiiiiiii"
-- send our message over our tls channel
send tls (toUtf8 toSend)
terminate tls
@ -128,21 +106,16 @@ testClient cert hostname portVar _ =
-- create a tcp connection with the server
watch ("client connecting to port: " ++ (toText port)) ()
sock = clientSocket "127.0.0.1" (Nat.toText port)
-- attach the TLS client to the TCP socket
tls = newClient tlsconfig sock
printLine "5555555555555555555"
-- verify that the server presents us with a certificate chain for
-- test.unison.cloud originating with a certificate we trust, and
-- that the server can use a compatible TLS version and cipher
match handshake.impl tls with
Right _ -> printLine "no eeror on client side"
Left (Failure _ t _) -> printLine ("error " ++ t)
reraise (handshake.impl tls)
printLine "666666666666666666"
-- receive a message from the server
fromUtf8 (receive tls)
@ -207,24 +180,19 @@ testCNReject _ =
portVar = !MVar.newEmpty
toSend = "12345"
tid = forkComp (serverThread portVar toSend)
unsafeRun! '(printLine "started tid")
-- Client
testClient None "wrong.host.name" portVar |> toEither |> checkError |> emit
unsafeRun! '(printLine "started client")
kill.impl tid
unsafeRun! '(printLine "killed")
runTest test
```
```ucm
--- STU: I'm commenting out this because there is a problem with Tls.handshake, see #2834
--- .> add
--- .> io.test testConnectSelfSigned
--- .> io.test testCAReject
--- .> io.test testCNReject
.> add
.> io.test testConnectSelfSigned
.> io.test testCAReject
.> io.test testCNReject
```

View File

@ -4,31 +4,11 @@
-- generated with:
-- openssl req -newkey rsa:2048 -subj '/CN=test.unison.cloud/O=Unison/C=US' -nodes -keyout key.pem -x509 -days 3650 -out cert.pem
join strs = List.foldLeft (a -> b -> b ++ a ++ "\n") "" strs
self_signed_key_pem="-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDtV0Lqk9i5DKJG\ne5zwDFuxHxSxhOygCuq6Jl4xonsjl4hdvXxUUiuqxGGbv4x9HSvavpHwyriGiIRQ\noIjanWiNK9Jp6VDYWOvErnTG/+Rfm1vCoUKQvn8lDrD9knSPUoTz3Cz7JS8FE/rr\nFR3IRyXa0gpXmvIwX16SeCS/Lb/Le9o1HJh9DrkxVyoFq3zlX1OE0AVV0a014IDB\nNprqLITwiVzyDPQkP8rbJF9WPI5afzW8+3+v5UanIFknOOPaJl8pf3gmqI5g8fxk\n/SSMlPgnLd1Fi7h90gBygdpJw3do3/ZA1IOvmFQ+LXE1xtqU1Ay3f3At3DiJgTxP\n8mwBYdtdAgMBAAECggEBAMo85QRF3xIvtcchZeUWYrtWpKdvgMIPC1x7fSAGN69o\nXAakg+DF8/ebRyET435o8QmAAZOQ6hOZGEYrxPGj14cTpEQjT4RKoPwDO/al7c+Z\n7mK2TqZP7L+C+UXZGgFWa3vwTVPjp2FIWTMf1zTli1geSjnECkM1wLxGK+nL7fZQ\nesHXPkJJG5AqzA84bJ/fY5OQ/dfcCxnHEv5XpHPq6VFgXg7jtcNbr1R9EBiQfreN\nU7Hd38R77jYjL1fT71HwEUQ0cwavfxTu0jZFXJxEC7CC1J65QXUguZXLf9vwgSB0\nm0gZgeJlQ905bDJrxUcqCFxdROy/SndP6qFnJSCsfwECgYEA+2cld/WCieUGstJd\njsIrJ6f/e+uuOSTnGTtnsBX6KoiHdcg3sVVVK18xI9El9V+YX9SjN37XeGFe/Wzu\ngE3M4A3Jqz7cgdNj/PaKjqQwJWNbcJnL5ku6eQvcAIpc5gAZxXVCPIbY1ZpeYcsh\nMwr3cOEpQu8UVFBbn/OeJ1r07dECgYEA8a5J3Ls5PSxXq8NDrkAxt3vUJIWLGQQJ\nbV2aGDI2XP2N+vh2WML9rlFeyyBOeRxK9TsErVOaEeOcQZV97//fzIGxCU+SXyiC\nnVMXT2U1mzOu5qPfzLO5Ga4sunxqKDman6NM2IPw2NPA7zMWNQMEIHAerwYZzjm5\nB5tFcMA8e80CgYBgF8rwkTz2LD5lN5dfK8SHAeXbnfgYC4zxzg0R9zSJ8WmlkYQI\nGk/VpisIP7c8lO+PIZ3JZohBkSZXw71d+V7n/R0qgXqTfRNo62uGnidxAws+fOq8\n+hEql2feJQThPQScvvc0X26eJsUQqC3mbripwsacuPmSSKzc9Kds741TIQKBgQCd\nXnG2CytATAliTKlbY218HmOKzHJAfcJttk9KhhekAW5cB0F4lq98vHtPJOA0OFoO\nyLlI63EdSOpMQj1Y83IUxjYy699Rmx1BuAMrral0P/kZMYfe0QAsWp/BZpXxT2EB\npeG58l/3sBqnJsrFBgu/24H/UaeoAyoaa96Rhntb2QKBgQCSEkcUnzTvoUyMFN14\n8NttxOUZiSsCmgoXk6Rk2QKyCPsJocGS4BffGt3kOMcotz/0YsvM1TBBLB7vIaAy\nE1eWLBxK4yYeS8dKXwiCZn170yaJyjoBwZC1RgqQiKa5Y22Di7KjJoMa4Da8Tk4z\nFbE5dBApbLhvNTyQ7BHZxlfmdg==\n-----END PRIVATE KEY-----"
self_signed_cert_pem2 = join [
"-----BEGIN CERTIFICATE-----",
"MIIDVTCCAj2gAwIBAgIUdMNT5sYMfDJYH48Rh8LrlN+5wwgwDQYJKoZIhvcNAQEL",
"BQAwOjEaMBgGA1UEAwwRdGVzdC51bmlzb24uY2xvdWQxDzANBgNVBAoMBlVuaXNv",
"bjELMAkGA1UEBhMCVVMwHhcNMjIwMTI0MjAxNzQ2WhcNMzIwMTIyMjAxNzQ2WjA6",
"MRowGAYDVQQDDBF0ZXN0LnVuaXNvbi5jbG91ZDEPMA0GA1UECgwGVW5pc29uMQsw",
"CQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO1XQuqT",
"2LkMokZ7nPAMW7EfFLGE7KAK6romXjGieyOXiF29fFRSK6rEYZu/jH0dK9q+kfDK",
"uIaIhFCgiNqdaI0r0mnpUNhY68SudMb/5F+bW8KhQpC+fyUOsP2SdI9ShPPcLPsl",
"LwUT+usVHchHJdrSClea8jBfXpJ4JL8tv8t72jUcmH0OuTFXKgWrfOVfU4TQBVXR",
"rTXggME2muoshPCJXPIM9CQ/ytskX1Y8jlp/Nbz7f6/lRqcgWSc449omXyl/eCao",
"jmDx/GT9JIyU+Cct3UWLuH3SAHKB2knDd2jf9kDUg6+YVD4tcTXG2pTUDLd/cC3c",
"OImBPE/ybAFh210CAwEAAaNTMFEwHQYDVR0OBBYEFIfwxpuqtqxfCpaJGW32jH2J",
"NbnYMB8GA1UdIwQYMBaAFIfwxpuqtqxfCpaJGW32jH2JNbnYMA8GA1UdEwEB/wQF",
"MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKh7EDo5XjSd6J190WGH3V8v49J0Sh8M",
"P7APe1eL8eTkW1Vh7/QCOhRpkSnyCz2OxJjjeFVAsCO3aLxlRM6wQZQKXu45iM2U",
"iPmv7ECS5xUn7LqRZd/JG1P6jvRPtBC1+oqA+NNDe27wzQp3rWyDG3pWZga8jJfW",
"q+2xQ+s6GfzszxYZ/8MLn4zaUSymnOA+70yQ8czXkSO7MT2jJ7QDX8jxuJPZZARW",
"uXeAYPRqD+b4MjdBATEtxgPTDWEi8gtfHFGUgInFhD4hOu+D3NLiE6lfR5brUqpQ",
"Z4v8prCI8OjGSUx1dIJhqQHB5O0vdaxO0hkVdfqDVE93UrGBPwBRDlo=",
"-----END CERTIFICATE-----"]
self_signed_cert_pem2 = "-----BEGIN CERTIFICATE-----\nMIIDVTCCAj2gAwIBAgIUdMNT5sYMfDJYH48Rh8LrlN+5wwgwDQYJKoZIhvcNAQEL\nBQAwOjEaMBgGA1UEAwwRdGVzdC51bmlzb24uY2xvdWQxDzANBgNVBAoMBlVuaXNv\nbjELMAkGA1UEBhMCVVMwHhcNMjIwMTI0MjAxNzQ2WhcNMzIwMTIyMjAxNzQ2WjA6\nMRowGAYDVQQDDBF0ZXN0LnVuaXNvbi5jbG91ZDEPMA0GA1UECgwGVW5pc29uMQsw\nCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO1XQuqT\n2LkMokZ7nPAMW7EfFLGE7KAK6romXjGieyOXiF29fFRSK6rEYZu/jH0dK9q+kfDK\nuIaIhFCgiNqdaI0r0mnpUNhY68SudMb/5F+bW8KhQpC+fyUOsP2SdI9ShPPcLPsl\nLwUT+usVHchHJdrSClea8jBfXpJ4JL8tv8t72jUcmH0OuTFXKgWrfOVfU4TQBVXR\nrTXggME2muoshPCJXPIM9CQ/ytskX1Y8jlp/Nbz7f6/lRqcgWSc449omXyl/eCao\njmDx/GT9JIyU+Cct3UWLuH3SAHKB2knDd2jf9kDUg6+YVD4tcTXG2pTUDLd/cC3c\nOImBPE/ybAFh210CAwEAAaNTMFEwHQYDVR0OBBYEFIfwxpuqtqxfCpaJGW32jH2J\nNbnYMB8GA1UdIwQYMBaAFIfwxpuqtqxfCpaJGW32jH2JNbnYMA8GA1UdEwEB/wQF\nMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKh7EDo5XjSd6J190WGH3V8v49J0Sh8M\nP7APe1eL8eTkW1Vh7/QCOhRpkSnyCz2OxJjjeFVAsCO3aLxlRM6wQZQKXu45iM2U\niPmv7ECS5xUn7LqRZd/JG1P6jvRPtBC1+oqA+NNDe27wzQp3rWyDG3pWZga8jJfW\nq+2xQ+s6GfzszxYZ/8MLn4zaUSymnOA+70yQ8czXkSO7MT2jJ7QDX8jxuJPZZARW\nuXeAYPRqD+b4MjdBATEtxgPTDWEi8gtfHFGUgInFhD4hOu+D3NLiE6lfR5brUqpQ\nZ4v8prCI8OjGSUx1dIJhqQHB5O0vdaxO0hkVdfqDVE93UrGBPwBRDlo=\n-----END CERTIFICATE-----"
not_a_cert = "-----BEGIN SCHERMIFICATE-----\n-----END SCHERMIFICATE-----"
```
# Using an alternative certificate store
@ -36,10 +16,14 @@ self_signed_cert_pem2 = join [
First lets make sure we can load our cert and private key
```unison
test> match (decodeCert.impl (toUtf8 self_signed_cert_pem2) with
test> this_should_work=match (decodeCert.impl (toUtf8 self_signed_cert_pem2) with
Left (Failure _ t _) -> [Fail t]
Right _ -> [Ok "succesfully decoded self_signed_pem"]
test> this_should_not_work=match (decodeCert.impl (toUtf8 not_a_cert) with
Left _ -> [Ok "failed"]
Right _ -> [Fail "um, that was a schmificate"]
```
```ucm
@ -50,14 +34,19 @@ test> match (decodeCert.impl (toUtf8 self_signed_cert_pem2) with
⍟ These new definitions are ok to `add`:
test.ko630itb5m (Unison bug, unknown term)
this_should_not_work : [Result]
this_should_work : [Result]
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
1 | test> match (decodeCert.impl (toUtf8 self_signed_cert_pem2) with
1 | test> this_should_work=match (decodeCert.impl (toUtf8 self_signed_cert_pem2) with
✅ Passed succesfully decoded self_signed_pem
5 | test> this_should_not_work=match (decodeCert.impl (toUtf8 not_a_cert) with
✅ Passed failed
```
Test handshaking a client/server a local TCP connection using our
@ -95,21 +84,15 @@ serverThread portVar toSend = 'let
-- start listening to the socket so that it starts accepting connections
listen sock
watch ("server listening on port: " ++ (toText port)) ()
-- accept a single connection on this socket
sock' = socketAccept sock
-- attach TLS to our TCP connection
tls = newServer tlsconfig sock'
printLine "oooooooooooooooo"
-- try to handshake the TLS connection with the client
match handshake.impl tls with
Right _ -> printLine "no error on server side"
Left (Failure _ t _) -> printLine ("error " ++ t)
reraise (handshake.impl tls)
printLine "iiiiiiiiiiiiiii"
-- send our message over our tls channel
send tls (toUtf8 toSend)
terminate tls
@ -134,21 +117,16 @@ testClient cert hostname portVar _ =
-- create a tcp connection with the server
watch ("client connecting to port: " ++ (toText port)) ()
sock = clientSocket "127.0.0.1" (Nat.toText port)
-- attach the TLS client to the TCP socket
tls = newClient tlsconfig sock
printLine "5555555555555555555"
-- verify that the server presents us with a certificate chain for
-- test.unison.cloud originating with a certificate we trust, and
-- that the server can use a compatible TLS version and cipher
match handshake.impl tls with
Right _ -> printLine "no eeror on client side"
Left (Failure _ t _) -> printLine ("error " ++ t)
reraise (handshake.impl tls)
printLine "666666666666666666"
-- receive a message from the server
fromUtf8 (receive tls)
@ -213,15 +191,12 @@ testCNReject _ =
portVar = !MVar.newEmpty
toSend = "12345"
tid = forkComp (serverThread portVar toSend)
unsafeRun! '(printLine "started tid")
-- Client
testClient None "wrong.host.name" portVar |> toEither |> checkError |> emit
unsafeRun! '(printLine "started client")
kill.impl tid
unsafeRun! '(printLine "killed")
runTest test
```
@ -245,9 +220,48 @@ testCNReject _ =
```
```ucm
--- STU: I'm commenting out this because there is a problem with Tls.handshake, see #2834
--- .> add
--- .> io.test testConnectSelfSigned
--- .> io.test testCAReject
--- .> io.test testCNReject
.> add
⍟ I've added these definitions:
serverThread : MVar Nat -> Text -> '{IO} ()
testCAReject : '{IO} [Result]
testCNReject : '{IO} [Result]
testClient : Optional SignedCert
-> Text
-> MVar Nat
-> '{IO, Exception} Text
testConnectSelfSigned : '{IO} [Result]
.> io.test testConnectSelfSigned
New test results:
◉ testConnectSelfSigned should have reaped what we've sown
✅ 1 test(s) passing
Tip: Use view testConnectSelfSigned to view the source of a
test.
.> io.test testCAReject
New test results:
◉ testCAReject correctly rejected self-signed cert
✅ 1 test(s) passing
Tip: Use view testCAReject to view the source of a test.
.> io.test testCNReject
New test results:
◉ testCNReject correctly rejected self-signed cert
✅ 1 test(s) passing
Tip: Use view testCNReject to view the source of a test.
```

View File

@ -30,7 +30,7 @@ The child branch has a single history node representing the addition of `parent.
#0r73mam57g (start of history)
1. #0r73mam57g (start of history)
```
If we add another thing to the child namespace it should add another history node to both the child and parent.
@ -51,26 +51,26 @@ parent.child.thing2 = "parent.child.thing2"
Note: The most recent namespace hash is immediately below this
message.
#2hv7t9lp40
1. #2hv7t9lp40
+ Adds / updates:
child.thing2
#i9lji1bli0 (start of history)
2. #i9lji1bli0 (start of history)
.> history parent.child
Note: The most recent namespace hash is immediately below this
message.
#ggnrs01131
1. #ggnrs01131
+ Adds / updates:
thing2
#0r73mam57g (start of history)
2. #0r73mam57g (start of history)
```
## Forking off some history on a separate branch
@ -101,19 +101,19 @@ The child should have a new history node after adding `thing3`
Note: The most recent namespace hash is immediately below this
message.
#9rcfgbsp81
1. #9rcfgbsp81
+ Adds / updates:
thing3
#ggnrs01131
2. #ggnrs01131
+ Adds / updates:
thing2
#0r73mam57g (start of history)
3. #0r73mam57g (start of history)
```
## Saving our parent state
@ -143,19 +143,19 @@ For a squash merge, when I squash-merge back into parent, we expect `parent_fork
Note: The most recent namespace hash is immediately below this
message.
#594e0e1p39
1. #594e0e1p39
+ Adds / updates:
child.thing3
#2hv7t9lp40
2. #2hv7t9lp40
+ Adds / updates:
child.thing2
#i9lji1bli0 (start of history)
3. #i9lji1bli0 (start of history)
```
Notice that with the current behaviour, the history of `parent.child` is completely wiped out, containing nothing from the source OR destination.
@ -166,32 +166,32 @@ Notice that with the current behaviour, the history of `parent.child` is complet
Note: The most recent namespace hash is immediately below this
message.
#ggnrs01131
1. #ggnrs01131
+ Adds / updates:
thing2
#0r73mam57g (start of history)
2. #0r73mam57g (start of history)
.> history parent_fork.child
Note: The most recent namespace hash is immediately below this
message.
#9rcfgbsp81
1. #9rcfgbsp81
+ Adds / updates:
thing3
#ggnrs01131
2. #ggnrs01131
+ Adds / updates:
thing2
#0r73mam57g (start of history)
3. #0r73mam57g (start of history)
.> history parent_squash_base.child
@ -200,7 +200,7 @@ Notice that with the current behaviour, the history of `parent.child` is complet
#19fd4mhpp4 (start of history)
1. #19fd4mhpp4 (start of history)
```
## Standard merge
@ -226,19 +226,19 @@ For a standard merge, if I merge back into parent, we expect `parent_fork.child.
Note: The most recent namespace hash is immediately below this
message.
#mtn8sha7gd
1. #mtn8sha7gd
+ Adds / updates:
child.thing3
#2hv7t9lp40
2. #2hv7t9lp40
+ Adds / updates:
child.thing2
#i9lji1bli0 (start of history)
3. #i9lji1bli0 (start of history)
```
Child histories should also be *merged*.
@ -249,50 +249,50 @@ Child histories should also be *merged*.
Note: The most recent namespace hash is immediately below this
message.
#ggnrs01131
1. #ggnrs01131
+ Adds / updates:
thing2
#0r73mam57g (start of history)
2. #0r73mam57g (start of history)
.> history parent_fork.child
Note: The most recent namespace hash is immediately below this
message.
#9rcfgbsp81
1. #9rcfgbsp81
+ Adds / updates:
thing3
#ggnrs01131
2. #ggnrs01131
+ Adds / updates:
thing2
#0r73mam57g (start of history)
3. #0r73mam57g (start of history)
.> history parent_merge_base.child
Note: The most recent namespace hash is immediately below this
message.
#9rcfgbsp81
1. #9rcfgbsp81
+ Adds / updates:
thing3
#ggnrs01131
2. #ggnrs01131
+ Adds / updates:
thing2
#0r73mam57g (start of history)
3. #0r73mam57g (start of history)
```

View File

@ -67,9 +67,9 @@ Test that replace works with types
.scratch> view.patch patch
Edited Types: X#68k40ra7l7 -> X
Edited Types: 1. X#68k40ra7l7 -> 3. X
Edited Terms: #gjmq673r1v -> x
Edited Terms: 2. #gjmq673r1v -> 4. x
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as

View File

@ -39,7 +39,7 @@ Copy the patch and make sure it's still there.
.> view.patch foo.patch
Edited Terms: #gjmq673r1v -> x
Edited Terms: 1. #gjmq673r1v -> 2. x
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
@ -51,7 +51,7 @@ Copy the patch and make sure it's still there.
.> view.patch bar.patch
Edited Terms: #gjmq673r1v -> x
Edited Terms: 1. #gjmq673r1v -> 2. x
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as

View File

@ -18,7 +18,7 @@ x = 2
```
```ucm
.> delete.term-replacement #rrsqv1ogaq
.> delete.term-replacement 1
.> view.patch
```
@ -40,7 +40,7 @@ unique[b] type Foo = Foo | Bar
```
```ucm
.> delete.type-replacement #tsgi4cbf2h
.> delete.type-replacement 1
.> view.patch
```
@ -60,6 +60,6 @@ unique[bb] type bar = Foo | Bar
```ucm
.> update
.> view.patch
.> delete.type-replacement #gcg6p503b0
.> delete.type-replacement 1
.> view.patch
```

View File

@ -48,7 +48,7 @@ x = 2
.> view.patch
Edited Terms: x#rrsqv1ogaq -> x
Edited Terms: 1. x#gjmq673r1v -> 2. x
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
@ -56,7 +56,7 @@ x = 2
```
```ucm
.> delete.term-replacement #rrsqv1ogaq
.> delete.term-replacement 1
Done.
@ -113,7 +113,7 @@ unique[b] type Foo = Foo | Bar
.> view.patch
Edited Types: Foo#tsgi4cbf2h -> Foo
Edited Types: 1. Foo#ool30cf4ma -> 2. Foo
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
@ -121,7 +121,7 @@ unique[b] type Foo = Foo | Bar
```
```ucm
.> delete.type-replacement #tsgi4cbf2h
.> delete.type-replacement 1
Done.
@ -181,13 +181,13 @@ unique[bb] type bar = Foo | Bar
.> view.patch
Edited Types: bar#gcg6p503b0 -> bar
Edited Types: 1. bar#evhqg163jj -> 2. bar
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
.> delete.type-replacement #gcg6p503b0
.> delete.type-replacement 1
Done.

View File

@ -169,7 +169,7 @@ y = 2
```ucm
.hashdiff> add
.hashdiff> history
.hashdiff> diff.namespace #r0471p61ch #q9cdigs0bo
.hashdiff> diff.namespace 2 1
```
##

View File

@ -43,10 +43,10 @@ fslkdjflskdjflksjdf = 663
New name conflicts:
1. fslkdjflskdjflksjdf#4vn50bh8pk : Nat
1. fslkdjflskdjflksjdf#u520d1t9kc : Nat
2. ┌ fslkdjflskdjflksjdf#4vn50bh8pk : Nat
3. └ fslkdjflskdjflksjdf#9mupj24g1n : Nat
2. ┌ fslkdjflskdjflksjdf#sekb3fdsvb : Nat
3. └ fslkdjflskdjflksjdf#u520d1t9kc : Nat
Tip: You can use `todo` to see if this generated any work to
do in this namespace and `test` to run the tests. Or you
@ -57,33 +57,33 @@ fslkdjflskdjflksjdf = 663
Resolved name conflicts:
1. ┌ fslkdjflskdjflksjdf#4vn50bh8pk : Nat
2. └ fslkdjflskdjflksjdf#9mupj24g1n : Nat
1. ┌ fslkdjflskdjflksjdf#sekb3fdsvb : Nat
2. └ fslkdjflskdjflksjdf#u520d1t9kc : Nat
3. fslkdjflskdjflksjdf#4vn50bh8pk : Nat
3. fslkdjflskdjflksjdf#u520d1t9kc : Nat
Name changes:
Original Changes
4. x ┐ 5. abc (added)
6. fslkdjflskdjflksjdf#4vn50bh8pk ┘ 7. fslkdjflskdjflksjdf (added)
8. fslkdjflskdjflksjdf#4vn50bh8pk (removed)
6. fslkdjflskdjflksjdf#u520d1t9kc ┘ 7. fslkdjflskdjflksjdf (added)
8. fslkdjflskdjflksjdf#u520d1t9kc (removed)
.b2> diff.namespace .b1
Resolved name conflicts:
1. ┌ fslkdjflskdjflksjdf#4vn50bh8pk : Nat
2. └ fslkdjflskdjflksjdf#9mupj24g1n : Nat
1. ┌ fslkdjflskdjflksjdf#sekb3fdsvb : Nat
2. └ fslkdjflskdjflksjdf#u520d1t9kc : Nat
3. fslkdjflskdjflksjdf#4vn50bh8pk : Nat
3. fslkdjflskdjflksjdf#u520d1t9kc : Nat
Name changes:
Original Changes
4. x ┐ 5. abc (added)
6. fslkdjflskdjflksjdf#4vn50bh8pk ┘ 7. fslkdjflskdjflksjdf (added)
8. fslkdjflskdjflksjdf#4vn50bh8pk (removed)
6. fslkdjflskdjflksjdf#u520d1t9kc ┘ 7. fslkdjflskdjflksjdf (added)
8. fslkdjflskdjflksjdf#u520d1t9kc (removed)
```
Things we want to test:
@ -184,10 +184,10 @@ fromJust = "asldkfjasldkfj"
New name conflicts:
1. fromJust#rrsqv1ogaq : Nat
1. fromJust#gjmq673r1v : Nat
2. ┌ fromJust#8vv2a5jnig : Text
3. └ fromJust#rrsqv1ogaq : Nat
2. ┌ fromJust#gjmq673r1v : Nat
3. └ fromJust#rnbo52q2sh : Text
Tip: You can use `todo` to see if this generated any work to
do in this namespace and `test` to run the tests. Or you
@ -232,10 +232,10 @@ unique type Y a b = Y a b
Resolved name conflicts:
1. ┌ fromJust#8vv2a5jnig : Text
2. └ fromJust#rrsqv1ogaq : Nat
1. ┌ fromJust#gjmq673r1v : Nat
2. └ fromJust#rnbo52q2sh : Text
3. fromJust#mkj3tehhkv : Nat
3. fromJust#6gn1k53ie0 : Nat
- 4. ns1.b : Nat
+ 5. ns2.b : Text
@ -277,10 +277,10 @@ unique type Y a b = Y a b
Resolved name conflicts:
1. ┌ fromJust#8vv2a5jnig : Text
2. └ fromJust#rrsqv1ogaq : Nat
1. ┌ fromJust#gjmq673r1v : Nat
2. └ fromJust#rnbo52q2sh : Text
3. fromJust#mkj3tehhkv : Nat
3. fromJust#6gn1k53ie0 : Nat
- 4. ns1.b : Nat
+ 5. ns2.b : Text
@ -332,10 +332,10 @@ unique type Y a b = Y a b
Resolved name conflicts:
1. ┌ fromJust#8vv2a5jnig : Text
2. └ fromJust#rrsqv1ogaq : Nat
1. ┌ fromJust#gjmq673r1v : Nat
2. └ fromJust#rnbo52q2sh : Text
3. fromJust#mkj3tehhkv : Nat
3. fromJust#6gn1k53ie0 : Nat
- 4. ns1.b : Nat
+ 5. ns2.b : Text
@ -380,10 +380,10 @@ unique type Y a b = Y a b
Resolved name conflicts:
1. ┌ fromJust#8vv2a5jnig : Text
2. └ fromJust#rrsqv1ogaq : Nat
1. ┌ fromJust#gjmq673r1v : Nat
2. └ fromJust#rnbo52q2sh : Text
3. fromJust#mkj3tehhkv : Nat
3. fromJust#6gn1k53ie0 : Nat
- 4. ns1.b : Nat
+ 5. ns2.b : Text
@ -431,8 +431,8 @@ unique type Y a b = Y a b
.> view.patch ns2.patch
Edited Terms:
ns1.b -> ns2.b
ns1.fromJust' -> ns2.fromJust
1. ns1.b -> 3. ns2.b
2. ns1.fromJust' -> 4. ns2.fromJust
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
@ -570,14 +570,14 @@ a = 555
New name conflicts:
1. a#er8q007v02 : Nat
1. a#mdl4vqtu00 : Nat
2. ┌ a#75jrr0qj1c : Nat
3. └ a#er8q007v02 : Nat
2. ┌ a#mdl4vqtu00 : Nat
3. └ a#vrs8gtkl2t : Nat
Updates:
4. b#j6aq9c9k9v : Nat
4. b#unkqhuu66p : Nat
There were 1 auto-propagated updates.
@ -597,10 +597,10 @@ a = 555
New name conflicts:
1. a#nfb8lmj46i : Nat
1. a#uiiiv8a86s : Nat
2. ┌ a#75jrr0qj1c : Nat
3. └ a#er8q007v02 : Nat
2. ┌ a#mdl4vqtu00 : Nat
3. └ a#vrs8gtkl2t : Nat
Updates:
@ -612,21 +612,21 @@ a = 555
.nsw> view a b
a#75jrr0qj1c : Nat
a#75jrr0qj1c = 555
a#mdl4vqtu00 : Nat
a#mdl4vqtu00 = 444
a#er8q007v02 : Nat
a#er8q007v02 = 444
a#vrs8gtkl2t : Nat
a#vrs8gtkl2t = 555
b#j6aq9c9k9v : Nat
b#j6aq9c9k9v =
b#aapqletas7 : Nat
b#aapqletas7 =
use Nat +
a#er8q007v02 + 1
a#vrs8gtkl2t + 1
b#p50ctv8q17 : Nat
b#p50ctv8q17 =
b#unkqhuu66p : Nat
b#unkqhuu66p =
use Nat +
a#75jrr0qj1c + 1
a#mdl4vqtu00 + 1
```
```unison
@ -662,21 +662,21 @@ a = 777
.nsw> view a b
a#75jrr0qj1c : Nat
a#75jrr0qj1c = 555
a#mdl4vqtu00 : Nat
a#mdl4vqtu00 = 444
a#er8q007v02 : Nat
a#er8q007v02 = 444
a#vrs8gtkl2t : Nat
a#vrs8gtkl2t = 555
b#j6aq9c9k9v : Nat
b#j6aq9c9k9v =
b#aapqletas7 : Nat
b#aapqletas7 =
use Nat +
a#er8q007v02 + 1
a#vrs8gtkl2t + 1
b#p50ctv8q17 : Nat
b#p50ctv8q17 =
b#unkqhuu66p : Nat
b#unkqhuu66p =
use Nat +
a#75jrr0qj1c + 1
a#mdl4vqtu00 + 1
```
## Should be able to diff a namespace hash from history.
@ -733,17 +733,17 @@ y = 2
Note: The most recent namespace hash is immediately below this
message.
#r0471p61ch
1. #ru1hnjofdj
+ Adds / updates:
y
#q9cdigs0bo (start of history)
2. #i52j9fd57b (start of history)
.hashdiff> diff.namespace #r0471p61ch #q9cdigs0bo
.hashdiff> diff.namespace 2 1
Removed definitions:
Added definitions:
1. y : Nat

View File

@ -0,0 +1,41 @@
Regression test to ensure that `type` and `ability` in embedded doc links are
lexed properly when they occur at the start of identifiers.
That is, `{abilityPatterns}` should be a link to the **term** `abilityPatterns`,
not the ability `Patterns`; the lexer should see this as a single identifier.
See https://github.com/unisonweb/unison/issues/2642 for an example.
```ucm:hide
.> builtins.mergeio
```
```unison:hide
abilityPatterns : ()
abilityPatterns = ()
structural ability Patterns where p : ()
typeLabels : Nat
typeLabels = 5
structural type Labels = Labels
docs.example1 = {{A doc that links to the {abilityPatterns} term}}
docs.example2 = {{A doc that links to the {ability Patterns} ability}}
docs.example3 = {{A doc that links to the {typeLabels} term}}
docs.example4 = {{A doc that links to the {type Labels} type}}
```
```ucm:hide
.> add
```
Now we check that each doc links to the object of the correct name:
```ucm
.> display docs.example1
.> display docs.example2
.> display docs.example3
.> display docs.example4
```

View File

@ -0,0 +1,45 @@
Regression test to ensure that `type` and `ability` in embedded doc links are
lexed properly when they occur at the start of identifiers.
That is, `{abilityPatterns}` should be a link to the **term** `abilityPatterns`,
not the ability `Patterns`; the lexer should see this as a single identifier.
See https://github.com/unisonweb/unison/issues/2642 for an example.
```unison
abilityPatterns : ()
abilityPatterns = ()
structural ability Patterns where p : ()
typeLabels : Nat
typeLabels = 5
structural type Labels = Labels
docs.example1 = {{A doc that links to the {abilityPatterns} term}}
docs.example2 = {{A doc that links to the {ability Patterns} ability}}
docs.example3 = {{A doc that links to the {typeLabels} term}}
docs.example4 = {{A doc that links to the {type Labels} type}}
```
Now we check that each doc links to the object of the correct name:
```ucm
.> display docs.example1
A doc that links to the abilityPatterns term
.> display docs.example2
A doc that links to the Patterns ability
.> display docs.example3
A doc that links to the typeLabels term
.> display docs.example4
A doc that links to the Labels type
```

View File

@ -39,13 +39,13 @@ The history of the namespace should still exist if requested explicitly.
Note: The most recent namespace hash is immediately below this
message.
#nvh8d4j0fm
1. #nvh8d4j0fm
- Deletes:
x
#i52j9fd57b (start of history)
2. #i52j9fd57b (start of history)
```
Merging an empty namespace should still copy its history if it has some.
@ -66,13 +66,13 @@ Merging an empty namespace should still copy its history if it has some.
Note: The most recent namespace hash is immediately below this
message.
#nvh8d4j0fm
1. #nvh8d4j0fm
- Deletes:
x
#i52j9fd57b (start of history)
2. #i52j9fd57b (start of history)
```
Add and then delete a term to add some history to a deleted namespace.
@ -102,7 +102,7 @@ The history from the `deleted` namespace should have been overwritten by the his
#q2dq4tsno1 (start of history)
1. #q2dq4tsno1 (start of history)
.> history deleted
@ -111,7 +111,7 @@ The history from the `deleted` namespace should have been overwritten by the his
#q2dq4tsno1 (start of history)
1. #q2dq4tsno1 (start of history)
```
## move.namespace
@ -140,7 +140,7 @@ The history should be that of the moved namespace.
#c5uisu4kll (start of history)
1. #c5uisu4kll (start of history)
.> move.namespace moveme moveoverme
@ -153,6 +153,6 @@ The history should be that of the moved namespace.
#c5uisu4kll (start of history)
1. #c5uisu4kll (start of history)
```

View File

@ -23,6 +23,5 @@ Update
```ucm
.> update
.> find.patch
.> view.patch patch
.> view.patch 1
```

View File

@ -62,17 +62,9 @@ Update
1. patch
.> view.patch patch
Edited Terms: hey#m0kuh98ou7 -> hey
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
.> view.patch 1
Edited Terms: hey#m0kuh98ou7 -> hey
Edited Terms: 1. hey#m0kuh98ou7 -> 2. hey
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as

View File

@ -37,7 +37,7 @@ As of the time of this writing, the history for `X` should be a single node, `#4
#das1se4g2i (start of history)
1. #das1se4g2i (start of history)
```
however, as of release/M1i, we saw an extraneous node appear. If your `ucm` is fixed, you won't see it below:

View File

@ -75,7 +75,7 @@ We used to have to know the full hash for a definition to be able to use the `re
.> view.patch
Edited Terms: f#f3lgjvjqoo -> f
Edited Terms: 1. f#f3lgjvjqoo -> 2. f
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as

View File

@ -0,0 +1,31 @@
```ucm:hide
.> builtins.merge
```
```unison
structural ability Split where
skip! : x
both : a -> a -> a
Split.append : '{Split, g} a -> '{Split, g} a -> '{Split, g} a
Split.append s1 s2 _ = force (both s1 s2)
force a = !a
Split.zipSame : '{Split, g} a -> '{Split, g} b -> '{Split, g} (a, b)
Split.zipSame sa sb _ =
go : '{Split,g2} y -> Request {Split} x ->{Split,g2} (x,y)
go sb = cases
{ a } -> (a, !sb)
{ skip! -> _ } -> skip!
{ both la ra -> k } ->
handle !sb with cases
{ _ } -> skip!
{ skip! -> k } -> skip!
{ both lb rb -> k2 } ->
force (Split.append
(zipSame '(k la) '(k2 lb))
(zipSame '(k ra) '(k2 rb)))
handle !sa with go sb
```

View File

@ -0,0 +1,46 @@
```unison
structural ability Split where
skip! : x
both : a -> a -> a
Split.append : '{Split, g} a -> '{Split, g} a -> '{Split, g} a
Split.append s1 s2 _ = force (both s1 s2)
force a = !a
Split.zipSame : '{Split, g} a -> '{Split, g} b -> '{Split, g} (a, b)
Split.zipSame sa sb _ =
go : '{Split,g2} y -> Request {Split} x ->{Split,g2} (x,y)
go sb = cases
{ a } -> (a, !sb)
{ skip! -> _ } -> skip!
{ both la ra -> k } ->
handle !sb with cases
{ _ } -> skip!
{ skip! -> k } -> skip!
{ both lb rb -> k2 } ->
force (Split.append
(zipSame '(k la) '(k2 lb))
(zipSame '(k ra) '(k2 rb)))
handle !sa with go sb
```
```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`:
structural ability Split
Split.append : '{g, Split} a
-> '{g, Split} a
-> '{g, Split} a
Split.zipSame : '{g, Split} a
-> '{g, Split} b
-> '{g, Split} (a, b)
force : '{g} o ->{g} o
```

View File

@ -0,0 +1,27 @@
```ucm:hide
.> builtins.merge
```
```unison
unique type Map k v = Tip | Bin Nat k v (Map k v) (Map k v)
mapWithKey : (k ->{e} a ->{e} b) -> Map k a ->{e} Map k b
mapWithKey f m = Tip
```
```ucm
.> add
```
```unison
naiomi =
susan: Nat -> Nat -> ()
susan a b = ()
pam: Map Nat Nat
pam = Tip
mapWithKey susan pam
```

View File

@ -0,0 +1,51 @@
```unison
unique type Map k v = Tip | Bin Nat k v (Map k v) (Map k v)
mapWithKey : (k ->{e} a ->{e} b) -> Map k a ->{e} Map k b
mapWithKey f m = Tip
```
```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`:
unique type Map k v
mapWithKey : (k ->{e} a ->{e} b) -> Map k a ->{e} Map k b
```
```ucm
.> add
⍟ I've added these definitions:
unique type Map k v
mapWithKey : (k ->{e} a ->{e} b) -> Map k a ->{e} Map k b
```
```unison
naiomi =
susan: Nat -> Nat -> ()
susan a b = ()
pam: Map Nat Nat
pam = Tip
mapWithKey susan pam
```
```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`:
naiomi : Map Nat ()
```

View File

@ -194,11 +194,11 @@ myLibrary.h x = x + 3
Note: The most recent namespace hash is immediately below this
message.
#fa706ukb83
1. #fa706ukb83
#ikha0ltbmc (start of history)
2. #ikha0ltbmc (start of history)
.> unlink coolFunction.doc coolFunction

View File

@ -135,9 +135,9 @@ b = 2
`history #som3n4m3space` to view history starting from a given
namespace hash.
#b7fr6ifj87
1. #b7fr6ifj87
#9npggauqo9
#dm4u1eokg1
2. #9npggauqo9
3. #dm4u1eokg1
```

View File

@ -112,26 +112,26 @@ We can also delete the fork if we're done with it. (Don't worry, it's still in t
Note: The most recent namespace hash is immediately below this
message.
#hsbtlt2og6
1. #hsbtlt2og6
- Deletes:
y
#q95r47tc4l (start of history)
2. #q95r47tc4l (start of history)
.> history
Note: The most recent namespace hash is immediately below this
message.
#6meejv5nn9
1. #6meejv5nn9
- Deletes:
feature1.y
#jiaec3stf0
2. #jiaec3stf0
+ Adds / updates:
@ -142,26 +142,26 @@ We can also delete the fork if we're done with it. (Don't worry, it's still in t
Original name New name(s)
feature1.y master.y
#oi6qeaaasg
3. #oi6qeaaasg
+ Adds / updates:
feature1.y
#s0e9mj6462
4. #s0e9mj6462
> Moves:
Original name New name
x master.x
#uiim9cuh1n
5. #uiim9cuh1n
+ Adds / updates:
x
#8oo4auc4cv (start of history)
6. #8oo4auc4cv (start of history)
```
To resurrect an old version of a namespace, you can learn its hash via the `history` command, then use `fork #namespacehash .newname`.

View File

@ -0,0 +1,17 @@
```ucm:hide
.> builtins.merge
```
```unison
oldRight: (b ->{e} a ->{e} b) -> [a] ->{e} [b]
oldRight f la = bug "out"
pecan: '{} [Text]
pecan = 'let
la = [1, 2, 3]
f: Text -> Nat -> Text
f = bug "out"
oldRight f la
```

View File

@ -0,0 +1,25 @@
```unison
oldRight: (b ->{e} a ->{e} b) -> [a] ->{e} [b]
oldRight f la = bug "out"
pecan: '{} [Text]
pecan = 'let
la = [1, 2, 3]
f: Text -> Nat -> Text
f = bug "out"
oldRight f la
```
```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`:
oldRight : (b ->{e} a ->{e} b) -> [a] ->{e} [b]
pecan : '[Text]
```

View File

@ -86,15 +86,15 @@ The namespace `c` now has an edit conflict, since the term `foo` was edited in t
.example.resolve.c> todo
```
We see that `#5cj58badlt` (the original hash of `a.foo`) got replaced with _both_ the `#39feiiunjf` and `#iqa41ufqol`.
We see that the original hash of `a.foo` got replaced with _two different_ hashes.
We can resolve this conflict by picking one of the terms as the "winner":
```ucm
.example.resolve.c> replace #5cj58badlt #39feiiunjf
.example.resolve.c> replace 1 2
```
This changes the merged `c.patch` so that only the edit from #5cj58badlt to #39feiiunjf remains:
This changes the merged `c.patch` so that only a single edit remains and resolves the conflict.
```ucm
.example.resolve.c> view.patch
@ -109,7 +109,7 @@ We still have a remaining _name conflict_ since it just so happened that both of
We can resolve the name conflict by deleting one of the names.
```ucm
.example.resolve.c> delete.term foo#iqa41ufqol
.example.resolve.c> delete.term 2
.example.resolve.c> todo
```

View File

@ -118,7 +118,7 @@ The `a` and `b` namespaces now each contain a patch named `patch`. We can view t
.example.resolve> view.patch a.patch
Edited Terms: c.foo -> a.foo
Edited Terms: 1. c.foo -> 2. a.foo
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
@ -126,7 +126,7 @@ The `a` and `b` namespaces now each contain a patch named `patch`. We can view t
.example.resolve> view.patch b.patch
Edited Terms: c.foo -> b.foo
Edited Terms: 1. c.foo -> 2. b.foo
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
@ -163,10 +163,10 @@ Let's now merge these namespaces into `c`:
New name conflicts:
1. foo#iqa41ufqol : Nat
1. foo#emomp74i93 : Nat
2. ┌ foo#39feiiunjf : Nat
3. └ foo#iqa41ufqol : Nat
2. ┌ foo#a84tg4er4k : Nat
3. └ foo#emomp74i93 : Nat
Updates:
@ -194,26 +194,27 @@ The namespace `c` now has an edit conflict, since the term `foo` was edited in t
have been merged into this one. You'll have to tell me what to
use as the new definition:
The term #5cj58badlt was replaced with foo#39feiiunjf and
foo#iqa41ufqol
The term 1. #qkhkl0n238 was replaced with
2. foo#a84tg4er4k
3. foo#emomp74i93
```
We see that `#5cj58badlt` (the original hash of `a.foo`) got replaced with _both_ the `#39feiiunjf` and `#iqa41ufqol`.
We see that the original hash of `a.foo` got replaced with _two different_ hashes.
We can resolve this conflict by picking one of the terms as the "winner":
```ucm
.example.resolve.c> replace #5cj58badlt #39feiiunjf
.example.resolve.c> replace 1 2
Done.
```
This changes the merged `c.patch` so that only the edit from #5cj58badlt to #39feiiunjf remains:
This changes the merged `c.patch` so that only a single edit remains and resolves the conflict.
```ucm
.example.resolve.c> view.patch
Edited Terms: #5cj58badlt -> foo#39feiiunjf
Edited Terms: 1. #qkhkl0n238 -> 2. foo#a84tg4er4k
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
@ -227,31 +228,32 @@ We still have a remaining _name conflict_ since it just so happened that both of
These terms have conflicting definitions: foo
The term foo has conflicting definitions:
1. foo#a84tg4er4k
2. foo#emomp74i93
Tip: This occurs when merging branches that both independently
introduce the same name. Use `view foo` to see the
conflicting definitions, then use `move.term` to resolve
the conflicts.
introduce the same name. Use `move.term` or `delete.term`
to resolve the conflicts.
```
We can resolve the name conflict by deleting one of the names.
```ucm
.example.resolve.c> delete.term foo#iqa41ufqol
.example.resolve.c> delete.term 2
Resolved name conflicts:
1. ┌ example.resolve.c.foo#39feiiunjf : Nat
2. └ example.resolve.c.foo#iqa41ufqol : Nat
1. ┌ example.resolve.c.foo#a84tg4er4k : Nat
2. └ example.resolve.c.foo#emomp74i93 : Nat
3. example.resolve.c.foo#39feiiunjf : Nat
3. example.resolve.c.foo#a84tg4er4k : Nat
Name changes:
Original Changes
4. example.resolve.a.foo ┐ 5. example.resolve.c.foo#iqa41ufqol (removed)
6. example.resolve.c.foo#iqa41ufqol
4. example.resolve.a.foo ┐ 5. example.resolve.c.foo#emomp74i93 (removed)
6. example.resolve.c.foo#emomp74i93
Tip: You can use `undo` or `reflog` to undo this change.

View File

@ -13,7 +13,7 @@ Let's look at some examples. We'll start with a namespace with just the builtins
#soipbkdq9m (start of history)
1. #soipbkdq9m (start of history)
.> fork builtin builtin2
@ -42,21 +42,21 @@ Now suppose we `fork` a copy of builtin, then rename `Nat.+` to `frobnicate`, th
Note: The most recent namespace hash is immediately below this
message.
#u2acmt4ut5
1. #u2acmt4ut5
> Moves:
Original name New name
Nat.frobnicate Nat.+
#tq3np8qtmn
2. #tq3np8qtmn
> Moves:
Original name New name
Nat.+ Nat.frobnicate
#soipbkdq9m (start of history)
3. #soipbkdq9m (start of history)
```
If we merge that back into `builtin`, we get that same chain of history:
@ -71,21 +71,21 @@ If we merge that back into `builtin`, we get that same chain of history:
Note: The most recent namespace hash is immediately below this
message.
#u2acmt4ut5
1. #u2acmt4ut5
> Moves:
Original name New name
Nat.frobnicate Nat.+
#tq3np8qtmn
2. #tq3np8qtmn
> Moves:
Original name New name
Nat.+ Nat.frobnicate
#soipbkdq9m (start of history)
3. #soipbkdq9m (start of history)
```
Let's try again, but using a `merge.squash` (or just `squash`) instead. The history will be unchanged:
@ -106,7 +106,7 @@ Let's try again, but using a `merge.squash` (or just `squash`) instead. The hist
#soipbkdq9m (start of history)
1. #soipbkdq9m (start of history)
```
The churn that happened in `mybuiltin` namespace ended up back in the same spot, so the squash merge of that namespace with our original namespace had no effect.
@ -191,47 +191,47 @@ At this point, Alice and Bob both have some history beyond what's in trunk:
#i52j9fd57b (start of history)
1. #i52j9fd57b (start of history)
.> history alice
Note: The most recent namespace hash is immediately below this
message.
#e9jd55555o
1. #e9jd55555o
> Moves:
Original name New name
neatoFun productionReadyId
#l5ocoo2eac
2. #l5ocoo2eac
> Moves:
Original name New name
radNumber superRadNumber
#i1vq05628n
3. #i1vq05628n
+ Adds / updates:
bodaciousNumero neatoFun radNumber
#i52j9fd57b (start of history)
4. #i52j9fd57b (start of history)
.> history bob
Note: The most recent namespace hash is immediately below this
message.
#brr4400742
1. #brr4400742
+ Adds / updates:
babyDon'tHurtMe no whatIsLove
#i52j9fd57b (start of history)
2. #i52j9fd57b (start of history)
```
Alice then squash merges into `trunk`, as does Bob. It's as if Alice and Bob both made their changes in one single commit.
@ -257,13 +257,13 @@ Alice then squash merges into `trunk`, as does Bob. It's as if Alice and Bob bot
Note: The most recent namespace hash is immediately below this
message.
#f9lvm9gd2k
1. #f9lvm9gd2k
+ Adds / updates:
bodaciousNumero productionReadyId superRadNumber
#i52j9fd57b (start of history)
2. #i52j9fd57b (start of history)
.> merge.squash bob trunk
@ -285,19 +285,19 @@ Alice then squash merges into `trunk`, as does Bob. It's as if Alice and Bob bot
Note: The most recent namespace hash is immediately below this
message.
#dbp78ts6q3
1. #dbp78ts6q3
+ Adds / updates:
babyDon'tHurtMe no whatIsLove
#f9lvm9gd2k
2. #f9lvm9gd2k
+ Adds / updates:
bodaciousNumero productionReadyId superRadNumber
#i52j9fd57b (start of history)
3. #i52j9fd57b (start of history)
```
Since squash merges don't produce any merge nodes, we can `undo` a couple times to get back to our starting state:
@ -336,7 +336,7 @@ Since squash merges don't produce any merge nodes, we can `undo` a couple times
#i52j9fd57b (start of history)
1. #i52j9fd57b (start of history)
```
This time, we'll first squash Alice and Bob's changes together before squashing their combined changes into `trunk`. The resulting `trunk` will have just a single entry in it, combining both Alice and Bob's changes:
@ -380,14 +380,14 @@ This time, we'll first squash Alice and Bob's changes together before squashing
Note: The most recent namespace hash is immediately below this
message.
#qtotqgds4i
1. #qtotqgds4i
+ Adds / updates:
babyDon'tHurtMe bodaciousNumero no productionReadyId
superRadNumber whatIsLove
#i52j9fd57b (start of history)
2. #i52j9fd57b (start of history)
```
So, there you have it. With squashing, you can control the granularity of your history.
@ -420,7 +420,7 @@ Another thing we can do is `squash` into an empty namespace. This effectively ma
#1d9haupn3d (start of history)
1. #1d9haupn3d (start of history)
```
There's nothing really special here, `squash src dest` discards `src` history that comes after the LCA of `src` and `dest`, it's just that in the case of an empty namespace, that LCA is the beginning of time (the empty namespace), so all the history of `src` is discarded.
@ -485,13 +485,13 @@ This checks to see that squashing correctly preserves deletions:
Note: The most recent namespace hash is immediately below this
message.
#n48gujdtqf
1. #n48gujdtqf
- Deletes:
Nat.* Nat.+
#soipbkdq9m (start of history)
2. #soipbkdq9m (start of history)
```
Notice that `Nat.+` and `Nat.*` are deleted by the squash, and we see them deleted in one atomic step in the history.

View File

@ -0,0 +1,72 @@
# Test the `todo` command
## Simple type-changing update.
```ucm:hide
.> builtins.mergeio
```
```unison:hide
x = 1
useX = x + 10
structural type MyType = MyType Nat
useMyType = match MyType 1 with
MyType a -> a + 10
```
```ucm:hide
.simple> add
```
Perform a type-changing update so dependents are added to our update frontier.
```unison:hide
x = -1
structural type MyType = MyType Text
```
```ucm:error
.simple> update
.simple> todo
```
## A merge with conflicting updates.
```unison:hide
x = 1
structural type MyType = MyType
```
Set up two branches with the same starting point.
```ucm:hide
.mergeA> add
.> fork .mergeA .mergeB
```
Update `x` to a different term in each branch.
```unison:hide
x = 2
structural type MyType = MyType Nat
```
```ucm:hide
.mergeA> update
```
```unison:hide
x = 3
structural type MyType = MyType Int
```
```ucm:hide
.mergeB> update
```
```ucm:error
.mergeA> merge .mergeB
.mergeA> todo
```

View File

@ -0,0 +1,131 @@
# Test the `todo` command
## Simple type-changing update.
```unison
x = 1
useX = x + 10
structural type MyType = MyType Nat
useMyType = match MyType 1 with
MyType a -> a + 10
```
Perform a type-changing update so dependents are added to our update frontier.
```unison
x = -1
structural type MyType = MyType Text
```
```ucm
.simple> update
⍟ I've updated these names to your new definition:
structural type MyType
x : Int
.simple> todo
🚧
The namespace has 2 transitive dependent(s) left to upgrade.
Your edit frontier is the dependents of these definitions:
structural type MyType#68k40ra7l7
x#gjmq673r1v : Nat
I recommend working on them in the following order:
1. useMyType : Nat
2. useX : Nat
```
## A merge with conflicting updates.
```unison
x = 1
structural type MyType = MyType
```
Set up two branches with the same starting point.
Update `x` to a different term in each branch.
```unison
x = 2
structural type MyType = MyType Nat
```
```unison
x = 3
structural type MyType = MyType Int
```
```ucm
.mergeA> merge .mergeB
Here's what's changed in the current namespace after the
merge:
New name conflicts:
1. structural type MyType#68k40ra7l7
2. ┌ structural type MyType#68k40ra7l7
3. └ structural type MyType#eo6rj0lj1b
4. MyType.MyType#68k40ra7l7#0 : Nat -> MyType#68k40ra7l7
5. ┌ MyType.MyType#68k40ra7l7#0 : Nat -> MyType#68k40ra7l7
6. └ MyType.MyType#eo6rj0lj1b#0 : Int -> MyType#eo6rj0lj1b
7. x#dcgdua2lj6 : Nat
8. ┌ x#dcgdua2lj6 : Nat
9. └ x#f3lgjvjqoo : Nat
Updates:
10. patch patch (added 2 updates)
Tip: You can use `todo` to see if this generated any work to
do in this namespace and `test` to run the tests. Or you
can use `undo` or `reflog` to undo the results of this
merge.
I tried to auto-apply the patch, but couldn't because it
contained contradictory entries.
.mergeA> todo
These definitions were edited differently in namespaces that
have been merged into this one. You'll have to tell me what to
use as the new definition:
The type 1. .builtin.Unit was replaced with
2. MyType#68k40ra7l7
3. MyType#eo6rj0lj1b
The term 4. #gjmq673r1v was replaced with
5. x#dcgdua2lj6
6. x#f3lgjvjqoo
The term MyType.MyType has conflicting definitions:
7. MyType.MyType#68k40ra7l7#0
8. MyType.MyType#eo6rj0lj1b#0
Tip: This occurs when merging branches that both independently
introduce the same name. Use `move.term` or `delete.term`
to resolve the conflicts.
```