mirror of
https://github.com/unisonweb/unison.git
synced 2024-09-17 13:27:30 +03:00
Merge branch 'trunk' into topic/rehash-codebase
This commit is contained in:
commit
3e3b44d1d1
75
.github/workflows/release.yaml
vendored
75
.github/workflows/release.yaml
vendored
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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" $
|
||||
|
@ -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
|
||||
|
@ -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 $
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
```
|
||||
|
||||
|
@ -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
|
||||
|
||||
```
|
||||
|
10
unison-src/transcripts-round-trip/nested.u
Normal file
10
unison-src/transcripts-round-trip/nested.u
Normal file
@ -0,0 +1,10 @@
|
||||
nested = {{
|
||||
|
||||
````raw
|
||||
|
||||
```unison
|
||||
r = "boopydoo"
|
||||
```
|
||||
|
||||
````
|
||||
}}
|
@ -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
|
||||
```
|
||||
|
@ -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.
|
||||
|
||||
```
|
||||
|
@ -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)
|
||||
|
||||
```
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
```
|
||||
|
@ -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.
|
||||
|
||||
|
@ -169,7 +169,7 @@ y = 2
|
||||
```ucm
|
||||
.hashdiff> add
|
||||
.hashdiff> history
|
||||
.hashdiff> diff.namespace #r0471p61ch #q9cdigs0bo
|
||||
.hashdiff> diff.namespace 2 1
|
||||
```
|
||||
|
||||
##
|
||||
|
@ -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
|
||||
|
||||
|
41
unison-src/transcripts/doc-type-link-keywords.md
Normal file
41
unison-src/transcripts/doc-type-link-keywords.md
Normal 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
|
||||
```
|
45
unison-src/transcripts/doc-type-link-keywords.output.md
Normal file
45
unison-src/transcripts/doc-type-link-keywords.output.md
Normal 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
|
||||
|
||||
```
|
@ -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)
|
||||
|
||||
```
|
||||
|
@ -23,6 +23,5 @@ Update
|
||||
```ucm
|
||||
.> update
|
||||
.> find.patch
|
||||
.> view.patch patch
|
||||
.> view.patch 1
|
||||
```
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
31
unison-src/transcripts/fix2423.md
Normal file
31
unison-src/transcripts/fix2423.md
Normal 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
|
||||
```
|
46
unison-src/transcripts/fix2423.output.md
Normal file
46
unison-src/transcripts/fix2423.output.md
Normal 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
|
||||
|
||||
```
|
27
unison-src/transcripts/fix2712.md
Normal file
27
unison-src/transcripts/fix2712.md
Normal 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
|
||||
|
||||
```
|
51
unison-src/transcripts/fix2712.output.md
Normal file
51
unison-src/transcripts/fix2712.output.md
Normal 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 ()
|
||||
|
||||
```
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
```
|
||||
|
@ -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`.
|
||||
|
17
unison-src/transcripts/old-fold-right.md
Normal file
17
unison-src/transcripts/old-fold-right.md
Normal 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
|
||||
```
|
||||
|
25
unison-src/transcripts/old-fold-right.output.md
Normal file
25
unison-src/transcripts/old-fold-right.output.md
Normal 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]
|
||||
|
||||
```
|
@ -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
|
||||
```
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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.
|
||||
|
72
unison-src/transcripts/todo.md
Normal file
72
unison-src/transcripts/todo.md
Normal 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
|
||||
```
|
131
unison-src/transcripts/todo.output.md
Normal file
131
unison-src/transcripts/todo.output.md
Normal 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.
|
||||
|
||||
```
|
Loading…
Reference in New Issue
Block a user