Merge remote-tracking branch 'upstream/trunk' into doc-lexer

This commit is contained in:
Greg Pfeil 2024-08-01 23:01:02 -06:00
commit 1ee188d0e3
No known key found for this signature in database
GPG Key ID: 1193ACD196ED61F2
31 changed files with 439 additions and 304 deletions

View File

@ -42,7 +42,7 @@ Some tests are executables instead:
* `stack exec transcripts` runs the transcripts-related integration tests, found in `unison-src/transcripts`. You can add more tests to this directory.
* `stack exec transcripts -- prefix-of-filename` runs only transcript tests with a matching filename prefix.
* `stack exec integration-tests` runs the additional integration tests for cli. These tests are not triggered by `tests` or `transcripts`.
* `stack exec cli-integration-tests` runs the additional integration tests for cli. These tests are not triggered by `tests` or `transcripts`.
* `stack exec unison -- transcript unison-src/transcripts-round-trip/main.md` runs the pretty-printing round trip tests
* `stack exec unison -- transcript unison-src/transcripts-manual/benchmarks.md` runs the benchmark suite. Output goes in unison-src/transcripts-manual/benchmarks/output.txt.
@ -220,3 +220,7 @@ nix develop '.#cabal-unison-parser-typechecker'
cd unison-cli
cabal run --enable-profiling unison-cli-main:exe:unison -- +RTS -p
```
## Native compilation
See the [readme](scheme-libs/racket/unison/Readme.md).

View File

@ -35,6 +35,7 @@ module Unison.PatternMatchCoverage
)
where
import Data.List.NonEmpty (nonEmpty)
import Data.Set qualified as Set
import Debug.Trace
import Unison.Debug
@ -53,24 +54,25 @@ import Unison.Util.Pretty qualified as P
checkMatch ::
forall vt v loc m.
(Pmc vt v loc m) =>
-- | the match location
loc ->
-- | scrutinee type
Type.Type vt loc ->
-- | match cases
[Term.MatchCase loc (Term.Term' vt v loc)] ->
-- | (redundant locations, inaccessible locations, inhabitants of uncovered refinement type)
m ([loc], [loc], [Pattern ()])
checkMatch matchLocation scrutineeType cases = do
checkMatch scrutineeType cases = do
ppe <- getPrettyPrintEnv
v0 <- fresh
grdtree0 <- desugarMatch matchLocation scrutineeType v0 cases
doDebug (P.hang (title "desugared:") (prettyGrdTree (prettyPmGrd ppe) (\_ -> "<loc>") grdtree0)) (pure ())
(uncovered, grdtree1) <- uncoverAnnotate (Set.singleton (NC.markDirty v0 $ NC.declVar v0 scrutineeType id NC.emptyNormalizedConstraints)) grdtree0
mgrdtree0 <- traverse (desugarMatch scrutineeType v0) (nonEmpty cases)
doDebug (P.hang (title "desugared:") (prettyGrdTreeMaybe (prettyPmGrd ppe) (\_ -> "<loc>") mgrdtree0)) (pure ())
let initialUncovered = Set.singleton (NC.markDirty v0 $ NC.declVar v0 scrutineeType id NC.emptyNormalizedConstraints)
(uncovered, grdtree1) <- case mgrdtree0 of
Nothing -> pure (initialUncovered, Nothing)
Just grdtree0 -> fmap Just <$> uncoverAnnotate initialUncovered grdtree0
doDebug
( P.sep
"\n"
[ P.hang (title "annotated:") (prettyGrdTree (NC.prettyDnf ppe) (NC.prettyDnf ppe . fst) grdtree1),
[ P.hang (title "annotated:") (prettyGrdTreeMaybe (NC.prettyDnf ppe) (NC.prettyDnf ppe . fst) grdtree1),
P.hang (title "uncovered:") (NC.prettyDnf ppe uncovered)
]
)
@ -78,9 +80,14 @@ checkMatch matchLocation scrutineeType cases = do
uncoveredExpanded <- concat . fmap Set.toList <$> traverse (expandSolution v0) (Set.toList uncovered)
doDebug (P.hang (title "uncovered expanded:") (NC.prettyDnf ppe (Set.fromList uncoveredExpanded))) (pure ())
let sols = map (generateInhabitants v0) uncoveredExpanded
let (_accessible, inaccessible, redundant) = classify grdtree1
let (_accessible, inaccessible, redundant) = case grdtree1 of
Nothing -> ([], [], [])
Just x -> classify x
pure (redundant, inaccessible, sols)
where
prettyGrdTreeMaybe prettyNode prettyLeaf = \case
Nothing -> "<empty>"
Just x -> prettyGrdTree prettyNode prettyLeaf x
title = P.bold
doDebug out = case shouldDebug PatternCoverage of
True -> trace (P.toAnsiUnbroken out)

View File

@ -20,19 +20,14 @@ import Unison.Type qualified as Type
desugarMatch ::
forall loc vt v m.
(Pmc vt v loc m) =>
-- | loc of match
loc ->
-- | scrutinee type
Type vt loc ->
-- | scrutinee variable
v ->
-- | match cases
[MatchCase loc (Term' vt v loc)] ->
NonEmpty (MatchCase loc (Term' vt v loc)) ->
m (GrdTree (PmGrd vt v loc) loc)
desugarMatch loc0 scrutineeType v0 cs0 =
traverse desugarClause cs0 >>= \case
[] -> pure $ Leaf loc0
x : xs -> pure $ Fork (x :| xs)
desugarMatch scrutineeType v0 cs0 = Fork <$> traverse desugarClause cs0
where
desugarClause :: MatchCase loc (Term' vt v loc) -> m (GrdTree (PmGrd vt v loc) loc)
desugarClause MatchCase {matchPattern, matchGuard} =

View File

@ -1525,7 +1525,7 @@ ensurePatternCoverage theMatch _theMatchType _scrutinee scrutineeType cases = do
constructorCache = mempty
}
(redundant, _inaccessible, uncovered) <- flip evalStateT pmcState do
checkMatch matchLoc scrutineeType cases
checkMatch scrutineeType cases
let checkUncovered = case Nel.nonEmpty uncovered of
Nothing -> pure ()
Just xs -> failWith (UncoveredPatterns matchLoc xs)

6
scheme-libs/racket/unison/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
compiled/
boot-generated.ss
builtin-generated.ss
compound-wrappers.ss
data-info.ss
simple-wrappers.ss

View File

@ -1,5 +1,18 @@
This directory contains libraries necessary for building and running
unison programs via Racket Scheme.
unison programs via Racket Scheme. The rough steps are as follows:
* Build Racket libraries from the current Unison version.
* Build the `unison-runtime` binary.
* Pass the path to `unison-runtime` to `ucm`.
Native compilation is done via the `compile.native` `ucm` command.
Under-the-hood, Unison does the following:
* Convert the function to bytecode (similar to how `compile` command works).
* Call `unison-runtime` which will convert the bytecode to a temporary Racket
file. The Racket file is usually placed in your `.cache/unisonlanguage`.
* folder. Call `raco exe file.rkt -o executable` which will create a native
executable from the Racket source code.
## Prerequisites
@ -9,20 +22,56 @@ You'll need to have a couple things installed on your system:
* [Racket](https://racket-lang.org/), with the executable `racket` on your path somewhere
* [BLAKE2](https://github.com/BLAKE2/libb2) (you may need to install this manually)
In particular, our crypto functions require on both `libcrypto` (from openssl) and `libb2`. You may have to tell racket where to find `libb2`, by adding an entry to the hash table in your [`config.rktd` file](https://docs.racket-lang.org/raco/config-file.html). This is what I had, for an M1 mac w/ libb2 installed via Homebrew:
In particular, our crypto functions require both `libcrypto` (from openssl or
eg. libressl) and `libb2`. You may have to tell racket where to find `libb2`, by
adding an entry to the hash table in your
[`config.rktd` file](https://docs.racket-lang.org/raco/config-file.html).
This is what I had, for an M1 mac with `libb2` installed via Homebrew:
```
(lib-search-dirs . (#f "/opt/homebrew/Cellar/libb2/0.98.1/lib/"))
$ cat scheme-libs/racket/config/config.rktd
#hash(
(lib-search-dirs . (#f "/opt/homebrew/Cellar/libb2/0.98.1/lib/"))
)
```
You'll also need to install `x509-lib` with `raco pkg install x509-lib`
Finally, some distributions only package `racket-minimal`. You'll need to
install the full compiler suite using `raco pkg install compiler-lib`
([source](https://www.dbrunner.de/blog/2016/01/12/using-racket-minimal-and-raco/))
## Building
First, make sure unison is built (see [development](../../../development.markdown))
Next, use unison to generate the racket libraries. These are dependencies for
building `unison-runtime`.
* Read [gen-racket-libs.md](../../../unison-src/transcripts-manual/gen-racket-libs.md).
It will contain two things:
* `ucm` and `unison` transcripts that generate the libraries
* Instructions on how to build `unison-runtime` using `raco`
If everything went well you should now have a new executable in `scheme-libs/racket/unison-runtime`.
For example:
```
$ file scheme-libs/racket/unison-runtime
scheme-libs/racket/unison-runtime: Mach-O 64-bit executable arm64
```
## Running the unison test suite
To run the test suite, first `stack build` (or `stack build --fast`), then:
Note that if you set up `config.rktd` above, you'll need to pass the path to its
folder in `PLTCONFIGDIR` before invoking unison or the test scripts:
```
./unison-src/builtin-tests/jit-tests.sh $(stack exec which unison) --runtime-path <path>
export PLTCONFIGDIR=$(pwd)/scheme-libs/racket/config
```
If you don't, some of the tests will fail with eg `ffi-lib: could not load foreign library`.
To run the test suite you can do:
```
./unison-src/builtin-tests/jit-tests.sh $(stack exec which unison) --runtime-path scheme-libs/racket/unison-runtime
```
OR if you want to run the same tests in interpreted mode:
@ -31,7 +80,9 @@ OR if you want to run the same tests in interpreted mode:
./unison-src/builtin-tests/interpreter-tests.sh
```
The above scripts fetch and cache a copy of base and the scheme-generating libraries, and copy this directory to `$XDG_DATA_DIRECTORY/unisonlanguage/scheme-libs`.
The above scripts fetch and cache a copy of base and the scheme-generating
libraries, and copy this directory to `$XDG_DATA_DIRECTORY/unisonlanguage/scheme-libs`.
Both scripts _should_ pass.
## Iterating more quickly

View File

@ -63,6 +63,7 @@ import Unison.Codebase.Editor.HandleInput.DeleteProject (handleDeleteProject)
import Unison.Codebase.Editor.HandleInput.EditNamespace (handleEditNamespace)
import Unison.Codebase.Editor.HandleInput.FindAndReplace (handleStructuredFindI, handleStructuredFindReplaceI)
import Unison.Codebase.Editor.HandleInput.FormatFile qualified as Format
import Unison.Codebase.Editor.HandleInput.Global qualified as Global
import Unison.Codebase.Editor.HandleInput.InstallLib (handleInstallLib)
import Unison.Codebase.Editor.HandleInput.LSPDebug qualified as LSPDebug
import Unison.Codebase.Editor.HandleInput.Load (EvalMode (Sandboxed), evalUnisonFile, handleLoad, loadUnisonFile)
@ -496,23 +497,27 @@ loop e = do
fixupOutput = HQ'.toHQ . Path.nameFromHQSplit
NamesI global query -> do
hqLength <- Cli.runTransaction Codebase.hashLength
(names, pped) <-
if global
then do
error "TODO: Implement names.global."
else do
names <- Cli.currentNames
let searchNames names = do
pped <- Cli.prettyPrintEnvDeclFromNames names
pure (names, pped)
let unsuffixifiedPPE = PPED.unsuffixifiedPPE pped
terms = Names.lookupHQTerm Names.IncludeSuffixes query names
types = Names.lookupHQType Names.IncludeSuffixes query names
terms' :: [(Referent, [HQ'.HashQualified Name])]
terms' = map (\r -> (r, PPE.allTermNames unsuffixifiedPPE r)) (Set.toList terms)
types' :: [(Reference, [HQ'.HashQualified Name])]
types' = map (\r -> (r, PPE.allTypeNames unsuffixifiedPPE r)) (Set.toList types)
Cli.respond $ ListNames global hqLength types' terms'
let unsuffixifiedPPE = PPED.unsuffixifiedPPE pped
terms = Names.lookupHQTerm Names.IncludeSuffixes query names
types = Names.lookupHQType Names.IncludeSuffixes query names
terms' :: [(Referent, [HQ'.HashQualified Name])]
terms' = map (\r -> (r, PPE.allTermNames unsuffixifiedPPE r)) (Set.toList terms)
types' :: [(Reference, [HQ'.HashQualified Name])]
types' = map (\r -> (r, PPE.allTypeNames unsuffixifiedPPE r)) (Set.toList types)
pure (terms', types')
if global
then do
Global.forAllProjectBranches \(projBranchNames, _ids) branch -> do
let names = Branch.toNames . Branch.head $ branch
(terms, types) <- searchNames names
when (not (null terms) || not (null types)) do
Cli.respond $ GlobalListNames projBranchNames hqLength types terms
else do
names <- Cli.currentNames
(terms, types) <- searchNames names
Cli.respond $ ListNames hqLength types terms
DocsI srcs -> do
for_ srcs docsI
CreateAuthorI authorNameSegment authorFullName -> do
@ -1088,7 +1093,7 @@ handleFindI ::
Cli ()
handleFindI isVerbose fscope ws input = do
Cli.Env {codebase} <- ask
(pped, names, searchRoot, branch0) <- case fscope of
case fscope of
FindLocal p -> do
searchRoot <- Cli.resolvePath' p
branch0 <- Cli.getBranch0FromProjectPath searchRoot
@ -1096,7 +1101,21 @@ handleFindI isVerbose fscope ws input = do
-- Don't exclude anything from the pretty printer, since the type signatures we print for
-- results may contain things in lib.
pped <- Cli.currentPrettyPrintEnvDecl
pure (pped, names, Just p, branch0)
let suffixifiedPPE = PPED.suffixifiedPPE pped
results <- searchBranch0 codebase branch0 names
if (null results)
then do
Cli.respond FindNoLocalMatches
-- We've already searched everything else, so now we search JUST the
-- names in lib.
let mayOnlyLibBranch = branch0 & Branch.children %%~ \cs -> Map.singleton NameSegment.libSegment <$> Map.lookup NameSegment.libSegment cs
case mayOnlyLibBranch of
Nothing -> respondResults codebase suffixifiedPPE (Just p) []
Just onlyLibBranch -> do
let onlyLibNames = Branch.toNames onlyLibBranch
results <- searchBranch0 codebase branch0 onlyLibNames
respondResults codebase suffixifiedPPE (Just p) results
else respondResults codebase suffixifiedPPE (Just p) results
FindLocalAndDeps p -> do
searchRoot <- Cli.resolvePath' p
branch0 <- Cli.getBranch0FromProjectPath searchRoot
@ -1104,64 +1123,57 @@ handleFindI isVerbose fscope ws input = do
-- Don't exclude anything from the pretty printer, since the type signatures we print for
-- results may contain things in lib.
pped <- Cli.currentPrettyPrintEnvDecl
pure (pped, names, Just p, branch0)
let suffixifiedPPE = PPED.suffixifiedPPE pped
results <- searchBranch0 codebase branch0 names
respondResults codebase suffixifiedPPE (Just p) results
FindGlobal -> do
-- TODO: Rewrite to be properly global again
projectRootNames <- Names.makeAbsolute . Branch.toNames <$> Cli.getCurrentProjectRoot0
pped <- Cli.prettyPrintEnvDeclFromNames projectRootNames
currentBranch0 <- Cli.getCurrentBranch0
pure (pped, projectRootNames, Nothing, currentBranch0)
let suffixifiedPPE = PPED.suffixifiedPPE pped
let getResults :: Names -> Cli [SearchResult]
getResults names =
case ws of
[] -> pure (List.sortBy SR.compareByName (SR.fromNames names))
-- type query
":" : ws -> do
typ <- parseSearchType (show input) (unwords ws)
let keepNamed = Set.intersection (Branch.deepReferents branch0)
(noExactTypeMatches, matches) <- do
Cli.runTransaction do
matches <- keepNamed <$> Codebase.termsOfType codebase typ
if null matches
then (True,) . keepNamed <$> Codebase.termsMentioningType codebase typ
else pure (False, matches)
when noExactTypeMatches (Cli.respond NoExactTypeMatches)
pure $
-- in verbose mode, aliases are shown, so we collapse all
-- aliases to a single search result; in non-verbose mode,
-- a separate result may be shown for each alias
(if isVerbose then uniqueBy SR.toReferent else id) $
searchResultsFor names (Set.toList matches) []
Global.forAllProjectBranches \(projAndBranchNames, _ids) branch -> do
let branch0 = Branch.head branch
let projectRootNames = Names.makeAbsolute . Branch.toNames $ branch0
pped <- Cli.prettyPrintEnvDeclFromNames projectRootNames
results <- searchBranch0 codebase branch0 projectRootNames
when (not $ null results) do
Cli.setNumberedArgs $ fmap (SA.SearchResult Nothing) results
results' <- Cli.runTransaction (Backend.loadSearchResults codebase results)
Cli.respond $ GlobalFindBranchResults projAndBranchNames (PPED.suffixifiedPPE pped) isVerbose results'
where
searchBranch0 :: Codebase.Codebase m Symbol Ann -> Branch0 IO -> Names -> Cli [SearchResult]
searchBranch0 codebase branch0 names =
case ws of
[] -> pure (List.sortBy SR.compareByName (SR.fromNames names))
-- type query
":" : ws -> do
typ <- parseSearchType (show input) (unwords ws)
let keepNamed = Set.intersection (Branch.deepReferents branch0)
(noExactTypeMatches, matches) <- do
Cli.runTransaction do
matches <- keepNamed <$> Codebase.termsOfType codebase typ
if null matches
then (True,) . keepNamed <$> Codebase.termsMentioningType codebase typ
else pure (False, matches)
when noExactTypeMatches (Cli.respond NoExactTypeMatches)
pure $
-- in verbose mode, aliases are shown, so we collapse all
-- aliases to a single search result; in non-verbose mode,
-- a separate result may be shown for each alias
(if isVerbose then uniqueBy SR.toReferent else id) $
searchResultsFor names (Set.toList matches) []
-- name query
qs -> do
let anythingBeforeHash :: Megaparsec.Parsec (L.Token Text) [Char] Text
anythingBeforeHash = Text.pack <$> Megaparsec.takeWhileP Nothing (/= '#')
let srs =
searchBranchScored
names
Find.simpleFuzzyScore
(mapMaybe (HQ.parseTextWith anythingBeforeHash . Text.pack) qs)
pure $ uniqueBy SR.toReferent srs
let respondResults results = do
Cli.setNumberedArgs $ fmap (SA.SearchResult searchRoot) results
results' <- Cli.runTransaction (Backend.loadSearchResults codebase results)
Cli.respond $ ListOfDefinitions fscope suffixifiedPPE isVerbose results'
results <- getResults names
case (results, fscope) of
([], FindLocal {}) -> do
Cli.respond FindNoLocalMatches
-- We've already searched everything else, so now we search JUST the
-- names in lib.
let mayOnlyLibBranch = branch0 & Branch.children %%~ \cs -> Map.singleton NameSegment.libSegment <$> Map.lookup NameSegment.libSegment cs
case mayOnlyLibBranch of
Nothing -> respondResults []
Just onlyLibBranch -> do
let onlyLibNames = Branch.toNames onlyLibBranch
results <- getResults onlyLibNames
respondResults results
_ -> respondResults results
-- name query
qs -> do
let anythingBeforeHash :: Megaparsec.Parsec (L.Token Text) [Char] Text
anythingBeforeHash = Text.pack <$> Megaparsec.takeWhileP Nothing (/= '#')
let srs =
searchBranchScored
names
Find.simpleFuzzyScore
(mapMaybe (HQ.parseTextWith anythingBeforeHash . Text.pack) qs)
pure $ uniqueBy SR.toReferent srs
respondResults :: Codebase.Codebase m Symbol Ann -> PPE.PrettyPrintEnv -> Maybe Path' -> [SearchResult] -> Cli ()
respondResults codebase ppe searchRoot results = do
Cli.setNumberedArgs $ fmap (SA.SearchResult searchRoot) results
results' <- Cli.runTransaction (Backend.loadSearchResults codebase results)
Cli.respond $ ListOfDefinitions fscope ppe isVerbose results'
handleDependencies :: HQ.HashQualified Name -> Cli ()
handleDependencies hq = do

