diff --git a/unison-cli/src/Unison/CommandLine.hs b/unison-cli/src/Unison/CommandLine.hs index 2c8be9bf43..155020304c 100644 --- a/unison-cli/src/Unison/CommandLine.hs +++ b/unison-cli/src/Unison/CommandLine.hs @@ -149,7 +149,27 @@ parseInput codebase currentPath numberedArgs patterns segments = runExceptT do Left (NoFZFOptions argDesc) -> throwError (noCompletionsMessage argDesc) Left FZFCancelled -> pure Nothing Right resolvedArgs -> do - parsedInput <- except . parse $ resolvedArgs + parsedInput <- + except + . first + ( \msg -> + P.warnCallout $ + P.wrap "Sorry, I wasn’t sure how to process your request:" + <> P.newline + <> P.newline + <> P.indentN 2 msg + <> P.newline + <> P.newline + <> P.wrap + ( P.text $ + "You can run `help " + <> Text.pack command + <> "` for more information on using `" + <> Text.pack command + <> "`." + ) + ) + $ parse resolvedArgs pure $ Just (Left command : resolvedArgs, parsedInput) Nothing -> throwE diff --git a/unison-cli/src/Unison/CommandLine/InputPattern.hs b/unison-cli/src/Unison/CommandLine/InputPattern.hs index 4014bc1dc7..f7d5547073 100644 --- a/unison-cli/src/Unison/CommandLine/InputPattern.hs +++ b/unison-cli/src/Unison/CommandLine/InputPattern.hs @@ -66,7 +66,16 @@ data InputPattern = InputPattern visibility :: Visibility, -- Allow hiding certain commands when debugging or work-in-progress args :: [(ArgumentDescription, IsOptional, ArgumentType)], help :: P.Pretty CT.ColorText, - parse :: Arguments -> Either (P.Pretty CT.ColorText) Input + -- | Parse the arguments and return either an error message or a command `Input`. + -- + -- __NB__: This function should return `Left` only on failure. For commands (like `help`) that simply produce + -- formatted output, use `pure . Input.CreateMessage`. The failure output should be fully formatted (using + -- `wrap`, etc.), but shouldn’t include any general error components like a warninng flag or the full help + -- message, and shouldn’t plan for the context it is being output to (e.g., don’t `P.indentN` the entire + -- message). + parse :: + Arguments -> + Either (P.Pretty CT.ColorText) Input } data ArgumentType = ArgumentType diff --git a/unison-cli/src/Unison/CommandLine/InputPatterns.hs b/unison-cli/src/Unison/CommandLine/InputPatterns.hs index 31fcd41ae6..8b795c6ca2 100644 --- a/unison-cli/src/Unison/CommandLine/InputPatterns.hs +++ b/unison-cli/src/Unison/CommandLine/InputPatterns.hs @@ -1,7 +1,4 @@ -{- - This module defines 'InputPattern' values for every supported input command. --} - +-- | This module defines 'InputPattern' values for every supported input command. module Unison.CommandLine.InputPatterns ( -- * Input commands add, @@ -302,18 +299,27 @@ searchResultToHQ oprefix = \case addPrefix :: Name -> Name addPrefix = maybe id Path.prefixNameIfRel oprefix -unsupportedStructuredArgument :: Text -> I.Argument -> Either (P.Pretty CT.ColorText) String -unsupportedStructuredArgument expected = - either pure (const . Left . P.text $ "can’t use a numbered argument for " <> expected) +unsupportedStructuredArgument :: Text -> Text -> I.Argument -> Either (P.Pretty CT.ColorText) String +unsupportedStructuredArgument command expected = + either pure . const . Left . P.text $ + "`" + <> command + <> "` can’t accept a numbered argument for " + <> expected + <> " and it’s not yet possible to provide un-expanded numbers as arguments." + +expectedButActually' :: Text -> String -> P.Pretty CT.ColorText +expectedButActually' expected actualValue = + P.text $ "I expected " <> expected <> ", but couldn’t recognize “" <> Text.pack actualValue <> "” as one." expectedButActually :: Text -> StructuredArgument -> Text -> P.Pretty CT.ColorText expectedButActually expected actualValue actualType = P.text $ - "Expected " + "I expected " <> expected - <> ", but the numbered arg resulted in " + <> ", but the numbered argument resulted in “" <> formatStructuredArgument Nothing actualValue - <> ", which is " + <> "”, which is " <> actualType <> "." @@ -334,6 +340,10 @@ wrongStructuredArgument expected actual = SA.ShallowListEntry _ _ -> "a name" SA.SearchResult _ _ -> "a search result" +wrongArgsLength :: Text -> [a] -> Either (P.Pretty CT.ColorText) b +wrongArgsLength expected args = + Left . P.text $ "I expected " <> expected <> ", but received " <> Text.pack (show $ length args) <> "." + patternName :: InputPattern -> P.Pretty P.ColorText patternName = fromString . I.patternName @@ -357,10 +367,7 @@ helpFor = I.help handleProjectArg :: I.Argument -> Either (P.Pretty CT.ColorText) ProjectName handleProjectArg = either - ( \name -> - first (const . P.text $ "“" <> Text.pack name <> "” is an invalid project name") . tryInto @ProjectName $ - Text.pack name - ) + (\name -> first (const $ expectedButActually' "a project" name) . tryInto @ProjectName $ Text.pack name) \case SA.Project project -> pure project otherArgType -> Left $ wrongStructuredArgument "a project" otherArgType @@ -368,7 +375,7 @@ handleProjectArg = handleLooseCodeOrProjectArg :: I.Argument -> Either (P.Pretty CT.ColorText) Input.LooseCodeOrProject handleLooseCodeOrProjectArg = either - (maybe (Left $ P.text "invalid path or project branch") pure . parseLooseCodeOrProject) + (\str -> maybe (Left $ expectedButActually' "a path or project branch" str) pure $ parseLooseCodeOrProject str) \case SA.AbsolutePath path -> pure . This $ Path.absoluteToPath' path SA.ProjectBranch pb -> pure $ That pb @@ -387,12 +394,12 @@ handleProjectMaybeBranchArg :: I.Argument -> Either (P.Pretty CT.ColorText) (ProjectAndBranch ProjectName (Maybe ProjectBranchNameOrLatestRelease)) handleProjectMaybeBranchArg = either - (first (const $ P.text "The argument wasn’t a project") . tryInto . Text.pack) + (\str -> first (const $ expectedButActually' "a project or branch" str) . tryInto $ Text.pack str) \case SA.Project proj -> pure $ ProjectAndBranch proj Nothing SA.ProjectBranch (ProjectAndBranch (Just proj) branch) -> pure . ProjectAndBranch proj . pure $ ProjectBranchNameOrLatestRelease'Name branch - otherArgType -> Left $ wrongStructuredArgument "a project" otherArgType + otherArgType -> Left $ wrongStructuredArgument "a project or branch" otherArgType handleHashQualifiedNameArg :: I.Argument -> Either (P.Pretty CT.ColorText) (HQ.HashQualified Name) handleHashQualifiedNameArg = @@ -498,7 +505,7 @@ handleBranchIdOrProjectArg :: Either (P.Pretty CT.ColorText) (These Input.BranchId (ProjectAndBranch (Maybe ProjectName) ProjectBranchName)) handleBranchIdOrProjectArg = either - (maybe (Left $ P.text "Expected a branch or project, but it’s not") pure . branchIdOrProject) + (\str -> maybe (Left $ expectedButActually' "a branch" str) pure $ branchIdOrProject str) \case SA.Namespace hash -> pure . This . Left $ SCH.fromFullHash hash SA.AbsolutePath path -> pure . This . pure $ Path.absoluteToPath' path @@ -684,16 +691,16 @@ handlePushTargetArg :: I.Argument -> Either (P.Pretty CT.ColorText) (WriteRemoteNamespace (These ProjectName ProjectBranchName)) handlePushTargetArg = either - (maybe (Left "Wanted a source to push from, but this ain’t it.") pure . parsePushTarget) + (\str -> maybe (Left $ expectedButActually' "a target to push to" str) pure $ parsePushTarget str) $ fmap RemoteRepo.WriteRemoteProjectBranch . \case SA.Project project -> pure $ This project SA.ProjectBranch (ProjectAndBranch project branch) -> pure $ maybe That These project branch - otherNumArg -> Left $ wrongStructuredArgument "a source to push from" otherNumArg + otherNumArg -> Left $ wrongStructuredArgument "a target to push to" otherNumArg handlePushSourceArg :: I.Argument -> Either (P.Pretty CT.ColorText) Input.PushSource handlePushSourceArg = either - (maybe (Left $ P.text "Wanted a source to push from, but this ain’t it.") pure . parsePushSource) + (\str -> maybe (Left $ expectedButActually' "a source to push from" str) pure $ parsePushSource str) \case SA.AbsolutePath path -> pure . Input.PathySource $ Path.absoluteToPath' path SA.Name name -> pure . Input.PathySource $ Path.fromName' name @@ -707,7 +714,7 @@ handlePushSourceArg = handleProjectAndBranchNamesArg :: I.Argument -> Either (P.Pretty CT.ColorText) ProjectAndBranchNames handleProjectAndBranchNamesArg = either - (first (const $ P.text "The argument wasn’t a project or branch") . tryInto @ProjectAndBranchNames . Text.pack) + (\str -> first (const $ expectedButActually' "a project or branch" str) . tryInto @ProjectAndBranchNames $ Text.pack str) $ fmap ProjectAndBranchNames'Unambiguous . \case SA.Project project -> pure $ This project SA.ProjectBranch (ProjectAndBranch mproj branch) -> pure $ maybe That These mproj branch @@ -724,7 +731,7 @@ mergeBuiltins = \case [] -> pure . Input.MergeBuiltinsI $ Nothing [p] -> Input.MergeBuiltinsI . Just <$> handlePathArg p - _ -> Left (I.help mergeBuiltins) + args -> wrongArgsLength "no more than one argument" args mergeIOBuiltins :: InputPattern mergeIOBuiltins = @@ -737,7 +744,7 @@ mergeIOBuiltins = \case [] -> pure . Input.MergeIOBuiltinsI $ Nothing [p] -> Input.MergeIOBuiltinsI . Just <$> handlePathArg p - _ -> Left (I.help mergeBuiltins) + args -> wrongArgsLength "no more than one argument" args updateBuiltins :: InputPattern updateBuiltins = @@ -765,7 +772,7 @@ todo = ) \case [] -> Right Input.TodoI - _ -> Left (I.help todo) + args -> wrongArgsLength "no arguments" args load :: InputPattern load = @@ -785,8 +792,8 @@ load = ) \case [] -> pure $ Input.LoadI Nothing - [file] -> Input.LoadI . Just <$> unsupportedStructuredArgument "a file name" file - _ -> Left (I.help load) + [file] -> Input.LoadI . Just <$> unsupportedStructuredArgument "load" "a file name" file + args -> wrongArgsLength "no more than one argument" args clear :: InputPattern clear = @@ -803,7 +810,7 @@ clear = ) \case [] -> pure Input.ClearI - _ -> Left (I.help clear) + args -> wrongArgsLength "no arguments" args add :: InputPattern add = @@ -846,7 +853,7 @@ update = <> "for your review.", parse = \case [] -> pure Input.Update2I - _ -> Left $ I.help update + args -> wrongArgsLength "no arguments" args } updateOldNoPatch :: InputPattern @@ -947,7 +954,7 @@ view = ] ) ( maybe - (Left $ I.help view) + (wrongArgsLength "at least one argument" []) ( fmap (Input.ShowDefinitionI Input.ConsoleLocation Input.ShowDefinitionLocal) . traverse handleHashQualifiedNameArg ) @@ -967,7 +974,7 @@ viewGlobal = ] ) ( maybe - (Left $ I.help viewGlobal) + (wrongArgsLength "at least one argument" []) ( fmap (Input.ShowDefinitionI Input.ConsoleLocation Input.ShowDefinitionGlobal) . traverse handleHashQualifiedNameArg ) @@ -986,7 +993,9 @@ display = "`display` without arguments invokes a search to select a definition to display, which requires that `fzf` can be found within your PATH." ] ) - $ maybe (Left $ I.help display) (fmap (Input.DisplayI Input.ConsoleLocation) . traverse handleHashQualifiedNameArg) + $ maybe + (wrongArgsLength "at least one argument" []) + (fmap (Input.DisplayI Input.ConsoleLocation) . traverse handleHashQualifiedNameArg) . NE.nonEmpty displayTo :: InputPattern @@ -1003,14 +1012,14 @@ displayTo = $ \case file : defs -> maybe - (Left $ I.help displayTo) + (wrongArgsLength "at least two arguments" [file]) ( \defs -> Input.DisplayI . Input.FileLocation - <$> unsupportedStructuredArgument "a file name" file + <$> unsupportedStructuredArgument "display.to" "a file name" file <*> traverse handleHashQualifiedNameArg defs ) $ NE.nonEmpty defs - _ -> Left (I.help displayTo) + [] -> wrongArgsLength "at least two arguments" [] docs :: InputPattern docs = @@ -1024,7 +1033,7 @@ docs = "`docs` without arguments invokes a search to select which definition to view documentation for, which requires that `fzf` can be found within your PATH." ] ) - $ maybe (Left $ I.help docs) (fmap Input.DocsI . traverse handleNameArg) . NE.nonEmpty + $ maybe (wrongArgsLength "at least one argument" []) (fmap Input.DocsI . traverse handleNameArg) . NE.nonEmpty api :: InputPattern api = @@ -1047,7 +1056,7 @@ ui = parse = \case [] -> pure $ Input.UiI Path.relativeEmpty' [path] -> Input.UiI <$> handlePath'Arg path - _ -> Left (I.help ui) + args -> wrongArgsLength "no more than one argument" args } undo :: InputPattern @@ -1064,10 +1073,9 @@ sfind :: InputPattern sfind = InputPattern "rewrite.find" ["sfind"] I.Visible [("rewrite-rule definition", Required, definitionQueryArg)] msg parse where - parse [q] = - Input.StructuredFindI (Input.FindLocal Path.relativeEmpty') - <$> handleHashQualifiedNameArg q - parse _ = Left "expected exactly one argument" + parse = \case + [q] -> Input.StructuredFindI (Input.FindLocal Path.relativeEmpty') <$> handleHashQualifiedNameArg q + args -> wrongArgsLength "exactly one argument" args msg = P.lines [ P.wrap $ @@ -1098,7 +1106,7 @@ sfindReplace = InputPattern "rewrite" ["sfind.replace"] I.Visible [("rewrite-rule definition", Required, definitionQueryArg)] msg parse where parse [q] = Input.StructuredFindReplaceI <$> handleHashQualifiedNameArg q - parse _ = Left "expected exactly one argument" + parse args = wrongArgsLength "exactly one argument" args msg :: P.Pretty CT.ColorText msg = P.lines @@ -1146,7 +1154,7 @@ findIn' cmd mkfscope = findHelp \case p : args -> Input.FindI False . mkfscope <$> handlePath'Arg p <*> pure (unifyArgument <$> args) - _ -> Left findHelp + args -> wrongArgsLength "at least one argument" args findHelp :: P.Pretty CT.ColorText findHelp = @@ -1210,7 +1218,7 @@ findShallow = ( fmap Input.FindShallowI . \case [] -> pure Path.relativeEmpty' [path] -> handlePath'Arg path - _ -> Left (I.help findShallow) + args -> wrongArgsLength "no more than one argument" args ) findVerbose :: InputPattern @@ -1249,7 +1257,7 @@ renameTerm = "`move.term foo bar` renames `foo` to `bar`." \case [oldName, newName] -> Input.MoveTermI <$> handleHashQualifiedSplit'Arg oldName <*> handleNewName newName - _ -> Left . P.warnCallout $ P.wrap "`rename.term` takes two arguments, like `rename.term oldname newname`." + _ -> Left $ P.wrap "`rename.term` takes two arguments, like `rename.term oldname newname`." moveAll :: InputPattern moveAll = @@ -1263,7 +1271,7 @@ moveAll = "`move foo bar` renames the term, type, and namespace foo to bar." \case [oldName, newName] -> Input.MoveAllI <$> handlePath'Arg oldName <*> handleNewPath newName - _ -> Left . P.warnCallout $ P.wrap "`move` takes two arguments, like `move oldname newname`." + _ -> Left $ P.wrap "`move` takes two arguments, like `move oldname newname`." renameType :: InputPattern renameType = @@ -1278,7 +1286,7 @@ renameType = \case [oldName, newName] -> Input.MoveTypeI <$> handleHashQualifiedSplit'Arg oldName <*> handleNewName newName _ -> - Left . P.warnCallout $ P.wrap "`rename.type` takes two arguments, like `rename.type oldname newname`." + Left $ P.wrap "`rename.type` takes two arguments, like `rename.type oldname newname`." deleteGen :: Maybe String -> ArgumentType -> String -> ([Path.HQSplit'] -> DeleteTarget) -> InputPattern deleteGen suffix queryCompletionArg target mkTarget = @@ -1304,7 +1312,7 @@ deleteGen suffix queryCompletionArg target mkTarget = "" ) ] - warn = + warning = P.sep " " [ backtick (P.string cmd), @@ -1318,7 +1326,7 @@ deleteGen suffix queryCompletionArg target mkTarget = [("definition to delete", OnePlus, queryCompletionArg)] info \case - [] -> Left . P.warnCallout $ P.wrap warn + [] -> Left $ P.wrap warning queries -> Input.DeleteI . mkTarget <$> traverse handleHashQualifiedSplit'Arg queries delete :: InputPattern @@ -1352,7 +1360,7 @@ deleteProject = ], parse = \case [name] -> Input.DeleteI . DeleteTarget'Project <$> handleProjectArg name - _ -> Left (showPatternHelp deleteProject) + args -> wrongArgsLength "exactly one argument" args } deleteBranch :: InputPattern @@ -1369,7 +1377,7 @@ deleteBranch = ], parse = \case [name] -> Input.DeleteI . DeleteTarget'ProjectBranch <$> handleMaybeProjectBranchArg name - _ -> Left (showPatternHelp deleteBranch) + args -> wrongArgsLength "exactly one argument" args } where suggestionsConfig = @@ -1389,7 +1397,7 @@ aliasTerm = help = "`alias.term foo bar` introduces `bar` with the same definition as `foo`.", parse = \case [oldName, newName] -> Input.AliasTermI False <$> handleShortHashOrHQSplit'Arg oldName <*> handleSplit'Arg newName - _ -> Left . warn $ P.wrap "`alias.term` takes two arguments, like `alias.term oldname newname`." + _ -> Left $ P.wrap "`alias.term` takes two arguments, like `alias.term oldname newname`." } debugAliasTermForce :: InputPattern @@ -1403,7 +1411,7 @@ debugAliasTermForce = parse = \case [oldName, newName] -> Input.AliasTermI True <$> handleShortHashOrHQSplit'Arg oldName <*> handleSplit'Arg newName _ -> - Left . warn $ + Left $ P.wrap "`debug.alias.term.force` takes two arguments, like `debug.alias.term.force oldname newname`." } @@ -1417,7 +1425,7 @@ aliasType = "`alias.type Foo Bar` introduces `Bar` with the same definition as `Foo`." \case [oldName, newName] -> Input.AliasTypeI False <$> handleShortHashOrHQSplit'Arg oldName <*> handleSplit'Arg newName - _ -> Left . warn $ P.wrap "`alias.type` takes two arguments, like `alias.type oldname newname`." + _ -> Left $ P.wrap "`alias.type` takes two arguments, like `alias.type oldname newname`." debugAliasTypeForce :: InputPattern debugAliasTypeForce = @@ -1430,7 +1438,7 @@ debugAliasTypeForce = parse = \case [oldName, newName] -> Input.AliasTypeI True <$> handleShortHashOrHQSplit'Arg oldName <*> handleSplit'Arg newName _ -> - Left . warn $ + Left $ P.wrap "`debug.alias.type.force` takes two arguments, like `debug.alias.type.force oldname newname`." } @@ -1453,7 +1461,7 @@ aliasMany = \case srcs@(_ : _) Cons.:> dest -> Input.AliasManyI <$> traverse handleHashQualifiedSplitArg srcs <*> handlePath'Arg dest - _ -> Left (I.help aliasMany) + args -> wrongArgsLength "at least two arguments" args up :: InputPattern up = @@ -1465,7 +1473,7 @@ up = (P.wrapColumn2 [(makeExample up [], "move current path up one level (deprecated)")]) \case [] -> Right Input.UpI - _ -> Left (I.help up) + args -> wrongArgsLength "no arguments" args cd :: InputPattern cd = @@ -1496,7 +1504,7 @@ cd = \case [Left ".."] -> Right Input.UpI [p] -> Input.SwitchBranchI <$> handlePath'Arg p - _ -> Left (I.help cd) + args -> wrongArgsLength "exactly one argument" args back :: InputPattern back = @@ -1513,7 +1521,7 @@ back = ) \case [] -> pure Input.PopBranchI - _ -> Left (I.help cd) + args -> wrongArgsLength "no arguments" args deleteNamespace :: InputPattern deleteNamespace = @@ -1523,7 +1531,7 @@ deleteNamespace = I.Visible [("namespace to delete", Required, namespaceArg)] "`delete.namespace ` deletes the namespace `foo`" - (deleteNamespaceParser (I.help deleteNamespace) Input.Try) + (deleteNamespaceParser Input.Try) deleteNamespaceForce :: InputPattern deleteNamespaceForce = @@ -1535,13 +1543,13 @@ deleteNamespaceForce = ( "`delete.namespace.force ` deletes the namespace `foo`," <> "deletion will proceed even if other code depends on definitions in foo." ) - (deleteNamespaceParser (I.help deleteNamespaceForce) Input.Force) + (deleteNamespaceParser Input.Force) -deleteNamespaceParser :: P.Pretty CT.ColorText -> Input.Insistence -> I.Arguments -> Either (P.Pretty CT.ColorText) Input -deleteNamespaceParser helpText insistence = \case +deleteNamespaceParser :: Input.Insistence -> I.Arguments -> Either (P.Pretty CT.ColorText) Input +deleteNamespaceParser insistence = \case [Left "."] -> first fromString . pure $ Input.DeleteI (DeleteTarget'Namespace insistence Nothing) [p] -> Input.DeleteI . DeleteTarget'Namespace insistence . pure <$> handleSplitArg p - _ -> Left helpText + args -> wrongArgsLength "exactly one argument" args renameBranch :: InputPattern renameBranch = @@ -1553,7 +1561,7 @@ renameBranch = "`move.namespace foo bar` renames the path `foo` to `bar`." \case [src, dest] -> Input.MoveBranchI <$> handlePath'Arg src <*> handlePath'Arg dest - _ -> Left (I.help renameBranch) + args -> wrongArgsLength "exactly two arguments" args history :: InputPattern history = @@ -1574,7 +1582,7 @@ history = \case [src] -> Input.HistoryI (Just 10) (Just 10) <$> handleBranchIdArg src [] -> pure $ Input.HistoryI (Just 10) (Just 10) (Right Path.currentPath) - _ -> Left (I.help history) + args -> wrongArgsLength "no more than one argument" args forkLocal :: InputPattern forkLocal = @@ -1599,7 +1607,7 @@ forkLocal = ) \case [src, dest] -> Input.ForkLocalBranchI <$> handleBranchId2Arg src <*> handleBranchRelativePathArg dest - _ -> Left (I.help forkLocal) + args -> wrongArgsLength "exactly two arguments" args libInstallInputPattern :: InputPattern libInstallInputPattern = @@ -1629,7 +1637,7 @@ libInstallInputPattern = ], parse = \case [arg] -> Input.LibInstallI False <$> handleProjectMaybeBranchArg arg - _ -> Left (I.help libInstallInputPattern) + args -> wrongArgsLength "exactly one argument" args } reset :: InputPattern @@ -1651,7 +1659,7 @@ reset = \case [arg0] -> Input.ResetI <$> handleBranchIdOrProjectArg arg0 <*> pure Nothing [arg0, arg1] -> Input.ResetI <$> handleBranchIdOrProjectArg arg0 <*> fmap pure (handleLooseCodeOrProjectArg arg1) - _ -> Left $ I.help reset + args -> wrongArgsLength "one or two arguments" args where config = ProjectBranchSuggestionsConfig @@ -1683,7 +1691,7 @@ resetRoot = ) $ \case [src] -> Input.ResetRootI <$> handleBranchIdArg src - _ -> Left (I.help resetRoot) + args -> wrongArgsLength "exactly one argument" args pull :: InputPattern pull = @@ -1780,31 +1788,26 @@ pullImpl name aliases pullMode addendum = do These sourceProject sourceBranch -> Right (Input.LibInstallI True (ProjectAndBranch sourceProject (Just sourceBranch))) (Right source, Left _, Right path) -> - Left . P.indentN 2 $ - P.wrap - ( "I think you're wanting to merge" - <> case source of - RemoteRepo.ReadShare'LooseCode _sourcePath -> "some non-project code" - RemoteRepo.ReadShare'ProjectBranch (This sourceProject) -> - prettyProjectNameSlash sourceProject - RemoteRepo.ReadShare'ProjectBranch (That ProjectBranchNameOrLatestRelease'LatestRelease) -> - "the latest release" - RemoteRepo.ReadShare'ProjectBranch (That (ProjectBranchNameOrLatestRelease'Name sourceBranch)) -> - prettySlashProjectBranchName sourceBranch - RemoteRepo.ReadShare'ProjectBranch (These sourceProject ProjectBranchNameOrLatestRelease'LatestRelease) -> - "the latest release of" <> prettyProjectName sourceProject - RemoteRepo.ReadShare'ProjectBranch (These sourceProject (ProjectBranchNameOrLatestRelease'Name sourceBranch)) -> - prettyProjectAndBranchName (ProjectAndBranch sourceProject sourceBranch) - <> "into the" - <> prettyPath' path - <> "namespace, but the" - <> makeExample' pull - <> "command only supports merging into the top level of a local project branch." - ) - <> P.newline - <> P.newline - <> P.wrap "Use `help pull` to see some examples." - _ -> Left $ I.help self + Left . P.wrap $ + "I think you want to merge " + <> case source of + RemoteRepo.ReadShare'LooseCode _sourcePath -> "some non-project code" + RemoteRepo.ReadShare'ProjectBranch (This sourceProject) -> + prettyProjectNameSlash sourceProject + RemoteRepo.ReadShare'ProjectBranch (That ProjectBranchNameOrLatestRelease'LatestRelease) -> + "the latest release" + RemoteRepo.ReadShare'ProjectBranch (That (ProjectBranchNameOrLatestRelease'Name sourceBranch)) -> + prettySlashProjectBranchName sourceBranch + RemoteRepo.ReadShare'ProjectBranch (These sourceProject ProjectBranchNameOrLatestRelease'LatestRelease) -> + "the latest release of" <> prettyProjectName sourceProject + RemoteRepo.ReadShare'ProjectBranch (These sourceProject (ProjectBranchNameOrLatestRelease'Name sourceBranch)) -> + prettyProjectAndBranchName (ProjectAndBranch sourceProject sourceBranch) + <> " into the " + <> prettyPath' path + <> " namespace, but the " + <> makeExample' pull + <> " command only supports merging into the top level of a local project branch." + args -> wrongArgsLength "no more than two arguments" args } debugTabCompletion :: InputPattern @@ -1819,7 +1822,7 @@ debugTabCompletion = P.wrap $ "Completions which are finished are prefixed with a * represent finished completions." ] ) - (fmap Input.DebugTabCompletionI . traverse (unsupportedStructuredArgument "text")) + (fmap Input.DebugTabCompletionI . traverse (unsupportedStructuredArgument "debug.tab-complete" "text")) debugFuzzyOptions :: InputPattern debugFuzzyOptions = @@ -1839,9 +1842,9 @@ debugFuzzyOptions = \case (cmd : args) -> Input.DebugFuzzyOptionsI - <$> unsupportedStructuredArgument "a command" cmd - <*> traverse (unsupportedStructuredArgument "text") args - _ -> Left (I.help debugFuzzyOptions) + <$> unsupportedStructuredArgument "debug.fuzzy-options" "a command" cmd + <*> traverse (unsupportedStructuredArgument "debug.fuzzy-options" "text") args + args -> wrongArgsLength "at least one argument" args debugFormat :: InputPattern debugFormat = @@ -1857,7 +1860,7 @@ debugFormat = ) ( \case [] -> Right Input.DebugFormatI - _ -> Left (I.help debugFormat) + args -> wrongArgsLength "no arguments" args ) push :: InputPattern @@ -1904,7 +1907,7 @@ push = [targetStr] -> Input.PushSourceTarget1 <$> handlePushTargetArg targetStr [targetStr, sourceStr] -> Input.PushSourceTarget2 <$> handlePushSourceArg sourceStr <*> handlePushTargetArg targetStr - _ -> Left (I.help push) + args -> wrongArgsLength "no more than two arguments" args where suggestionsConfig = ProjectBranchSuggestionsConfig @@ -1955,7 +1958,7 @@ pushCreate = [targetStr] -> Input.PushSourceTarget1 <$> handlePushTargetArg targetStr [targetStr, sourceStr] -> Input.PushSourceTarget2 <$> handlePushSourceArg sourceStr <*> handlePushTargetArg targetStr - _ -> Left (I.help pushForce) + args -> wrongArgsLength "no more than two arguments" args where suggestionsConfig = ProjectBranchSuggestionsConfig @@ -1985,7 +1988,7 @@ pushForce = [targetStr] -> Input.PushSourceTarget1 <$> handlePushTargetArg targetStr [targetStr, sourceStr] -> Input.PushSourceTarget2 <$> handlePushSourceArg sourceStr <*> handlePushTargetArg targetStr - _ -> Left (I.help pushForce) + args -> wrongArgsLength "no more than two arguments" args where suggestionsConfig = ProjectBranchSuggestionsConfig @@ -2025,7 +2028,7 @@ pushExhaustive = [targetStr] -> Input.PushSourceTarget1 <$> handlePushTargetArg targetStr [targetStr, sourceStr] -> Input.PushSourceTarget2 <$> handlePushSourceArg sourceStr <*> handlePushTargetArg targetStr - _ -> Left (I.help pushExhaustive) + args -> wrongArgsLength "no more than two arguments" args where suggestionsConfig = ProjectBranchSuggestionsConfig @@ -2057,7 +2060,7 @@ mergeOldSquashInputPattern = <$> handleLooseCodeOrProjectArg src <*> handleLooseCodeOrProjectArg dest <*> pure Branch.SquashMerge - _ -> Left $ I.help mergeOldSquashInputPattern + args -> wrongArgsLength "exactly two arguments" args } where suggestionsConfig = @@ -2108,7 +2111,7 @@ mergeOldInputPattern = <$> handleLooseCodeOrProjectArg src <*> handleLooseCodeOrProjectArg dest <*> pure Branch.RegularMerge - _ -> Left $ I.help mergeOldInputPattern + args -> wrongArgsLength "one or two arguments" args ) where config = @@ -2138,9 +2141,8 @@ mergeInputPattern = help = P.wrap $ makeExample mergeInputPattern ["/branch"] <> "merges `branch` into the current branch", parse = \case - [branchString] -> - Input.MergeI <$> handleMaybeProjectBranchArg branchString - _ -> Left $ I.help mergeInputPattern + [branchString] -> Input.MergeI <$> handleMaybeProjectBranchArg branchString + args -> wrongArgsLength "exactly one argument" args } mergeCommitInputPattern :: InputPattern @@ -2182,7 +2184,7 @@ mergeCommitInputPattern = ), parse = \case [] -> Right Input.MergeCommitI - _ -> Left (I.help mergeCommitInputPattern) + args -> wrongArgsLength "no arguments" args } parseLooseCodeOrProject :: String -> Maybe Input.LooseCodeOrProject @@ -2215,7 +2217,7 @@ diffNamespace = ( \case [before, after] -> Input.DiffNamespaceI <$> handleBranchIdArg before <*> handleBranchIdArg after [before] -> Input.DiffNamespaceI <$> handleBranchIdArg before <*> pure (pure Path.currentPath) - _ -> Left $ I.help diffNamespace + args -> wrongArgsLength "one or two arguments" args ) where suggestionsConfig = @@ -2245,7 +2247,7 @@ mergeOldPreviewInputPattern = [src] -> Input.PreviewMergeLocalBranchI <$> handleLooseCodeOrProjectArg src <*> pure (This Path.relativeEmpty') [src, dest] -> Input.PreviewMergeLocalBranchI <$> handleLooseCodeOrProjectArg src <*> handleLooseCodeOrProjectArg dest - _ -> Left $ I.help mergeOldPreviewInputPattern + args -> wrongArgsLength "one or two arguments" args ) where suggestionsConfig = @@ -2266,7 +2268,7 @@ viewReflog = ( \case [] -> pure Input.ShowReflogI _ -> - Left . warn . P.string $ + Left . P.string $ I.patternName viewReflog ++ " doesn't take any arguments." ) @@ -2285,7 +2287,7 @@ edit = ], parse = maybe - (Left $ I.help edit) + (wrongArgsLength "at least one argument" []) ( fmap (Input.ShowDefinitionI Input.LatestFileLocation Input.ShowDefinitionLocal) . traverse handleHashQualifiedNameArg ) @@ -2325,13 +2327,13 @@ helpTopics = [("topic", Optional, topicNameArg)] ("`help-topics` lists all topics and `help-topics ` shows an explanation of that topic.") ( \case - [] -> Left topics + [] -> Right $ Input.CreateMessage topics [topic] -> do - topic <- unsupportedStructuredArgument "a help topic" topic + topic <- unsupportedStructuredArgument "help-topics" "a help topic" topic case Map.lookup topic helpTopicsMap of - Nothing -> Left . warn $ "I don't know of that topic. Try `help-topics`." - Just t -> Left t - _ -> Left $ warn "Use `help-topics ` or `help-topics`." + Nothing -> Left $ "I don't know of that topic. Try `help-topics`." + Just t -> Right $ Input.CreateMessage t + _ -> Left $ "Use `help-topics ` or `help-topics`." ) where topics = @@ -2341,7 +2343,7 @@ helpTopics = "", P.indentN 2 $ P.sep "\n" (P.string <$> Map.keys helpTopicsMap), "", - aside "Example" "use `help filestatus` to learn more about that topic." + aside "Example" "use `help-topics filestatus` to learn more about that topic." ] helpTopicsMap :: Map String (P.Pretty P.ColorText) @@ -2510,21 +2512,21 @@ help = "`help` shows general help and `help ` shows help for one command." $ \case [] -> - Left $ + Right . Input.CreateMessage $ intercalateMap "\n\n" showPatternHelp visibleInputs [cmd] -> do - cmd <- unsupportedStructuredArgument "a command" cmd + cmd <- unsupportedStructuredArgument "help" "a command" cmd case (Map.lookup cmd commandsByName, isHelp cmd) of - (Nothing, Just msg) -> Left msg - (Nothing, Nothing) -> Left . warn $ "I don't know of that command. Try `help`." - (Just pat, Nothing) -> Left $ showPatternHelp pat + (Nothing, Just msg) -> Right $ Input.CreateMessage msg + (Nothing, Nothing) -> Left $ "I don't know of that command. Try `help`." + (Just pat, Nothing) -> Right . Input.CreateMessage $ showPatternHelp pat -- If we have a command and a help topic with the same name (like "projects"), then append a tip to the -- command's help that suggests running `help-topic command` (Just pat, Just _) -> - Left $ + Right . Input.CreateMessage $ showPatternHelp pat <> P.newline <> P.newline @@ -2534,7 +2536,7 @@ help = <> "use" <> makeExample helpTopics [P.string cmd] ) - _ -> Left $ warn "Use `help ` or `help`." + _ -> Left "Use `help ` or `help`." where commandsByName = Map.fromList $ do @@ -2565,7 +2567,7 @@ names isGlobal = (P.wrap $ makeExample (names isGlobal) ["foo"] <> " shows the hash and all known names for `foo`.") $ \case [thing] -> Input.NamesI isGlobal <$> handleHashQualifiedNameArg thing - _ -> Left (I.help (names isGlobal)) + args -> wrongArgsLength "exactly one argument" args where cmdName = if isGlobal then "names.global" else "names" @@ -2579,7 +2581,7 @@ dependents = "List the named dependents of the specified definition." $ \case [thing] -> Input.ListDependentsI <$> handleHashQualifiedNameArg thing - _ -> Left (I.help dependents) + args -> wrongArgsLength "exactly one argument" args dependencies = InputPattern "dependencies" @@ -2589,7 +2591,7 @@ dependencies = "List the dependencies of the specified definition." $ \case [thing] -> Input.ListDependenciesI <$> handleHashQualifiedNameArg thing - _ -> Left (I.help dependencies) + args -> wrongArgsLength "exactly one argument" args namespaceDependencies :: InputPattern namespaceDependencies = @@ -2602,7 +2604,7 @@ namespaceDependencies = $ \case [p] -> Input.NamespaceDependenciesI . pure <$> handlePath'Arg p [] -> pure (Input.NamespaceDependenciesI Nothing) - _ -> Left (I.help namespaceDependencies) + args -> wrongArgsLength "no more than one argument" args debugNumberedArgs :: InputPattern debugNumberedArgs = @@ -2654,7 +2656,7 @@ debugTerm = "View debugging information for a given term." ( \case [thing] -> Input.DebugTermI False <$> handleHashQualifiedNameArg thing - _ -> Left (I.help debugTerm) + args -> wrongArgsLength "exactly one argument" args ) debugTermVerbose :: InputPattern @@ -2667,7 +2669,7 @@ debugTermVerbose = "View verbose debugging information for a given term." ( \case [thing] -> Input.DebugTermI True <$> handleHashQualifiedNameArg thing - _ -> Left (I.help debugTermVerbose) + args -> wrongArgsLength "exactly one argument" args ) debugType :: InputPattern @@ -2680,7 +2682,7 @@ debugType = "View debugging information for a given type." ( \case [thing] -> Input.DebugTypeI <$> handleHashQualifiedNameArg thing - _ -> Left (I.help debugType) + args -> wrongArgsLength "exactly one argument" args ) debugLSPFoldRanges :: InputPattern @@ -2714,7 +2716,7 @@ debugDoctor = ) ( \case [] -> Right $ Input.DebugDoctorI - _ -> Left (showPatternHelp debugDoctor) + args -> wrongArgsLength "no arguments" args ) debugNameDiff :: InputPattern @@ -2727,7 +2729,7 @@ debugNameDiff = help = P.wrap "List all name changes between two causal hashes. Does not detect patch changes.", parse = \case [from, to] -> Input.DebugNameDiffI <$> handleShortCausalHashArg from <*> handleShortCausalHashArg to - _ -> Left (I.help debugNameDiff) + args -> wrongArgsLength "exactly two arguments" args } test :: InputPattern @@ -2756,7 +2758,7 @@ test = . \case [] -> pure Path.empty [pathString] -> handlePathArg pathString - _ -> Left $ I.help test + args -> wrongArgsLength "no more than one argument" args } testAll :: InputPattern @@ -2798,8 +2800,8 @@ docsToHtml = [namespacePath, destinationFilePath] -> Input.DocsToHtmlI <$> handleBranchRelativePathArg namespacePath - <*> unsupportedStructuredArgument "a directory name" destinationFilePath - _ -> Left $ showPatternHelp docsToHtml + <*> unsupportedStructuredArgument "docs.to-html" "a file name" destinationFilePath + args -> wrongArgsLength "exactly two arguments" args docToMarkdown :: InputPattern docToMarkdown = @@ -2816,7 +2818,7 @@ docToMarkdown = ) \case [docNameText] -> Input.DocToMarkdownI <$> handleNameArg docNameText - _ -> Left $ showPatternHelp docToMarkdown + args -> wrongArgsLength "exactly one argument" args execute :: InputPattern execute = @@ -2838,8 +2840,8 @@ execute = main : args -> Input.ExecuteI <$> handleHashQualifiedNameArg main - <*> traverse (unsupportedStructuredArgument "a command-line argument") args - _ -> Left $ showPatternHelp execute + <*> traverse (unsupportedStructuredArgument "run" "a command-line argument") args + [] -> wrongArgsLength "at least one argument" [] saveExecuteResult :: InputPattern saveExecuteResult = @@ -2853,7 +2855,7 @@ saveExecuteResult = ) $ \case [w] -> Input.SaveExecuteResultI <$> handleNameArg w - _ -> Left $ showPatternHelp saveExecuteResult + args -> wrongArgsLength "exactly one argument" args ioTest :: InputPattern ioTest = @@ -2870,7 +2872,7 @@ ioTest = ], parse = \case [thing] -> Input.IOTestI <$> handleHashQualifiedNameArg thing - _ -> Left $ showPatternHelp ioTest + args -> wrongArgsLength "exactly one argument" args } ioTestAll :: InputPattern @@ -2888,7 +2890,7 @@ ioTestAll = ], parse = \case [] -> Right Input.IOTestAllI - _ -> Left $ showPatternHelp ioTest + args -> wrongArgsLength "no arguments" args } makeStandalone :: InputPattern @@ -2909,9 +2911,9 @@ makeStandalone = $ \case [main, file] -> Input.MakeStandaloneI - <$> unsupportedStructuredArgument "a file name" file + <$> unsupportedStructuredArgument "compile" "a file name" file <*> handleHashQualifiedNameArg main - _ -> Left $ showPatternHelp makeStandalone + args -> wrongArgsLength "exactly two arguments" args runScheme :: InputPattern runScheme = @@ -2930,8 +2932,8 @@ runScheme = main : args -> Input.ExecuteSchemeI <$> handleHashQualifiedNameArg main - <*> traverse (unsupportedStructuredArgument "a command-line argument") args - _ -> Left $ showPatternHelp runScheme + <*> traverse (unsupportedStructuredArgument "run.native" "a command-line argument") args + [] -> wrongArgsLength "at least one argument" [] compileScheme :: InputPattern compileScheme = @@ -2951,9 +2953,9 @@ compileScheme = $ \case [main, file] -> Input.CompileSchemeI . Text.pack - <$> unsupportedStructuredArgument "a file name" file + <$> unsupportedStructuredArgument "compile.native" "a file name" file <*> handleHashQualifiedNameArg main - _ -> Left $ showPatternHelp compileScheme + args -> wrongArgsLength "exactly two arguments" args createAuthor :: InputPattern createAuthor = @@ -2977,8 +2979,10 @@ createAuthor = symbolStr : authorStr@(_ : _) -> Input.CreateAuthorI <$> handleRelativeNameSegmentArg symbolStr - <*> fmap (parseAuthorName . unwords) (traverse (unsupportedStructuredArgument "text") authorStr) - _ -> Left $ showPatternHelp createAuthor + <*> fmap + (parseAuthorName . unwords) + (traverse (unsupportedStructuredArgument "create.author" "text") authorStr) + args -> wrongArgsLength "at least two arguments" args where -- let's have a real parser in not too long parseAuthorName :: String -> Text @@ -3002,7 +3006,7 @@ authLogin = ) ( \case [] -> Right $ Input.AuthLoginI - _ -> Left (showPatternHelp authLogin) + args -> wrongArgsLength "no arguments" args ) printVersion :: InputPattern @@ -3016,7 +3020,7 @@ printVersion = ) ( \case [] -> Right $ Input.VersionI - _ -> Left (showPatternHelp printVersion) + args -> wrongArgsLength "no arguments" args ) projectCreate :: InputPattern @@ -3034,7 +3038,7 @@ projectCreate = parse = \case [] -> pure $ Input.ProjectCreateI True Nothing [name] -> Input.ProjectCreateI True . pure <$> handleProjectArg name - _ -> Left $ showPatternHelp projectCreate + args -> wrongArgsLength "no more than one argument" args } projectCreateEmptyInputPattern :: InputPattern @@ -3052,7 +3056,7 @@ projectCreateEmptyInputPattern = parse = \case [] -> pure $ Input.ProjectCreateI False Nothing [name] -> Input.ProjectCreateI False . pure <$> handleProjectArg name - _ -> Left $ showPatternHelp projectCreateEmptyInputPattern + args -> wrongArgsLength "no more than one argument" args } projectRenameInputPattern :: InputPattern @@ -3068,7 +3072,7 @@ projectRenameInputPattern = ], parse = \case [nameString] -> Input.ProjectRenameI <$> handleProjectArg nameString - _ -> Left (showPatternHelp projectRenameInputPattern) + args -> wrongArgsLength "exactly one argument" args } projectSwitch :: InputPattern @@ -3087,7 +3091,7 @@ projectSwitch = ], parse = \case [name] -> Input.ProjectSwitchI <$> handleProjectAndBranchNamesArg name - _ -> Left (showPatternHelp projectSwitch) + args -> wrongArgsLength "exactly one argument" args } where suggestionsConfig = @@ -3123,7 +3127,7 @@ branchesInputPattern = parse = \case [] -> Right (Input.BranchesI Nothing) [nameString] -> Input.BranchesI . pure <$> handleProjectArg nameString - _ -> Left (showPatternHelp branchesInputPattern) + args -> wrongArgsLength "no more than one argument" args } branchInputPattern :: InputPattern @@ -3148,7 +3152,7 @@ branchInputPattern = <$> handleLooseCodeOrProjectArg source0 <*> handleMaybeProjectBranchArg name [name] -> Input.BranchI Input.BranchSourceI'CurrentContext <$> handleMaybeProjectBranchArg name - _ -> Left $ showPatternHelp branchInputPattern + args -> wrongArgsLength "one or two arguments" args } where newBranchNameArg = @@ -3176,7 +3180,7 @@ branchEmptyInputPattern = [name] -> Input.BranchI Input.BranchSourceI'Empty <$> handleMaybeProjectBranchArg name - _ -> Left (showPatternHelp branchEmptyInputPattern) + args -> wrongArgsLength "exactly one argument" args } branchRenameInputPattern :: InputPattern @@ -3191,7 +3195,7 @@ branchRenameInputPattern = [("`branch.rename foo`", "renames the current branch to `foo`")], parse = \case [name] -> Input.BranchRenameI <$> handleProjectBranchNameArg name - _ -> Left (showPatternHelp branchRenameInputPattern) + args -> wrongArgsLength "exactly one argument" args } clone :: InputPattern @@ -3229,7 +3233,7 @@ clone = Input.CloneI <$> handleProjectAndBranchNamesArg remoteNames <*> fmap pure (handleProjectAndBranchNamesArg localNames) - _ -> Left $ showPatternHelp clone + args -> wrongArgsLength "one or two arguments" args } releaseDraft :: InputPattern @@ -3245,8 +3249,8 @@ releaseDraft = bimap (const "Couldn’t parse version number") Input.ReleaseDraftI . tryInto @Semver . Text.pack - =<< unsupportedStructuredArgument "a version number" semverString - _ -> Left (showPatternHelp releaseDraft) + =<< unsupportedStructuredArgument "release.draft" "a version number" semverString + args -> wrongArgsLength "exactly one argument" args } upgrade :: InputPattern @@ -3262,7 +3266,7 @@ upgrade = parse = \case [oldString, newString] -> Input.UpgradeI <$> handleRelativeNameSegmentArg oldString <*> handleRelativeNameSegmentArg newString - _ -> Left $ I.help upgrade + args -> wrongArgsLength "exactly two arguments" args } upgradeCommitInputPattern :: InputPattern @@ -3304,7 +3308,7 @@ upgradeCommitInputPattern = ), parse = \case [] -> Right Input.UpgradeCommitI - _ -> Left (I.help upgradeCommitInputPattern) + args -> wrongArgsLength "no arguments" args } validInputs :: [InputPattern] @@ -4020,7 +4024,6 @@ parseHashQualifiedName :: parseHashQualifiedName s = maybe ( Left - . P.warnCallout . P.wrap $ P.string s <> " is not a well-formed name, hash, or hash-qualified name. " diff --git a/unison-cli/src/Unison/CommandLine/OutputMessages.hs b/unison-cli/src/Unison/CommandLine/OutputMessages.hs index f17f483adf..298af27879 100644 --- a/unison-cli/src/Unison/CommandLine/OutputMessages.hs +++ b/unison-cli/src/Unison/CommandLine/OutputMessages.hs @@ -2132,7 +2132,7 @@ notifyUser dir = \case <> P.group (IP.makeExample IP.libInstallInputPattern [prettyProjectAndBranchName libdep] <> ".") PullIntoMissingBranch source (ProjectAndBranch maybeTargetProject targetBranch) -> pure . P.wrap $ - "I think you're wanting to merge" + "I think you want to merge" <> sourcePretty <> "into the" <> targetPretty diff --git a/unison-src/transcripts/help.md b/unison-src/transcripts/help.md new file mode 100644 index 0000000000..79ffa1846d --- /dev/null +++ b/unison-src/transcripts/help.md @@ -0,0 +1,14 @@ +# Shows `help` output + +```ucm +scratch/main> help +scratch/main> help-topics +scratch/main> help-topic filestatus +scratch/main> help-topic messages.disallowedAbsolute +scratch/main> help-topic namespaces +scratch/main> help-topic projects +scratch/main> help-topic remotes +scratch/main> help-topic testcache +``` + +We should add a command to show help for hidden commands also. diff --git a/unison-src/transcripts/help.output.md b/unison-src/transcripts/help.output.md new file mode 100644 index 0000000000..27a6d74897 --- /dev/null +++ b/unison-src/transcripts/help.output.md @@ -0,0 +1,968 @@ +# Shows `help` output + +```ucm +scratch/main> help + + add + `add` adds to the codebase all the definitions from the most recently typechecked file. + + add.preview + `add.preview` previews additions to the codebase from the most recently typechecked file. This command only displays cached typechecking results. Use `load` to reparse & typecheck the file if the context has changed. + + add.run + `add.run name` adds to the codebase the result of the most recent `run` command as `name`. + + alias.many (or copy) + `alias.many [relative2...] ` creates + aliases `relative1`, `relative2`, ... in the namespace + `namespace`. + `alias.many foo.foo bar.bar .quux` creates aliases + `.quux.foo.foo` and `.quux.bar.bar`. + + alias.term + `alias.term foo bar` introduces `bar` with the same definition as `foo`. + + alias.type + `alias.type Foo Bar` introduces `Bar` with the same definition as `Foo`. + + api + `api` provides details about the API. + + auth.login + Obtain an authentication session with Unison Share. + `auth.login`authenticates ucm with Unison Share. + + back (or popd) + `back` undoes the last `switch` command. + + branch (or branch.create, create.branch) + `branch foo` forks the current project branch to a new + branch `foo` + `branch /bar foo` forks the branch `bar` of the current + project to a new branch `foo` + `branch .bar foo` forks the path `.bar` of the current + project to a new branch `foo` + + branch.empty (or branch.create-empty, create.empty-branch) + Create a new empty branch. + + branch.rename (or rename.branch) + `branch.rename foo` renames the current branch to `foo` + + branches (or list.branch, ls.branch, branch.list) + `branches` lists all branches in the current project + `branches foo` lists all branches in the project `foo` + + clear + `clear` Clears the screen. + + clone + `clone @unison/json/topic json/my-topic` creates + `json/my-topic` from + the remote branch + `@unison/json/topic` + `clone @unison/base base/` creates `base/main` + from the remote + branch + `@unison/base/main` + `clone @unison/base /main2` creates the branch + `main2` in the + current project from + the remote branch + `@unison/base/main` + `clone /main /main2` creates the branch + `main2` in the + current project from + the remote branch + `main` of the + current project's + associated remote + (see + `help-topics remotes`) + `clone /main my-fork/` creates + `my-fork/main` from + the branch `main` of + the current + project's associated + remote (see + `help-topics remotes`) + + compile (or compile.output) + `compile main file` Outputs a stand alone file that can be + directly loaded and executed by unison. + Said execution will have the effect of + running `!main`. + + create.author + `create.author alicecoder "Alice McGee"` creates `alicecoder` + values in `metadata.authors` and `metadata.copyrightHolders.` + + debug.clear-cache + Clear the watch expression cache + + debug.doc-to-markdown + `debug.doc-to-markdown term.doc` Render a doc to markdown. + + debug.doctor + Analyze your codebase for errors and inconsistencies. + + debug.dump-namespace + Dump the namespace to a text file + + debug.dump-namespace-simple + Dump the namespace to a text file + + debug.file + View details about the most recent successfully typechecked file. + + debug.numberedArgs + Dump the contents of the numbered args state. + + delete + `delete foo` removes the term or type name `foo` from the namespace. + `delete foo bar` removes the term or type name `foo` and `bar` from the namespace. + + delete.branch (or branch.delete) + `delete.branch foo/bar` deletes the branch `bar` in the + project `foo` + `delete.branch /bar` deletes the branch `bar` in the + current project + + delete.namespace + `delete.namespace ` deletes the namespace `foo` + + delete.namespace.force + `delete.namespace.force ` deletes the namespace `foo`,deletion will proceed even if other code depends on definitions in foo. + + delete.project (or project.delete) + `delete.project foo` deletes the local project `foo` + + delete.term + `delete.term foo` removes the term name `foo` from the namespace. + `delete.term foo bar` removes the term name `foo` and `bar` from the namespace. + + delete.term.verbose + `delete.term.verbose foo` removes the term name `foo` from the namespace. + `delete.term.verbose foo bar` removes the term name `foo` and `bar` from the namespace. + + delete.type + `delete.type foo` removes the type name `foo` from the namespace. + `delete.type foo bar` removes the type name `foo` and `bar` from the namespace. + + delete.type.verbose + `delete.type.verbose foo` removes the type name `foo` from the namespace. + `delete.type.verbose foo bar` removes the type name `foo` and `bar` from the namespace. + + delete.verbose + `delete.verbose foo` removes the term or type name `foo` from the namespace. + `delete.verbose foo bar` removes the term or type name `foo` and `bar` from the namespace. + + dependencies + List the dependencies of the specified definition. + + dependents + List the named dependents of the specified definition. + + deprecated.cd (or deprecated.namespace) + Moves your perspective to a different namespace. Deprecated for now because too many important things depend on your perspective selection. + + `deprecated.cd foo.bar` descends into foo.bar from the + current namespace. + `deprecated.cd .cat.dog` sets the current namespace to the + absolute namespace .cat.dog. + `deprecated.cd ..` moves to the parent of the current + namespace. E.g. moves from + '.cat.dog' to '.cat' + `deprecated.cd` invokes a search to select which + namespace to move to, which requires + that `fzf` can be found within your + PATH. + + diff.namespace + `diff.namespace before after` shows how the namespace `after` + differs from the namespace + `before` + `diff.namespace before` shows how the current namespace + differs from the namespace + `before` + + display + `display foo` prints a rendered version of the term `foo`. + `display` without arguments invokes a search to select a definition to display, which requires that `fzf` can be found within your PATH. + + display.to + `display.to foo` prints a rendered version of the + term `foo` to the given file. + + docs + `docs foo` shows documentation for the definition `foo`. + `docs` without arguments invokes a search to select which definition to view documentation for, which requires that `fzf` can be found within your PATH. + + docs.to-html + `docs.to-html .path.to.ns doc-dir` Render + all docs + contained + within + the + namespace + `.path.to.ns`, + no matter + how deep, + to html + files in + `doc-dir` + in the + directory + UCM was + run from. + `docs.to-html project0/branch0:a.path /tmp/doc-dir` Renders + all docs + anywhere + in the + namespace + `a.path` + from + `branch0` + of + `project0` + to html + in + `/tmp/doc-dir`. + + edit + `edit foo` prepends the definition of `foo` to the top of the most recently saved file. + `edit` without arguments invokes a search to select a definition for editing, which requires that `fzf` can be found within your PATH. + + edit.namespace + `edit.namespace` will load all terms and types contained within the current namespace into your scratch file. This includes definitions in namespaces, but excludes libraries. + `edit.namespace ns1 ns2 ...` loads the terms and types contained within the provided namespaces. + + find + `find` lists all definitions in the + current namespace. + `find foo` lists all definitions with a + name similar to 'foo' in the + current namespace (excluding + those under 'lib'). + `find foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the current + namespace (excluding those + under 'lib'). + `find-in namespace` lists all definitions in the + specified subnamespace. + `find-in namespace foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the specified + subnamespace. + find.all foo lists all definitions with a + name similar to 'foo' in the + current namespace (including + one level of 'lib'). + `find-in.all namespace` lists all definitions in the + specified subnamespace + (including one level of its + 'lib'). + `find-in.all namespace foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the specified + subnamespace (including one + level of its 'lib'). + find.global foo lists all definitions with a + name similar to 'foo' in any + namespace + + find-in + `find` lists all definitions in the + current namespace. + `find foo` lists all definitions with a + name similar to 'foo' in the + current namespace (excluding + those under 'lib'). + `find foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the current + namespace (excluding those + under 'lib'). + `find-in namespace` lists all definitions in the + specified subnamespace. + `find-in namespace foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the specified + subnamespace. + find.all foo lists all definitions with a + name similar to 'foo' in the + current namespace (including + one level of 'lib'). + `find-in.all namespace` lists all definitions in the + specified subnamespace + (including one level of its + 'lib'). + `find-in.all namespace foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the specified + subnamespace (including one + level of its 'lib'). + find.global foo lists all definitions with a + name similar to 'foo' in any + namespace + + find-in.all + `find` lists all definitions in the + current namespace. + `find foo` lists all definitions with a + name similar to 'foo' in the + current namespace (excluding + those under 'lib'). + `find foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the current + namespace (excluding those + under 'lib'). + `find-in namespace` lists all definitions in the + specified subnamespace. + `find-in namespace foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the specified + subnamespace. + find.all foo lists all definitions with a + name similar to 'foo' in the + current namespace (including + one level of 'lib'). + `find-in.all namespace` lists all definitions in the + specified subnamespace + (including one level of its + 'lib'). + `find-in.all namespace foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the specified + subnamespace (including one + level of its 'lib'). + find.global foo lists all definitions with a + name similar to 'foo' in any + namespace + + find.all + `find` lists all definitions in the + current namespace. + `find foo` lists all definitions with a + name similar to 'foo' in the + current namespace (excluding + those under 'lib'). + `find foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the current + namespace (excluding those + under 'lib'). + `find-in namespace` lists all definitions in the + specified subnamespace. + `find-in namespace foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the specified + subnamespace. + find.all foo lists all definitions with a + name similar to 'foo' in the + current namespace (including + one level of 'lib'). + `find-in.all namespace` lists all definitions in the + specified subnamespace + (including one level of its + 'lib'). + `find-in.all namespace foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the specified + subnamespace (including one + level of its 'lib'). + find.global foo lists all definitions with a + name similar to 'foo' in any + namespace + + find.all.verbose + `find.all.verbose` searches for definitions like `find.all`, but includes hashes and aliases in the results. + + find.global + `find` lists all definitions in the + current namespace. + `find foo` lists all definitions with a + name similar to 'foo' in the + current namespace (excluding + those under 'lib'). + `find foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the current + namespace (excluding those + under 'lib'). + `find-in namespace` lists all definitions in the + specified subnamespace. + `find-in namespace foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the specified + subnamespace. + find.all foo lists all definitions with a + name similar to 'foo' in the + current namespace (including + one level of 'lib'). + `find-in.all namespace` lists all definitions in the + specified subnamespace + (including one level of its + 'lib'). + `find-in.all namespace foo bar` lists all definitions with a + name similar to 'foo' or + 'bar' in the specified + subnamespace (including one + level of its 'lib'). + find.global foo lists all definitions with a + name similar to 'foo' in any + namespace + + find.verbose + `find.verbose` searches for definitions like `find`, but includes hashes and aliases in the results. + + fork (or copy.namespace) + `fork src dest` creates + the + namespace + `dest` as + a copy of + `src`. + `fork project0/branch0:a.path project1/branch1:foo` creates + the + namespace + `foo` in + `branch1` + of + `project1` + as a copy + of + `a.path` + in + `project0/branch0`. + `fork srcproject/srcbranch dest` creates + the + namespace + `dest` as + a copy of + the + branch + `srcbranch` + of + `srcproject`. + + help (or ?) + `help` shows general help and `help ` shows help for one command. + + help-topics (or help-topic) + `help-topics` lists all topics and `help-topics ` shows an explanation of that topic. + + history + `history` Shows the history of the current + path. + `history .foo` Shows history of the path .foo. + `history #9dndk3kbsk13nbpeu` Shows the history of the + namespace with the given hash. + The full hash must be provided. + + io.test (or test.io) + `io.test mytest` Runs `!mytest`, where `mytest` is a delayed + test that can use the `IO` and `Exception` + abilities. + + io.test.all (or test.io.all) + `io.test.all` runs unit tests for the current branch that use + IO + + lib.install (or install.lib) + The `lib.install` command installs a dependency into the `lib` + namespace. + + `lib.install @unison/base/releases/latest` installs the + latest release of + `@unison/base` + `lib.install @unison/base/releases/3.0.0` installs version + 3.0.0 of + `@unison/base` + `lib.install @unison/base/topic` installs the + `topic` branch of + `@unison/base` + + list (or ls, dir) + `list` lists definitions and namespaces at the current + level of the current namespace. + `list foo` lists the 'foo' namespace. + `list .foo` lists the '.foo' namespace. + + load + `load` parses, typechecks, and evaluates the + most recent scratch file. + `load ` parses, typechecks, and evaluates the + given scratch file. + + merge + `merge /branch` merges `branch` into the current branch + + merge.commit (or commit.merge) + `merge.commit` merges a temporary branch created by the + `merge` command back into its parent branch, and removes the + temporary branch. + + For example, if you've done `merge topic` from main, then + `merge.commit` is equivalent to doing + + * switch /main + * merge /merge-topic-into-main + * delete.branch /merge-topic-into-main + + move (or rename) + `move foo bar` renames the term, type, and namespace foo to bar. + + move.namespace (or rename.namespace) + `move.namespace foo bar` renames the path `foo` to `bar`. + + move.term (or rename.term) + `move.term foo bar` renames `foo` to `bar`. + + move.type (or rename.type) + `move.type foo bar` renames `foo` to `bar`. + + names + `names foo` shows the hash and all known names for `foo`. + + names.global + `names.global foo` shows the hash and all known names for + `foo`. + + namespace.dependencies + List the external dependencies of the specified namespace. + + project.create (or create.project) + `project.create` creates a project with a random name + `project.create foo` creates a project named `foo` + + project.rename (or rename.project) + `project.rename foo` renames the current project to `foo` + + projects (or list.project, ls.project, project.list) + List projects. + + pull + The `pull` command merges a remote namespace into a local + branch + + `pull @unison/base/main` merges the branch + `main` of the Unison + Share hosted project + `@unison/base` into + the current branch + `pull @unison/base/main my-base/topic` merges the branch + `main` of the Unison + Share hosted project + `@unison/base` into + the branch `topic` of + the local `my-base` + project + + where `remote` is a project or project branch, such as: + Project (defaults to the /main branch) `@unison/base` + Project Branch `@unison/base/feature` + Contributor Branch `@unison/base/@johnsmith/feature` + Project Release `@unison/base/releases/1.0.0` + + pull.without-history + The `pull.without-history` command merges a remote namespace + into a local branch without including the remote's history. + This usually results in smaller codebase sizes. + + `pull.without-history @unison/base/main` merges + the + branch + `main` + of the + Unison + Share + hosted + project + `@unison/base` + into + the + current + branch + `pull.without-history @unison/base/main my-base/topic` merges + the + branch + `main` + of the + Unison + Share + hosted + project + `@unison/base` + into + the + branch + `topic` + of the + local + `my-base` + project + + where `remote` is a project or project branch, such as: + Project (defaults to the /main branch) `@unison/base` + Project Branch `@unison/base/feature` + Contributor Branch `@unison/base/@johnsmith/feature` + Project Release `@unison/base/releases/1.0.0` + + push + The `push` command merges a local project or namespace into a + remote project or namespace. + + `push ` publishes the contents of a local + namespace or branch into a remote + namespace or branch. + `push ` publishes the current namespace or + branch into a remote namespace or + branch + `push` publishes the current namespace or + branch. Remote mappings for + namespaces are configured in your + `.unisonConfig` at the key + `RemoteMappings.` where + `` is the current + namespace. Remote mappings for + branches default to the branch that + you cloned from or pushed to + initially. Otherwise, it is pushed to + @/ + + where `remote` is a project or project branch, such as: + Project (defaults to the /main branch) `@unison/base` + Project Branch `@unison/base/feature` + Contributor Branch `@unison/base/@johnsmith/feature` + + push.create + The `push.create` command pushes a local namespace to an empty + remote namespace. + + `push.create remote local` pushes the contents of the local + namespace `local` into the empty + remote namespace `remote`. + `push.create remote` publishes the current namespace + into the empty remote namespace + `remote` + `push.create` publishes the current namespace + into the remote namespace + configured in your `.unisonConfig` + at the key + `RemoteMappings.` where + `` is the current + namespace, then publishes the + current namespace to that + location. + + where `remote` is a project or project branch, such as: + Project (defaults to the /main branch) `@unison/base` + Project Branch `@unison/base/feature` + Contributor Branch `@unison/base/@johnsmith/feature` + + quit (or exit, :q) + Exits the Unison command line interface. + + reflog + `reflog` lists the changes that have affected the root namespace + + release.draft (or draft.release) + Draft a release. + + reset + `reset #pvfd222s8n` reset the current namespace to the + causal `#pvfd222s8n` + `reset foo` reset the current namespace to + that of the `foo` namespace. + `reset foo bar` reset the namespace `bar` to that + of the `foo` namespace. + `reset #pvfd222s8n /topic` reset the branch `topic` of the + current project to the causal + `#pvfd222s8n`. + + rewrite (or sfind.replace) + `rewrite rule1` rewrites definitions in the latest scratch file. + + The argument `rule1` must refer to a `@rewrite` block or a + function that immediately returns a `@rewrite` block. It can + be in the codebase or scratch file. An example: + + rule1 x = @rewrite term x + 1 ==> Nat.increment x + + Here, `x` will stand in for any expression wherever this + rewrite is applied, so this rule will match `(42+10+11) + 1` + and replace it with `Nat.increment (42+10+11)`. + + See https://unison-lang.org/learn/structured-find to learn more. + + Also see the related command `rewrite.find` + + rewrite.find (or sfind) + `rewrite.find rule1` finds definitions that match any of the + left side(s) of `rule` in the current namespace. + + The argument `rule1` must refer to a `@rewrite` block or a + function that immediately returns a `@rewrite` block. It can + be in the codebase or scratch file. An example: + + -- right of ==> is ignored by this command + rule1 x = @rewrite term x + 1 ==> () + + Here, `x` will stand in for any expression, so this rule will + match `(42+10+11) + 1`. + + See https://unison-lang.org/learn/structured-find to learn more. + + Also see the related command `rewrite` + + run + `run mymain args...` Runs `!mymain`, where `mymain` is + searched for in the most recent + typechecked file, or in the codebase. + Any provided arguments will be passed as + program arguments as though they were + provided at the command line when + running mymain as an executable. + + run.native + `run.native main args` Executes !main using native + compilation via scheme. + + switch + `switch` opens an interactive selector to pick a + project and branch + `switch foo/bar` switches to the branch `bar` in the project + `foo` + `switch foo/` switches to the last branch you visited in + the project `foo` + `switch /bar` switches to the branch `bar` in the current + project + + test + `test` runs unit tests for the current branch + `test foo` runs unit tests for the current branch defined in + namespace `foo` + + test.all + `test.all` runs unit tests for the current branch (including the `lib` namespace). + + todo + `todo` lists the current namespace's outstanding issues, + including conflicted names, dependencies with missing names, + and merge precondition violations. + + ui + `ui` opens the Local UI in the default browser. + + undo + `undo` reverts the most recent change to the codebase. + + update + Adds everything in the most recently typechecked file to the + namespace, replacing existing definitions having the same + name, and attempts to update all the existing dependents + accordingly. If the process can't be completed automatically, + the dependents will be added back to the scratch file for your + review. + + update.old + `update.old` works like `add`, except that if a definition in + the file has the same name as an existing definition, the name + gets updated to point to the new definition. If the old + definition has any dependents, `update` will add those + dependents to a refactoring session, specified by an optional + patch.`update.old` adds all definitions in + the .u file, noting replacements + in the default patch for the + current namespace. + `update.old ` adds all definitions in the .u + file, noting replacements in the + specified patch. + `update.old foo bar` adds `foo`, `bar`, and their + dependents from the .u file, + noting any replacements into the + specified patch. + + update.old.nopatch + `update.old.nopatch` works like `update.old`, except it + doesn't add a patch entry for any updates. Use this when you + want to make changes to definitions without pushing those + changes to dependents beyond your codebase. An example is when + updating docs, or when updating a term you just added.`update.old.nopatch` updates + all definitions in the .u file. + `update.old.nopatch foo bar` updates `foo`, `bar`, and their + dependents from the .u file. + + update.old.preview + `update.old.preview` previews updates to the codebase from the most recently typechecked file. This command only displays cached typechecking results. Use `load` to reparse & typecheck the file if the context has changed. + + upgrade + `upgrade old new` upgrades library dependency `lib.old` to + `lib.new`, and, if successful, deletes `lib.old`. + + upgrade.commit (or commit.upgrade) + `upgrade.commit` merges a temporary branch created by the + `upgrade` command back into its parent branch, and removes the + temporary branch. + + For example, if you've done `upgrade foo bar` from main, then + `upgrade.commit` is equivalent to doing + + * switch /main + * merge /upgrade-foo-to-bar + * delete.branch /upgrade-foo-to-bar + + version + Print the version of unison you're running + + view + `view foo` shows definitions named `foo` within your current + namespace. + `view` without arguments invokes a search to select + definitions to view, which requires that `fzf` can be found + within your PATH. + + Supports glob syntax, where ? acts a wildcard, so + `view List.?` will show `List.map`, `List.filter`, etc, but + not `List.map.doc` (since ? only matches 1 name segment). + + view.global + `view.global foo` prints definitions of `foo` within your codebase. + `view.global` without arguments invokes a search to select definitions to view, which requires that `fzf` can be found within your PATH. + +scratch/main> help-topics + + 🌻 + + Here's a list of topics I can tell you more about: + + filestatus + messages.disallowedAbsolute + namespaces + projects + remotes + testcache + + Example: use `help-topics filestatus` to learn more about that topic. + +scratch/main> help-topic filestatus + + 📓 + + Here's a list of possible status messages you might see for + definitions in a .u file. + + needs update A definition with the same name as an + existing definition. Doing `update` + instead of `add` will turn this failure + into a successful update. + + term/ctor collision A definition with the same name as an + existing constructor for some data type. + Rename your definition or the data type + before trying again to `add` or `update`. + + ctor/term collision A type defined in the file has a + constructor that's named the same as an + existing term. Rename that term or your + constructor before trying again to `add` + or `update`. + + blocked This definition was blocked because it + dependended on a definition with a failed + status. + + extra dependency This definition was added because it was + a dependency of a definition explicitly + selected. + +scratch/main> help-topic messages.disallowedAbsolute + + 🤖 + + Although I can understand absolute (ex: .foo.bar) or relative + (ex: util.math.sqrt) references to existing definitions + (help namespaces to learn more), I can't yet handle giving new + definitions with absolute names in a .u file. + + As a workaround, you can give definitions with a relative name + temporarily (like `exports.blah.foo`) and then use `move.*`. + +scratch/main> help-topic namespaces + + 🧐 + + There are two kinds of namespaces, absolute, such as (.foo.bar + or .base.math.+) and relative, such as (math.sqrt or + util.List.++). + + Relative names are converted to absolute names by prepending + the current namespace. For example, if your Unison prompt + reads: + + .foo.bar> + + and your .u file looks like: + + x = 41 + + then doing an add will create the definition with the absolute + name .foo.bar.x = 41 + + and you can refer to x by its absolute name .foo.bar.x + elsewhere in your code. For instance: + + answerToLifeTheUniverseAndEverything = .foo.bar.x + 1 + +scratch/main> help-topic projects + + A project is a versioned collection of code that can be + edited, published, and depended on other projects. Unison + projects are analogous to Git repositories. + + project.create create a new project + projects list all your projects + branch create a new workstream + branches list all your branches + merge merge one branch into another + switch switch to a project or branch + push upload your changes to Unison Share + pull download code(/changes/updates) from Unison Share + clone download a Unison Share project or branch for contribution + + Tip: Use `help project.create` to learn more. + + For full documentation, see + https://unison-lang.org/learn/projects + +scratch/main> help-topic remotes + + 🤖 + + Local projects may be associated with at most one remote + project on Unison Share. When this relationship is + established, it becomes the default argument for a number of + share commands. For example, running `push` or `pull` in a + project with no arguments will push to or pull from the + associated remote, if it exists. + + This association is created automatically on when a project is + created by `clone`. If the project was created locally then + the relationship will be established on the first `push`. + +scratch/main> help-topic testcache + + 🎈 + + Unison caches the results of test> watch expressions. Since + these expressions are pure and always yield the same result + when evaluated, there's no need to run them more than once! + + A test is rerun only if it has changed, or if one of the + definitions it depends on has changed. + +``` +We should add a command to show help for hidden commands also. diff --git a/unison-src/transcripts/input-parse-errors.md b/unison-src/transcripts/input-parse-errors.md new file mode 100644 index 0000000000..fe67a06cd9 --- /dev/null +++ b/unison-src/transcripts/input-parse-errors.md @@ -0,0 +1,173 @@ +# demonstrating our new input parsing errors + +```ucm:hide +scratch/main> builtins.merge lib.builtin +``` + +```unison:hide +x = 55 +``` +```ucm:hide +scratch/main> add +``` + +`handleNameArg` parse error in `add` +```ucm:error +scratch/main> add . +scratch/main> ls +scratch/main> add 1 +scratch/main> ls +scratch/main> add 2 +``` + +todo: +```haskell + SA.Name name -> pure name + SA.NameWithBranchPrefix (Left _) name -> pure name + SA.NameWithBranchPrefix (Right prefix) name -> pure $ Path.prefixNameIfRel (Path.AbsolutePath' prefix) name + SA.HashQualified hqname -> maybe (Left "can’t find a name from the numbered arg") pure $ HQ.toName hqname + SA.HashQualifiedWithBranchPrefix (Left _) hqname -> pure $ HQ'.toName hqname + SA.HashQualifiedWithBranchPrefix (Right prefix) hqname -> + pure . Path.prefixNameIfRel (Path.AbsolutePath' prefix) $ HQ'.toName hqname + SA.ShallowListEntry prefix entry -> + pure . HQ'.toName . fmap (Path.prefixNameIfRel prefix) $ shallowListEntryToHQ' entry + SA.SearchResult mpath result -> + maybe (Left "can’t find a name from the numbered arg") pure . HQ.toName $ searchResultToHQ mpath result + otherNumArg -> Left . I.Formatted $ wrongStructuredArgument "a name" otherNumArg +``` + +aliasMany: skipped -- similar to `add` + +```ucm:error +scratch/main> update arg +``` + +aliasTerm +``` +scratch/main> alias.term ##Nat.+ Nat.+ +``` + +aliasTermForce, +aliasType, + + +todo: +``` + +aliasMany, +api, +authLogin, +back, +branchEmptyInputPattern, +branchInputPattern, +branchRenameInputPattern, +branchesInputPattern, +cd, +clear, +clone, +compileScheme, +createAuthor, +debugClearWatchCache, +debugDoctor, +debugDumpNamespace, +debugDumpNamespaceSimple, +debugTerm, +debugTermVerbose, +debugType, +debugLSPFoldRanges, +debugFileHashes, +debugNameDiff, +debugNumberedArgs, +debugTabCompletion, +debugFuzzyOptions, +debugFormat, +delete, +deleteBranch, +deleteProject, +deleteNamespace, +deleteNamespaceForce, +deleteTerm, +deleteTermVerbose, +deleteType, +deleteTypeVerbose, +deleteVerbose, +dependencies, +dependents, +diffNamespace, +display, +displayTo, +docToMarkdown, +docs, +docsToHtml, +edit, +editNamespace, +execute, +find, +findIn, +findAll, +findInAll, +findGlobal, +findShallow, +findVerbose, +findVerboseAll, +sfind, +sfindReplace, +forkLocal, +help, +helpTopics, +history, +ioTest, +ioTestAll, +libInstallInputPattern, +load, +makeStandalone, +mergeBuiltins, +mergeIOBuiltins, +mergeOldInputPattern, +mergeOldPreviewInputPattern, +mergeOldSquashInputPattern, +mergeInputPattern, +mergeCommitInputPattern, +names False, -- names +names True, -- names.global +namespaceDependencies, +previewAdd, +previewUpdate, +printVersion, +projectCreate, +projectCreateEmptyInputPattern, +projectRenameInputPattern, +projectSwitch, +projectsInputPattern, +pull, +pullWithoutHistory, +push, +pushCreate, +pushExhaustive, +pushForce, +quit, +releaseDraft, +renameBranch, +renameTerm, +renameType, +moveAll, +reset, +resetRoot, +runScheme, +saveExecuteResult, +test, +testAll, +todo, +ui, +undo, +up, +update, +updateBuiltins, +updateOld, +updateOldNoPatch, +upgrade, +upgradeCommitInputPattern, +view, +viewGlobal, +viewReflog +``` diff --git a/unison-src/transcripts/input-parse-errors.output.md b/unison-src/transcripts/input-parse-errors.output.md new file mode 100644 index 0000000000..9eced0311f --- /dev/null +++ b/unison-src/transcripts/input-parse-errors.output.md @@ -0,0 +1,207 @@ +# demonstrating our new input parsing errors + +```unison +x = 55 +``` + +`handleNameArg` parse error in `add` +```ucm +scratch/main> add . + +⚠️ + +Sorry, I wasn’t sure how to process your request: + + 1:2: + | + 1 | . + | ^ + unexpected end of input + expecting '`' or operator (valid characters: !$%&*+-/:<=>\^|~) + + +You can run `help add` for more information on using `add`. + +scratch/main> ls + + 1. lib/ (469 terms, 74 types) + 2. x (Nat) + +scratch/main> add 1 + + + +scratch/main> ls + + 1. lib/ (469 terms, 74 types) + 2. x (Nat) + +scratch/main> add 2 + + ⊡ Ignored previously added definitions: x + +``` +todo: +```haskell + + SA.Name name -> pure name + SA.NameWithBranchPrefix (Left _) name -> pure name + SA.NameWithBranchPrefix (Right prefix) name -> pure $ Path.prefixNameIfRel (Path.AbsolutePath' prefix) name + SA.HashQualified hqname -> maybe (Left "can’t find a name from the numbered arg") pure $ HQ.toName hqname + SA.HashQualifiedWithBranchPrefix (Left _) hqname -> pure $ HQ'.toName hqname + SA.HashQualifiedWithBranchPrefix (Right prefix) hqname -> + pure . Path.prefixNameIfRel (Path.AbsolutePath' prefix) $ HQ'.toName hqname + SA.ShallowListEntry prefix entry -> + pure . HQ'.toName . fmap (Path.prefixNameIfRel prefix) $ shallowListEntryToHQ' entry + SA.SearchResult mpath result -> + maybe (Left "can’t find a name from the numbered arg") pure . HQ.toName $ searchResultToHQ mpath result + otherNumArg -> Left . I.Formatted $ wrongStructuredArgument "a name" otherNumArg + +``` + +aliasMany: skipped -- similar to `add` + +```ucm +scratch/main> update arg + +⚠️ + +Sorry, I wasn’t sure how to process your request: + + I expected no arguments, but received 1. + +You can run `help update` for more information on using +`update`. + +``` +aliasTerm +```scratch +/main> alias.term ##Nat.+ Nat.+ + +``` + +aliasTermForce, +aliasType, + + +todo: +```alias +Many, +api, +authLogin, +back, +branchEmptyInputPattern, +branchInputPattern, +branchRenameInputPattern, +branchesInputPattern, +cd, +clear, +clone, +compileScheme, +createAuthor, +debugClearWatchCache, +debugDoctor, +debugDumpNamespace, +debugDumpNamespaceSimple, +debugTerm, +debugTermVerbose, +debugType, +debugLSPFoldRanges, +debugFileHashes, +debugNameDiff, +debugNumberedArgs, +debugTabCompletion, +debugFuzzyOptions, +debugFormat, +delete, +deleteBranch, +deleteProject, +deleteNamespace, +deleteNamespaceForce, +deleteTerm, +deleteTermVerbose, +deleteType, +deleteTypeVerbose, +deleteVerbose, +dependencies, +dependents, +diffNamespace, +display, +displayTo, +docToMarkdown, +docs, +docsToHtml, +edit, +editNamespace, +execute, +find, +findIn, +findAll, +findInAll, +findGlobal, +findShallow, +findVerbose, +findVerboseAll, +sfind, +sfindReplace, +forkLocal, +help, +helpTopics, +history, +ioTest, +ioTestAll, +libInstallInputPattern, +load, +makeStandalone, +mergeBuiltins, +mergeIOBuiltins, +mergeOldInputPattern, +mergeOldPreviewInputPattern, +mergeOldSquashInputPattern, +mergeInputPattern, +mergeCommitInputPattern, +names False, -- names +names True, -- names.global +namespaceDependencies, +previewAdd, +previewUpdate, +printVersion, +projectCreate, +projectCreateEmptyInputPattern, +projectRenameInputPattern, +projectSwitch, +projectsInputPattern, +pull, +pullWithoutHistory, +push, +pushCreate, +pushExhaustive, +pushForce, +quit, +releaseDraft, +renameBranch, +renameTerm, +renameType, +moveAll, +reset, +resetRoot, +runScheme, +saveExecuteResult, +test, +testAll, +todo, +ui, +undo, +up, +update, +updateBuiltins, +updateOld, +updateOldNoPatch, +upgrade, +upgradeCommitInputPattern, +view, +viewGlobal, +viewReflog + +``` + diff --git a/unison-src/transcripts/merge.md b/unison-src/transcripts/merge.md index 6dfb48d04e..164b458f5d 100644 --- a/unison-src/transcripts/merge.md +++ b/unison-src/transcripts/merge.md @@ -3,7 +3,7 @@ The `merge` command merges together two branches in the same project: the current branch (unspecificed), and the target branch. For example, to merge `topic` into `main`, switch to `main` and run `merge topic`: -```ucm:error +```ucm scratch/main> help merge scratch/main> help merge.commit ``` diff --git a/unison-src/transcripts/merge.output.md b/unison-src/transcripts/merge.output.md index 625441f613..d0251764e2 100644 --- a/unison-src/transcripts/merge.output.md +++ b/unison-src/transcripts/merge.output.md @@ -6,22 +6,22 @@ branch. For example, to merge `topic` into `main`, switch to `main` and run `mer ```ucm scratch/main> help merge -merge -`merge /branch` merges `branch` into the current branch + merge + `merge /branch` merges `branch` into the current branch scratch/main> help merge.commit -merge.commit (or commit.merge) -`merge.commit` merges a temporary branch created by the `merge` -command back into its parent branch, and removes the temporary -branch. - -For example, if you've done `merge topic` from main, then -`merge.commit` is equivalent to doing - - * switch /main - * merge /merge-topic-into-main - * delete.branch /merge-topic-into-main + merge.commit (or commit.merge) + `merge.commit` merges a temporary branch created by the + `merge` command back into its parent branch, and removes the + temporary branch. + + For example, if you've done `merge topic` from main, then + `merge.commit` is equivalent to doing + + * switch /main + * merge /merge-topic-into-main + * delete.branch /merge-topic-into-main ``` Let's see a simple unconflicted merge in action: Alice (us) and Bob (them) add different terms. The merged result diff --git a/unison-src/transcripts/pull-errors.output.md b/unison-src/transcripts/pull-errors.output.md index a2894f6468..063c439dd5 100644 --- a/unison-src/transcripts/pull-errors.output.md +++ b/unison-src/transcripts/pull-errors.output.md @@ -12,27 +12,32 @@ test/main> pull @aryairani/test-almost-empty/main lib.base_latest test/main> pull @aryairani/test-almost-empty/main a.b - I think you're wanting to merge - @aryairani/test-almost-empty/main into the a.b namespace, but - the `pull` command only supports merging into the top level of - a local project branch. - - Use `help pull` to see some examples. +⚠️ + +Sorry, I wasn’t sure how to process your request: + + I think you want to merge @aryairani/test-almost-empty/main + into the a.b namespace, but the `pull` command only supports + merging into the top level of a local project branch. + +You can run `help pull` for more information on using `pull`. test/main> pull @aryairani/test-almost-empty/main a - I think you're wanting to merge - @aryairani/test-almost-empty/main into the a branch, but it - doesn't exist. If you want, you can create it with - `branch.empty a`, and then `pull` again. + I think you want to merge @aryairani/test-almost-empty/main + into the a branch, but it doesn't exist. If you want, you can + create it with `branch.empty a`, and then `pull` again. test/main> pull @aryairani/test-almost-empty/main .a - I think you're wanting to merge - @aryairani/test-almost-empty/main into the .a namespace, but - the `pull` command only supports merging into the top level of - a local project branch. - - Use `help pull` to see some examples. +⚠️ + +Sorry, I wasn’t sure how to process your request: + + I think you want to merge @aryairani/test-almost-empty/main + into the .a namespace, but the `pull` command only supports + merging into the top level of a local project branch. + +You can run `help pull` for more information on using `pull`. ```