diff --git a/unison-cli/src/Unison/Cli/Monad.hs b/unison-cli/src/Unison/Cli/Monad.hs index 500a015a9a..7f9d97cde4 100644 --- a/unison-cli/src/Unison/Cli/Monad.hs +++ b/unison-cli/src/Unison/Cli/Monad.hs @@ -164,8 +164,8 @@ data Env = Env generateUniqueName :: IO Parser.UniqueName, -- | How to load source code. loadSource :: SourceName -> IO LoadSourceResult, - -- | How to write source code. - writeSource :: SourceName -> Text -> IO (), + -- | How to write source code. Bool = make new fold? + writeSource :: SourceName -> Text -> Bool -> IO (), -- | What to do with output for the user. notify :: Output -> IO (), -- | What to do with numbered output for the user. diff --git a/unison-cli/src/Unison/Cli/Pretty.hs b/unison-cli/src/Unison/Cli/Pretty.hs index 07a67d1c63..9b72ee98d8 100644 --- a/unison-cli/src/Unison/Cli/Pretty.hs +++ b/unison-cli/src/Unison/Cli/Pretty.hs @@ -37,7 +37,9 @@ module Unison.Cli.Pretty prettySharePath, prettyShareURI, prettySlashProjectBranchName, + prettyTerm, prettyTermName, + prettyType, prettyTypeName, prettyTypeResultHeader', prettyTypeResultHeaderFull', @@ -47,14 +49,11 @@ module Unison.Cli.Pretty prettyWriteRemoteNamespace, shareOrigin, unsafePrettyTermResultSigFull', - prettyTermDisplayObjects, - prettyTypeDisplayObjects, ) where import Control.Lens hiding (at) import Control.Monad.Writer (Writer, runWriter) -import Data.List qualified as List import Data.Map qualified as Map import Data.Set qualified as Set import Data.Time (UTCTime) @@ -92,7 +91,6 @@ import Unison.HashQualified qualified as HQ import Unison.HashQualifiedPrime qualified as HQ' import Unison.LabeledDependency as LD import Unison.Name (Name) -import Unison.Name qualified as Name import Unison.NameSegment (NameSegment) import Unison.NameSegment.Internal qualified as NameSegment import Unison.Parser.Ann (Ann) @@ -102,10 +100,9 @@ import Unison.PrettyPrintEnv.Names qualified as PPE import Unison.PrettyPrintEnv.Util qualified as PPE import Unison.PrettyPrintEnvDecl qualified as PPED import Unison.Project (ProjectAndBranch (..), ProjectName, Semver (..)) -import Unison.Reference (Reference, TermReferenceId) +import Unison.Reference (Reference) import Unison.Reference qualified as Reference import Unison.Referent (Referent) -import Unison.Referent qualified as Referent import Unison.Server.SearchResultPrime qualified as SR' import Unison.ShortHash (ShortHash) import Unison.Symbol (Symbol) @@ -439,34 +436,6 @@ prettyUnisonFile ppe uf@(UF.UnisonFileId datas effects terms watches) = rd = Reference.DerivedId hqv v = HQ.unsafeFromVar v -prettyTypeDisplayObjects :: - PPED.PrettyPrintEnvDecl -> - (Map Reference (DisplayObject () (DD.Decl Symbol Ann))) -> - [P.Pretty SyntaxText] -prettyTypeDisplayObjects pped types = - types - & Map.toList - & map (\(ref, dt) -> (PPE.typeName unsuffixifiedPPE ref, ref, dt)) - & List.sortBy (\(n0, _, _) (n1, _, _) -> Name.compareAlphabetical n0 n1) - & map (prettyType pped) - where - unsuffixifiedPPE = PPED.unsuffixifiedPPE pped - -prettyTermDisplayObjects :: - PPED.PrettyPrintEnvDecl -> - Bool -> - (TermReferenceId -> Bool) -> - (Map Reference.TermReference (DisplayObject (Type Symbol Ann) (Term Symbol Ann))) -> - [P.Pretty SyntaxText] -prettyTermDisplayObjects pped isSourceFile isTest terms = - terms - & Map.toList - & map (\(ref, dt) -> (PPE.termName unsuffixifiedPPE (Referent.Ref ref), ref, dt)) - & List.sortBy (\(n0, _, _) (n1, _, _) -> Name.compareAlphabetical n0 n1) - & map (\t -> prettyTerm pped isSourceFile (fromMaybe False . fmap isTest . Reference.toId $ (t ^. _2)) t) - where - unsuffixifiedPPE = PPED.unsuffixifiedPPE pped - prettyTerm :: PPED.PrettyPrintEnvDecl -> Bool {- whether we're printing to a source-file or not. -} -> diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs index 265a04a886..f4c24c3586 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs @@ -14,7 +14,6 @@ import Control.Monad.State qualified as State import Data.Foldable qualified as Foldable import Data.List qualified as List import Data.List.Extra (nubOrd) -import Data.List.NonEmpty (NonEmpty) import Data.List.NonEmpty qualified as Nel import Data.Map qualified as Map import Data.Set qualified as Set @@ -85,7 +84,7 @@ import Unison.Codebase.Editor.HandleInput.Reflogs qualified as Reflogs import Unison.Codebase.Editor.HandleInput.ReleaseDraft (handleReleaseDraft) import Unison.Codebase.Editor.HandleInput.Run (handleRun) import Unison.Codebase.Editor.HandleInput.RuntimeUtils qualified as RuntimeUtils -import Unison.Codebase.Editor.HandleInput.ShowDefinition (showDefinitions) +import Unison.Codebase.Editor.HandleInput.ShowDefinition (handleShowDefinition) import Unison.Codebase.Editor.HandleInput.TermResolution (resolveMainRef) import Unison.Codebase.Editor.HandleInput.Tests qualified as Tests import Unison.Codebase.Editor.HandleInput.Todo (handleTodo) @@ -616,7 +615,7 @@ loop e = do DisplayI outputLoc namesToDisplay -> do traverse_ (displayI outputLoc) namesToDisplay ShowDefinitionI outputLoc showDefinitionScope query -> handleShowDefinition outputLoc showDefinitionScope query - EditNamespaceI paths -> handleEditNamespace LatestFileLocation paths + EditNamespaceI paths -> handleEditNamespace (LatestFileLocation AboveFold) paths FindShallowI pathArg -> handleLs pathArg FindI isVerbose fscope ws -> handleFindI isVerbose fscope ws input StructuredFindI _fscope ws -> handleStructuredFindI ws @@ -763,7 +762,7 @@ loop e = do Nothing -> do Cli.respond DebugFuzzyOptionsNoResolver DebugFormatI -> do - Cli.Env {writeSource, loadSource} <- ask + env <- ask void $ runMaybeT do (filePath, _) <- MaybeT Cli.getLatestFile pf <- lift Cli.getLatestParsedFile @@ -771,17 +770,17 @@ loop e = do names <- lift Cli.currentNames let buildPPED uf tf = let names' = (fromMaybe mempty $ (UF.typecheckedToNames <$> tf) <|> (UF.toNames <$> uf)) `Names.shadowing` names - in pure (PPED.makePPED (PPE.hqNamer 10 names') (PPE.suffixifyByHashName names')) + in pure (PPED.makePPED (PPE.hqNamer 10 names') (PPE.suffixifyByHashName names')) let formatWidth = 80 currentPath <- lift $ Cli.getCurrentPath updates <- MaybeT $ Format.formatFile buildPPED formatWidth currentPath pf tf Nothing source <- - liftIO (loadSource (Text.pack filePath)) >>= \case + liftIO (env.loadSource (Text.pack filePath)) >>= \case Cli.InvalidSourceNameError -> lift $ Cli.returnEarly $ Output.InvalidSourceName filePath Cli.LoadError -> lift $ Cli.returnEarly $ Output.SourceLoadFailed filePath Cli.LoadSuccess contents -> pure contents let updatedSource = Format.applyTextReplacements updates source - liftIO $ writeSource (Text.pack filePath) updatedSource + liftIO $ env.writeSource (Text.pack filePath) updatedSource True DebugDumpNamespacesI -> do let seen h = State.gets (Set.member h) set h = State.modify (Set.insert h) @@ -1264,50 +1263,6 @@ handleDependents hq = do Cli.setNumberedArgs . map SA.HashQualified $ types <> terms Cli.respond (ListDependents ppe lds types terms) --- | Handle a @ShowDefinitionI@ input command, i.e. `view` or `edit`. -handleShowDefinition :: OutputLocation -> ShowDefinitionScope -> NonEmpty (HQ.HashQualified Name) -> Cli () -handleShowDefinition outputLoc showDefinitionScope query = do - Cli.Env {codebase} <- ask - hqLength <- Cli.runTransaction Codebase.hashLength - let hasAbsoluteQuery = any (any Name.isAbsolute) query - (names, unbiasedPPED) <- case (hasAbsoluteQuery, showDefinitionScope) of - -- TODO: We should instead print each definition using the names from its project-branch root. - (True, _) -> do - root <- Cli.getCurrentProjectRoot - let root0 = Branch.head root - let names = Names.makeAbsolute $ Branch.toNames root0 - let pped = PPED.makePPED (PPE.hqNamer 10 names) (suffixify names) - pure (names, pped) - (_, ShowDefinitionGlobal) -> do - -- TODO: Maybe rewrite to be properly global - root <- Cli.getCurrentProjectRoot - let root0 = Branch.head root - let names = Names.makeAbsolute $ Branch.toNames root0 - let pped = PPED.makePPED (PPE.hqNamer 10 names) (suffixify names) - pure (names, pped) - (_, ShowDefinitionLocal) -> do - currentNames <- Cli.currentNames - let pped = PPED.makePPED (PPE.hqNamer 10 currentNames) (suffixify currentNames) - pure (currentNames, pped) - let pped = PPED.biasTo (mapMaybe HQ.toName (toList query)) unbiasedPPED - Backend.DefinitionResults terms types misses <- do - let nameSearch = NameSearch.makeNameSearch hqLength names - Cli.runTransaction (Backend.definitionsByName codebase nameSearch includeCycles Names.IncludeSuffixes (toList query)) - showDefinitions outputLoc pped terms types misses - where - suffixify = - case outputLoc of - ConsoleLocation -> PPE.suffixifyByHash - FileLocation _ -> PPE.suffixifyByHashName - LatestFileLocation -> PPE.suffixifyByHashName - - -- `view`: don't include cycles; `edit`: include cycles - includeCycles = - case outputLoc of - ConsoleLocation -> Backend.DontIncludeCycles - FileLocation _ -> Backend.IncludeCycles - LatestFileLocation -> Backend.IncludeCycles - -- todo: compare to `getHQTerms` / `getHQTypes`. Is one universally better? resolveHQToLabeledDependencies :: HQ.HashQualified Name -> Cli (Set LabeledDependency) resolveHQToLabeledDependencies = \case @@ -1355,8 +1310,8 @@ doDisplay outputLoc names tm = do rendered <- DisplayValues.displayTerm pped loadTerm loadTypeOfTerm' evalTerm loadDecl tm mayFP <- case outputLoc of ConsoleLocation -> pure Nothing - FileLocation path -> Just <$> Directory.canonicalizePath path - LatestFileLocation -> traverse Directory.canonicalizePath $ fmap fst (loopState ^. #latestFile) <|> Just "scratch.u" + FileLocation path _ -> Just <$> Directory.canonicalizePath path + LatestFileLocation _ -> traverse Directory.canonicalizePath $ fmap fst (loopState ^. #latestFile) <|> Just "scratch.u" whenJust mayFP \fp -> do liftIO $ prependFile fp (Text.pack . P.toPlain 80 $ rendered) Cli.respond $ DisplayRendered mayFP rendered @@ -1364,8 +1319,8 @@ doDisplay outputLoc names tm = do suffixify = case outputLoc of ConsoleLocation -> PPE.suffixifyByHash - FileLocation _ -> PPE.suffixifyByHashName - LatestFileLocation -> PPE.suffixifyByHashName + FileLocation _ _ -> PPE.suffixifyByHashName + LatestFileLocation _ -> PPE.suffixifyByHashName prependFile :: FilePath -> Text -> IO () prependFile filePath txt = do @@ -1475,7 +1430,7 @@ doCompile profile native output main = do outf | native = output | otherwise = output <> ".uc" - copts = Runtime.defaultCompileOpts { Runtime.profile = profile } + copts = Runtime.defaultCompileOpts {Runtime.profile = profile} whenJustM ( liftIO $ Runtime.compileTo theRuntime copts codeLookup ppe ref outf @@ -1661,8 +1616,8 @@ displayI outputLoc hq = do suffixify = case outputLoc of ConsoleLocation -> PPE.suffixifyByHash - FileLocation _ -> PPE.suffixifyByHashName - LatestFileLocation -> PPE.suffixifyByHashName + FileLocation _ _ -> PPE.suffixifyByHashName + LatestFileLocation _ -> PPE.suffixifyByHashName docsI :: Name -> Cli () docsI src = do diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/FindAndReplace.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/FindAndReplace.hs index 54fc3f870e..35d9d786da 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/FindAndReplace.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/FindAndReplace.hs @@ -52,7 +52,7 @@ import Unison.Var qualified as Var handleStructuredFindReplaceI :: HQ.HashQualified Name -> Cli () handleStructuredFindReplaceI rule = do - Cli.Env {writeSource} <- ask + env <- ask uf0 <- Cli.expectLatestParsedFile let (prepare, uf, finish) = UF.prepareRewrite uf0 (ppe, _ns, rules) <- lookupRewrite InvalidStructuredFindReplace prepare rule @@ -67,7 +67,7 @@ handleStructuredFindReplaceI rule = do #latestTypecheckedFile .= Just (Left . snd $ uf') let msg = "| Rewrote using: " let rendered = Text.pack . P.toPlain 80 $ renderRewrittenFile ppe msg uf' - liftIO $ writeSource (Text.pack dest) rendered + liftIO $ env.writeSource (Text.pack dest) rendered True Cli.respond $ OutputRewrittenFile dest vs handleStructuredFindI :: HQ.HashQualified Name -> Cli () @@ -116,13 +116,13 @@ handleTextFindI allowLib tokens = do results0 <- traverse ok results let results = Alphabetical.sortAlphabetically [hq | (hq, True) <- results0] Cli.setNumberedArgs $ map SA.HashQualified results - Cli.respond (ListTextFind allowLib results) + Cli.respond (ListTextFind allowLib results) where tokensTxt = Text.pack <$> tokens - containsTokens tm = + containsTokens tm = hasAll . join $ ABT.find txts tm - where - hasAll txts = all (\tok -> any (\haystack -> Text.isInfixOf tok haystack) txts) tokensTxt + where + hasAll txts = all (\tok -> any (\haystack -> Text.isInfixOf tok haystack) txts) tokensTxt txts (Term.Text' haystack) = ABT.Found [haystack] txts (Term.Nat' haystack) = ABT.Found [Text.pack (show haystack)] txts (Term.Int' haystack) = ABT.Found [Text.pack (show haystack)] diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Merge2.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Merge2.hs index 6c4a374877..cb39f76ad0 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Merge2.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Merge2.hs @@ -318,7 +318,7 @@ doMerge info = do blob5 <- maybeBlob5 & onNothing do - Cli.Env {writeSource} <- ask + env <- ask (_temporaryBranchId, temporaryBranchName) <- HandleInput.Branch.createBranch info.description @@ -336,7 +336,7 @@ doMerge info = do Cli.getLatestFile <&> \case Nothing -> "scratch.u" Just (file, _) -> file - liftIO $ writeSource (Text.pack scratchFilePath) (Text.pack $ Pretty.toPlain 80 blob3.unparsedFile) + liftIO $ env.writeSource (Text.pack scratchFilePath) (Text.pack $ Pretty.toPlain 80 blob3.unparsedFile) True done (Output.MergeFailure scratchFilePath mergeSourceAndTarget temporaryBranchName) Cli.runTransaction (Codebase.addDefsToCodebase env.codebase blob5.file) diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/ShowDefinition.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/ShowDefinition.hs index 0c4cfada13..2d451150ea 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/ShowDefinition.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/ShowDefinition.hs @@ -1,31 +1,104 @@ -module Unison.Codebase.Editor.HandleInput.ShowDefinition (showDefinitions) where +module Unison.Codebase.Editor.HandleInput.ShowDefinition + ( handleShowDefinition, + showDefinitions, + ) +where import Control.Lens import Control.Monad.Reader (ask) import Control.Monad.State qualified as State +import Data.List qualified as List +import Data.List.NonEmpty qualified as List (NonEmpty) +import Data.List.NonEmpty qualified as List.NonEmpty import Data.Map qualified as Map import Data.Set qualified as Set import Data.Text qualified as Text import Unison.Builtin.Decls qualified as DD import Unison.Cli.Monad (Cli) import Unison.Cli.Monad qualified as Cli +import Unison.Cli.MonadUtils qualified as Cli +import Unison.Cli.NamesUtils qualified as Cli import Unison.Cli.Pretty qualified as Pretty import Unison.Codebase qualified as Codebase +import Unison.Codebase.Branch qualified as Branch +import Unison.Codebase.Branch.Names qualified as Branch import Unison.Codebase.Editor.DisplayObject (DisplayObject) -import Unison.Codebase.Editor.Input +import Unison.Codebase.Editor.Input (OutputLocation (..), RelativeToFold (..), ShowDefinitionScope (..)) import Unison.Codebase.Editor.Output import Unison.DataDeclaration (Decl) +import Unison.DataDeclaration qualified as DD import Unison.HashQualified qualified as HQ import Unison.Name (Name) +import Unison.Name qualified as Name +import Unison.Names qualified as Names +import Unison.NamesWithHistory qualified as Names import Unison.Parser.Ann (Ann) import Unison.Prelude +import Unison.PrettyPrintEnv qualified as PPE +import Unison.PrettyPrintEnv.Names qualified as PPE import Unison.PrettyPrintEnvDecl qualified as PPED +import Unison.PrettyPrintEnvDecl.Names qualified as PPED +import Unison.Reference (Reference, TermReferenceId) import Unison.Reference qualified as Reference +import Unison.Referent qualified as Referent +import Unison.Server.Backend qualified as Backend +import Unison.Server.NameSearch.FromNames qualified as NameSearch import Unison.Symbol (Symbol) +import Unison.Syntax.Name qualified as Name (toVar) +import Unison.Syntax.NamePrinter (SyntaxText) import Unison.Term (Term) import Unison.Type (Type) +import Unison.UnisonFile (TypecheckedUnisonFile (..), UnisonFile (..)) +import Unison.UnisonFile qualified as UnisonFile +import Unison.Util.Defns (Defns (..)) +import Unison.Util.Pretty (Pretty) import Unison.Util.Pretty qualified as Pretty import Unison.Util.Set qualified as Set +import Unison.WatchKind qualified as WatchKind + +-- | Handle a @ShowDefinitionI@ input command, i.e. `view` or `edit`. +handleShowDefinition :: OutputLocation -> ShowDefinitionScope -> List.NonEmpty (HQ.HashQualified Name) -> Cli () +handleShowDefinition outputLoc showDefinitionScope query = do + env <- ask + + let hasAbsoluteQuery = any (any Name.isAbsolute) query + (names, unbiasedPPED) <- case (hasAbsoluteQuery, showDefinitionScope) of + -- TODO: We should instead print each definition using the names from its project-branch root. + (True, _) -> do + root <- Cli.getCurrentProjectRoot + let root0 = Branch.head root + let names = Names.makeAbsolute (Branch.toNames root0) + let pped = PPED.makePPED (PPE.hqNamer 10 names) (suffixify names) + pure (names, pped) + (_, ShowDefinitionGlobal) -> do + -- TODO: Maybe rewrite to be properly global + root <- Cli.getCurrentProjectRoot + let root0 = Branch.head root + let names = Names.makeAbsolute $ Branch.toNames root0 + let pped = PPED.makePPED (PPE.hqNamer 10 names) (suffixify names) + pure (names, pped) + (_, ShowDefinitionLocal) -> do + currentNames <- Cli.currentNames + let pped = PPED.makePPED (PPE.hqNamer 10 currentNames) (suffixify currentNames) + pure (currentNames, pped) + let pped = PPED.biasTo (mapMaybe HQ.toName (List.NonEmpty.toList query)) unbiasedPPED + Backend.DefinitionResults terms types misses <- do + let nameSearch = NameSearch.makeNameSearch 10 names + Cli.runTransaction (Backend.definitionsByName env.codebase nameSearch includeCycles Names.IncludeSuffixes (toList query)) + showDefinitions outputLoc pped terms types misses + where + suffixify = + case outputLoc of + ConsoleLocation -> PPE.suffixifyByHash + FileLocation _ _ -> PPE.suffixifyByHashName + LatestFileLocation _ -> PPE.suffixifyByHashName + + -- `view`: don't include cycles; `edit`: include cycles + includeCycles = + case outputLoc of + ConsoleLocation -> Backend.DontIncludeCycles + FileLocation _ _ -> Backend.IncludeCycles + LatestFileLocation _ -> Backend.IncludeCycles -- | Show the provided definitions to console or scratch file. -- The caller is responsible for ensuring that the definitions include cycles if that's @@ -41,7 +114,7 @@ showDefinitions :: [HQ.HashQualified Name] -> Cli () showDefinitions outputLoc pped terms types misses = do - Cli.Env {codebase, writeSource} <- ask + env <- ask outputPath <- getOutputPath case outputPath of _ | null terms && null types -> pure () @@ -50,37 +123,130 @@ showDefinitions outputLoc pped terms types misses = do let isTest _ = False let isSourceFile = False -- No filepath, render code to console. - let renderedCodePretty = renderCodePretty pped isSourceFile isTest terms types + let (renderedCodePretty, _numRendered) = + renderCodePretty + pped + isSourceFile + isTest + terms + types + (Defns Set.empty Set.empty) Cli.respond $ DisplayDefinitions renderedCodePretty - Just fp -> do + Just (fp, relToFold) -> do + -- Of all the names we were asked to show, if this is a `WithinFold` showing, then exclude the ones that are + -- already bound in the file + excludeNames <- + case relToFold of + AboveFold -> pure (Defns Set.empty Set.empty) + WithinFold -> + use #latestTypecheckedFile <&> \case + Nothing -> Defns Set.empty Set.empty + Just (Left unisonFile) -> + let boundTermNames = Map.keysSet unisonFile.terms + boundTestWatchNames = + Map.toList unisonFile.watches + & foldMap \case + (WatchKind.TestWatch, watches) -> Set.fromList (map (view _1) watches) + _ -> Set.empty + boundDataDeclNames = Map.keysSet unisonFile.dataDeclarationsId + boundEffectDeclNames = Map.keysSet unisonFile.effectDeclarationsId + in Defns + { terms = boundTermNames <> boundTestWatchNames, + types = boundDataDeclNames <> boundEffectDeclNames + } + Just (Right typecheckedUnisonFile) -> + let boundTermNames = foldMap (Set.fromList . map (view _1)) typecheckedUnisonFile.topLevelComponents' + boundTestWatchNames = + typecheckedUnisonFile.watchComponents & foldMap \case + (WatchKind.TestWatch, watches) -> Set.fromList (map (view _1) watches) + _ -> Set.empty + in Defns + { terms = boundTermNames <> boundTestWatchNames, + types = UnisonFile.typeNamespaceBindings typecheckedUnisonFile + } + -- We build an 'isTest' check to prepend "test>" to tests in a scratch file. - testRefs <- Cli.runTransaction (Codebase.filterTermsByReferenceIdHavingType codebase (DD.testResultListType mempty) (Map.keysSet terms & Set.mapMaybe Reference.toId)) + testRefs <- + Cli.runTransaction do + Codebase.filterTermsByReferenceIdHavingType + env.codebase + (DD.testResultListType mempty) + (Map.keysSet terms & Set.mapMaybe Reference.toId) let isTest r = Set.member r testRefs let isSourceFile = True - let renderedCodePretty = renderCodePretty pped isSourceFile isTest terms types - let renderedCodeText = Text.pack $ Pretty.toPlain 80 renderedCodePretty + let (renderedCodePretty, numRendered) = renderCodePretty pped isSourceFile isTest terms types excludeNames + when (numRendered > 0) do + let renderedCodeText = Text.pack $ Pretty.toPlain 80 renderedCodePretty + + -- We set latestFile to be programmatically generated, if we + -- are viewing these definitions to a file - this will skip the + -- next update for that file (which will happen immediately) + #latestFile ?= (fp, True) + liftIO $ + env.writeSource (Text.pack fp) renderedCodeText case relToFold of + AboveFold -> True + WithinFold -> False + Cli.respond $ LoadedDefinitionsToSourceFile fp numRendered - -- We set latestFile to be programmatically generated, if we - -- are viewing these definitions to a file - this will skip the - -- next update for that file (which will happen immediately) - #latestFile ?= (fp, True) - liftIO $ writeSource (Text.pack fp) renderedCodeText - let numDefinitions = Map.size terms + Map.size types - Cli.respond $ LoadedDefinitionsToSourceFile fp numDefinitions when (not (null misses)) (Cli.respond (SearchTermsNotFound misses)) where -- Get the file path to send the definition(s) to. `Nothing` means the terminal. - getOutputPath :: Cli (Maybe FilePath) + getOutputPath :: Cli (Maybe (FilePath, RelativeToFold)) getOutputPath = case outputLoc of ConsoleLocation -> pure Nothing - FileLocation path -> pure (Just path) - LatestFileLocation -> do + FileLocation path relToFold -> pure (Just (path, relToFold)) + LatestFileLocation relToFold -> do loopState <- State.get pure case loopState ^. #latestFile of - Nothing -> Just "scratch.u" - Just (path, _) -> Just path + Nothing -> Just ("scratch.u", relToFold) + Just (path, _) -> Just (path, relToFold) + + renderCodePretty pped isSourceFile isTest terms types excludeNames = + let prettyTypes = prettyTypeDisplayObjects pped types excludeNames.types + prettyTerms = prettyTermDisplayObjects pped isSourceFile isTest terms excludeNames.terms + in ( Pretty.syntaxToColor (Pretty.sep "\n\n" (prettyTypes ++ prettyTerms)), + length prettyTerms + length prettyTypes + ) - renderCodePretty pped isSourceFile isTest terms types = - Pretty.syntaxToColor . Pretty.sep "\n\n" $ - Pretty.prettyTypeDisplayObjects pped types <> Pretty.prettyTermDisplayObjects pped isSourceFile isTest terms +prettyTypeDisplayObjects :: + PPED.PrettyPrintEnvDecl -> + (Map Reference (DisplayObject () (DD.Decl Symbol Ann))) -> + Set Symbol -> + [Pretty SyntaxText] +prettyTypeDisplayObjects pped types excludeNames = + types + & Map.toList + & mapMaybe + ( \(ref, dt) -> do + let hqName = PPE.typeName unsuffixifiedPPE ref + whenJust (HQ.toName hqName) \name -> + guard (Set.notMember (Name.toVar name) excludeNames) + Just (hqName, ref, dt) + ) + & List.sortBy (\(n0, _, _) (n1, _, _) -> Name.compareAlphabetical n0 n1) + & map (Pretty.prettyType pped) + where + unsuffixifiedPPE = PPED.unsuffixifiedPPE pped + +prettyTermDisplayObjects :: + PPED.PrettyPrintEnvDecl -> + Bool -> + (TermReferenceId -> Bool) -> + (Map Reference.TermReference (DisplayObject (Type Symbol Ann) (Term Symbol Ann))) -> + Set Symbol -> + [Pretty SyntaxText] +prettyTermDisplayObjects pped isSourceFile isTest terms excludeNames = + terms + & Map.toList + & mapMaybe + ( \(ref, dt) -> do + let hqName = PPE.termName unsuffixifiedPPE (Referent.Ref ref) + whenJust (HQ.toName hqName) \name -> + guard (Set.notMember (Name.toVar name) excludeNames) + Just (hqName, ref, dt) + ) + & List.sortBy (\(n0, _, _) (n1, _, _) -> Name.compareAlphabetical n0 n1) + & map (\t -> Pretty.prettyTerm pped isSourceFile (fromMaybe False . fmap isTest . Reference.toId $ (t ^. _2)) t) + where + unsuffixifiedPPE = PPED.unsuffixifiedPPE pped diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Update2.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Update2.hs index b8a96f0141..b783b00e5f 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Update2.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Update2.hs @@ -151,7 +151,7 @@ handleUpdate2 = do secondTuf <- parseAndTypecheck prettyUnisonFile parsingEnv & onNothingM do scratchFilePath <- fst <$> Cli.expectLatestFile - liftIO $ env.writeSource (Text.pack scratchFilePath) (Text.pack $ Pretty.toPlain 80 prettyUnisonFile) + liftIO $ env.writeSource (Text.pack scratchFilePath) (Text.pack $ Pretty.toPlain 80 prettyUnisonFile) True Cli.returnEarly Output.UpdateTypecheckingFailure Cli.respond Output.UpdateTypecheckingSuccess diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Upgrade.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Upgrade.hs index 5e0fe63009..c4331b99f6 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Upgrade.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Upgrade.hs @@ -87,7 +87,7 @@ handleUpgrade oldName newName = do when (oldName == newName) do Cli.returnEarlyWithoutOutput - Cli.Env {codebase, writeSource} <- ask + env <- ask let oldPath = Path.Absolute (Path.fromList [NameSegment.libSegment, oldName]) let newPath = Path.Absolute (Path.fromList [NameSegment.libSegment, newName]) @@ -156,7 +156,7 @@ handleUpgrade oldName newName = do unisonFile <- do addDefinitionsToUnisonFile abort - codebase + env.codebase (findCtorNames Output.UOUUpgrade currentLocalNames currentLocalConstructorNames) dependents UnisonFile.emptyUnisonFile @@ -197,13 +197,13 @@ handleUpgrade oldName newName = do Cli.getLatestFile <&> \case Nothing -> "scratch.u" Just (file, _) -> file - liftIO $ writeSource (Text.pack scratchFilePath) (Text.pack $ Pretty.toPlain 80 prettyUnisonFile) + liftIO $ env.writeSource (Text.pack scratchFilePath) (Text.pack $ Pretty.toPlain 80 prettyUnisonFile) True Cli.returnEarly $ Output.UpgradeFailure (projectBranch ^. #name) temporaryBranchName scratchFilePath oldName newName branchUpdates <- Cli.runTransactionWithRollback \abort -> do - Codebase.addDefsToCodebase codebase typecheckedUnisonFile + Codebase.addDefsToCodebase env.codebase typecheckedUnisonFile typecheckedUnisonFileToBranchUpdates abort (findCtorNamesMaybe Output.UOUUpgrade currentLocalNames currentLocalConstructorNames Nothing) diff --git a/unison-cli/src/Unison/Codebase/Editor/Input.hs b/unison-cli/src/Unison/Codebase/Editor/Input.hs index 9514afde74..f8022f4906 100644 --- a/unison-cli/src/Unison/Codebase/Editor/Input.hs +++ b/unison-cli/src/Unison/Codebase/Editor/Input.hs @@ -8,6 +8,7 @@ module Unison.Codebase.Editor.Input TestInput (..), Event (..), OutputLocation (..), + RelativeToFold (..), PatchPath, BranchIdG (..), BranchId, @@ -126,8 +127,8 @@ data Input | PullI !PullSourceTarget !PullMode | PushRemoteBranchI PushRemoteBranchInput | ResetI (BranchId2 {- namespace to reset it to -}) (Maybe UnresolvedProjectBranch {- ProjectBranch to reset -}) - -- todo: Q: Does it make sense to publish to not-the-root of a Github repo? - | -- Does it make sense to fork from not-the-root of a Github repo? + | -- todo: Q: Does it make sense to publish to not-the-root of a Github repo? + -- Does it make sense to fork from not-the-root of a Github repo? -- used in Welcome module to give directions to user CreateMessage (P.Pretty P.ColorText) | -- Change directory. @@ -292,11 +293,17 @@ data TestInput = TestInput -- Some commands, like `view`, can dump output to either console or a file. data OutputLocation = ConsoleLocation - | LatestFileLocation - | FileLocation FilePath + | LatestFileLocation RelativeToFold + | FileLocation FilePath RelativeToFold -- ClipboardLocation deriving (Eq, Show) +-- | Above a new fold, or within the topmost fold? +data RelativeToFold + = AboveFold + | WithinFold + deriving stock (Eq, Show) + data FindScope = FindLocal Path' | FindLocalAndDeps Path' diff --git a/unison-cli/src/Unison/Codebase/Transcript/Runner.hs b/unison-cli/src/Unison/Codebase/Transcript/Runner.hs index 95e7c4af7f..6cde38b7da 100644 --- a/unison-cli/src/Unison/Codebase/Transcript/Runner.hs +++ b/unison-cli/src/Unison/Codebase/Transcript/Runner.hs @@ -348,8 +348,8 @@ run isTest verbosity dir stanzas codebase runtime sbRuntime nRuntime ucmVersion let f = Cli.LoadSuccess <$> readUtf8 (Text.unpack name) in f <|> pure Cli.InvalidSourceNameError - writeSourceFile :: ScratchFileName -> Text -> IO () - writeSourceFile fp contents = do + writeSource :: ScratchFileName -> Text -> Bool -> IO () + writeSource fp contents _addFold = do shouldShowSourceChanges <- (== Shown) <$> readIORef hidden when shouldShowSourceChanges $ do atomically (Q.enqueue ucmScratchFileUpdatesQueue (fp, contents)) @@ -420,7 +420,7 @@ run isTest verbosity dir stanzas codebase runtime sbRuntime nRuntime ucmVersion i <- atomicModifyIORef' seedRef \i -> let !i' = i + 1 in (i', i) pure (Parser.uniqueBase32Namegen (Random.drgNewSeed (Random.seedFromInteger (fromIntegral i)))), loadSource = loadPreviousUnisonBlock, - writeSource = writeSourceFile, + writeSource, notify = print, notifyNumbered = printNumbered, runtime, diff --git a/unison-cli/src/Unison/CommandLine/InputPatterns.hs b/unison-cli/src/Unison/CommandLine/InputPatterns.hs index f0b2463570..eac52019c0 100644 --- a/unison-cli/src/Unison/CommandLine/InputPatterns.hs +++ b/unison-cli/src/Unison/CommandLine/InputPatterns.hs @@ -141,6 +141,7 @@ where import Control.Lens.Cons qualified as Cons import Data.Bitraversable (bitraverse) +import Data.Char (isSpace) import Data.List (intercalate) import Data.List.Extra qualified as List import Data.List.NonEmpty qualified as NE @@ -148,7 +149,6 @@ import Data.Map qualified as Map import Data.Maybe (fromJust) import Data.Set qualified as Set import Data.Text qualified as Text -import Data.Char (isSpace) import Data.These (These (..)) import Network.URI qualified as URI import System.Console.Haskeline.Completion (Completion (Completion)) @@ -1026,10 +1026,10 @@ displayTo = file : defs -> maybe (wrongArgsLength "at least two arguments" [file]) - ( \defs -> - Input.DisplayI . Input.FileLocation - <$> unsupportedStructuredArgument displayTo "a file name" file - <*> traverse handleHashQualifiedNameArg defs + ( \defs -> do + file <- unsupportedStructuredArgument displayTo "a file name" file + names <- traverse handleHashQualifiedNameArg defs + pure (Input.DisplayI (Input.FileLocation file Input.AboveFold) names) ) $ NE.nonEmpty defs [] -> wrongArgsLength "at least two arguments" [] @@ -1086,14 +1086,13 @@ textfind :: Bool -> InputPattern textfind allowLib = InputPattern cmdName aliases I.Visible [("token", OnePlus, noCompletionsArg)] msg parse where - (cmdName, aliases, alternate) = - if allowLib then - ("text.find.all", ["grep.all"], "Use `text.find` to exclude `lib` from search.") - else - ("text.find", ["grep"], "Use `text.find.all` to include search of `lib`.") + (cmdName, aliases, alternate) = + if allowLib + then ("text.find.all", ["grep.all"], "Use `text.find` to exclude `lib` from search.") + else ("text.find", ["grep"], "Use `text.find.all` to include search of `lib`.") parse = \case [] -> Left (P.text "Please supply at least one token.") - words -> pure $ Input.TextFindI allowLib (untokenize $ [ e | Left e <- words ]) + words -> pure $ Input.TextFindI allowLib (untokenize $ [e | Left e <- words]) msg = P.lines [ P.wrap $ @@ -1101,26 +1100,27 @@ textfind allowLib = <> " finds terms with literals (text or numeric) containing" <> "`token1`, `99`, and `token2`.", "", - P.wrap $ "Numeric literals must be quoted (ex: \"42\")" <> - "but single words need not be quoted.", + P.wrap $ + "Numeric literals must be quoted (ex: \"42\")" + <> "but single words need not be quoted.", "", P.wrap alternate ] --- | Reinterprets `"` in the expected way, combining tokens until reaching --- the closing quote. +-- | Reinterprets `"` in the expected way, combining tokens until reaching +-- the closing quote. -- Example: `untokenize ["\"uno", "dos\""]` becomes `["uno dos"]`. untokenize :: [String] -> [String] untokenize words = go (unwords words) where - go words = case words of - [] -> [] - '"' : quoted -> takeWhile (/= '"') quoted : go (drop 1 . dropWhile (/= '"') $ quoted) - unquoted -> case span ok unquoted of - ("", rem) -> go (dropWhile isSpace rem) - (tok, rem) -> tok : go (dropWhile isSpace rem) - where - ok ch = ch /= '"' && not (isSpace ch) + go words = case words of + [] -> [] + '"' : quoted -> takeWhile (/= '"') quoted : go (drop 1 . dropWhile (/= '"') $ quoted) + unquoted -> case span ok unquoted of + ("", rem) -> go (dropWhile isSpace rem) + (tok, rem) -> tok : go (dropWhile isSpace rem) + where + ok ch = ch /= '"' && not (isSpace ch) sfind :: InputPattern sfind = @@ -2377,7 +2377,24 @@ edit = parse = maybe (wrongArgsLength "at least one argument" []) - ( fmap (Input.ShowDefinitionI Input.LatestFileLocation Input.ShowDefinitionLocal) + ( fmap (Input.ShowDefinitionI (Input.LatestFileLocation Input.WithinFold) Input.ShowDefinitionLocal) + . traverse handleHashQualifiedNameArg + ) + . NE.nonEmpty + } + +editNew :: InputPattern +editNew = + InputPattern + { patternName = "edit.new", + aliases = [], + visibility = I.Visible, + args = [("definition to edit", OnePlus, definitionQueryArg)], + help = "Like `edit`, but adds a new fold line below the definitions.", + parse = + maybe + (wrongArgsLength "at least one argument" []) + ( fmap (Input.ShowDefinitionI (Input.LatestFileLocation Input.AboveFold) Input.ShowDefinitionLocal) . traverse handleHashQualifiedNameArg ) . NE.nonEmpty @@ -3489,6 +3506,7 @@ validInputs = docsToHtml, edit, editNamespace, + editNew, execute, find, findIn, diff --git a/unison-cli/src/Unison/CommandLine/Main.hs b/unison-cli/src/Unison/CommandLine/Main.hs index cfefd666c0..64e070be74 100644 --- a/unison-cli/src/Unison/CommandLine/Main.hs +++ b/unison-cli/src/Unison/CommandLine/Main.hs @@ -208,12 +208,14 @@ main dir welcome ppIds initialInputs runtime sbRuntime nRuntime codebase serverB writeIORef pageOutput True pure x - let foldLine :: Text - foldLine = "\n\n---- Anything below this line is ignored by Unison.\n\n" - let writeSourceFile :: Text -> Text -> IO () - writeSourceFile fp contents = do + let writeSource :: Text -> Text -> Bool -> IO () + writeSource fp contents addFold = do path <- Directory.canonicalizePath (Text.unpack fp) - prependUtf8 path (contents <> foldLine) + prependUtf8 + path + if addFold + then contents <> "\n\n---- Anything below this line is ignored by Unison.\n\n" + else contents <> "\n\n" let env = Cli.Env @@ -221,7 +223,7 @@ main dir welcome ppIds initialInputs runtime sbRuntime nRuntime codebase serverB codebase, credentialManager, loadSource = loadSourceFile, - writeSource = writeSourceFile, + writeSource, generateUniqueName = Parser.uniqueBase32Namegen <$> Random.getSystemDRG, notify, notifyNumbered = \o -> diff --git a/unison-src/transcripts-round-trip/main.md b/unison-src/transcripts-round-trip/main.md index 26ddb2f9f1..fc9e320c04 100644 --- a/unison-src/transcripts-round-trip/main.md +++ b/unison-src/transcripts-round-trip/main.md @@ -22,7 +22,7 @@ scratch/a1> find So we can see the pretty-printed output: ``` ucm -scratch/a1> edit 1-1000 +scratch/a1> edit.new 1-1000 ``` ``` ucm :hide @@ -63,7 +63,7 @@ scratch/a3> find ``` ``` ucm -scratch/a3> edit 1-5000 +scratch/a3> edit.new 1-5000 ``` ``` ucm :hide @@ -82,12 +82,12 @@ scratch/main> diff.namespace /a3_new: /a3: ## Other regression tests not covered by above -### Builtins should appear commented out in the edit command +### Builtins should appear commented out in the edit.new command Regression test for https://github.com/unisonweb/unison/pull/3548 ``` ucm scratch/regressions> alias.term ##Nat.+ plus -scratch/regressions> edit plus +scratch/regressions> edit.new plus scratch/regressions> load ``` diff --git a/unison-src/transcripts-round-trip/main.output.md b/unison-src/transcripts-round-trip/main.output.md index acca30ca30..fce6d1cb66 100644 --- a/unison-src/transcripts-round-trip/main.output.md +++ b/unison-src/transcripts-round-trip/main.output.md @@ -20,7 +20,7 @@ x = () So we can see the pretty-printed output: ``` ucm -scratch/a1> edit 1-1000 +scratch/a1> edit.new 1-1000 ☝️ @@ -825,7 +825,7 @@ x = () ``` ``` ucm -scratch/a3> edit 1-5000 +scratch/a3> edit.new 1-5000 ☝️ @@ -871,7 +871,7 @@ scratch/main> diff.namespace /a3_new: /a3: ``` ## Other regression tests not covered by above -### Builtins should appear commented out in the edit command +### Builtins should appear commented out in the edit.new command Regression test for https://github.com/unisonweb/unison/pull/3548 @@ -880,7 +880,7 @@ scratch/regressions> alias.term ##Nat.+ plus Done. -scratch/regressions> edit plus +scratch/regressions> edit.new plus ☝️ diff --git a/unison-src/transcripts/edit-command.md b/unison-src/transcripts/edit-command.md index 756805737f..7e6b3ee9da 100644 --- a/unison-src/transcripts/edit-command.md +++ b/unison-src/transcripts/edit-command.md @@ -1,8 +1,8 @@ -``` ucm +``` ucm :hide scratch/main> builtins.merge ``` -``` unison /private/tmp/scratch.u +``` unison foo = 123 bar = 456 @@ -12,10 +12,53 @@ mytest = [Ok "ok"] ``` ucm scratch/main> add -scratch/main> edit foo bar -scratch/main> edit mytest +scratch/main> edit.new foo bar +scratch/main> edit.new mytest ``` ``` ucm :error -scratch/main> edit missing +scratch/main> edit.new missing +``` + +``` ucm :hide +scratch/main> project.delete scratch +``` + +# `edit` + +The `edit` command adds to the current fold, and takes care not to add definitions that are already in the file. + +``` ucm :hide +scratch/main> builtins.mergeio lib.builtin +``` + +This stanza does nothing for some reason (transcript runner bug?), so we repeat it twice. + +``` unison +foo = 17 +bar = 18 +baz = 19 +``` + +``` unison +foo = 17 +bar = 18 +baz = 19 +``` + +``` ucm +scratch/main> add +``` + +``` unison +foo = 17 +bar = 18 +``` + +``` ucm +scratch/main> edit bar baz +``` + +``` ucm :hide +scratch/main> project.delete scratch ``` diff --git a/unison-src/transcripts/edit-command.output.md b/unison-src/transcripts/edit-command.output.md index 1dfd0382d1..1f544d968d 100644 --- a/unison-src/transcripts/edit-command.output.md +++ b/unison-src/transcripts/edit-command.output.md @@ -1,28 +1,18 @@ -``` ucm -scratch/main> builtins.merge - - Done. - -``` ``` unison ---- -title: /private/tmp/scratch.u ---- foo = 123 bar = 456 mytest = [Ok "ok"] - ``` ``` ucm - Loading changes detected in /private/tmp/scratch.u. + Loading changes detected in scratch.u. - I found and typechecked these definitions in - /private/tmp/scratch.u. If you do an `add` or `update`, here's - how your codebase would change: + 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`: @@ -40,26 +30,26 @@ scratch/main> add foo : Nat mytest : [Result] -scratch/main> edit foo bar +scratch/main> edit.new foo bar ☝️ - I added 2 definitions to the top of /private/tmp/scratch.u + I added 2 definitions to the top of scratch.u You can edit them there, then run `update` to replace the definitions currently in this namespace. -scratch/main> edit mytest +scratch/main> edit.new mytest ☝️ - I added 1 definitions to the top of /private/tmp/scratch.u + I added 1 definitions to the top of scratch.u You can edit them there, then run `update` to replace the definitions currently in this namespace. ``` -``` unison :added-by-ucm /private/tmp/scratch.u +``` unison :added-by-ucm scratch.u bar : Nat bar = 456 @@ -67,12 +57,12 @@ foo : Nat foo = 123 ``` -``` unison :added-by-ucm /private/tmp/scratch.u +``` unison :added-by-ucm scratch.u test> mytest = [Ok "ok"] ``` ``` ucm -scratch/main> edit missing +scratch/main> edit.new missing ⚠️ @@ -80,3 +70,78 @@ scratch/main> edit missing missing ``` +# `edit` + +The `edit` command adds to the current fold, and takes care not to add definitions that are already in the file. + +This stanza does nothing for some reason (transcript runner bug?), so we repeat it twice. + +``` unison +foo = 17 +bar = 18 +baz = 19 +``` + +``` ucm + +``` +``` unison +foo = 17 +bar = 18 +baz = 19 +``` + +``` 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`: + + bar : Nat + baz : Nat + foo : Nat + +``` +``` ucm +scratch/main> add + + ⍟ I've added these definitions: + + bar : Nat + baz : Nat + foo : Nat + +``` +``` unison +foo = 17 +bar = 18 +``` + +``` ucm + + Loading changes detected in scratch.u. + + I found and typechecked the definitions in scratch.u. This + file has been previously added to the codebase. + +``` +``` ucm +scratch/main> edit bar baz + + ☝️ + + I added 1 definitions to the top of scratch.u + + You can edit them there, then run `update` to replace the + definitions currently in this namespace. + +``` +``` unison :added-by-ucm scratch.u +baz : Nat +baz = 19 +``` + diff --git a/unison-src/transcripts/fix-5374.md b/unison-src/transcripts/fix-5374.md index 689b8834ff..29c589edcd 100644 --- a/unison-src/transcripts/fix-5374.md +++ b/unison-src/transcripts/fix-5374.md @@ -12,5 +12,5 @@ thing = indirect.foo + indirect.foo ``` ucm scratch/main> add scratch/main> view thing -scratch/main> edit thing +scratch/main> edit.new thing ``` diff --git a/unison-src/transcripts/fix-5374.output.md b/unison-src/transcripts/fix-5374.output.md index 6d1561b10e..8f54d87312 100644 --- a/unison-src/transcripts/fix-5374.output.md +++ b/unison-src/transcripts/fix-5374.output.md @@ -43,7 +43,7 @@ scratch/main> view thing use indirect foo foo + foo -scratch/main> edit thing +scratch/main> edit.new thing ☝️ diff --git a/unison-src/transcripts/fix2826.md b/unison-src/transcripts/fix2826.md index bdbc788a85..758b45771f 100644 --- a/unison-src/transcripts/fix2826.md +++ b/unison-src/transcripts/fix2826.md @@ -18,6 +18,6 @@ And round-trips properly. ``` ucm scratch/main> add -scratch/main> edit doc +scratch/main> edit.new doc scratch/main> load scratch.u ``` diff --git a/unison-src/transcripts/fix2826.output.md b/unison-src/transcripts/fix2826.output.md index 932afef306..1effb6af14 100644 --- a/unison-src/transcripts/fix2826.output.md +++ b/unison-src/transcripts/fix2826.output.md @@ -38,7 +38,7 @@ scratch/main> add doc : Doc2 -scratch/main> edit doc +scratch/main> edit.new doc ☝️ diff --git a/unison-src/transcripts/fix3977.md b/unison-src/transcripts/fix3977.md index 0e324b3977..652d5d35c1 100644 --- a/unison-src/transcripts/fix3977.md +++ b/unison-src/transcripts/fix3977.md @@ -12,6 +12,6 @@ foo = Left (failure ("a loooooooooooooooooooooooooooooooooong" ++ "message with ``` ucm scratch/main> add -scratch/main> edit foo +scratch/main> edit.new foo scratch/main> load scratch.u ``` diff --git a/unison-src/transcripts/fix3977.output.md b/unison-src/transcripts/fix3977.output.md index f5498f2645..7deb2c7142 100644 --- a/unison-src/transcripts/fix3977.output.md +++ b/unison-src/transcripts/fix3977.output.md @@ -14,7 +14,7 @@ scratch/main> add failure : Text -> context -> Failure foo : Either Failure b -scratch/main> edit foo +scratch/main> edit.new foo ☝️ diff --git a/unison-src/transcripts/fix4711.md b/unison-src/transcripts/fix4711.md index 5087b4802a..9789f5e272 100644 --- a/unison-src/transcripts/fix4711.md +++ b/unison-src/transcripts/fix4711.md @@ -14,6 +14,6 @@ Since this is fixed, `thisDoesNotWork` now does work. ``` ucm scratch/main> add -scratch/main> edit thisWorks thisDoesNotWork +scratch/main> edit.new thisWorks thisDoesNotWork scratch/main> load ``` diff --git a/unison-src/transcripts/fix4711.output.md b/unison-src/transcripts/fix4711.output.md index 0bd5785547..93b8eebf54 100644 --- a/unison-src/transcripts/fix4711.output.md +++ b/unison-src/transcripts/fix4711.output.md @@ -30,7 +30,7 @@ scratch/main> add thisDoesNotWork : ['{g} Int] thisWorks : 'Int -scratch/main> edit thisWorks thisDoesNotWork +scratch/main> edit.new thisWorks thisDoesNotWork ☝️ diff --git a/unison-src/transcripts/help.output.md b/unison-src/transcripts/help.output.md index deabd7ca56..510fe617cc 100644 --- a/unison-src/transcripts/help.output.md +++ b/unison-src/transcripts/help.output.md @@ -282,6 +282,9 @@ scratch/main> help `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. + edit.new + Like `edit`, but adds a new fold line below the definitions. + find `find` lists all definitions in the current namespace.