mirror of
https://github.com/unisonweb/unison.git
synced 2024-09-11 02:25:39 +03:00
gut existing todo implementation
This commit is contained in:
parent
87f1544ad2
commit
6e04dbd083
@ -737,7 +737,7 @@ loop e = do
|
||||
currentNames <- Branch.toNames <$> Cli.getCurrentBranch0
|
||||
let sr = Slurp.slurpFile uf vars Slurp.UpdateOp currentNames
|
||||
previewResponse sourceName sr uf
|
||||
TodoI patchPath branchPath -> handleTodo patchPath branchPath
|
||||
TodoI -> handleTodo
|
||||
TestI testInput -> Tests.handleTest testInput
|
||||
ExecuteI main args -> handleRun False main args
|
||||
MakeStandaloneI output main -> doCompile False output main
|
||||
|
@ -4,114 +4,22 @@ module Unison.Codebase.Editor.HandleInput.Todo
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Lens hiding (from)
|
||||
import Control.Monad.Reader (ask)
|
||||
import Data.Set qualified as Set
|
||||
import U.Codebase.Sqlite.Queries qualified as Queries
|
||||
import Unison.Cli.Monad (Cli)
|
||||
import Unison.Cli.Monad qualified as Cli
|
||||
import Unison.Cli.MonadUtils qualified as Cli
|
||||
import Unison.Cli.PrettyPrintUtils qualified as Cli
|
||||
import Unison.Codebase (Codebase)
|
||||
import Unison.Codebase qualified as Codebase
|
||||
import Unison.Codebase.Branch.Names qualified as Branch
|
||||
import Unison.Codebase.Editor.DisplayObject
|
||||
import Unison.Codebase.Editor.Output
|
||||
import Unison.Codebase.Editor.StructuredArgument qualified as SA
|
||||
import Unison.Codebase.Editor.TodoOutput qualified as TO
|
||||
import Unison.Codebase.Patch (Patch (..))
|
||||
import Unison.Codebase.Patch qualified as Patch
|
||||
import Unison.Codebase.Path qualified as Path
|
||||
import Unison.DataDeclaration qualified as DD
|
||||
import Unison.HashQualified qualified as HQ
|
||||
import Unison.Names (Names)
|
||||
import Unison.Names qualified as Names
|
||||
import Unison.Parser.Ann (Ann (..))
|
||||
import Unison.Prelude
|
||||
import Unison.Reference (Reference)
|
||||
import Unison.Reference qualified as Reference
|
||||
import Unison.Sqlite qualified as Sqlite
|
||||
import Unison.Symbol (Symbol)
|
||||
import Unison.Type (Type)
|
||||
import Unison.Util.Monoid qualified as Monoid
|
||||
import Unison.Util.Relation qualified as R
|
||||
import Unison.Util.TransitiveClosure (transitiveClosure)
|
||||
|
||||
handleTodo :: Maybe Path.Split' -> Path.Path' -> Cli ()
|
||||
handleTodo patchPath branchPath' = do
|
||||
patch <- Cli.getPatchAt (fromMaybe Cli.defaultPatchPath patchPath)
|
||||
branchPath <- Cli.resolvePath' branchPath'
|
||||
doShowTodoOutput patch branchPath
|
||||
|
||||
-- | Show todo output if there are any conflicts or edits.
|
||||
doShowTodoOutput :: Patch -> Path.Absolute -> Cli ()
|
||||
doShowTodoOutput patch scopePath = do
|
||||
Cli.Env {codebase} <- ask
|
||||
names0 <- Branch.toNames <$> Cli.getBranch0At scopePath
|
||||
todo <- Cli.runTransaction (checkTodo codebase patch names0)
|
||||
if TO.noConflicts todo && TO.noEdits todo
|
||||
then Cli.respond NoConflictsOrEdits
|
||||
else do
|
||||
Cli.setNumberedArgs $
|
||||
SA.HashQualified . HQ.HashOnly . Reference.toShortHash . view _2
|
||||
<$> fst (TO.todoFrontierDependents todo)
|
||||
pped <- Cli.currentPrettyPrintEnvDecl
|
||||
Cli.respondNumbered $ TodoOutput pped todo
|
||||
|
||||
checkTodo :: Codebase m Symbol Ann -> Patch -> Names -> Sqlite.Transaction (TO.TodoOutput Symbol Ann)
|
||||
checkTodo codebase patch names0 = do
|
||||
let -- Get the dependents of a reference which:
|
||||
-- 1. Don't appear on the LHS of this patch
|
||||
-- 2. Have a name in this namespace
|
||||
getDependents :: Reference -> Sqlite.Transaction (Set Reference)
|
||||
getDependents ref = do
|
||||
dependents <- Codebase.dependents Queries.ExcludeSelf ref
|
||||
pure (dependents & removeEditedThings & removeNamelessThings)
|
||||
-- (r,r2) ∈ dependsOn if r depends on r2, excluding self-references (i.e. (r,r))
|
||||
dependsOn <- Monoid.foldMapM (\ref -> R.fromManyDom <$> getDependents ref <*> pure ref) edited
|
||||
let dirty = R.dom dependsOn
|
||||
transitiveDirty <- transitiveClosure getDependents dirty
|
||||
(frontierTerms, frontierTypes) <- loadDisplayInfo codebase (R.ran dependsOn)
|
||||
(dirtyTerms, dirtyTypes) <- loadDisplayInfo codebase dirty
|
||||
pure $
|
||||
TO.TodoOutput
|
||||
(Set.size transitiveDirty)
|
||||
(frontierTerms, frontierTypes)
|
||||
(score dirtyTerms, score dirtyTypes)
|
||||
(Names.conflicts names0)
|
||||
(Patch.conflicts patch)
|
||||
where
|
||||
-- Remove from a all references that were edited, i.e. appear on the LHS of this patch.
|
||||
removeEditedThings :: Set Reference -> Set Reference
|
||||
removeEditedThings =
|
||||
(`Set.difference` edited)
|
||||
-- Remove all references that don't have a name in the given namespace
|
||||
removeNamelessThings :: Set Reference -> Set Reference
|
||||
removeNamelessThings =
|
||||
Set.filter (Names.contains names0)
|
||||
-- todo: something more intelligent here?
|
||||
score :: [(a, b)] -> [(TO.Score, a, b)]
|
||||
score = map (\(x, y) -> (1, x, y))
|
||||
edited :: Set Reference
|
||||
edited = R.dom (Patch._termEdits patch) <> R.dom (Patch._typeEdits patch)
|
||||
|
||||
loadDisplayInfo ::
|
||||
Codebase m Symbol Ann ->
|
||||
Set Reference ->
|
||||
Sqlite.Transaction
|
||||
( [(Reference, Maybe (Type Symbol Ann))],
|
||||
[(Reference, DisplayObject () (DD.Decl Symbol Ann))]
|
||||
)
|
||||
loadDisplayInfo codebase refs = do
|
||||
termRefs <- filterM (Codebase.isTerm codebase) (toList refs)
|
||||
typeRefs <- filterM (Codebase.isType codebase) (toList refs)
|
||||
terms <- forM termRefs $ \r -> (r,) <$> Codebase.getTypeOfTerm codebase r
|
||||
types <- forM typeRefs $ \r -> (r,) <$> loadTypeDisplayObject codebase r
|
||||
pure (terms, types)
|
||||
|
||||
loadTypeDisplayObject :: Codebase m Symbol Ann -> Reference -> Sqlite.Transaction (DisplayObject () (DD.Decl Symbol Ann))
|
||||
loadTypeDisplayObject codebase = \case
|
||||
Reference.Builtin _ -> pure (BuiltinObject ())
|
||||
Reference.DerivedId id ->
|
||||
maybe (MissingObject $ Reference.idToShortHash id) UserObject
|
||||
<$> Codebase.getTypeDeclaration codebase id
|
||||
handleTodo :: Cli ()
|
||||
handleTodo = do
|
||||
branch0 <- Cli.getCurrentBranch0
|
||||
let names0 = Branch.toNames branch0
|
||||
let todo =
|
||||
TO.TodoOutput
|
||||
{ nameConflicts = Names.conflicts names0
|
||||
}
|
||||
pped <- Cli.currentPrettyPrintEnvDecl
|
||||
Cli.respondNumbered $ TodoOutput pped todo
|
||||
|
@ -150,7 +150,7 @@ data Input
|
||||
| UpdateI OptionalPatch (Set Name)
|
||||
| Update2I
|
||||
| PreviewUpdateI (Set Name)
|
||||
| TodoI (Maybe PatchPath) Path'
|
||||
| TodoI
|
||||
| UndoI
|
||||
| -- First `Maybe Int` is cap on number of results, if any
|
||||
-- Second `Maybe Int` is cap on diff elements shown, if any
|
||||
|
@ -293,8 +293,6 @@ data Output
|
||||
| PreviewMergeAlreadyUpToDate
|
||||
(Either Path' (ProjectAndBranch Sqlite.Project Sqlite.ProjectBranch))
|
||||
(Either Path' (ProjectAndBranch Sqlite.Project Sqlite.ProjectBranch))
|
||||
| -- | No conflicts or edits remain for the current patch.
|
||||
NoConflictsOrEdits
|
||||
| NotImplemented
|
||||
| NoBranchWithHash ShortCausalHash
|
||||
| ListDependencies PPE.PrettyPrintEnv (Set LabeledDependency) [HQ.HashQualified Name] [HQ.HashQualified Name] -- types, terms
|
||||
@ -554,7 +552,6 @@ isFailure o = case o of
|
||||
MergeAlreadyUpToDate {} -> False
|
||||
MergeAlreadyUpToDate2 {} -> False
|
||||
PreviewMergeAlreadyUpToDate {} -> False
|
||||
NoConflictsOrEdits {} -> False
|
||||
ListShallow _ es -> null es
|
||||
HashAmbiguous {} -> True
|
||||
ShowReflog {} -> False
|
||||
@ -669,4 +666,4 @@ isNumberedFailure = \case
|
||||
ShowDiffAfterUndo {} -> False
|
||||
ShowDiffNamespace _ _ _ bd -> BD.isEmpty bd
|
||||
ListNamespaceDependencies {} -> False
|
||||
TodoOutput _ todo -> TO.todoScore todo > 0 || not (TO.noConflicts todo)
|
||||
TodoOutput {} -> False
|
||||
|
@ -1,70 +1,15 @@
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
module Unison.Codebase.Editor.TodoOutput
|
||||
( TodoOutput (..),
|
||||
noConflicts,
|
||||
)
|
||||
where
|
||||
|
||||
module Unison.Codebase.Editor.TodoOutput where
|
||||
|
||||
import Data.Set qualified as Set
|
||||
import Unison.Codebase.Editor.DisplayObject (DisplayObject (UserObject))
|
||||
import Unison.Codebase.Patch (Patch)
|
||||
import Unison.Codebase.Patch qualified as Patch
|
||||
import Unison.DataDeclaration (Decl)
|
||||
import Unison.DataDeclaration qualified as DD
|
||||
import Unison.LabeledDependency (LabeledDependency)
|
||||
import Unison.LabeledDependency qualified as LD
|
||||
import Unison.Names (Names)
|
||||
import Unison.Names qualified as Names
|
||||
import Unison.Prelude
|
||||
import Unison.Reference (Reference)
|
||||
import Unison.Type (Type)
|
||||
import Unison.Type qualified as Type
|
||||
import Unison.Util.Relation qualified as R
|
||||
|
||||
type Score = Int
|
||||
|
||||
data TodoOutput v a = TodoOutput
|
||||
{ todoScore :: Score,
|
||||
todoFrontier ::
|
||||
( [(Reference, Maybe (Type v a))],
|
||||
[(Reference, DisplayObject () (Decl v a))]
|
||||
),
|
||||
todoFrontierDependents ::
|
||||
( [(Score, Reference, Maybe (Type v a))],
|
||||
[(Score, Reference, DisplayObject () (Decl v a))]
|
||||
),
|
||||
nameConflicts :: Names,
|
||||
editConflicts :: Patch
|
||||
{ nameConflicts :: Names
|
||||
}
|
||||
|
||||
labeledDependencies :: (Ord v) => TodoOutput v a -> Set LabeledDependency
|
||||
labeledDependencies TodoOutput {..} =
|
||||
Set.fromList
|
||||
( -- term refs
|
||||
[LD.termRef r | (r, _) <- fst todoFrontier]
|
||||
<> [LD.termRef r | (_, r, _) <- fst todoFrontierDependents]
|
||||
<> [LD.typeRef r | (r, _) <- snd todoFrontier]
|
||||
<> [LD.typeRef r | (_, r, _) <- snd todoFrontierDependents]
|
||||
<>
|
||||
-- types of term refs
|
||||
[ LD.typeRef r | (_, Just t) <- fst todoFrontier, r <- toList (Type.dependencies t)
|
||||
]
|
||||
<> [ LD.typeRef r | (_, _, Just t) <- fst todoFrontierDependents, r <- toList (Type.dependencies t)
|
||||
]
|
||||
<>
|
||||
-- and decls of type refs
|
||||
[ labeledDep | (declRef, UserObject d) <- snd todoFrontier, labeledDep <- toList (DD.labeledDeclDependenciesIncludingSelf declRef d)
|
||||
]
|
||||
<> [ labeledDep | (_, declRef, UserObject d) <- snd todoFrontierDependents, labeledDep <- toList (DD.labeledDeclDependenciesIncludingSelf declRef d)
|
||||
]
|
||||
)
|
||||
<>
|
||||
-- name conflicts
|
||||
Set.map LD.referent (R.ran (Names.terms nameConflicts))
|
||||
<> Set.map LD.typeRef (R.ran (Names.types nameConflicts))
|
||||
<> Patch.labeledDependencies editConflicts
|
||||
|
||||
noConflicts :: TodoOutput v a -> Bool
|
||||
noConflicts todo =
|
||||
nameConflicts todo == mempty && editConflicts todo == Patch.empty
|
||||
|
||||
noEdits :: TodoOutput v a -> Bool
|
||||
noEdits todo =
|
||||
todoScore todo == 0
|
||||
nameConflicts todo == mempty
|
||||
|
@ -756,30 +756,15 @@ todo =
|
||||
"todo"
|
||||
[]
|
||||
I.Visible
|
||||
[("patch", Optional, patchArg), ("namespace", Optional, namespaceArg)]
|
||||
( P.wrapColumn2
|
||||
[ ( makeExample' todo,
|
||||
"lists the refactor work remaining in the default patch for the current"
|
||||
<> " namespace."
|
||||
),
|
||||
( makeExample todo ["<patch>"],
|
||||
"lists the refactor work remaining in the given patch in the current "
|
||||
<> "namespace."
|
||||
),
|
||||
( makeExample todo ["<patch>", "[path]"],
|
||||
"lists the refactor work remaining in the given patch in given namespace."
|
||||
)
|
||||
]
|
||||
[]
|
||||
( P.wrap $
|
||||
makeExample' todo
|
||||
<> "lists the current namespace's outstanding issues, including conflicted names, dependencies with missing"
|
||||
<> "names, and merge precondition violations."
|
||||
)
|
||||
\case
|
||||
patchStr : ws -> first warn $ do
|
||||
patch <- handleSplit'Arg patchStr
|
||||
branch <- case ws of
|
||||
[] -> pure Path.relativeEmpty'
|
||||
[pathStr] -> handlePath'Arg pathStr
|
||||
_ -> Left "`todo` just takes a patch and one optional namespace"
|
||||
Right $ Input.TodoI (Just patch) branch
|
||||
[] -> Right $ Input.TodoI Nothing Path.relativeEmpty'
|
||||
[] -> Right Input.TodoI
|
||||
_ -> Left (I.help todo)
|
||||
|
||||
load :: InputPattern
|
||||
load =
|
||||
|
@ -65,7 +65,6 @@ import Unison.Codebase.Editor.StructuredArgument (StructuredArgument)
|
||||
import Unison.Codebase.Editor.StructuredArgument qualified as SA
|
||||
import Unison.Codebase.Editor.TodoOutput qualified as TO
|
||||
import Unison.Codebase.IntegrityCheck (IntegrityResult (..), prettyPrintIntegrityErrors)
|
||||
import Unison.Codebase.Patch (Patch (..))
|
||||
import Unison.Codebase.Patch qualified as Patch
|
||||
import Unison.Codebase.Path qualified as Path
|
||||
import Unison.Codebase.PushBehavior qualified as PushBehavior
|
||||
@ -73,8 +72,6 @@ import Unison.Codebase.Runtime qualified as Runtime
|
||||
import Unison.Codebase.ShortCausalHash (ShortCausalHash)
|
||||
import Unison.Codebase.ShortCausalHash qualified as SCH
|
||||
import Unison.Codebase.SqliteCodebase.Conversions qualified as Cv
|
||||
import Unison.Codebase.TermEdit qualified as TermEdit
|
||||
import Unison.Codebase.TypeEdit qualified as TypeEdit
|
||||
import Unison.CommandLine (bigproblem, note, tip)
|
||||
import Unison.CommandLine.FZFResolvers qualified as FZFResolvers
|
||||
import Unison.CommandLine.InputPattern (InputPattern)
|
||||
@ -137,7 +134,6 @@ import Unison.Syntax.NamePrinter
|
||||
prettyReference,
|
||||
prettyReferent,
|
||||
prettyShortHash,
|
||||
styleHashQualified,
|
||||
)
|
||||
import Unison.Syntax.NameSegment qualified as NameSegment
|
||||
import Unison.Syntax.TermPrinter qualified as TermPrinter
|
||||
@ -1483,8 +1479,6 @@ notifyUser dir = \case
|
||||
<> P.group (prettyNamespaceKey src <> ".")
|
||||
DumpNumberedArgs schLength args ->
|
||||
pure . P.numberedList $ fmap (P.text . IP.formatStructuredArgument (pure schLength)) args
|
||||
NoConflictsOrEdits ->
|
||||
pure (P.okCallout "No conflicts or edits in progress.")
|
||||
HelpMessage pat -> pure $ IP.showPatternHelp pat
|
||||
NoOp -> pure $ P.string "I didn't make any changes."
|
||||
DumpBitBooster head map ->
|
||||
@ -2628,66 +2622,6 @@ renderNameConflicts ppe conflictedNames = do
|
||||
)
|
||||
`P.hang` P.lines prettyConflicts
|
||||
|
||||
renderEditConflicts ::
|
||||
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)
|
||||
numberedHQName :: HQ.HashQualified Name -> Numbered Pretty
|
||||
numberedHQName hqName = do
|
||||
n <- addNumberedArg $ SA.HashQualified 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.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.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 StructuredArgument)
|
||||
|
||||
addNumberedArg :: StructuredArgument -> Numbered Int
|
||||
@ -2706,88 +2640,13 @@ runNumbered m =
|
||||
|
||||
todoOutput :: (Var v) => PPED.PrettyPrintEnvDecl -> TO.TodoOutput v a -> (Pretty, NumberedArgs)
|
||||
todoOutput ppe todo = runNumbered do
|
||||
conflicts <- todoConflicts
|
||||
edits <- todoEdits
|
||||
pure (conflicts <> edits)
|
||||
if TO.noConflicts todo
|
||||
then pure mempty
|
||||
else do
|
||||
nameConflicts <- renderNameConflicts ppeu (TO.nameConflicts todo)
|
||||
pure $ P.lines $ P.nonEmpty [nameConflicts]
|
||||
where
|
||||
ppeu = PPED.unsuffixifiedPPE ppe
|
||||
ppes = PPED.suffixifiedPPE ppe
|
||||
(frontierTerms, frontierTypes) = TO.todoFrontier todo
|
||||
(dirtyTerms, dirtyTypes) = TO.todoFrontierDependents todo
|
||||
corruptTerms =
|
||||
[(PPE.termName ppeu (Referent.Ref r), r) | (r, Nothing) <- frontierTerms]
|
||||
corruptTypes =
|
||||
[(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 :: Numbered Pretty
|
||||
todoConflicts = do
|
||||
if TO.noConflicts todo
|
||||
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
|
||||
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
|
||||
-- foo -> #c
|
||||
-- as well as an edit conflict:
|
||||
-- #a -> #b
|
||||
-- #a -> #c
|
||||
-- We want to hide/ignore the name conflicts that are also targets of an
|
||||
-- edit conflict, so that the edit conflict will be dealt with first.
|
||||
-- For example, if hash `h` has multiple edit targets { #x, #y, #z, ...},
|
||||
-- we'll temporarily remove name conflicts pointing to { #x, #y, #z, ...}.
|
||||
removeEditConflicts :: Patch -> Names -> Names
|
||||
removeEditConflicts Patch {..} Names {..} = Names terms' types'
|
||||
where
|
||||
terms' = R.filterRan (`Set.notMember` conflictedTermEditTargets) terms
|
||||
types' = R.filterRan (`Set.notMember` conflictedTypeEditTargets) types
|
||||
conflictedTypeEditTargets :: Set Reference
|
||||
conflictedTypeEditTargets =
|
||||
Set.fromList $ toList (R.ran typeEditConflicts) >>= TypeEdit.references
|
||||
conflictedTermEditTargets :: Set Referent.Referent
|
||||
conflictedTermEditTargets =
|
||||
Set.fromList . fmap Referent.Ref $
|
||||
toList (R.ran termEditConflicts) >>= TermEdit.references
|
||||
typeEditConflicts = R.filterDom (`R.manyDom` _typeEdits) _typeEdits
|
||||
termEditConflicts = R.filterDom (`R.manyDom` _termEdits) _termEdits
|
||||
|
||||
todoEdits :: Numbered Pretty
|
||||
todoEdits = do
|
||||
numberedTypes <- for (unscore <$> dirtyTypes) \(ref, displayObj) -> do
|
||||
n <- addNumberedArg . SA.HashQualified $ PPE.typeName ppeu ref
|
||||
pure $ formatNum n <> prettyDeclPair ppeu (ref, displayObj)
|
||||
let filteredTerms = goodTerms (unscore <$> dirtyTerms)
|
||||
termNumbers <- for filteredTerms \(ref, _, _) -> do
|
||||
n <- addNumberedArg . SA.HashQualified $ 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) => Input.FindScope -> PPE.PrettyPrintEnv -> E.ListDetailed -> [SR'.SearchResult' v a] -> IO Pretty
|
||||
|
@ -179,14 +179,10 @@ Merge back into the ancestor.
|
||||
|
||||
.s> todo
|
||||
|
||||
✅
|
||||
|
||||
No conflicts or edits in progress.
|
||||
|
||||
.m> todo
|
||||
|
||||
✅
|
||||
|
||||
No conflicts or edits in progress.
|
||||
|
||||
```
|
||||
|
@ -106,9 +106,7 @@ Let's do the update now, and verify that the definitions all look good and there
|
||||
|
||||
.a2> todo
|
||||
|
||||
✅
|
||||
|
||||
No conflicts or edits in progress.
|
||||
|
||||
```
|
||||
## Record updates
|
||||
@ -213,8 +211,6 @@ And checking that after updating this record, there's nothing `todo`:
|
||||
|
||||
.a4> todo
|
||||
|
||||
✅
|
||||
|
||||
No conflicts or edits in progress.
|
||||
|
||||
```
|
||||
|
@ -1,139 +0,0 @@
|
||||
# Test the `todo` command
|
||||
|
||||
## Simple type-changing update.
|
||||
|
||||
```ucm:hide
|
||||
.simple> builtins.merge
|
||||
```
|
||||
|
||||
```unison:hide
|
||||
x = 1
|
||||
useX = x + 10
|
||||
|
||||
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
|
||||
|
||||
type MyType = MyType Text
|
||||
```
|
||||
|
||||
```ucm:error
|
||||
.simple> update.old
|
||||
.simple> todo
|
||||
```
|
||||
|
||||
## A merge with conflicting updates.
|
||||
|
||||
```ucm:hide
|
||||
.mergeA> builtins.merge
|
||||
```
|
||||
|
||||
```unison:hide
|
||||
x = 1
|
||||
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
|
||||
type MyType = MyType Nat
|
||||
```
|
||||
|
||||
```ucm:hide
|
||||
.mergeA> update.old
|
||||
```
|
||||
|
||||
```unison:hide
|
||||
x = 3
|
||||
type MyType = MyType Int
|
||||
```
|
||||
|
||||
```ucm:hide
|
||||
.mergeB> update.old
|
||||
```
|
||||
|
||||
```ucm:error
|
||||
.mergeA> merge.old .mergeB
|
||||
.mergeA> todo
|
||||
```
|
||||
|
||||
## A named value that appears on the LHS of a patch isn't shown
|
||||
|
||||
```ucm:hide
|
||||
.lhs> builtins.merge
|
||||
```
|
||||
|
||||
```unison
|
||||
foo = 801
|
||||
```
|
||||
|
||||
```ucm
|
||||
.lhs> add
|
||||
```
|
||||
|
||||
```unison
|
||||
foo = 802
|
||||
```
|
||||
|
||||
```ucm
|
||||
.lhs> update.old
|
||||
```
|
||||
|
||||
```unison
|
||||
oldfoo = 801
|
||||
```
|
||||
|
||||
```ucm
|
||||
.lhs> add
|
||||
.lhs> todo
|
||||
```
|
||||
|
||||
## A type-changing update to one element of a cycle, which doesn't propagate to the other
|
||||
|
||||
```ucm:hide
|
||||
.cycle2> builtins.merge
|
||||
```
|
||||
|
||||
```unison
|
||||
even = cases
|
||||
0 -> true
|
||||
n -> odd (drop 1 n)
|
||||
|
||||
odd = cases
|
||||
0 -> false
|
||||
n -> even (drop 1 n)
|
||||
```
|
||||
|
||||
```ucm
|
||||
.cycle2> add
|
||||
```
|
||||
|
||||
```unison
|
||||
even = 17
|
||||
```
|
||||
|
||||
```ucm
|
||||
.cycle2> update.old
|
||||
```
|
||||
|
||||
```ucm:error
|
||||
.cycle2> todo
|
||||
```
|
@ -1,292 +0,0 @@
|
||||
# Test the `todo` command
|
||||
|
||||
## Simple type-changing update.
|
||||
|
||||
```unison
|
||||
x = 1
|
||||
useX = x + 10
|
||||
|
||||
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
|
||||
|
||||
type MyType = MyType Text
|
||||
```
|
||||
|
||||
```ucm
|
||||
.simple> update.old
|
||||
|
||||
⍟ I've updated these names to your new definition:
|
||||
|
||||
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:
|
||||
|
||||
type #vijug0om28
|
||||
#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
|
||||
type MyType = MyType
|
||||
```
|
||||
|
||||
Set up two branches with the same starting point.
|
||||
|
||||
Update `x` to a different term in each branch.
|
||||
|
||||
```unison
|
||||
x = 2
|
||||
type MyType = MyType Nat
|
||||
```
|
||||
|
||||
```unison
|
||||
x = 3
|
||||
type MyType = MyType Int
|
||||
```
|
||||
|
||||
```ucm
|
||||
.mergeA> merge.old .mergeB
|
||||
|
||||
Here's what's changed in the current namespace after the
|
||||
merge:
|
||||
|
||||
New name conflicts:
|
||||
|
||||
1. type MyType#ig1g2ka7lv
|
||||
↓
|
||||
2. ┌ type MyType#8c6f40i3tj
|
||||
3. └ type MyType#ig1g2ka7lv
|
||||
|
||||
4. MyType.MyType#ig1g2ka7lv#0 : Nat -> MyType#ig1g2ka7lv
|
||||
↓
|
||||
5. ┌ MyType.MyType#8c6f40i3tj#0 : Int -> MyType#8c6f40i3tj
|
||||
6. └ MyType.MyType#ig1g2ka7lv#0 : Nat -> MyType#ig1g2ka7lv
|
||||
|
||||
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.
|
||||
|
||||
Applying changes from patch...
|
||||
|
||||
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. #8h7qq3ougl was replaced with
|
||||
2. MyType#8c6f40i3tj
|
||||
3. MyType#ig1g2ka7lv
|
||||
The term 4. #gjmq673r1v was replaced with
|
||||
5. x#dcgdua2lj6
|
||||
6. x#f3lgjvjqoo
|
||||
❓
|
||||
|
||||
The term MyType.MyType has conflicting definitions:
|
||||
7. MyType.MyType#8c6f40i3tj#0
|
||||
8. MyType.MyType#ig1g2ka7lv#0
|
||||
|
||||
Tip: This occurs when merging branches that both independently
|
||||
introduce the same name. Use `move.term` or `delete.term`
|
||||
to resolve the conflicts.
|
||||
|
||||
```
|
||||
## A named value that appears on the LHS of a patch isn't shown
|
||||
|
||||
```unison
|
||||
foo = 801
|
||||
```
|
||||
|
||||
```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`:
|
||||
|
||||
foo : Nat
|
||||
|
||||
```
|
||||
```ucm
|
||||
.lhs> add
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
foo : Nat
|
||||
|
||||
```
|
||||
```unison
|
||||
foo = 802
|
||||
```
|
||||
|
||||
```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
|
||||
.lhs> update.old
|
||||
|
||||
⍟ I've updated these names to your new definition:
|
||||
|
||||
foo : Nat
|
||||
|
||||
```
|
||||
```unison
|
||||
oldfoo = 801
|
||||
```
|
||||
|
||||
```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`:
|
||||
|
||||
oldfoo : Nat
|
||||
|
||||
```
|
||||
```ucm
|
||||
.lhs> add
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
oldfoo : Nat
|
||||
|
||||
.lhs> todo
|
||||
|
||||
✅
|
||||
|
||||
No conflicts or edits in progress.
|
||||
|
||||
```
|
||||
## A type-changing update to one element of a cycle, which doesn't propagate to the other
|
||||
|
||||
```unison
|
||||
even = cases
|
||||
0 -> true
|
||||
n -> odd (drop 1 n)
|
||||
|
||||
odd = cases
|
||||
0 -> false
|
||||
n -> even (drop 1 n)
|
||||
```
|
||||
|
||||
```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`:
|
||||
|
||||
even : Nat -> Boolean
|
||||
odd : Nat -> Boolean
|
||||
|
||||
```
|
||||
```ucm
|
||||
.cycle2> add
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
even : Nat -> Boolean
|
||||
odd : Nat -> Boolean
|
||||
|
||||
```
|
||||
```unison
|
||||
even = 17
|
||||
```
|
||||
|
||||
```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:
|
||||
|
||||
even : Nat
|
||||
|
||||
```
|
||||
```ucm
|
||||
.cycle2> update.old
|
||||
|
||||
⍟ I've updated these names to your new definition:
|
||||
|
||||
even : Nat
|
||||
|
||||
```
|
||||
```ucm
|
||||
.cycle2> todo
|
||||
|
||||
🚧
|
||||
|
||||
The namespace has 1 transitive dependent(s) left to upgrade.
|
||||
Your edit frontier is the dependents of these definitions:
|
||||
|
||||
#kkohl7ba1e : Nat -> Boolean
|
||||
|
||||
I recommend working on them in the following order:
|
||||
|
||||
1. odd : Nat -> Boolean
|
||||
|
||||
|
||||
|
||||
```
|
Loading…
Reference in New Issue
Block a user