delete a bunch of patch manipulation commands

This commit is contained in:
Mitchell Rosen 2024-05-24 11:01:45 -04:00
parent 8a27961e9a
commit 6adb88f5b3
27 changed files with 23 additions and 2498 deletions

View File

@ -15,8 +15,6 @@ module Unison.Codebase.BranchUtil
makeAddTermName,
makeDeleteTermName,
makeAnnihilateTermName,
makeDeletePatch,
makeReplacePatch,
)
where
@ -24,7 +22,6 @@ import Data.Map qualified as Map
import Data.Set qualified as Set
import Unison.Codebase.Branch (Branch, Branch0)
import Unison.Codebase.Branch qualified as Branch
import Unison.Codebase.Patch (Patch)
import Unison.Codebase.Path (Path)
import Unison.Codebase.Path qualified as Path
import Unison.HashQualified' (HashQualified (HashQualified, NameOnly))
@ -83,12 +80,6 @@ makeAnnihilateTermName (p, name) = (p, Branch.annihilateTermName name)
makeAnnihilateTypeName :: Path.Split -> (Path, Branch0 m -> Branch0 m)
makeAnnihilateTypeName (p, name) = (p, Branch.annihilateTypeName name)
makeReplacePatch :: (Applicative m) => Path.Split -> Patch -> (Path, Branch0 m -> Branch0 m)
makeReplacePatch (p, name) patch = (p, Branch.replacePatch name patch)
makeDeletePatch :: Path.Split -> (Path, Branch0 m -> Branch0 m)
makeDeletePatch (p, name) = (p, Branch.deletePatch name)
makeAddTypeName :: Path.Split -> Reference -> (Path, Branch0 m -> Branch0 m)
makeAddTypeName (p, name) r = (p, Branch.addTypeName r name)

View File

@ -67,9 +67,6 @@ module Unison.Cli.MonadUtils
-- ** Getting patches
getPatchAt,
getMaybePatchAt,
expectPatchAt,
assertNoPatchAt,
-- * Latest touched Unison file
getLatestFile,
@ -514,16 +511,6 @@ getMaybePatchAt path0 = do
branch <- getBranch0At path
liftIO (Branch.getMaybePatch name branch)
-- | Get the patch at a path, or return early if there's no such patch.
expectPatchAt :: Path.Split' -> Cli Patch
expectPatchAt path =
getMaybePatchAt path & onNothingM (Cli.returnEarly (Output.PatchNotFound path))
-- | Assert that there's no patch at a path, or return early if there is one.
assertNoPatchAt :: Path.Split' -> Cli ()
assertNoPatchAt path = do
whenJustM (getMaybePatchAt path) \_ -> Cli.returnEarly (Output.PatchAlreadyExists path)
------------------------------------------------------------------------------------------------------------------------
-- Latest (typechecked) unison file utils

View File