View File

@ -0,0 +1,22 @@
module Unison.Codebase.Editor.HandleInput.Global (forAllProjectBranches) where
import Control.Monad.Reader
import U.Codebase.Sqlite.DbId (ProjectBranchId, ProjectId)
import U.Codebase.Sqlite.Queries qualified as Q
import Unison.Cli.Monad (Cli)
import Unison.Cli.Monad qualified as Cli
import Unison.Codebase qualified as Codebase
import Unison.Codebase.Branch (Branch)
import Unison.Core.Project
import Unison.Prelude
import Unison.Util.Monoid (foldMapM)
-- | Map over ALL project branches in the codebase.
-- This is a _very_ big hammer, that you should basically never use, except for things like debugging or migrations.
forAllProjectBranches :: (Monoid r) => ((ProjectAndBranch ProjectName ProjectBranchName, ProjectAndBranch ProjectId ProjectBranchId) -> Branch IO -> Cli r) -> Cli r
forAllProjectBranches f = do
Cli.Env {codebase} <- ask
projectBranches <- Cli.runTransaction Q.loadAllProjectBranchNamePairs
projectBranches & foldMapM \(names, ids@(ProjectAndBranch projId branchId)) -> do
b <- liftIO $ Codebase.expectProjectBranchRoot codebase projId branchId
f (names, ids) b