@ -27,7 +27,6 @@ import Text.Megaparsec qualified as Megaparsec
import U.Codebase.Branch.Diff qualified as V2Branch.Diff
import U.Codebase.Causal qualified as V2Causal
import U.Codebase.HashTags (CausalHash (..))
import U.Codebase.Reference qualified as V2 (Reference)
import U.Codebase.Reflog qualified as Reflog
import U.Codebase.Sqlite.Project qualified as Sqlite
import U.Codebase.Sqlite.ProjectBranch qualified as Sqlite
@ -78,7 +77,7 @@ import Unison.Codebase.Editor.HandleInput.ProjectCreate (projectCreate)
import Unison.Codebase.Editor.HandleInput.ProjectRename (handleProjectRename)
import Unison.Codebase.Editor.HandleInput.ProjectSwitch (projectSwitch)
import Unison.Codebase.Editor.HandleInput.Projects (handleProjects)
import Unison.Codebase.Editor.HandleInput.Pull (handlePull, mergeBranchAndPropagateDefaultPatch, propagatePatch)
import Unison.Codebase.Editor.HandleInput.Pull (handlePull, mergeBranchAndPropagateDefaultPatch)
import Unison.Codebase.Editor.HandleInput.Push (handleGist, handlePushRemoteBranch)
import Unison.Codebase.Editor.HandleInput.ReleaseDraft (handleReleaseDraft)
import Unison.Codebase.Editor.HandleInput.Run (handleRun)
@ -106,15 +105,8 @@ import Unison.Codebase.Patch qualified as Patch
import Unison.Codebase.Path (Path, Path' (..))
import Unison.Codebase.Path qualified as HQSplit'
import Unison.Codebase.Path qualified as Path
import Unison.Codebase.Path.Parse qualified as Path
import Unison.Codebase.Runtime qualified as Runtime
import Unison.Codebase.ShortCausalHash qualified as SCH
import Unison.Codebase.SqliteCodebase.Conversions qualified as Conversions
import Unison.Codebase.TermEdit (TermEdit (..))
import Unison.Codebase.TermEdit qualified as TermEdit
import Unison.Codebase.TermEdit.Typing qualified as TermEdit
import Unison.Codebase.TypeEdit (TypeEdit)
import Unison.Codebase.TypeEdit qualified as TypeEdit
import Unison.CommandLine.BranchRelativePath (BranchRelativePath)
import Unison.CommandLine.Completion qualified as Completion
import Unison.CommandLine.DisplayValues qualified as DisplayValues
@ -132,7 +124,6 @@ import Unison.LabeledDependency qualified as LD
import Unison.LabeledDependency qualified as LabeledDependency
import Unison.Name (Name)
import Unison.Name qualified as Name
import Unison.NameSegment (NameSegment (..))
import Unison.NameSegment qualified as NameSegment
import Unison.Names (Names (Names))
import Unison.Names qualified as Names
@ -148,7 +139,7 @@ import Unison.PrettyPrintEnvDecl qualified as PPED
import Unison.PrettyPrintEnvDecl.Names qualified as PPED
import Unison.Project (ProjectAndBranch (..))
import Unison.Project.Util (projectContextFromPath)
import Unison.Reference (Reference, TermReference)
import Unison.Reference (Reference)
import Unison.Reference qualified as Reference
import Unison.Referent (Referent)
import Unison.Referent qualified as Referent
@ -159,7 +150,6 @@ import Unison.Server.CodebaseServer qualified as Server
import Unison.Server.Doc.Markdown.Render qualified as Md
import Unison.Server.Doc.Markdown.Types qualified as Md
import Unison.Server.NameSearch.FromNames qualified as NameSearch
import Unison.Server.QueryResult
import Unison.Server.SearchResult (SearchResult)
import Unison.Server.SearchResult qualified as SR
import Unison.Share.Codeserver qualified as Codeserver
@ -207,60 +197,7 @@ loop e = do
Just (_, True) -> (#latestFile . _Just . _2) .= False
_ -> loadUnisonFile sourceName text
Right input ->
let typeReferences :: [SearchResult] -> [Reference]
typeReferences rs =
[r | SR.Tp (SR.TypeResult _ r _) <- rs]
termReferences :: [SearchResult] -> [Reference]
termReferences rs =
[r | SR.Tm (SR.TermResult _ (Referent.Ref r) _) <- rs]
termResults rs = [r | SR.Tm r <- rs]
typeResults rs = [r | SR.Tp r <- rs]
doRemoveReplacement :: HQ.HashQualified Name -> Maybe PatchPath -> Bool -> Cli ()
doRemoveReplacement from patchPath isTerm = do
let patchPath' = fromMaybe Cli.defaultPatchPath patchPath
patch <- Cli.getPatchAt patchPath'
QueryResult misses allHits <- hqNameQuery Names.IncludeSuffixes [from]
let tpRefs = Set.fromList $ typeReferences allHits
tmRefs = Set.fromList $ termReferences allHits
(hits, opHits) =
let tmResults = Set.fromList $ SR.termName <$> termResults allHits
tpResults = Set.fromList $ SR.typeName <$> typeResults allHits
in case isTerm of
True -> (tmResults, tpResults)
False -> (tpResults, tmResults)
go :: Text -> Reference -> Cli ()
go description fr = do
let termPatch = over Patch.termEdits (R.deleteDom fr) patch
typePatch = over Patch.typeEdits (R.deleteDom fr) patch
(patchPath'', patchName) <- Cli.resolveSplit' patchPath'
-- Save the modified patch
Cli.stepAtM
description
( Path.unabsolute patchPath'',
Branch.modifyPatches
patchName
(const (if isTerm then termPatch else typePatch))
)
-- Say something
Cli.respond Success
when (Set.null hits) do
Cli.respond (SearchTermsNotFoundDetailed isTerm misses (Set.toList opHits))
description <- inputDescription input
traverse_ (go description) (if isTerm then tmRefs else tpRefs)
saveAndApplyPatch :: Path -> NameSegment -> Patch -> Cli ()
saveAndApplyPatch patchPath'' patchName patch' = do
description <- inputDescription input
Cli.stepAtM
(description <> " (1/2)")
( patchPath'',
Branch.modifyPatches patchName (const patch')
)
-- Apply the modified patch to the current path
-- since we might be able to propagate further.
currentPath <- Cli.getCurrentPath
void $ propagatePatch description patch' currentPath
Cli.respond Success
previewResponse sourceName sr uf = do
let previewResponse sourceName sr uf = do
names <- Cli.currentNames
let namesWithDefinitionsFromFile = UF.addNamesFromTypeCheckedUnisonFile uf names
filePPED <- Cli.prettyPrintEnvDeclFromNames namesWithDefinitionsFromFile
@ -463,27 +400,6 @@ loop e = do
hasConfirmed <- confirmedCommand input
description <- inputDescription input
doMoveBranch description hasConfirmed src' dest'
MovePatchI src' dest' -> do
description <- inputDescription input
p <- Cli.expectPatchAt src'
Cli.assertNoPatchAt dest'
src <- Cli.resolveSplit' src'
dest <- Cli.resolveSplit' dest'
Cli.stepManyAt
description
[ BranchUtil.makeDeletePatch (Path.convert src),
BranchUtil.makeReplacePatch (Path.convert dest) p
]
Cli.respond Success
CopyPatchI src dest' -> do
description <- inputDescription input
p <- Cli.expectPatchAt src
Cli.assertNoPatchAt dest'
dest <- Cli.resolveSplit' dest'
Cli.stepAt
description
(BranchUtil.makeReplacePatch (Path.convert dest) p)
Cli.respond Success
SwitchBranchI path' -> do
path <- Cli.resolvePath' path'
branchExists <- Cli.branchExistsAtPath' path'
@ -727,14 +643,6 @@ loop e = do
DeleteTarget'TermOrType doutput hqs -> delete input doutput Cli.getTermsAt Cli.getTypesAt hqs
DeleteTarget'Type doutput hqs -> delete input doutput (const (pure Set.empty)) Cli.getTypesAt hqs
DeleteTarget'Term doutput hqs -> delete input doutput Cli.getTermsAt (const (pure Set.empty)) hqs
DeleteTarget'Patch src' -> do
_ <- Cli.expectPatchAt src'
description <- inputDescription input
src <- Cli.resolveSplit' src'
Cli.stepAt
description
(BranchUtil.makeDeletePatch (Path.convert src))
Cli.respond Success
DeleteTarget'Namespace insistence Nothing -> do
hasConfirmed <- confirmedCommand input
if hasConfirmed || insistence == Force
@ -777,15 +685,6 @@ loop e = do
traverse_ (displayI outputLoc) namesToDisplay
ShowDefinitionI outputLoc showDefinitionScope query -> handleShowDefinition outputLoc showDefinitionScope query
EditNamespaceI paths -> handleEditNamespace LatestFileLocation paths
FindPatchI -> do
branch <- Cli.getCurrentBranch0
let patches =
[ Path.unsafeToName $ Path.snoc p seg
| (p, b) <- Branch.toList0 branch,
(seg, _) <- Map.toList (Branch._edits b)
]
Cli.respond $ ListOfPatches $ Set.fromList patches
Cli.setNumberedArgs $ fmap (Text.unpack . Name.toText) patches
FindShallowI pathArg -> do
Cli.Env {codebase} <- ask
@ -818,98 +717,6 @@ loop e = do
FindI isVerbose fscope ws -> handleFindI isVerbose fscope ws input
StructuredFindI _fscope ws -> handleStructuredFindI ws
StructuredFindReplaceI ws -> handleStructuredFindReplaceI ws
ReplaceI from to patchPath -> do
Cli.Env {codebase} <- ask
hqLength <- Cli.runTransaction Codebase.hashLength
let patchPath' = fromMaybe Cli.defaultPatchPath patchPath
patch <- Cli.getPatchAt patchPath'
QueryResult fromMisses' fromHits <- hqNameQuery Names.IncludeSuffixes [from]
QueryResult toMisses' toHits <- hqNameQuery Names.IncludeSuffixes [to]
let termsFromRefs = termReferences fromHits
termsToRefs = termReferences toHits
typesFromRefs = typeReferences fromHits
typesToRefs = typeReferences toHits
--- Here are all the kinds of misses
--- [X] [X]
--- [Type] [Term]
--- [Term] [Type]
--- [Type] [X]
--- [Term] [X]
--- [X] [Type]
--- [X] [Term]
-- Type hits are term misses
termFromMisses = fromMisses' <> (SR.typeName <$> typeResults fromHits)
termToMisses = toMisses' <> (SR.typeName <$> typeResults toHits)
-- Term hits are type misses
typeFromMisses = fromMisses' <> (SR.termName <$> termResults fromHits)
typeToMisses = toMisses' <> (SR.termName <$> termResults toHits)
termMisses = termFromMisses <> termToMisses
typeMisses = typeFromMisses <> typeToMisses
replaceTerms :: Reference -> Reference -> Cli ()
replaceTerms fr tr = do
(mft, mtt) <-
Cli.runTransaction do
mft <- Codebase.getTypeOfTerm codebase fr
mtt <- Codebase.getTypeOfTerm codebase tr
pure (mft, mtt)
let termNotFound =
Cli.returnEarly
. TermNotFound'
. SH.shortenTo hqLength
. Reference.toShortHash
ft <- mft & onNothing (termNotFound fr)
tt <- mtt & onNothing (termNotFound tr)
let patch' =
-- The modified patch
over
Patch.termEdits
( R.insert fr (Replace tr (TermEdit.typing tt ft))
. R.deleteDom fr
)
patch
(patchPath'', patchName) <- Cli.resolveSplit' patchPath'
saveAndApplyPatch (Path.convert patchPath'') patchName patch'
replaceTypes :: Reference -> Reference -> Cli ()
replaceTypes fr tr = do
let patch' =
-- The modified patch
over
Patch.typeEdits
(R.insert fr (TypeEdit.Replace tr) . R.deleteDom fr)
patch
(patchPath'', patchName) <- Cli.resolveSplit' patchPath'
saveAndApplyPatch (Path.convert patchPath'') patchName patch'
ambiguous :: HQ.HashQualified Name -> [TermReference] -> Cli a
ambiguous t rs =
Cli.returnEarly case t of
HQ.HashOnly h -> HashAmbiguous h rs'
(Path.parseHQSplit' . Text.unpack . HQ.toText -> Right n) -> DeleteNameAmbiguous hqLength n rs' Set.empty
_ -> BadName (HQ.toText t)
where
rs' = Set.map Referent.Ref $ Set.fromList rs
mismatch typeName termName = Cli.respond $ TypeTermMismatch typeName termName
case (termsFromRefs, termsToRefs, typesFromRefs, typesToRefs) of
([], [], [], []) -> Cli.respond $ SearchTermsNotFound termMisses
([_], [], [], [_]) -> mismatch to from
([], [_], [_], []) -> mismatch from to
([_], [], _, _) -> Cli.respond $ SearchTermsNotFound termMisses
([], [_], _, _) -> Cli.respond $ SearchTermsNotFound termMisses
(_, _, [_], []) -> Cli.respond $ SearchTermsNotFound typeMisses
(_, _, [], [_]) -> Cli.respond $ SearchTermsNotFound typeMisses
([fr], [tr], [], []) -> replaceTerms fr tr
([], [], [fr], [tr]) -> replaceTypes fr tr
(froms, [_], [], []) -> ambiguous from froms
([], [], froms, [_]) -> ambiguous from froms
([_], tos, [], []) -> ambiguous to tos
([], [], [_], tos) -> ambiguous to tos
(_, _, _, _) -> error "unpossible"
LoadI maybePath -> handleLoad maybePath
ClearI -> Cli.respond ClearScreen
AddI requestedNames -> do
@ -949,12 +756,6 @@ loop e = do
branchPath <- Cli.resolvePath' branchPath'
doShowTodoOutput patch branchPath
TestI testInput -> Tests.handleTest testInput
PropagatePatchI patchPath scopePath' -> do
description <- inputDescription input
patch <- Cli.getPatchAt patchPath
scopePath <- Cli.resolvePath' scopePath'
updated <- propagatePatch description patch scopePath
when (not updated) (Cli.respond $ NothingToPatch patchPath scopePath')
ExecuteI main args -> handleRun False main args
MakeStandaloneI output main -> doCompile False output main
CompileSchemeI output main ->
@ -1015,11 +816,6 @@ loop e = do
_ <- Cli.updateAtM description destPath \destb ->
liftIO (Branch.merge'' (Codebase.lca codebase) Branch.RegularMerge srcb destb)
Cli.respond Success
ListEditsI maybePath -> do
patch <- Cli.getPatchAt (fromMaybe Cli.defaultPatchPath maybePath)
pped <- Cli.currentPrettyPrintEnvDecl
let suffixifiedPPE = PPED.suffixifiedPPE pped
Cli.respondNumbered $ ListEdits patch suffixifiedPPE
PullI sourceTarget pullMode -> handlePull sourceTarget pullMode
PushRemoteBranchI pushRemoteBranchInput -> handlePushRemoteBranch pushRemoteBranchInput
ListDependentsI hq -> handleDependents hq
@ -1160,10 +956,6 @@ loop e = do
nameChanges <- V2Branch.Diff.allNameChanges Nothing treeDiff
pure (DisplayDebugNameDiff nameChanges)
Cli.respond output
DeprecateTermI {} -> Cli.respond NotImplemented
DeprecateTypeI {} -> Cli.respond NotImplemented
RemoveTermReplacementI from patchPath -> doRemoveReplacement from patchPath True
RemoveTypeReplacementI from patchPath -> doRemoveReplacement from patchPath False
UpdateBuiltinsI -> Cli.respond NotImplemented
QuitI -> Cli.haltRepl
GistI input -> handleGist input
@ -1171,9 +963,6 @@ loop e = do
VersionI -> do
Cli.Env {ucmVersion} <- ask
Cli.respond $ PrintVersion ucmVersion
DiffNamespaceToPatchI diffNamespaceToPatchInput -> do
description <- inputDescription input
handleDiffNamespaceToPatch description diffNamespaceToPatchInput
ProjectRenameI name -> handleProjectRename name
ProjectSwitchI name -> projectSwitch name
ProjectCreateI tryDownloadingBase name -> projectCreate tryDownloadingBase name
@ -1244,14 +1033,6 @@ inputDescription input =
src <- p' src0
dest <- p' dest0
pure ("move " <> src <> " " <> dest)
MovePatchI src0 dest0 -> do
src <- ps' src0
dest <- ps' dest0
pure ("move.patch " <> src <> " " <> dest)
CopyPatchI src0 dest0 -> do
src <- ps' src0
dest <- ps' dest0
pure ("copy.patch " <> src <> " " <> dest)
DeleteI dtarget -> do
case dtarget of
DeleteTarget'TermOrType DeleteOutput'NoDiff things0 -> do
@ -1278,20 +1059,8 @@ inputDescription input =
DeleteTarget'Namespace Force opath0 -> do
opath <- ops opath0
pure ("delete.namespace.force " <> opath)
DeleteTarget'Patch path0 -> do
path <- ps' path0
pure ("delete.patch " <> path)
DeleteTarget'ProjectBranch _ -> wat
DeleteTarget'Project _ -> wat
ReplaceI src target p0 -> do
p <- opatch p0
pure $
"replace "
<> HQ.toText src
<> " "
<> HQ.toText target
<> " "
<> p
AddI _selection -> pure "add"
UpdateI p0 _selection -> do
p <-
@ -1301,10 +1070,6 @@ inputDescription input =
UsePatch p0 -> (" " <>) <$> ps' p0
pure ("update.old" <> p)
Update2I -> pure ("update")
PropagatePatchI p0 scope0 -> do
p <- ps' p0
scope <- p' scope0
pure ("patch " <> p <> " " <> scope)
UndoI {} -> pure "undo"
ExecuteI s args -> pure ("execute " <> Text.unwords (s : fmap Text.pack args))
IOTestI hq -> pure ("io.test " <> HQ.toText hq)
@ -1319,17 +1084,6 @@ inputDescription input =
pure $ "run.native " <> Text.unwords (nm : fmap Text.pack args)
CompileSchemeI fi nm -> pure ("compile.native " <> HQ.toText nm <> " " <> fi)
CreateAuthorI id name -> pure ("create.author " <> NameSegment.toEscapedText id <> " " <> name)
RemoveTermReplacementI src p0 -> do
p <- opatch p0
pure ("delete.term-replacement" <> HQ.toText src <> " " <> p)
RemoveTypeReplacementI src p0 -> do
p <- opatch p0
pure ("delete.type-replacement" <> HQ.toText src <> " " <> p)
DiffNamespaceToPatchI input -> do
branchId1 <- hp' (input ^. #branchId1)
branchId2 <- hp' (input ^. #branchId2)
patch <- ps' (input ^. #patch)
pure (Text.unwords ["diff.namespace.to-patch", branchId1, branchId2, patch])
ClearI {} -> pure "clear"
DocToMarkdownI name -> pure ("debug.doc-to-markdown " <> Name.toText name)
--
@ -1356,14 +1110,11 @@ inputDescription input =
DebugFuzzyOptionsI cmd input -> pure . Text.pack $ "debug.fuzzy-completions " <> unwords (cmd : toList input)
DebugFormatI -> pure "debug.format"
DebugTypecheckedUnisonFileI {} -> wat
DeprecateTermI {} -> wat
DeprecateTypeI {} -> wat
DiffNamespaceI {} -> wat
DisplayI {} -> wat
DocsI {} -> wat
DocsToHtmlI {} -> wat
FindI {} -> wat
FindPatchI {} -> wat
FindShallowI {} -> wat
StructuredFindI {} -> wat
StructuredFindReplaceI {} -> wat
@ -1372,7 +1123,6 @@ inputDescription input =
LibInstallI {} -> wat
ListDependenciesI {} -> wat
ListDependentsI {} -> wat
ListEditsI {} -> wat
LoadI {} -> wat
MergeI {} -> wat
NamesI {} -> wat
@ -1411,8 +1161,6 @@ inputDescription input =
brp = fmap from . ProjectUtils.resolveBranchRelativePath
ops :: Maybe Path.Split -> Cli Text
ops = maybe (pure ".") ps
opatch :: Maybe Path.Split' -> Cli Text
opatch = ps' . fromMaybe Cli.defaultPatchPath
wat = error $ show input ++ " is not expected to alter the branch"
hhqs' :: Either SH.ShortHash Path.HQSplit' -> Cli Text
hhqs' = \case
@ -1592,73 +1340,6 @@ handleDependents hq = do
Cli.setNumberedArgs $ map (Text.unpack . Reference.toText . view _2) (types <> terms)
Cli.respond (ListDependents ppe lds (fst <$> types) (fst <$> terms))
handleDiffNamespaceToPatch :: Text -> DiffNamespaceToPatchInput -> Cli ()
handleDiffNamespaceToPatch description input = do
Cli.Env {codebase} <- ask
absBranchId1 <- Cli.resolveBranchIdToAbsBranchId (input ^. #branchId1)
absBranchId2 <- Cli.resolveBranchIdToAbsBranchId (input ^. #branchId2)
patch <- do
Cli.runTransactionWithRollback \rollback -> do
branch1 <- Cli.resolveAbsBranchIdV2 rollback absBranchId1
branch2 <- Cli.resolveAbsBranchIdV2 rollback absBranchId2
branchDiff <- V2Branch.Diff.diffBranches branch1 branch2 >>= V2Branch.Diff.nameBasedDiff
termEdits <-
(branchDiff ^. #terms)
& Relation.domain
& Map.toList
& traverse \(oldRef, newRefs) -> makeTermEdit codebase oldRef newRefs
pure
Patch
{ _termEdits =
termEdits
& catMaybes
& Relation.fromList,
_typeEdits =
(branchDiff ^. #types)
& Relation.domain
& Map.toList
& mapMaybe (\(oldRef, newRefs) -> makeTypeEdit oldRef newRefs)
& Relation.fromList
}
-- Display the patch that we are about to create.
suffixifiedPPE <- PPED.suffixifiedPPE <$> Cli.currentPrettyPrintEnvDecl
Cli.respondNumbered (ListEdits patch suffixifiedPPE)
(patchPath, patchName) <- Cli.resolveSplit' (input ^. #patch)
-- Add the patch to the in-memory root branch and flush it all to SQLite.
-- If there's already a patch at the given path, overwrite it.
Cli.stepAtM
description
(Path.unabsolute patchPath, Branch.modifyPatches patchName (const patch))
where
-- Given {old reference} and {new references}, create term edit patch entries as follows:
--
-- * If the {new references} is a singleton set {new reference}, proceed. (Otherwise, the patch we might create
-- would not be a function, which is a bogus/conflicted patch).
-- * Look up {old reference} and {new reference} types in the codebase (which can technically fail, due to
-- non-transactionality of this command, though we don't typically delete anything from SQLite), and create a
-- patch entry that maps {old reference} to {new reference} with the typing relationship.
makeTermEdit ::
Codebase m Symbol Ann ->
V2.Reference ->
Set V2.Reference ->
Sqlite.Transaction (Maybe (Reference, TermEdit))
makeTermEdit codebase (Conversions.reference2to1 -> oldRef) newRefs =
runMaybeT do
newRef <- Conversions.reference2to1 <$> MaybeT (pure (Set.asSingleton newRefs))
oldRefType <- MaybeT (Codebase.getTypeOfTerm codebase oldRef)
newRefType <- MaybeT (Codebase.getTypeOfTerm codebase newRef)
pure (oldRef, TermEdit.Replace newRef (TermEdit.typing oldRefType newRefType))
-- Same idea as 'makeTermEdit', but simpler, because there's nothing to look up in the database.
makeTypeEdit :: V2.Reference -> Set V2.Reference -> Maybe (Reference, TypeEdit)
makeTypeEdit (Conversions.reference2to1 -> oldRef) newRefs =
Set.asSingleton newRefs <&> \newRef -> (oldRef, TypeEdit.Replace (Conversions.reference2to1 newRef))
-- | Handle a @ShowDefinitionI@ input command, i.e. `view` or `edit`.
handleShowDefinition :: OutputLocation -> ShowDefinitionScope -> NonEmpty (HQ.HashQualified Name) -> Cli ()
handleShowDefinition outputLoc showDefinitionScope query = do
@ -2205,15 +1886,6 @@ addWatch watchName (Just uf) = do
)
_ -> addWatch watchName Nothing
hqNameQuery :: Names.SearchType -> [HQ.HashQualified Name] -> Cli QueryResult
hqNameQuery searchType query = do
Cli.Env {codebase} <- ask
names <- Cli.currentNames
Cli.runTransaction do
hqLength <- Codebase.hashLength
let nameSearch = NameSearch.makeNameSearch hqLength names
Backend.hqNameQuery codebase nameSearch searchType query
looseCodeOrProjectToPath :: Either Path' (ProjectAndBranch Sqlite.Project Sqlite.ProjectBranch) -> Path'
looseCodeOrProjectToPath = \case
Left pth -> pth

View File

@ -1,7 +1,6 @@
module Unison.Codebase.Editor.Input
( Input (..),
BranchSourceI (..),
DiffNamespaceToPatchInput (..),
GistInput (..),
PullSourceTarget (..),
PushRemoteBranchInput (..),
@ -142,8 +141,6 @@ data Input
MoveTermI Path.HQSplit' Path.Split'
| MoveTypeI Path.HQSplit' Path.Split'
| MoveBranchI Path.Path' Path.Path'
| MovePatchI Path.Split' Path.Split'
| CopyPatchI Path.Split' Path.Split'
| -- delete = unname
DeleteI DeleteTarget
| -- edits stuff:
@ -155,14 +152,6 @@ data Input
| Update2I
| PreviewUpdateI (Set Name)
| TodoI (Maybe PatchPath) Path'
| PropagatePatchI PatchPath Path'
| ListEditsI (Maybe PatchPath)
| -- -- create and remove update directives
DeprecateTermI PatchPath Path.HQSplit'
| DeprecateTypeI PatchPath Path.HQSplit'
| ReplaceI (HQ.HashQualified Name) (HQ.HashQualified Name) (Maybe PatchPath)
| RemoveTermReplacementI (HQ.HashQualified Name) (Maybe PatchPath)
| RemoveTypeReplacementI (HQ.HashQualified Name) (Maybe PatchPath)
| UndoI
| -- First `Maybe Int` is cap on number of results, if any
-- Second `Maybe Int` is cap on diff elements shown, if any
@ -190,7 +179,6 @@ data Input
| -- other
FindI Bool FindScope [String] -- FindI isVerbose findScope query
| FindShallowI Path'
| FindPatchI
| StructuredFindI FindScope (HQ.HashQualified Name) -- sfind findScope query
| StructuredFindReplaceI (HQ.HashQualified Name) -- sfind.replace rewriteQuery
| -- Show provided definitions.
@ -225,7 +213,6 @@ data Input
| GistI GistInput
| AuthLoginI
| VersionI
| DiffNamespaceToPatchI DiffNamespaceToPatchInput
| ProjectCreateI Bool {- try downloading base? -} (Maybe ProjectName)
| ProjectRenameI ProjectName
| ProjectSwitchI ProjectAndBranchNames
@ -252,16 +239,6 @@ data BranchSourceI
BranchSourceI'LooseCodeOrProject LooseCodeOrProject
deriving stock (Eq, Show)
data DiffNamespaceToPatchInput = DiffNamespaceToPatchInput
{ -- The first/earlier namespace.
branchId1 :: BranchId,
-- The second/later namespace.
branchId2 :: BranchId,
-- Where to store the patch that corresponds to the diff between the namespaces.
patch :: Path.Split'
}
deriving stock (Eq, Generic, Show)
-- | @"push.gist repo"@ pushes the contents of the current namespace to @repo@.
data GistInput = GistInput
{ repo :: WriteGitRepo
@ -332,7 +309,6 @@ data DeleteTarget
| DeleteTarget'Term DeleteOutput [Path.HQSplit']
| DeleteTarget'Type DeleteOutput [Path.HQSplit']
| DeleteTarget'Namespace Insistence (Maybe Path.Split)
| DeleteTarget'Patch Path.Split'
| DeleteTarget'ProjectBranch (ProjectAndBranch (Maybe ProjectName) ProjectBranchName)
| DeleteTarget'Project ProjectName
deriving stock (Eq, Show)

View File

@ -17,7 +17,6 @@ module Unison.Codebase.Editor.Output
where
import Data.List.NonEmpty (NonEmpty)
import Data.Set qualified as Set
import Data.Set.NonEmpty (NESet)
import Data.Time (UTCTime)
import Network.URI (URI)
@ -39,7 +38,6 @@ import Unison.Codebase.Editor.SlurpResult (SlurpResult (..))
import Unison.Codebase.Editor.SlurpResult qualified as SR
import Unison.Codebase.Editor.TodoOutput qualified as TO
import Unison.Codebase.IntegrityCheck (IntegrityResult (..))
import Unison.Codebase.Patch (Patch)
import Unison.Codebase.Path (Path')
import Unison.Codebase.Path qualified as Path
import Unison.Codebase.PushBehavior (PushBehavior)
@ -128,7 +126,6 @@ data NumberedOutput
HashLength
[(CausalHash, Names.Diff)]
HistoryTail -- 'origin point' of this view of history.
| ListEdits Patch PPE.PrettyPrintEnv
| ListProjects [Sqlite.Project]
| ListBranches ProjectName [(ProjectBranchName, [(URI, ProjectName, ProjectBranchName)])]
| AmbiguousSwitch ProjectName (ProjectAndBranch ProjectName ProjectBranchName)
@ -173,7 +170,6 @@ data Output
| CreatedNewBranch Path.Absolute
| BranchAlreadyExists Path'
| FindNoLocalMatches
| PatchAlreadyExists Path.Split'
| NoExactTypeMatches
| TypeAlreadyExists Path.Split' (Set Reference)
| TypeParseError String (Parser.Err Symbol)
@ -192,13 +188,11 @@ data Output
| EmptyProjectBranchPush (ProjectAndBranch ProjectName ProjectBranchName)
| NameNotFound Path.HQSplit'
| NamesNotFound [Name]
| PatchNotFound Path.Split'
| TypeNotFound Path.HQSplit'
| TermNotFound Path.HQSplit'
| MoveNothingFound Path'
| TypeNotFound' ShortHash
| TermNotFound' ShortHash
| TypeTermMismatch (HQ.HashQualified Name) (HQ.HashQualified Name)
| NoLastRunResult
| SaveTermNameConflict Name
| SearchTermsNotFound [HQ.HashQualified Name]
@ -231,7 +225,6 @@ data Output
-- list of all the definitions within this branch
| ListOfDefinitions FindScope PPE.PrettyPrintEnv ListDetailed [SearchResult' Symbol Ann]
| ListShallow (IO PPE.PrettyPrintEnv) [ShallowListEntry Symbol Ann]
| ListOfPatches (Set Name)
| ListStructuredFind [HQ.HashQualified Name]
| -- ListStructuredFind patternMatchingUsages termBodyUsages
-- show the result of add/update
@ -275,8 +268,6 @@ data Output
| ConfiguredRemoteMappingParseError PushPull Path.Absolute Text String
| TermMissingType Reference
| AboutToPropagatePatch
| -- todo: tell the user to run `todo` on the same patch they just used
NothingToPatch PatchPath Path'
| PatchNeedsToBeConflictFree
| PatchInvolvesExternalDependents PPE.PrettyPrintEnv (Set Reference)
| StartOfCurrentPathHistory
@ -488,7 +479,6 @@ isFailure o = case o of
BranchAlreadyExists {} -> True
-- we do a global search after finding no local matches, so let's not call this a failure yet
FindNoLocalMatches {} -> False
PatchAlreadyExists {} -> True
NoExactTypeMatches -> True
BranchEmpty {} -> True
EmptyLooseCodePush {} -> True
@ -508,13 +498,11 @@ isFailure o = case o of
BranchNotFound {} -> True
NameNotFound {} -> True
NamesNotFound _ -> True
PatchNotFound {} -> True
TypeNotFound {} -> True
TypeNotFound' {} -> True
TermNotFound {} -> True
MoveNothingFound {} -> True
TermNotFound' {} -> True
TypeTermMismatch {} -> True
SearchTermsNotFound ts -> not (null ts)
SearchTermsNotFoundDetailed _ misses otherHits -> not (null misses && null otherHits)
DeleteBranchConfirmation {} -> False
@ -524,7 +512,6 @@ isFailure o = case o of
DeletedEverything -> False
ListNames _ _ tys tms -> null tms && null tys
ListOfDefinitions _ _ _ ds -> null ds
ListOfPatches s -> Set.null s
ListStructuredFind tms -> null tms
SlurpOutput _ _ sr -> not $ SR.isOk sr
ParseErrors {} -> True
@ -549,7 +536,6 @@ isFailure o = case o of
PatchNeedsToBeConflictFree {} -> True
PatchInvolvesExternalDependents {} -> True
AboutToPropagatePatch {} -> False
NothingToPatch {} -> False
StartOfCurrentPathHistory -> True
NotImplemented -> True
DumpNumberedArgs {} -> False
@ -662,7 +648,6 @@ isNumberedFailure = \case
DeletedDespiteDependents {} -> False
History {} -> False
ListBranches {} -> False
ListEdits {} -> False
ListProjects {} -> False
ShowDiffAfterCreateAuthor {} -> False
ShowDiffAfterDeleteBranch {} -> False

View File

@ -19,7 +19,6 @@ module Unison.CommandLine.InputPatterns
clear,
clone,
compileScheme,
copyPatch,
createAuthor,
debugClearWatchCache,
debugDoctor,
@ -39,19 +38,15 @@ module Unison.CommandLine.InputPatterns
deleteBranch,
deleteNamespace,
deleteNamespaceForce,
deletePatch,
deleteProject,
deleteTerm,
deleteTermReplacement,
deleteTermVerbose,
deleteType,
deleteTypeReplacement,
deleteTypeVerbose,
deleteVerbose,
dependencies,
dependents,
diffNamespace,
diffNamespaceToPatch,
display,
displayTo,
docToMarkdown,
@ -65,7 +60,6 @@ module Unison.CommandLine.InputPatterns
findGlobal,
findIn,
findInAll,
findPatch,
findShallow,
findVerbose,
findVerboseAll,
@ -88,7 +82,6 @@ module Unison.CommandLine.InputPatterns
moveAll,
names,
namespaceDependencies,
patch,
previewAdd,
previewUpdate,
printVersion,
@ -106,10 +99,8 @@ module Unison.CommandLine.InputPatterns
quit,
releaseDraft,
renameBranch,
renamePatch,
renameTerm,
renameType,
replace,
reset,
resetRoot,
runScheme,
@ -129,12 +120,9 @@ module Unison.CommandLine.InputPatterns
upgrade,
view,
viewGlobal,
viewPatch,
viewReflog,
-- * Misc
deleteTermReplacementCommand,
deleteTypeReplacementCommand,
helpFor,
makeExample',
makeExample,
@ -495,45 +483,6 @@ previewUpdate =
)
\ws -> pure $ Input.PreviewUpdateI (Set.fromList $ map (Name.unsafeParseText . Text.pack) ws)
patch :: InputPattern
patch =
InputPattern
"patch"
[]
I.Visible
[("patch", Required, patchArg), ("namespace", Optional, namespaceArg)]
( P.lines
[ P.wrap $
makeExample' patch
<> "rewrites any definitions that depend on "
<> "definitions with type-preserving edits to use the updated versions of"
<> "these dependencies.",
"",
P.wrapColumn2
[ ( makeExample patch ["<patch>", "[path]"],
"applies the given patch"
<> "to the given namespace"
),
( makeExample patch ["<patch>"],
"applies the given patch"
<> "to the current namespace"
)
]
]
)
\case
patchStr : ws -> first P.text do
patch <- Path.parseSplit' patchStr
branch <- case ws of
[pathStr] -> Path.parsePath' pathStr
_ -> pure Path.relativeEmpty'
pure $ Input.PropagatePatchI patch branch
[] ->
Left $
warn $
makeExample' patch
<> "takes a patch and an optional namespace."
view :: InputPattern
view =
InputPattern
@ -852,18 +801,6 @@ findVerboseAll =
)
(pure . Input.FindI True (Input.FindLocalAndDeps Path.empty))
findPatch :: InputPattern
findPatch =
InputPattern
"find.patch"
["list.patch", "ls.patch"]
I.Visible
[]
( P.wrapColumn2
[("`find.patch`", "lists all patches in the current namespace.")]
)
(pure . const Input.FindPatchI)
renameTerm :: InputPattern
renameTerm =
InputPattern
@ -989,54 +926,6 @@ deleteType = deleteGen (Just "type") exactDefinitionTypeQueryArg "type" (DeleteT
deleteTypeVerbose :: InputPattern
deleteTypeVerbose = deleteGen (Just "type.verbose") exactDefinitionTypeQueryArg "type" (DeleteTarget'Type DeleteOutput'Diff)
deleteTermReplacementCommand :: String
deleteTermReplacementCommand = "delete.term-replacement"
deleteTypeReplacementCommand :: String
deleteTypeReplacementCommand = "delete.type-replacement"
deleteReplacement :: Bool -> InputPattern
deleteReplacement isTerm =
InputPattern
commandName
[]
I.Visible
[("definition", Required, if isTerm then exactDefinitionTermQueryArg else exactDefinitionTypeQueryArg), ("patch", Optional, patchArg)]
( P.string $
commandName
<> " <foo> <patch>` removes any edit of the "
<> str
<> " `foo` from the patch `patch`, "
<> "or from the default patch if none is specified. Note that `foo` refers to the "
<> "original name for the "
<> str
<> " - not the one in place after the edit."
)
( \case
query : patch -> do
patch <- first P.text . traverse Path.parseSplit' $ listToMaybe patch
q <- parseHashQualifiedName query
pure $ input q patch
_ ->
Left
. P.warnCallout
. P.wrapString
$ commandName
<> " needs arguments. See `help "
<> commandName
<> "`."
)
where
input =
if isTerm
then Input.RemoveTermReplacementI
else Input.RemoveTypeReplacementI
str = if isTerm then "term" else "type"
commandName =
if isTerm
then deleteTermReplacementCommand
else deleteTypeReplacementCommand
deleteProject :: InputPattern
deleteProject =
InputPattern
@ -1082,12 +971,6 @@ deleteBranch =
branchInclusion = AllBranches
}
deleteTermReplacement :: InputPattern
deleteTermReplacement = deleteReplacement True
deleteTypeReplacement :: InputPattern
deleteTypeReplacement = deleteReplacement False
aliasTerm :: InputPattern
aliasTerm =
InputPattern
@ -1243,56 +1126,6 @@ deleteNamespaceParser helpText insistence = \case
pure $ Input.DeleteI (DeleteTarget'Namespace insistence (Just p))
_ -> Left helpText
deletePatch :: InputPattern
deletePatch =
InputPattern
"delete.patch"
[]
I.Visible
[("patch to delete", Required, patchArg)]
"`delete.patch <foo>` deletes the patch `foo`"
\case
[p] -> first P.text do
p <- Path.parseSplit' p
pure . Input.DeleteI $ DeleteTarget'Patch p
_ -> Left (I.help deletePatch)
movePatch :: String -> String -> Either (P.Pretty CT.ColorText) Input
movePatch src dest = first P.text do
src <- Path.parseSplit' src
dest <- Path.parseSplit' dest
pure $ Input.MovePatchI src dest
copyPatch' :: String -> String -> Either (P.Pretty CT.ColorText) Input
copyPatch' src dest = first P.text do
src <- Path.parseSplit' src
dest <- Path.parseSplit' dest
pure $ Input.CopyPatchI src dest
copyPatch :: InputPattern
copyPatch =
InputPattern
"copy.patch"
[]
I.Visible
[("patch to copy", Required, patchArg), ("copy destination", Required, newNameArg)]
"`copy.patch foo bar` copies the patch `foo` to `bar`."
\case
[src, dest] -> copyPatch' src dest
_ -> Left (I.help copyPatch)
renamePatch :: InputPattern
renamePatch =
InputPattern
"move.patch"
["rename.patch"]
I.Visible
[("patch", Required, patchArg), ("new location", Required, newNameArg)]
"`move.patch foo bar` renames the patch `foo` to `bar`."
\case
[src, dest] -> movePatch src dest
_ -> Left (I.help renamePatch)
renameBranch :: InputPattern
renameBranch =
InputPattern
@ -2012,45 +1845,6 @@ mergeOldPreviewInputPattern =
branchInclusion = AllBranches
}
replaceEdit ::
( HQ.HashQualified Name ->
HQ.HashQualified Name ->
Maybe Input.PatchPath ->
Input
) ->
InputPattern
replaceEdit f = self
where
self =
InputPattern
"replace"
[]
I.Visible
[ ("definition to replace", Required, definitionQueryArg),
("definition replacement", Required, definitionQueryArg),
("patch", Optional, patchArg)
]
( P.wrapColumn2
[ ( makeExample self ["<from>", "<to>", "<patch>"],
"Replace the term/type <from> in the given patch with the term/type <to>."
),
( makeExample self ["<from>", "<to>"],
"Replace the term/type <from> with <to> in the default patch."
)
]
)
( \case
source : target : patch -> do
patch <- first P.text <$> traverse Path.parseSplit' $ listToMaybe patch
sourcehq <- parseHashQualifiedName source
targethq <- parseHashQualifiedName target
pure $ f sourcehq targethq patch
_ -> Left $ I.help self
)
replace :: InputPattern
replace = replaceEdit Input.ReplaceI
viewReflog :: InputPattern
viewReflog =
InputPattern
@ -2348,29 +2142,6 @@ quit =
[] -> pure Input.QuitI
_ -> Left "Use `quit`, `exit`, or <Ctrl-D> to quit."
viewPatch :: InputPattern
viewPatch =
InputPattern
"view.patch"
[]
I.Visible
[("patch", Optional, patchArg)]
( P.wrapColumn2
[ ( makeExample' viewPatch,
"Lists all the edits in the default patch."
),
( makeExample viewPatch ["<patch>"],
"Lists all the edits in the given patch."
)
]
)
\case
[] -> Right $ Input.ListEditsI Nothing
[patchStr] -> mapLeft P.text do
patch <- Path.parseSplit' patchStr
Right $ Input.ListEditsI (Just patch)
_ -> Left $ warn "`view.patch` takes a patch and that's it."
names :: Input.IsGlobal -> InputPattern
names isGlobal =
InputPattern
@ -2865,24 +2636,6 @@ printVersion =
_ -> Left (showPatternHelp printVersion)
)
diffNamespaceToPatch :: InputPattern
diffNamespaceToPatch =
InputPattern
{ patternName = "diff.namespace.to-patch",
aliases = [],
visibility = I.Visible,
args = [],
help = P.wrap "Create a patch from a namespace diff.",
parse = \case
[branchId1, branchId2, patch] ->
mapLeft P.text do
branchId1 <- Input.parseBranchId branchId1
branchId2 <- Input.parseBranchId branchId2
patch <- Path.parseSplit' patch
pure (Input.DiffNamespaceToPatchI Input.DiffNamespaceToPatchInput {branchId1, branchId2, patch})
_ -> Left (showPatternHelp diffNamespaceToPatch)
}
projectCreate :: InputPattern
projectCreate =
InputPattern
@ -3174,7 +2927,6 @@ validInputs =
clear,
clone,
compileScheme,
copyPatch,
createAuthor,
debugClearWatchCache,
debugDoctor,
@ -3195,18 +2947,14 @@ validInputs =
deleteProject,
deleteNamespace,
deleteNamespaceForce,
deletePatch,
deleteTerm,
deleteTermReplacement,
deleteTermVerbose,
deleteType,
deleteTypeReplacement,
deleteTypeVerbose,
deleteVerbose,
dependencies,
dependents,
diffNamespace,
diffNamespaceToPatch,
display,
displayTo,
docToMarkdown,
@ -3220,7 +2968,6 @@ validInputs =
findAll,
findInAll,
findGlobal,
findPatch,
findShallow,
findVerbose,
findVerboseAll,
@ -3245,7 +2992,6 @@ validInputs =
names False, -- names
names True, -- names.global
namespaceDependencies,
patch,
previewAdd,
previewUpdate,
printVersion,
@ -3263,11 +3009,9 @@ validInputs =
quit,
releaseDraft,
renameBranch,
renamePatch,
renameTerm,
renameType,
moveAll,
replace,
reset,
resetRoot,
runScheme,
@ -3285,7 +3029,6 @@ validInputs =
upgrade,
view,
viewGlobal,
viewPatch,
viewReflog
]

View File

@ -6,9 +6,7 @@
module Unison.CommandLine.OutputMessages where
import Control.Lens hiding (at)
import Control.Monad.State
import Control.Monad.State.Strict qualified as State
import Control.Monad.Writer (Writer, runWriter, tell)
import Data.ByteString.Lazy qualified as LazyByteString
import Data.Foldable qualified as Foldable
import Data.List (stripPrefix)
@ -128,7 +126,6 @@ import Unison.Server.Backend qualified as Backend
import Unison.Server.SearchResult' qualified as SR'
import Unison.Share.Sync qualified as Share
import Unison.Share.Sync.Types (CodeserverTransportError (..))
import Unison.ShortHash qualified as ShortHash
import Unison.Sync.Types qualified as Share
import Unison.Syntax.DeclPrinter qualified as DeclPrinter
import Unison.Syntax.HashQualified qualified as HQ (toText, unsafeFromVar)
@ -405,7 +402,6 @@ notifyNumbered = \case
],
numberedArgsForEndangerments ppeDecl endangerments
)
ListEdits patch ppe -> showListEdits patch ppe
ListProjects projects ->
( P.numberedList (map (prettyProjectName . view #name) projects),
map (Text.unpack . into @Text . view #name) projects
@ -551,99 +547,6 @@ undoTip =
<> 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 = Text.unpack . ShortHash.toText . 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], [Text.unpack (HQ.toText 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 = Text.unpack . ShortHash.toText . 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], [Text.unpack (HQ.toText rhsTypeName)])
pure
( showNum n1 <> (P.syntaxToColor . prettyHashQualified $ lhsTypeName),
"-> " <> showNum n2 <> (P.syntaxToColor . prettyHashQualified $ rhsTypeName)
)
notifyUser :: FilePath -> Output -> IO Pretty
notifyUser dir = \case
SaveTermNameConflict name ->
@ -782,13 +685,6 @@ notifyUser dir = \case
<> " by someone else. Trying your command again might fix it."
]
EvaluationFailure err -> pure err
TypeTermMismatch typeName termName ->
pure $
P.warnCallout "I was expecting either two types or two terms but was given a type "
<> P.syntaxToColor (prettyHashQualified typeName)
<> " and a term "
<> P.syntaxToColor (prettyHashQualified termName)
<> "."
SearchTermsNotFound hqs | null hqs -> pure mempty
SearchTermsNotFound hqs ->
pure $
@ -814,8 +710,6 @@ notifyUser dir = \case
P.warnCallout typeOrTermMsg
<> P.newline
<> P.syntaxToColor (P.indent " " (P.lines (prettyHashQualified <$> otherHits)))
PatchNotFound _ ->
pure . P.warnCallout $ "I don't know about that patch."
NameNotFound _ ->
pure . P.warnCallout $ "I don't know about that name."
NamesNotFound hqs ->
@ -833,8 +727,6 @@ notifyUser dir = \case
pure . P.warnCallout $ "A term by that name already exists."
TypeAlreadyExists _ _ ->
pure . P.warnCallout $ "A type by that name already exists."
PatchAlreadyExists _ ->
pure . P.warnCallout $ "A patch by that name already exists."
BranchEmpty b ->
pure . P.warnCallout . P.wrap $
P.group (prettyWhichBranchEmpty b) <> "is an empty namespace."
@ -1356,17 +1248,6 @@ notifyUser dir = \case
"You're missing:" `P.hang` P.lines (fmap (P.text . Reference.toText) new),
"I'm missing:" `P.hang` P.lines (fmap (P.text . Reference.toText) old)
]
ListOfPatches patches ->
pure $
if null patches
then P.lit "nothing to show"
else numberedPatches patches
where
numberedPatches :: Set Name -> Pretty
numberedPatches patches =
(P.column2 . fmap format) ([(1 :: Integer) ..] `zip` (toList patches))
where
format (i, p) = (P.hiBlack . fromString $ show i <> ".", prettyName p)
NoConfiguredRemoteMapping pp p -> do
let (localPathExample, sharePathExample) =
if Path.isRoot p
@ -1500,12 +1381,6 @@ notifyUser dir = \case
"I could't find a type with hash "
<> (prettyShortHash sh)
AboutToPropagatePatch -> pure "Applying changes from patch..."
NothingToPatch _patchPath dest ->
pure $
P.callout "😶" . P.wrap $
"This had no effect. Perhaps the patch has already been applied"
<> "or it doesn't intersect with the definitions in"
<> P.group (prettyPath' dest <> ".")
PatchNeedsToBeConflictFree ->
pure . P.wrap $
"I tried to auto-apply the patch, but couldn't because it contained"

View File

@ -1,58 +0,0 @@
# Replace with terms and types
Let's set up some definitions to start:
```ucm:hide
.lib> builtins.merge
```
```unison
x = 1
y = 2
structural type X = One Nat
structural type Y = Two Nat Nat
```
```ucm
.> add
```
Test that replace works with terms
```ucm
.> replace x y
.> view x
```
Test that replace works with types
```ucm
.> replace X Y
.> find
.> view.patch patch
.> view X
```
Try with a type/term mismatch
```ucm:error
.> replace X x
```
```ucm:error
.> replace y Y
```
Try with missing references
```ucm:error
.> replace X NOPE
```
```ucm:error
.> replace y nope
```
```ucm:error
.> replace nope X
```
```ucm:error
.> replace nope y
```
```ucm:error
.> replace nope nope
```

View File

@ -1,146 +0,0 @@
# Replace with terms and types
Let's set up some definitions to start:
```unison
x = 1
y = 2
structural type X = One Nat
structural type Y = Two Nat Nat
```
```ucm
Loading changes detected in scratch.u.
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 type X
structural type Y
x : Nat
y : Nat
```
```ucm
.> add
⍟ I've added these definitions:
structural type X
structural type Y
x : Nat
y : Nat
```
Test that replace works with terms
```ucm
.> replace x y
Done.
.> view x
x : Nat
x = 2
```
Test that replace works with types
```ucm
.> replace X Y
Done.
.> find
1. structural type X
2. x : Nat
3. X.One : Nat -> Nat -> X
4. structural type Y
5. y : Nat
6. Y.Two : Nat -> Nat -> X
.> view.patch patch
Edited Types: 1. #68k40ra7l7 -> 3. X
Edited Terms: 2. #gjmq673r1v -> 4. x
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
.> view X
structural type X = One Nat Nat
```
Try with a type/term mismatch
```ucm
.> replace X x
⚠️
I was expecting either two types or two terms but was given a type X and a term x.
```
```ucm
.> replace y Y
⚠️
I was expecting either two types or two terms but was given a type Y and a term y.
```
Try with missing references
```ucm
.> replace X NOPE
⚠️
The following names were not found in the codebase. Check your spelling.
NOPE
```
```ucm
.> replace y nope
⚠️
The following names were not found in the codebase. Check your spelling.
nope
```
```ucm
.> replace nope X
⚠️
The following names were not found in the codebase. Check your spelling.
nope
```
```ucm
.> replace nope y
⚠️
The following names were not found in the codebase. Check your spelling.
nope
```
```ucm
.> replace nope nope
⚠️
The following names were not found in the codebase. Check your spelling.
nope
nope
```

View File

@ -1,42 +0,0 @@
# Test that copying a patch works as expected
```unison:hide
x = 1
```
```ucm
.> add
```
Change the definition of `x` so something goes in our patch:
```unison:hide
x = 2
```
```ucm
.> update.old foo.patch
```
Copy the patch and make sure it's still there.
```ucm
.> copy.patch foo.patch bar.patch
.> ls foo
.> view.patch foo.patch
.> ls bar
.> view.patch bar.patch
```
Now move the patch.
```ucm
.> move.patch foo.patch qux.patch
```
The moved patch should be gone.
```ucm:error
.> view.patch foo.patch
.> ls foo
```

View File

@ -1,80 +0,0 @@
# Test that copying a patch works as expected
```unison
x = 1
```
```ucm
.> add
⍟ I've added these definitions:
x : ##Nat
```
Change the definition of `x` so something goes in our patch:
```unison
x = 2
```
```ucm
.> update.old foo.patch
⍟ I've updated these names to your new definition:
x : ##Nat
```
Copy the patch and make sure it's still there.
```ucm
.> copy.patch foo.patch bar.patch
Done.
.> ls foo
1. patch (patch)
.> view.patch foo.patch
Edited Terms: 1. #gjmq673r1v -> 2. x
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
.> ls bar
1. patch (patch)
.> view.patch bar.patch
Edited Terms: 1. #gjmq673r1v -> 2. x
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
```
Now move the patch.
```ucm
.> move.patch foo.patch qux.patch
Done.
```
The moved patch should be gone.
```ucm
.> view.patch foo.patch
This patch is empty.
.> ls foo
nothing to show
```

View File

@ -1,94 +0,0 @@
# Deleting term and type replacements from patches
```unison
x = 1
```
```ucm
.> add
```
```unison
x = 2
```
```ucm
.> update.old
.> view.patch
```
```ucm
.> delete.term-replacement 1
.> view.patch
```
```unison
unique[a] type Foo = Foo
```
```ucm
.> add
```
```unison
unique[b] type Foo = Foo | Bar
```
```ucm
.> update.old
.> view.patch
```
```ucm
.> delete.type-replacement 1
.> view.patch
```
```unison
bar = 3
unique[aa] type bar = Foo
```
```ucm
.> add
```
```unison
unique[bb] type bar = Foo | Bar
```
```ucm
.> update.old
.> view.patch
.> delete.type-replacement 1
.> view.patch
```
we get an error when attempting to delete something that is neither a type nor a term
```ucm:error
.> view.patch
.> delete.type-replacement notHere
.> view.patch
```
When attempting to delete a type/term that doesn't exist, but a term/type exists
with that name, alert the user.
```unison
baz = 0
```
```ucm:error
.> add baz
.> delete.type-replacement baz
.> view.patch
```
```unison
unique type qux = Qux
```
```ucm:error
.> add qux
.> delete.term-replacement qux
.> view.patch
```

View File

@ -1,302 +0,0 @@
# Deleting term and type replacements from patches
```unison
x = 1
```
```ucm
Loading changes detected in scratch.u.
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`:
x : ##Nat
```
```ucm
.> add
⍟ I've added these definitions:
x : ##Nat
```
```unison
x = 2
```
```ucm
Loading changes detected in scratch.u.
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update`, here's how your codebase would
change:
⍟ These names already exist. You can `update` them to your
new definition:
x : ##Nat
```
```ucm
.> update.old
⍟ I've updated these names to your new definition:
x : ##Nat
.> view.patch
Edited Terms: 1. #gjmq673r1v -> 2. x
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
```
```ucm
.> delete.term-replacement 1
Done.
.> view.patch
This patch is empty.
```
```unison
unique[a] type Foo = Foo
```
```ucm
Loading changes detected in scratch.u.
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`:
type Foo
```
```ucm
.> add
⍟ I've added these definitions:
type Foo
```
```unison
unique[b] type Foo = Foo | Bar
```
```ucm
Loading changes detected in scratch.u.
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update`, here's how your codebase would
change:
⍟ These names already exist. You can `update` them to your
new definition:
type Foo
```
```ucm
.> update.old
⍟ I've updated these names to your new definition:
type Foo
.> view.patch
Edited Types: 1. #ool30cf4ma -> 2. Foo
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
```
```ucm
.> delete.type-replacement 1
Done.
.> view.patch
This patch is empty.
```
```unison
bar = 3
unique[aa] type bar = Foo
```
```ucm
Loading changes detected in scratch.u.
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`:
type bar
bar : ##Nat
```
```ucm
.> add
⍟ I've added these definitions:
type bar
bar : ##Nat
```
```unison
unique[bb] type bar = Foo | Bar
```
```ucm
Loading changes detected in scratch.u.
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update`, here's how your codebase would
change:
⍟ These names already exist. You can `update` them to your
new definition:
type bar
```
```ucm
.> update.old
⍟ I've updated these names to your new definition:
type bar
.> view.patch
Edited Types: 1. #evhqg163jj -> 2. bar
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
.> delete.type-replacement 1
Done.
.> view.patch
This patch is empty.
```
we get an error when attempting to delete something that is neither a type nor a term
```ucm
.> view.patch
This patch is empty.
.> delete.type-replacement notHere
⚠️
The following names were not found in the codebase. Check your spelling.
notHere
.> view.patch
This patch is empty.
```
When attempting to delete a type/term that doesn't exist, but a term/type exists
with that name, alert the user.
```unison
baz = 0
```
```ucm
Loading changes detected in scratch.u.
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`:
baz : ##Nat
```
```ucm
.> add baz
⍟ I've added these definitions:
baz : ##Nat
.> delete.type-replacement baz
⚠️
I was expecting the following names to be types, though I found terms instead.
baz
.> view.patch
This patch is empty.
```
```unison
unique type qux = Qux
```
```ucm
Loading changes detected in scratch.u.
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`:
type qux
```
```ucm
.> add qux
⍟ I've added these definitions:
type qux
.> delete.term-replacement qux
⚠️
I was expecting the following names to be terms, though I found types instead.
qux
.> view.patch
This patch is empty.
```

View File

@ -1,43 +0,0 @@
We can create a patch from the diff between two namespaces.
```ucm:hide
.> builtins.merge
```
```unison:hide
one.a = 1
one.b = 2
oneconflicts.b = 20
one.c = 3
one.d = 4
one.e = 4
two.a = 100
two.b = 200
two.c = 300
twoconflicts.c = 30
two.d = 5
two.e = 6
```
```ucm:hide
.> add
.> merge.old oneconflicts one
.> merge.old twoconflicts two
.> delete.namespace oneconflicts
.> delete.namespace twoconflicts
```
```ucm
.> find one.
.> find two.
.> diff.namespace.to-patch one two thepatch
```
A summary of the diff:
* `one.a` -> `two.a` is a normal update.
* Even though `one.b` is conflicted, both `one.b#hash1` and `one.b#hash2` get mapped to `two.b`.
* Because `two.c` is conflicted, `one.c` doesn't end up on the left-hand side of the patch.
* Because `one.d` and `one.e` are aliases, they don't end up on the left-hand side of the patch.
* Neither `one.f` nor `two.g` end up in the patch because the names `f` and `g` are not common to both namespaces.

View File

@ -24,7 +24,7 @@ two.e = 6
3. one.b#dcg : Nat
4. one.c : Nat
5. one.d : Nat
.> find two.
@ -34,24 +34,18 @@ two.e = 6
4. two.c#qpo : Nat
5. two.d : Nat
6. two.e : Nat
.> diff.namespace.to-patch one two thepatch
Edited Terms:
1. one.b#cp6ri8mtg0 -> 4. two.b
2. one.b#dcgdua2lj6 -> 5. two.b
3. one.a -> 6. two.a
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
```
A summary of the diff:
* `one.a` -> `two.a` is a normal update.
* Even though `one.b` is conflicted, both `one.b#hash1` and `one.b#hash2` get mapped to `two.b`.
* Because `two.c` is conflicted, `one.c` doesn't end up on the left-hand side of the patch.
* Because `one.d` and `one.e` are aliases, they don't end up on the left-hand side of the patch.
* Neither `one.f` nor `two.g` end up in the patch because the names `f` and `g are not common to both namespaces.
🛑
The transcript failed due to an error in the stanza above. The error is:
⚠️
I don't know how to diff.namespace.to-patch. Type `help` or `?`
to get help.

View File

@ -299,323 +299,16 @@ unique type Y a b = Y a b
.> view.patch ns2.patch
Edited Terms:
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
appropriate.
.> fork ns2 ns3
Done.
.> alias.term ns2.fromJust' ns2.yoohoo
Done.
.> delete.term.verbose ns2.fromJust'
Name changes:
Original Changes
1. ns2.fromJust ┐ 2. ns2.fromJust' (removed)
3. ns2.fromJust' │
4. ns2.yoohoo │
5. ns3.fromJust │
6. ns3.fromJust' ┘
Tip: You can use `undo` or `reflog` to undo this change.
.> diff.namespace ns3 ns2
Name changes:
Original Changes
1. fromJust ┐ 2. yoohoo (added)
3. fromJust' ┘ 4. fromJust' (removed)
```
```unison
bdependent = "banana"
```
```ucm
.ns3> update.old
⍟ I've updated these names to your new definition:
bdependent : ##Text
.> diff.namespace ns2 ns3
Updates:
1. bdependent : Nat
2. bdependent : Text
3. patch patch (added 1 updates)
Name changes:
Original Changes
4. fromJust ┐ 5. fromJust' (added)
6. yoohoo ┘ 7. yoohoo (removed)
```
## Two different auto-propagated changes creating a name conflict
Currently, the auto-propagated name-conflicted definitions are not explicitly
shown, only their also-conflicted dependency is shown.
```unison
a = 333
b = a + 1
.ns2> update.old.> diff.namespace ns1 ns2.> alias.term ns2.d ns2.d'.> alias.type ns2.A ns2.A'.> alias.type ns2.X ns2.X'.> diff.namespace ns1 ns2.> alias.type ns1.X ns1.X2.> alias.type ns2.A' ns2.A''.> view.patch ns2.patch.> fork ns2 ns3.> alias.term ns2.fromJust' ns2.yoohoo.> delete.term.verbose ns2.fromJust'.> diff.namespace ns3 ns2
```
```ucm
☝️ The namespace .nsx is empty.
.nsx> add
🛑
⍟ I've added these definitions:
a : ##Nat
b : ##Nat
The transcript failed due to an error in the stanza above. The error is:
.> fork nsx nsy
Done.
.> fork nsx nsz
Done.
```
```unison
a = 444
```
```ucm
.nsy> update.old
⍟ I've updated these names to your new definition:
a : ##Nat
```
```unison
a = 555
```
```ucm
.nsz> update.old
⍟ I've updated these names to your new definition:
a : ##Nat
.> merge.old nsy nsw
Here's what's changed in nsw after the merge:
Added definitions:
1. a : Nat
2. b : Nat
3. patch patch (added 1 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.
Applying changes from patch...
```
```ucm
.> merge.old nsz nsw
Here's what's changed in nsw after the merge:
New name conflicts:
1. a#mdl4vqtu00 : Nat
2. ┌ a#mdl4vqtu00 : Nat
3. └ a#vrs8gtkl2t : Nat
4. b#unkqhuu66p : Nat
5. ┌ b#aapqletas7 : Nat
6. └ b#unkqhuu66p : Nat
Updates:
7. patch patch (added 1 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.
Applying changes from patch...
I tried to auto-apply the patch, but couldn't because it
contained contradictory entries.
```
```ucm
.> diff.namespace nsx nsw
New name conflicts:
1. a#uiiiv8a86s : Nat
2. ┌ a#mdl4vqtu00 : Nat
3. └ a#vrs8gtkl2t : Nat
4. b#lhigeb1let : Nat
5. ┌ b#aapqletas7 : Nat
6. └ b#unkqhuu66p : Nat
Added definitions:
7. patch patch (added 2 updates)
.nsw> view a b
a#mdl4vqtu00 : ##Nat
a#mdl4vqtu00 = 444
a#vrs8gtkl2t : ##Nat
a#vrs8gtkl2t = 555
b#aapqletas7 : ##Nat
b#aapqletas7 = ##Nat.+ a#vrs8gtkl2t 1
b#unkqhuu66p : ##Nat
b#unkqhuu66p = ##Nat.+ a#mdl4vqtu00 1
```
## Should be able to diff a namespace hash from history.
```unison
x = 1
```
```ucm
Loading changes detected in scratch.u.
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`:
x : ##Nat
```
```ucm
☝️ The namespace .hashdiff is empty.
.hashdiff> add
⍟ I've added these definitions:
x : ##Nat
```
```unison
y = 2
```
```ucm
Loading changes detected in scratch.u.
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`:
y : ##Nat
```
```ucm
.hashdiff> add
⍟ I've added these definitions:
y : ##Nat
.hashdiff> history
Note: The most recent namespace hash is immediately below this
message.
⊙ 1. #ru1hnjofdj
+ Adds / updates:
y
□ 2. #i52j9fd57b (start of history)
.hashdiff> diff.namespace 2 1
Added definitions:
1. y : ##Nat
```
##
Updates: -- 1 to 1
New name conflicts: -- updates where RHS has multiple hashes (excluding when RHS=LHS)
1. foo#jk19sm5bf8 : Nat - do we want to force a hashqualified? Arya thinks so
2. ┌ foo#0ja1qfpej6 : Nat
3. └ foo#jk19sm5bf8 : Nat
Resolved name conflicts: -- updates where LHS had multiple hashes and RHS has one
4. ┌ bar#0ja1qfpej6 : Nat
5. └ bar#jk19sm5bf8 : Nat
6. bar#jk19sm5bf8 : Nat
## Display issues to fixup
- [d] Do we want to surface new edit conflicts in patches?
- [t] two different auto-propagated changes creating a name conflict should show
up somewhere besides the auto-propagate count
- [t] Things look screwy when the type signature doesn't fit and has to get broken
up into multiple lines. Maybe just disallow that?
- [d] Delete blank line in between copies / renames entries if all entries are 1 to 1
see todo in the code
- [x] incorrectly calculated bracket alignment on hashqualified "Name changes" (delete.output.md)
- [x] just handle deletion of isPropagated in propagate function, leave HandleInput alone (assuming this does the trick)
- [x] might want unqualified names to be qualified sometimes:
- [x] if a name is updated to a not-yet-named reference, it's shown as both an update and an add
- [x] similarly, if a conflicted name is resolved by deleting the last name to
a reference, I (arya) suspect it will show up as a Remove
- [d] Maybe group and/or add headings to the types, constructors, terms
- [x] add tagging of propagated updates to test propagated updates output
- [x] missing old names in deletion ppe (delete.output.md) (superseded by \#1143)
- [x] delete.term has some bonkers output
- [x] Make a decision about how we want to show constructors in the diff
- [x] 12.patch patch needs a space
- [x] This looks like garbage
- [x] Extra 2 blank lines at the end of the add section
- [x] Fix alignment issues with buildTable, convert to column3M (to be written)
- [x] adding an alias is showing up as an Add and a Copy; should just show as Copy
- [x] removing one of multiple aliases appears in removes + moves + copies section
- [x] some overlapping cases between Moves and Copies^
- [x] Maybe don't list the type signature twice for aliases?
⚠️
I don't know how to view.patch. Type `help` or `?` to get help.

View File

@ -1,27 +0,0 @@
# find.patch Test
```ucm:hide
.> builtins.merge
```
```unison test.u
hey = "yello"
```
```ucm
.> add
```
Update
```unison test.u
hey = "hello"
```
Update
```ucm
.> update.old
.> find.patch
.> view.patch 1
```

View File

@ -1,77 +0,0 @@
# find.patch Test
```unison
---
title: test.u
---
hey = "yello"
```
```ucm
Loading changes detected in test.u.
I found and typechecked these definitions in test.u. If you do
an `add` or `update`, here's how your codebase would change:
⍟ These new definitions are ok to `add`:
hey : Text
```
```ucm
.> add
⍟ I've added these definitions:
hey : Text
```
Update
```unison
---
title: test.u
---
hey = "hello"
```
```ucm
Loading changes detected in test.u.
I found and typechecked these definitions in test.u. If you do
an `add` or `update`, here's how your codebase would change:
⍟ These names already exist. You can `update` them to your
new definition:
hey : Text
```
Update
```ucm
.> update.old
⍟ I've updated these names to your new definition:
hey : Text
.> find.patch
1. patch
.> view.patch 1
Edited Terms: 1. #m0kuh98ou7 -> 2. hey
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
```

View File

@ -1,8 +1,6 @@
Previously, the `alias.term` and `alias.type` would fail if the source argument was hash-only, and there was no way to create an alias for a definition that didn't already have a name. Also, the `replace.term` and `replace.type` _only_ worked on hashes, and they had to be _full_ hashes.
With this PR, the source of an alias can be a short hash (even of a definition that doesn't currently have a name in the namespace) along with a name or hash-qualified name from the current namespace as usual, and the arguments to `replace.term` and `replace.type` can be a short hash, a name, or a hash-qualified name.
Note: `replace.term` and `replace.type` have since been replaced with just `replace`.
With this PR, the source of an alias can be a short hash (even of a definition that doesn't currently have a name in the namespace) along with a name or hash-qualified name from the current namespace as usual.
Let's make some hash-only aliases, now that we can. :mad-with-power-emoji:
@ -10,29 +8,3 @@ Let's make some hash-only aliases, now that we can. :mad-with-power-emoji:
.> alias.type ##Nat Cat
.> alias.term ##Nat.+ please_fix_763.+
```
And some functions that use them:
```unison
f = 3
g = 4
h = f + 1
> h
```
```ucm
.> add
```
We used to have to know the full hash for a definition to be able to use the `replace` commands, but now we don't:
```ucm
.> names g
.> replace f g
.> names g
.> view.patch
```
The value of `h` should have been updated too:
```unison
> h
```

View File

@ -1,8 +1,6 @@
Previously, the `alias.term` and `alias.type` would fail if the source argument was hash-only, and there was no way to create an alias for a definition that didn't already have a name. Also, the `replace.term` and `replace.type` _only_ worked on hashes, and they had to be _full_ hashes.
With this PR, the source of an alias can be a short hash (even of a definition that doesn't currently have a name in the namespace) along with a name or hash-qualified name from the current namespace as usual, and the arguments to `replace.term` and `replace.type` can be a short hash, a name, or a hash-qualified name.
Note: `replace.term` and `replace.type` have since been replaced with just `replace`.
With this PR, the source of an alias can be a short hash (even of a definition that doesn't currently have a name in the namespace) along with a name or hash-qualified name from the current namespace as usual.
Let's make some hash-only aliases, now that we can. :mad-with-power-emoji:
@ -16,96 +14,3 @@ Let's make some hash-only aliases, now that we can. :mad-with-power-emoji:
Done.
```
And some functions that use them:
```unison
f = 3
g = 4
h = f + 1
> h
```
```ucm
Loading changes detected in scratch.u.
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`:
f : Cat
g : Cat
h : Cat
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
5 | > h
4
```
```ucm
.> add
⍟ I've added these definitions:
f : Cat
g : Cat
h : Cat
```
We used to have to know the full hash for a definition to be able to use the `replace` commands, but now we don't:
```ucm
.> names g
Term
Hash: #vcfbbslncd
Names: g
Tip: Use `names.global` to see more results.
.> replace f g
Done.
.> names g
Term
Hash: #vcfbbslncd
Names: f g
Tip: Use `names.global` to see more results.
.> view.patch
Edited Terms: 1. #f3lgjvjqoo -> 2. f
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
```
The value of `h` should have been updated too:
```unison
> h
```
```ucm
Loading changes detected in scratch.u.
scratch.u changed.
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
1 | > h
5
```

View File

@ -1,116 +0,0 @@
# Resolving edit conflicts in `ucm`
```ucm:hide
.> builtins.merge
```
The `ucm` tool tracks edits to hashes in an object called a _patch_. When patches get merged, sometimes those patches will have conflicting edits. The `replace` command helps resolve such conflicts.
First, let's make a new namespace, `example.resolve` and add the builtins:
```ucm:hide
.example.resolve> builtins.merge
```
Now let's add a term named `a.foo`:
```unison
a.foo = 42
```
```ucm
.example.resolve> add
```
We'll fork the namespace `a` into a new namespace `b`, so we can edit the two concurrently.
```ucm
.example.resolve> fork a b
```
We'll also make a second fork `c` which we'll use as the target for our patch later.
```ucm
.example.resolve> fork a c
```
Now let's make a change to `foo` in the `a` namespace:
```ucm
.example.resolve> deprecated.cd a
```
```unison
foo = 43
```
```ucm
.example.resolve.a> update.old
```
And make a different change in the `b` namespace:
```ucm
.example.resolve> deprecated.cd .example.resolve.b
```
```unison
foo = 44
```
```ucm
.example.resolve.b> update.old
```
The `a` and `b` namespaces now each contain a patch named `patch`. We can view these:
```ucm
.example.resolve.b> deprecated.cd .example.resolve
.example.resolve> view.patch a.patch
.example.resolve> view.patch b.patch
```
Let's now merge these namespaces into `c`:
```ucm
.example.resolve> merge.old a c
```
```ucm:error
.example.resolve> merge.old b c
```
The namespace `c` now has an edit conflict, since the term `foo` was edited in two different ways.
```ucm:error
.example.resolve> deprecated.cd c
.example.resolve.c> todo
```
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 1 2
```
This changes the merged `c.patch` so that only a single edit remains and resolves the conflict.
```ucm
.example.resolve.c> view.patch
```
We still have a remaining _name conflict_ since it just so happened that both of the definitions in the edits were named `foo`.
```ucm:error
.example.resolve.c> todo
```
We can resolve the name conflict by deleting one of the names.
```ucm
.example.resolve.c> delete.term.verbose 2
.example.resolve.c> todo
```
And that's how you resolve edit conflicts with UCM.

View File

@ -1,265 +0,0 @@
# Resolving edit conflicts in `ucm`
The `ucm` tool tracks edits to hashes in an object called a _patch_. When patches get merged, sometimes those patches will have conflicting edits. The `replace` command helps resolve such conflicts.
First, let's make a new namespace, `example.resolve` and add the builtins:
Now let's add a term named `a.foo`:
```unison
a.foo = 42
```
```ucm
Loading changes detected in scratch.u.
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`:
a.foo : Nat
```
```ucm
.example.resolve> add
⍟ I've added these definitions:
a.foo : Nat
```
We'll fork the namespace `a` into a new namespace `b`, so we can edit the two concurrently.
```ucm
.example.resolve> fork a b
Done.
```
We'll also make a second fork `c` which we'll use as the target for our patch later.
```ucm
.example.resolve> fork a c
Done.
```
Now let's make a change to `foo` in the `a` namespace:
```ucm
.example.resolve> deprecated.cd a
```
```unison
foo = 43
```
```ucm
Loading changes detected in scratch.u.
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update`, here's how your codebase would
change:
⍟ These names already exist. You can `update` them to your
new definition:
foo : ##Nat
```
```ucm
.example.resolve.a> update.old
⍟ I've updated these names to your new definition:
foo : ##Nat
```
And make a different change in the `b` namespace:
```ucm
.example.resolve> deprecated.cd .example.resolve.b
```
```unison
foo = 44
```
```ucm
Loading changes detected in scratch.u.
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update`, here's how your codebase would
change:
⍟ These names already exist. You can `update` them to your
new definition:
foo : ##Nat
```
```ucm
.example.resolve.b> update.old
⍟ I've updated these names to your new definition:
foo : ##Nat
```
The `a` and `b` namespaces now each contain a patch named `patch`. We can view these:
```ucm
.example.resolve.b> deprecated.cd .example.resolve
.example.resolve> view.patch a.patch
Edited Terms: 1. c.foo -> 2. a.foo
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
.example.resolve> view.patch b.patch
Edited Terms: 1. c.foo -> 2. b.foo
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
```
Let's now merge these namespaces into `c`:
```ucm
.example.resolve> merge.old a c
Here's what's changed in c after the merge:
Updates:
1. foo : Nat
2. foo : Nat
Added definitions:
3. patch patch (added 1 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.
Applying changes from patch...
```
```ucm
.example.resolve> merge.old b c
Here's what's changed in c after the merge:
New name conflicts:
1. foo#emomp74i93 : Nat
2. ┌ foo#a84tg4er4k : Nat
3. └ foo#emomp74i93 : Nat
Updates:
4. patch patch (added 1 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.
Applying changes from patch...
I tried to auto-apply the patch, but couldn't because it
contained contradictory entries.
```
The namespace `c` now has an edit conflict, since the term `foo` was edited in two different ways.
```ucm
.example.resolve> deprecated.cd c
.example.resolve.c> 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 term 1. #qkhkl0n238 was replaced with
2. foo#a84tg4er4k
3. foo#emomp74i93
```
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 1 2
Done.
```
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: 1. #qkhkl0n238 -> 2. foo#a84tg4er4k
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
```
We still have a remaining _name conflict_ since it just so happened that both of the definitions in the edits were named `foo`.
```ucm
.example.resolve.c> todo
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 `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.verbose 2
Resolved name conflicts:
1. ┌ foo#a84tg4er4k : ##Nat
2. └ foo#emomp74i93 : ##Nat
3. foo#a84tg4er4k : ##Nat
Tip: You can use `undo` or `reflog` to undo this change.
.example.resolve.c> todo
No conflicts or edits in progress.
```
And that's how you resolve edit conflicts with UCM.

View File

@ -9,20 +9,16 @@ Test that tab completion works as expected.
view
view.global
view.patch
.> debug.tab-complete delete.
delete.branch
delete.namespace
delete.namespace.force
delete.patch
delete.project
delete.term
delete.term-replacement
delete.term.verbose
delete.type
delete.type-replacement
delete.type.verbose
delete.verbose

View File

@ -103,7 +103,6 @@ oldfoo = 801
```ucm
.lhs> add
.lhs> view.patch patch
.lhs> todo
```

View File

@ -205,14 +205,6 @@ oldfoo = 801
oldfoo : Nat
.lhs> view.patch patch
Edited Terms: 1. oldfoo -> 2. foo
Tip: To remove entries from a patch, use
delete.term-replacement or delete.type-replacement, as
appropriate.
.lhs> todo

View File

@ -17,7 +17,7 @@ Cause a conflict:
.merged> merge.old .b
```
Updating conflicted definitions works fine, and the associated patch contains two entries.
Updating conflicted definitions works fine.
```unison
x = 3
@ -25,5 +25,4 @@ x = 3
```ucm
.merged> update
.merged> view.patch
```

View File

@ -64,7 +64,7 @@ Cause a conflict:
Applying changes from patch...
```
Updating conflicted definitions works fine, and the associated patch contains two entries.
Updating conflicted definitions works fine.
```unison
x = 3
@ -92,8 +92,4 @@ x = 3
Done.
.merged> view.patch
This patch is empty.
```