View File

@ -127,8 +127,8 @@ data Input
| 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?
| -- used in Welcome module to give directions to user
| -- 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.
SwitchBranchI Path'

View File

@ -261,7 +261,11 @@ data Output
| MovedOverExistingBranch Path'
| DeletedEverything
| ListNames
IsGlobal
Int -- hq length to print References
[(Reference, [HQ'.HashQualified Name])] -- type match, type names
[(Referent, [HQ'.HashQualified Name])] -- term match, term names
| GlobalListNames
(ProjectAndBranch ProjectName ProjectBranchName)
Int -- hq length to print References
[(Reference, [HQ'.HashQualified Name])] -- type match, type names
[(Referent, [HQ'.HashQualified Name])] -- term match, term names
@ -269,6 +273,7 @@ data Output
| ListOfDefinitions FindScope PPE.PrettyPrintEnv ListDetailed [SearchResult' Symbol Ann]
| ListShallow (IO PPE.PrettyPrintEnv) [ShallowListEntry Symbol Ann]
| ListStructuredFind [HQ.HashQualified Name]
| GlobalFindBranchResults (ProjectAndBranch ProjectName ProjectBranchName) PPE.PrettyPrintEnv ListDetailed [SearchResult' Symbol Ann]
| -- ListStructuredFind patternMatchingUsages termBodyUsages
-- show the result of add/update
SlurpOutput Input PPE.PrettyPrintEnv SlurpResult
@ -543,8 +548,10 @@ isFailure o = case o of
MoveRootBranchConfirmation -> False
MovedOverExistingBranch {} -> False
DeletedEverything -> False
ListNames _ _ tys tms -> null tms && null tys
ListNames _ tys tms -> null tms && null tys
GlobalListNames {} -> False
ListOfDefinitions _ _ _ ds -> null ds
GlobalFindBranchResults _ _ _ _ -> False
ListStructuredFind tms -> null tms
SlurpOutput _ _ sr -> not $ SR.isOk sr
ParseErrors {} -> True

View File

@ -24,11 +24,10 @@ where
import CMark qualified
import Data.Char qualified as Char
import Data.Text qualified as Text
import Data.These (These (..))
import Text.Megaparsec qualified as P
import Unison.Codebase.Transcript
import Unison.Prelude
import Unison.Project (ProjectAndBranch (ProjectAndBranch))
import Unison.Project (fullyQualifiedProjectAndBranchNamesParser)
formatAPIRequest :: APIRequest -> Text
formatAPIRequest = \case
@ -72,24 +71,16 @@ ucmLine :: P UcmLine
ucmLine = ucmCommand <|> ucmComment
where
ucmCommand :: P UcmLine
ucmCommand = do
context <-
P.try do
contextString <- P.takeWhile1P Nothing (/= '>')
context <-
case (tryFrom @Text contextString) of
(Right (These project branch)) -> pure (UcmContextProject (ProjectAndBranch project branch))
_ -> fail "expected project/branch or absolute path"
void $ lineToken $ word ">"
pure context
line <- P.takeWhileP Nothing (/= '\n') <* spaces
pure $ UcmCommand context line
ucmCommand =
UcmCommand
<$> fmap UcmContextProject (P.try $ fullyQualifiedProjectAndBranchNamesParser <* lineToken (word ">"))
<*> P.takeWhileP Nothing (/= '\n')
<* spaces
ucmComment :: P UcmLine
ucmComment = do
word "--"
line <- P.takeWhileP Nothing (/= '\n') <* spaces
pure $ UcmComment line
ucmComment =
P.label "comment (delimited with “--”)" $
UcmComment <$> (word "--" *> P.takeWhileP Nothing (/= '\n')) <* spaces
apiRequest :: P APIRequest
apiRequest = do
@ -118,7 +109,7 @@ fenced info = do
hide <- hidden
err <- expectingError
P.setInput body
pure . Ucm hide err <$> (spaces *> many ucmLine)
pure . Ucm hide err <$> (spaces *> P.manyTill ucmLine P.eof)
"unison" ->
do
-- todo: this has to be more interesting
@ -132,7 +123,7 @@ fenced info = do
pure . Unison hide err fileName <$> (spaces *> P.getInput)
"api" -> do
P.setInput body
pure . API <$> (spaces *> many apiRequest)
pure . API <$> (spaces *> P.manyTill apiRequest P.eof)
_ -> pure Nothing
word :: Text -> P Text

View File

@ -1149,7 +1149,7 @@ findAll :: InputPattern
findAll = find' "find.all" (Input.FindLocalAndDeps Path.relativeEmpty')
findGlobal :: InputPattern
findGlobal = find' "find.global" Input.FindGlobal
findGlobal = find' "debug.find.global" Input.FindGlobal
findIn, findInAll :: InputPattern
findIn = findIn' "find-in" Input.FindLocal
@ -1197,8 +1197,8 @@ findHelp =
"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"
( "debug.find.global foo",
"Iteratively searches all projects and branches and lists all definitions with a name similar to 'foo'. Note that this is a very slow operation."
)
]
)
@ -2611,12 +2611,15 @@ names isGlobal =
[]
I.Visible
[("name or hash", Required, definitionQueryArg)]
(P.wrap $ makeExample (names isGlobal) ["foo"] <> " shows the hash and all known names for `foo`.")
(P.wrap $ makeExample (names isGlobal) ["foo"] <> description)
$ \case
[thing] -> Input.NamesI isGlobal <$> handleHashQualifiedNameArg thing
args -> wrongArgsLength "exactly one argument" args
where
cmdName = if isGlobal then "names.global" else "names"
description
| isGlobal = "Iteratively search across all projects and branches for names matching `foo`. Note that this is expected to be quite slow and is primarily for debugging issues with your codebase."
| otherwise = "List all known names for `foo` in the current branch."
cmdName = if isGlobal then "debug.names.global" else "names"
dependents, dependencies :: InputPattern
dependents =
@ -3456,7 +3459,7 @@ validInputs =
mergeInputPattern,
mergeCommitInputPattern,
names False, -- names
names True, -- names.global
names True, -- debug.names.global
namespaceDependencies,
previewAdd,
previewUpdate,

View File

@ -855,49 +855,24 @@ notifyUser dir = \case
]
ListOfDefinitions fscope ppe detailed results ->
listOfDefinitions fscope ppe detailed results
ListNames global len types terms ->
if null types && null terms
then
pure . P.callout "😶" $
P.sepNonEmpty "\n\n" $
[ P.wrap "I couldn't find anything by that name.",
globalTip
]
else
pure . P.sepNonEmpty "\n\n" $
[ formatTypes types,
formatTerms terms,
globalTip
]
where
globalTip =
if global
then mempty
else (tip $ "Use " <> IP.makeExample (IP.names True) [] <> " to see more results.")
formatTerms tms =
P.lines . P.nonEmpty $ P.plural tms (P.blue "Term") : List.intersperse "" (go <$> tms)
where
go (ref, hqs) =
P.column2
[ ("Hash:", P.syntaxToColor (prettyReferent len ref)),
( "Names: ",
P.group $
P.spaced $
P.bold . P.syntaxToColor . prettyHashQualified' <$> List.sortBy Name.compareAlphabetical hqs
)
]
formatTypes types =
P.lines . P.nonEmpty $ P.plural types (P.blue "Type") : List.intersperse "" (go <$> types)
where
go (ref, hqs) =
P.column2
[ ("Hash:", P.syntaxToColor (prettyReference len ref)),
( "Names:",
P.group $
P.spaced $
P.bold . P.syntaxToColor . prettyHashQualified' <$> List.sortBy Name.compareAlphabetical hqs
)
]
GlobalFindBranchResults projBranchName ppe detailed results -> do
output <- listOfDefinitions Input.FindGlobal ppe detailed results
pure $
P.lines
[ P.wrap $ "Found results in " <> P.text (into @Text projBranchName),
"",
output
]
ListNames len types terms ->
listOfNames len types terms
GlobalListNames projectBranchName len types terms -> do
output <- listOfNames len types terms
pure $
P.lines
[ P.wrap $ "Found results in " <> P.text (into @Text projectBranchName),
"",
output
]
-- > names foo
-- Terms:
-- Hash: #asdflkjasdflkjasdf
@ -2816,6 +2791,45 @@ listOfDefinitions ::
listOfDefinitions fscope ppe detailed results =
pure $ listOfDefinitions' fscope ppe detailed results
listOfNames :: Int -> [(Reference, [HQ'.HashQualified Name])] -> [(Referent, [HQ'.HashQualified Name])] -> IO Pretty
listOfNames len types terms = do
if null types && null terms
then
pure . P.callout "😶" $
P.sepNonEmpty "\n\n" $
[ P.wrap "I couldn't find anything by that name."
]
else
pure . P.sepNonEmpty "\n\n" $
[ formatTypes types,
formatTerms terms
]
where
formatTerms tms =
P.lines . P.nonEmpty $ P.plural tms (P.blue "Term") : List.intersperse "" (go <$> tms)
where
go (ref, hqs) =
P.column2
[ ("Hash:", P.syntaxToColor (prettyReferent len ref)),
( "Names: ",
P.group $
P.spaced $
P.bold . P.syntaxToColor . prettyHashQualified' <$> List.sortBy Name.compareAlphabetical hqs
)
]
formatTypes types =
P.lines . P.nonEmpty $ P.plural types (P.blue "Type") : List.intersperse "" (go <$> types)
where
go (ref, hqs) =
P.column2
[ ("Hash:", P.syntaxToColor (prettyReference len ref)),
( "Names:",
P.group $
P.spaced $
P.bold . P.syntaxToColor . prettyHashQualified' <$> List.sortBy Name.compareAlphabetical hqs
)
]
data ShowNumbers = ShowNumbers | HideNumbers
-- | `ppe` is just for rendering type signatures

View File

@ -64,6 +64,7 @@ library
Unison.Codebase.Editor.HandleInput.EditNamespace
Unison.Codebase.Editor.HandleInput.FindAndReplace
Unison.Codebase.Editor.HandleInput.FormatFile
Unison.Codebase.Editor.HandleInput.Global
Unison.Codebase.Editor.HandleInput.InstallLib
Unison.Codebase.Editor.HandleInput.Load
Unison.Codebase.Editor.HandleInput.Ls

View File

@ -155,6 +155,15 @@ instance (ToJSON b, ToJSON a) => ToJSON (DisplayObject b a) where
MissingObject sh -> object ["tag" Aeson..= String "MissingObject", "contents" Aeson..= sh]
UserObject a -> object ["tag" Aeson..= String "UserObject", "contents" Aeson..= a]
instance (FromJSON a, FromJSON b) => FromJSON (DisplayObject b a) where
parseJSON = withObject "DisplayObject" \o -> do
tag <- o .: "tag"
case tag of
"BuiltinObject" -> BuiltinObject <$> o .: "contents"
"MissingObject" -> MissingObject <$> o .: "contents"
"UserObject" -> UserObject <$> o .: "contents"
_ -> fail $ "Invalid tag: " <> Text.unpack tag
deriving instance (ToSchema b, ToSchema a) => ToSchema (DisplayObject b a)
-- [21/10/07] Hello, this is Mitchell. Name refactor in progress. Changing internal representation from a flat text to a

View File

@ -20,12 +20,11 @@ complement of unison libraries for a given combination of ucm version
and @unison/internal version.
To set up racket to use these files, we need to create a package with
them. This is accomplished by running.
them. This is accomplished by running:
raco pkg install -t dir unison
raco pkg install -t dir scheme-libs/racket/unison
in the directory where the `unison` directory is located. Then the
runtime executable can be built with
After, the runtime executable can be built with
raco exe scheme-libs/racket/unison-runtime.rkt

View File

@ -1,22 +1,21 @@
When we start out, `./scheme-libs/racket` contains a bunch of library files that we'll need. They define the Unison builtins for Racket.
Next, we'll download the jit project and generate a few Racket files from it.
```ucm
``` ucm
jit-setup/main> lib.install @unison/internal/releases/0.0.18
Downloaded 14917 entities.
Downloaded 14949 entities.
I installed @unison/internal/releases/0.0.18 as
unison_internal_0_0_18.
```
```unison
``` unison
go = generateSchemeBoot "scheme-libs/racket"
```
```ucm
``` ucm
Loading changes detected in scratch.u.
@ -29,7 +28,7 @@ go = generateSchemeBoot "scheme-libs/racket"
go : '{IO, Exception} ()
```
```ucm
``` ucm
jit-setup/main> run go
()
@ -42,16 +41,23 @@ and @unison/internal version.
To set up racket to use these files, we need to create a package with
them. This is accomplished by running.
raco pkg install -t dir unison
```
raco pkg install -t dir unison
```
in the directory where the `unison directory is located. Then the
in the directory where the `unison` directory is located. Then the
runtime executable can be built with
raco exe scheme-libs/racket/unison-runtime.rkt
```
raco exe scheme-libs/racket/unison-runtime.rkt
```
and a distributable directory can be produced with:
raco distribute <output-dir> scheme-libs/racket/unison-runtime
```
raco distribute <output-dir> scheme-libs/racket/unison-runtime
```
At that point, <output-dir> should contain the executable and all
dependencies necessary to run it.

View File

@ -45,7 +45,5 @@ scratch/main> names term1
Term
Hash: #8hum58rlih
Names: term1 term2
Tip: Use `names.global` to see more results.
```

View File

@ -48,16 +48,12 @@ scratch/app1> names a
Term
Hash: #gjmq673r1v
Names: lib.text_v1.a lib.text_v2.a
Tip: Use `names.global` to see more results.
scratch/app1> names x
Term
Hash: #nsmc4p1ra4
Names: lib.http_v3.x lib.http_v4.x
Tip: Use `names.global` to see more results.
```
Our `app2` project includes the `http` library twice as direct dependencies, and once as an indirect dependency via `webutil`.
@ -102,15 +98,11 @@ scratch/app2> names a
Term
Hash: #gjmq673r1v
Names: lib.webutil.lib.text_v1.a
Tip: Use `names.global` to see more results.
scratch/app2> names x
Term
Hash: #nsmc4p1ra4
Names: lib.http_v1.x lib.http_v2.x
Tip: Use `names.global` to see more results.
```

View File

@ -25,7 +25,7 @@ scratch/main> find.verbose
No results. Check your spelling, or try using tab completion
to supply command arguments.
`find.global` can be used to search outside the current
`debug.find.global` can be used to search outside the current
namespace.
```
@ -42,7 +42,7 @@ scratch/main> find mynamespace
No results. Check your spelling, or try using tab completion
to supply command arguments.
`find.global` can be used to search outside the current
`debug.find.global` can be used to search outside the current
namespace.
```

View File

@ -0,0 +1,3 @@
``` api:error
DELETE /something/important
```

View File

@ -0,0 +1,5 @@
``` ucm:error
scratch/main> builtins.merge
-- As of 0.5.25, we no longer allow loose code paths for UCM commands.
.> ls
```

View File

@ -34,15 +34,10 @@ Finding within a namespace
```ucm
scratch/main> find bar
-- Shows UUIDs
-- scratch/main> find.global bar
scratch/other> debug.find.global bar
scratch/main> find-in somewhere bar
```
```ucm:error
scratch/main> find baz
```
```ucm:error
scratch/main> find.global notHere
```

View File

@ -65,8 +65,15 @@ scratch/main> find bar
1. somewhere.bar : Nat
-- Shows UUIDs
-- scratch/main> find.global bar
scratch/other> debug.find.global bar
Found results in scratch/main
1. .cat.lib.bar : Nat
2. .lib.bar : Nat
3. .somewhere.bar : Nat
scratch/main> find-in somewhere bar
1. bar : Nat
@ -86,17 +93,7 @@ scratch/main> find baz
No results. Check your spelling, or try using tab completion
to supply command arguments.
`find.global` can be used to search outside the current
`debug.find.global` can be used to search outside the current
namespace.
```
``` ucm
scratch/main> find.global notHere
😶
No results. Check your spelling, or try using tab completion
to supply command arguments.
```

View File

@ -113,6 +113,50 @@ scratch/main> help
debug.file
View details about the most recent successfully typechecked file.
debug.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').
debug.find.global foo Iteratively searches all
projects and branches and
lists all definitions with a
name similar to 'foo'. Note
that this is a very slow
operation.
debug.names.global
`debug.names.global foo` Iteratively search across all
projects and branches for names matching `foo`. Note that this
is expected to be quite slow and is primarily for debugging
issues with your codebase.
debug.numberedArgs
Dump the contents of the numbered args state.
@ -269,9 +313,12 @@ scratch/main> help
'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
debug.find.global foo Iteratively searches all
projects and branches and
lists all definitions with a
name similar to 'foo'. Note
that this is a very slow
operation.
find-in
`find` lists all definitions in the
@ -304,9 +351,12 @@ scratch/main> help
'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
debug.find.global foo Iteratively searches all
projects and branches and
lists all definitions with a
name similar to 'foo'. Note
that this is a very slow
operation.
find-in.all
`find` lists all definitions in the
@ -339,9 +389,12 @@ scratch/main> help
'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
debug.find.global foo Iteratively searches all
projects and branches and
lists all definitions with a
name similar to 'foo'. Note
that this is a very slow
operation.
find.all
`find` lists all definitions in the
@ -374,48 +427,16 @@ scratch/main> help
'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
debug.find.global foo Iteratively searches all
projects and branches and
lists all definitions with a
name similar to 'foo'. Note
that this is a very slow
operation.
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.
@ -526,11 +547,8 @@ scratch/main> help
`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`.
`names foo` List all known names for `foo` in the current
branch.
namespace.dependencies
List the external dependencies of the specified namespace.

View File

@ -1435,8 +1435,6 @@ project/alice> names A
Type
Hash: #65mdg7015r
Names: A A.inner.X
Tip: Use `names.global` to see more results.
```
Bob's branch:

View File

@ -32,16 +32,13 @@ scratch/main> names #gjmq673r1v
scratch/main> names .some.place.x
```
`names.global` searches from the root, and absolutely qualifies results
`debug.names.global` searches from the root, and absolutely qualifies results
TODO: swap this back to a 'ucm' block when names.global is re-implemented
```
```ucm
-- We can search from a different branch and find all names in the codebase named 'x', and each of their aliases respectively.
scratch/other> names.global x
scratch/other> debug.names.global x
-- We can search by hash, and see all aliases of that hash in the codebase
scratch/other> names.global #gjmq673r1v
scratch/other> debug.names.global #gjmq673r1v
-- We can search using an absolute name
scratch/other> names.global .some.place.x
scratch/other> debug.names.global .some.place.x
```

View File

@ -59,8 +59,6 @@ scratch/main> names x
Hash: #pi25gcdv0o
Names: some.otherplace.x
Tip: Use `names.global` to see more results.
-- We can search by hash, and see all aliases of that hash
scratch/main> names #gjmq673r1v
@ -68,8 +66,6 @@ scratch/main> names #gjmq673r1v
Term
Hash: #gjmq673r1v
Names: some.otherplace.y some.place.x somewhere.z
Tip: Use `names.global` to see more results.
-- Works with absolute names too
scratch/main> names .some.place.x
@ -77,20 +73,39 @@ scratch/main> names .some.place.x
Term
Hash: #gjmq673r1v
Names: some.otherplace.y some.place.x somewhere.z
Tip: Use `names.global` to see more results.
```
`names.global` searches from the root, and absolutely qualifies results
`debug.names.global` searches from the root, and absolutely qualifies results
TODO: swap this back to a 'ucm' block when names.global is re-implemented
```
``` ucm
-- We can search from a different branch and find all names in the codebase named 'x', and each of their aliases respectively.
scratch/other> names.global x
-- We can search by hash, and see all aliases of that hash in the codebase
scratch/other> names.global #gjmq673r1v
-- We can search using an absolute name
scratch/other> names.global .some.place.x
```
scratch/other> debug.names.global x
Found results in scratch/main
Terms
Hash: #gjmq673r1v
Names: some.otherplace.y some.place.x somewhere.z
Hash: #pi25gcdv0o
Names: some.otherplace.x
-- We can search by hash, and see all aliases of that hash in the codebase
scratch/other> debug.names.global #gjmq673r1v
Found results in scratch/main
Term
Hash: #gjmq673r1v
Names: some.otherplace.y some.place.x somewhere.z
-- We can search using an absolute name
scratch/other> debug.names.global .some.place.x
Found results in scratch/main
Term
Hash: #gjmq673r1v
Names: some.otherplace.y some.place.x somewhere.z
```

View File

@ -165,8 +165,6 @@ scratch/main> names distributed.lib.baz.qux
Term
Hash: #nhup096n2s
Names: lib.distributed.lib.baz.qux
Tip: Use `names.global` to see more results.
```
## Corner cases

View File

@ -60,8 +60,6 @@ scratch/main> names A
Term
Hash: #uj8oalgadr#0
Names: A.A
Tip: Use `names.global` to see more results.
```
``` unison
@ -99,8 +97,6 @@ scratch/main> names A
Term
Hash: #ufo5tuc7ho#0
Names: A.A
Tip: Use `names.global` to see more results.
```
``` unison
@ -140,7 +136,5 @@ scratch/main> names A
Term
Hash: #uj8oalgadr#0
Names: A.A
Tip: Use `names.global` to see more results.
```

View File

@ -62,7 +62,5 @@ scratch/main> names foo
Term
Hash: #9ntnotdp87
Names: foo
Tip: Use `names.global` to see more results.
```