mirror of
https://github.com/unisonweb/unison.git
synced 2024-09-11 10:35:57 +03:00
Merge remote-tracking branch 'origin/trunk' into lsp/binding-annotations
This commit is contained in:
commit
f51840e6fd
6
.github/pull_request_template.md
vendored
6
.github/pull_request_template.md
vendored
@ -1,7 +1,5 @@
|
||||
**Choose your PR title well:** Your pull request title is what's used to create release notes, so please make it descriptive of the change itself, which may be different from the initial motivation to make the change.
|
||||
|
||||
Note: CI will check that all code has been formatted with Ormolu. See [development.markdown](https://github.com/unisonweb/unison/blob/trunk/development.markdown) for details of how to set this up.
|
||||
|
||||
## Overview
|
||||
|
||||
What does this change accomplish and why?
|
||||
@ -18,12 +16,12 @@ How does it accomplish it, in broad strokes? i.e. How does it change the Haskell
|
||||
|
||||
## Interesting/controversial decisions
|
||||
|
||||
Include anything that you thought twice about, debated, chose arbitrarily, etc.
|
||||
Include anything that you thought twice about, debated, chose arbitrarily, etc.
|
||||
What could have been done differently, but wasn't? And why?
|
||||
|
||||
## Test coverage
|
||||
|
||||
Have you included tests (which could be a transcript) for this change, or is it somehow covered by existing tests?
|
||||
Have you included tests (which could be a transcript) for this change, or is it somehow covered by existing tests?
|
||||
|
||||
Would you recommend improving the test coverage (either as part of this PR or as a separate issue) or do you think it’s adequate?
|
||||
|
||||
|
37
.github/workflows/ci.yaml
vendored
37
.github/workflows/ci.yaml
vendored
@ -22,11 +22,25 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v37
|
||||
with:
|
||||
path: unison
|
||||
- uses: mrkkrp/ormolu-action@v11
|
||||
# globs copied from default settings for run-ormolu
|
||||
files: |
|
||||
**/*.hs
|
||||
**/*.hs-boot
|
||||
separator: "\n"
|
||||
- uses: unisonweb/run-ormolu@8e1437595b4127e368c114cabd1aeedb3b873918
|
||||
with:
|
||||
version: "0.5.0.1"
|
||||
mode: inplace
|
||||
pattern: ${{ steps.changed-files.outputs.all_changed_files }}
|
||||
- name: apply formatting changes
|
||||
uses: stefanzweifel/git-auto-commit-action@v4
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
commit_message: automatically run ormolu
|
||||
|
||||
build:
|
||||
name: ${{ matrix.os }}
|
||||
@ -34,7 +48,6 @@ jobs:
|
||||
needs: ormolu
|
||||
defaults:
|
||||
run:
|
||||
working-directory: unison
|
||||
shell: bash
|
||||
strategy:
|
||||
# Run each build to completion, regardless of if any have failed
|
||||
@ -47,8 +60,6 @@ jobs:
|
||||
- windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
path: unison
|
||||
|
||||
# The number towards the beginning of the cache keys allow you to manually avoid using a previous cache.
|
||||
# GitHub will automatically delete caches that haven't been accessed in 7 days, but there is no way to
|
||||
@ -121,14 +132,14 @@ jobs:
|
||||
# The installation process differs by OS.
|
||||
- name: install stack (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
working-directory: ${{ github.workspace }}
|
||||
working-directory: ${{ runner.temp }}
|
||||
run: |
|
||||
mkdir stack && cd stack
|
||||
curl -L https://github.com/commercialhaskell/stack/releases/download/v2.9.1/stack-2.9.1-linux-x86_64.tar.gz | tar -xz
|
||||
echo "$PWD/stack-"* >> $GITHUB_PATH
|
||||
|
||||
- name: install stack (macOS)
|
||||
working-directory: ${{ github.workspace }}
|
||||
working-directory: ${{ runner.temp }}
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
mkdir stack && cd stack
|
||||
@ -136,7 +147,7 @@ jobs:
|
||||
echo "$PWD/stack-"* >> $GITHUB_PATH
|
||||
|
||||
- name: install stack (windows)
|
||||
working-directory: ${{ github.workspace }}
|
||||
working-directory: ${{ runner.temp }}
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
mkdir stack && cd stack
|
||||
@ -189,8 +200,14 @@ jobs:
|
||||
run: stack --no-terminal build --fast --no-run-tests --test
|
||||
|
||||
# Run each test suite (tests and transcripts)
|
||||
- name: check disk space before
|
||||
if: ${{ always() }}
|
||||
run: df -h
|
||||
- name: unison-cli test
|
||||
run: stack --no-terminal build --fast --test unison-cli
|
||||
- name: check disk space after
|
||||
if: ${{ always() }}
|
||||
run: df -h
|
||||
- name: unison-core tests
|
||||
run: stack --no-terminal build --fast --test unison-core
|
||||
- name: unison-parser-typechecker tests
|
||||
@ -247,8 +264,8 @@ jobs:
|
||||
if: runner.os == 'Linux'
|
||||
with:
|
||||
path: ~/.cache/unisonlanguage/base.unison
|
||||
key: base.unison_${{hashFiles('**/unison-src/builtin-tests/base.md')}}-${{github.sha}}
|
||||
restore-keys: base.unison_${{hashFiles('**/unison-src/builtin-tests/base.md')}}-
|
||||
key: base.unison_${{hashFiles('**/unison-src/builtin-tests/base.md','**/unison-cli/src/Unison/JitInfo.hs')}}-${{github.sha}}
|
||||
restore-keys: base.unison_${{hashFiles('**/unison-src/builtin-tests/base.md','**/unison-cli/src/Unison/JitInfo.hs')}}-
|
||||
|
||||
- name: set up `base` codebase
|
||||
if: runner.os == 'Linux'
|
||||
|
@ -27,8 +27,6 @@ library:
|
||||
source-dirs: src
|
||||
exposed-modules:
|
||||
- U.Codebase.Sqlite.V2.HashHandle
|
||||
- U.Codebase.Branch.Hashing
|
||||
- U.Codebase.Causal.Hashing
|
||||
when:
|
||||
- condition: false
|
||||
other-modules: Paths_unison_codebase_sqlite_hashing_v2
|
||||
|
@ -5,8 +5,8 @@ import Data.Set qualified as Set
|
||||
import U.Codebase.HashTags (BranchHash (..), CausalHash (..))
|
||||
import Unison.Hashing.V2 qualified as Hashing
|
||||
|
||||
hashCausal :: Set CausalHash -> BranchHash -> CausalHash
|
||||
hashCausal ancestors branchHash =
|
||||
hashCausal :: BranchHash -> Set CausalHash -> CausalHash
|
||||
hashCausal branchHash ancestors =
|
||||
CausalHash . Hashing.contentHash $
|
||||
Hashing.Causal
|
||||
{ Hashing.branchHash = unBranchHash branchHash,
|
||||
|
@ -4,6 +4,8 @@ module U.Codebase.Sqlite.V2.HashHandle
|
||||
where
|
||||
|
||||
import Data.Set qualified as Set
|
||||
import U.Codebase.Branch.Hashing qualified as H2
|
||||
import U.Codebase.Causal.Hashing qualified as H2
|
||||
import U.Codebase.Sqlite.HashHandle
|
||||
import U.Util.Type (removeAllEffectVars)
|
||||
import Unison.Hashing.V2 qualified as H2
|
||||
@ -15,5 +17,7 @@ v2HashHandle =
|
||||
{ toReference = h2ToV2Reference . H2.typeToReference . v2ToH2Type . removeAllEffectVars,
|
||||
toReferenceMentions = Set.map h2ToV2Reference . H2.typeToReferenceMentions . v2ToH2Type . removeAllEffectVars,
|
||||
toReferenceDecl = \h -> h2ToV2Reference . H2.typeToReference . v2ToH2TypeD h . removeAllEffectVars,
|
||||
toReferenceDeclMentions = \h -> Set.map h2ToV2Reference . H2.typeToReferenceMentions . v2ToH2TypeD h . removeAllEffectVars
|
||||
toReferenceDeclMentions = \h -> Set.map h2ToV2Reference . H2.typeToReferenceMentions . v2ToH2TypeD h . removeAllEffectVars,
|
||||
hashBranch = H2.hashBranch,
|
||||
hashCausal = H2.hashCausal
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
cabal-version: 1.12
|
||||
|
||||
-- This file has been generated from package.yaml by hpack version 0.35.1.
|
||||
-- This file has been generated from package.yaml by hpack version 0.35.2.
|
||||
--
|
||||
-- see: https://github.com/sol/hpack
|
||||
|
||||
@ -18,9 +18,9 @@ source-repository head
|
||||
library
|
||||
exposed-modules:
|
||||
U.Codebase.Sqlite.V2.HashHandle
|
||||
other-modules:
|
||||
U.Codebase.Branch.Hashing
|
||||
U.Codebase.Causal.Hashing
|
||||
other-modules:
|
||||
Unison.Hashing.V2.Convert2
|
||||
hs-source-dirs:
|
||||
src
|
||||
|
31
codebase2/codebase-sqlite/U/Codebase/Causal/Squash.hs
Normal file
31
codebase2/codebase-sqlite/U/Codebase/Causal/Squash.hs
Normal file
@ -0,0 +1,31 @@
|
||||
module U.Codebase.Causal.Squash (squashCausal) where
|
||||
|
||||
import U.Codebase.Branch.Type
|
||||
import U.Codebase.Causal (Causal (..))
|
||||
import U.Codebase.Sqlite.HashHandle qualified as HH
|
||||
import U.Codebase.Sqlite.Operations qualified as SqliteOps
|
||||
import Unison.Prelude
|
||||
import Unison.Sqlite qualified as Sqlite
|
||||
|
||||
-- Recursively discards history, resulting in a namespace tree with only single a single
|
||||
-- Causal node at every level.
|
||||
squashCausal :: HH.HashHandle -> CausalBranch Sqlite.Transaction -> Sqlite.Transaction (CausalBranch Sqlite.Transaction)
|
||||
squashCausal hashHandle@HH.HashHandle {hashCausal, hashBranch} Causal {valueHash = unsquashedBranchHash, value} = do
|
||||
runMaybeT (MaybeT (SqliteOps.tryGetSquashResult unsquashedBranchHash) >>= MaybeT . SqliteOps.loadCausalBranchByCausalHash) >>= \case
|
||||
Just cb -> pure cb
|
||||
Nothing -> do
|
||||
branch@Branch {children} <- value
|
||||
squashedChildren <- traverse (squashCausal hashHandle) children
|
||||
let squashedBranchHead = branch {children = squashedChildren}
|
||||
squashedBranchHash <- hashBranch squashedBranchHead
|
||||
let squashedCausalHash = hashCausal squashedBranchHash mempty
|
||||
let squashedCausalBranch =
|
||||
Causal
|
||||
{ causalHash = squashedCausalHash,
|
||||
valueHash = squashedBranchHash,
|
||||
parents = mempty,
|
||||
value = pure squashedBranchHead
|
||||
}
|
||||
SqliteOps.saveBranch hashHandle squashedCausalBranch
|
||||
SqliteOps.saveSquashResult unsquashedBranchHash squashedCausalHash
|
||||
pure squashedCausalBranch
|
@ -3,6 +3,8 @@ module U.Codebase.Sqlite.HashHandle
|
||||
)
|
||||
where
|
||||
|
||||
import U.Codebase.Branch.Type (Branch)
|
||||
import U.Codebase.HashTags
|
||||
import U.Codebase.Reference qualified as C
|
||||
import U.Codebase.Sqlite.Symbol (Symbol)
|
||||
import U.Codebase.Term qualified as C.Term
|
||||
@ -18,5 +20,12 @@ data HashHandle = HashHandle
|
||||
-- | Hash the type of a single constructor in a decl component. The provided hash argument is the hash of the decl component.
|
||||
toReferenceDecl :: Hash -> C.Type.TypeD Symbol -> C.Reference,
|
||||
-- | Hash decl's mentions
|
||||
toReferenceDeclMentions :: Hash -> C.Type.TypeD Symbol -> Set C.Reference
|
||||
toReferenceDeclMentions :: Hash -> C.Type.TypeD Symbol -> Set C.Reference,
|
||||
hashBranch :: forall m. Monad m => Branch m -> m BranchHash,
|
||||
hashCausal ::
|
||||
-- The causal's namespace hash
|
||||
BranchHash ->
|
||||
-- The causal's parents
|
||||
Set CausalHash ->
|
||||
CausalHash
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ module U.Codebase.Sqlite.Operations
|
||||
expectBranchByBranchHashId,
|
||||
expectNamespaceStatsByHash,
|
||||
expectNamespaceStatsByHashId,
|
||||
tryGetSquashResult,
|
||||
saveSquashResult,
|
||||
|
||||
-- * terms
|
||||
Q.saveTermComponent,
|
||||
@ -1404,6 +1406,21 @@ deleteNameLookupsExceptFor reachable = do
|
||||
bhIds <- for (Set.toList reachable) Q.expectBranchHashId
|
||||
Q.deleteNameLookupsExceptFor bhIds
|
||||
|
||||
-- | Get the causal hash which would be the result of squashing the provided branch hash.
|
||||
-- Returns Nothing if we haven't computed it before.
|
||||
tryGetSquashResult :: BranchHash -> Transaction (Maybe CausalHash)
|
||||
tryGetSquashResult bh = do
|
||||
bhId <- Q.expectBranchHashId bh
|
||||
chId <- Q.tryGetSquashResult bhId
|
||||
traverse Q.expectCausalHash chId
|
||||
|
||||
-- | Saves the result of a squash
|
||||
saveSquashResult :: BranchHash -> CausalHash -> Transaction ()
|
||||
saveSquashResult bh ch = do
|
||||
bhId <- Q.expectBranchHashId bh
|
||||
chId <- Q.saveCausalHash ch
|
||||
Q.saveSquashResult bhId chId
|
||||
|
||||
-- | Search for term or type names which contain the provided list of segments in order.
|
||||
-- Search is case insensitive.
|
||||
fuzzySearchDefinitions ::
|
||||
|
@ -75,6 +75,7 @@ module U.Codebase.Sqlite.Queries
|
||||
-- ** causal table
|
||||
saveCausal,
|
||||
isCausalHash,
|
||||
causalExistsByHash32,
|
||||
expectCausal,
|
||||
loadCausalHashIdByCausalHash,
|
||||
expectCausalHashIdByCausalHash,
|
||||
@ -85,6 +86,8 @@ module U.Codebase.Sqlite.Queries
|
||||
loadBranchObjectIdByBranchHashId,
|
||||
expectBranchObjectIdByCausalHashId,
|
||||
expectBranchObjectIdByBranchHashId,
|
||||
tryGetSquashResult,
|
||||
saveSquashResult,
|
||||
|
||||
-- ** causal_parent table
|
||||
saveCausalParents,
|
||||
@ -233,6 +236,7 @@ module U.Codebase.Sqlite.Queries
|
||||
fixScopedNameLookupTables,
|
||||
addNameLookupMountTables,
|
||||
addMostRecentNamespaceTable,
|
||||
addSquashResultTable,
|
||||
|
||||
-- ** schema version
|
||||
currentSchemaVersion,
|
||||
@ -386,7 +390,7 @@ type TextPathSegments = [Text]
|
||||
-- * main squeeze
|
||||
|
||||
currentSchemaVersion :: SchemaVersion
|
||||
currentSchemaVersion = 13
|
||||
currentSchemaVersion = 14
|
||||
|
||||
createSchema :: Transaction ()
|
||||
createSchema = do
|
||||
@ -439,6 +443,10 @@ addMostRecentNamespaceTable :: Transaction ()
|
||||
addMostRecentNamespaceTable =
|
||||
executeStatements (Text.pack [hereFile|unison/sql/008-add-most-recent-namespace-table.sql|])
|
||||
|
||||
addSquashResultTable :: Transaction ()
|
||||
addSquashResultTable =
|
||||
executeStatements (Text.pack [hereFile|unison/sql/009-add-squash-cache-table.sql|])
|
||||
|
||||
schemaVersion :: Transaction SchemaVersion
|
||||
schemaVersion =
|
||||
queryOneCol
|
||||
@ -1215,6 +1223,19 @@ isCausalHash hash =
|
||||
)
|
||||
|]
|
||||
|
||||
-- | Return whether or not a causal exists with the given hash32.
|
||||
causalExistsByHash32 :: Hash32 -> Transaction Bool
|
||||
causalExistsByHash32 hash =
|
||||
queryOneCol
|
||||
[sql|
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM causal
|
||||
JOIN hash ON causal.self_hash_id = hash.id
|
||||
WHERE hash.base32 = :hash
|
||||
)
|
||||
|]
|
||||
|
||||
loadBranchObjectIdByCausalHashId :: CausalHashId -> Transaction (Maybe BranchObjectId)
|
||||
loadBranchObjectIdByCausalHashId id = queryMaybeCol (loadBranchObjectIdByCausalHashIdSql id)
|
||||
|
||||
@ -2179,7 +2200,7 @@ termNamesForRefWithinNamespace bhId namespaceRoot ref maySuffix = do
|
||||
let suffixGlob = case maySuffix of
|
||||
Just suffix -> toSuffixGlob suffix
|
||||
Nothing -> "*"
|
||||
queryListColCheck
|
||||
directNames <- queryListColCheck
|
||||
[sql|
|
||||
SELECT reversed_name FROM scoped_term_name_lookup
|
||||
WHERE root_branch_hash_id = :bhId
|
||||
@ -2196,6 +2217,26 @@ termNamesForRefWithinNamespace bhId namespaceRoot ref maySuffix = do
|
||||
AND reversed_name GLOB :suffixGlob
|
||||
|]
|
||||
\reversedNames -> for reversedNames reversedNameToReversedSegments
|
||||
-- If we don't find a name in the name lookup, expand the search to recursively include transitive deps
|
||||
-- and just return the first one we find.
|
||||
if null directNames
|
||||
then do
|
||||
toList
|
||||
<$> queryMaybeColCheck
|
||||
[sql|
|
||||
$transitive_dependency_mounts
|
||||
SELECT (reversed_name || reversed_mount_path) AS reversed_name
|
||||
FROM transitive_dependency_mounts
|
||||
INNER JOIN scoped_term_name_lookup
|
||||
ON scoped_term_name_lookup.root_branch_hash_id = transitive_dependency_mounts.root_branch_hash_id
|
||||
WHERE referent_builtin IS @ref AND referent_component_hash IS @ AND referent_component_index IS @ AND referent_constructor_index IS @
|
||||
AND reversed_name GLOB :suffixGlob
|
||||
LIMIT 1
|
||||
|]
|
||||
(\reversedName -> reversedNameToReversedSegments reversedName)
|
||||
else pure directNames
|
||||
where
|
||||
transitive_dependency_mounts = transitiveDependenciesSql bhId
|
||||
|
||||
-- | NOTE: requires that the codebase has an up-to-date name lookup index. As of writing, this
|
||||
-- is only true on Share.
|
||||
@ -2208,7 +2249,7 @@ typeNamesForRefWithinNamespace bhId namespaceRoot ref maySuffix = do
|
||||
let suffixGlob = case maySuffix of
|
||||
Just suffix -> toSuffixGlob suffix
|
||||
Nothing -> "*"
|
||||
queryListColCheck
|
||||
directNames <- queryListColCheck
|
||||
[sql|
|
||||
SELECT reversed_name FROM scoped_type_name_lookup
|
||||
WHERE root_branch_hash_id = :bhId
|
||||
@ -2225,6 +2266,48 @@ typeNamesForRefWithinNamespace bhId namespaceRoot ref maySuffix = do
|
||||
AND reversed_name GLOB :suffixGlob
|
||||
|]
|
||||
\reversedNames -> for reversedNames reversedNameToReversedSegments
|
||||
-- If we don't find a name in the name lookup, expand the search to recursively include transitive deps
|
||||
-- and just return the first one we find.
|
||||
if null directNames
|
||||
then
|
||||
toList
|
||||
<$> queryMaybeColCheck
|
||||
[sql|
|
||||
$transitive_dependency_mounts
|
||||
SELECT (reversed_name || reversed_mount_path) AS reversed_name
|
||||
FROM transitive_dependency_mounts
|
||||
INNER JOIN scoped_type_name_lookup
|
||||
ON scoped_type_name_lookup.root_branch_hash_id = transitive_dependency_mounts.root_branch_hash_id
|
||||
WHERE reference_builtin IS @ref AND reference_component_hash IS @ AND reference_component_index IS @
|
||||
AND reversed_name GLOB :suffixGlob
|
||||
LIMIT 1
|
||||
|]
|
||||
(\reversedName -> reversedNameToReversedSegments reversedName)
|
||||
else pure directNames
|
||||
where
|
||||
transitive_dependency_mounts = transitiveDependenciesSql bhId
|
||||
|
||||
-- | Brings into scope the transitive_dependency_mounts CTE table, which contains all transitive deps of the given root, but does NOT include the direct dependencies.
|
||||
-- @transitive_dependency_mounts(root_branch_hash_id, reversed_mount_path)@
|
||||
-- Where @reversed_mount_path@ is the reversed path from the provided root to the mounted
|
||||
-- dependency's root.
|
||||
transitiveDependenciesSql :: BranchHashId -> Sql
|
||||
transitiveDependenciesSql rootBranchHashId =
|
||||
[sql|
|
||||
-- Recursive table containing all transitive deps
|
||||
WITH RECURSIVE
|
||||
transitive_dependency_mounts(root_branch_hash_id, reversed_mount_path) AS (
|
||||
-- We've already searched direct deps above, so start with children of direct deps
|
||||
SELECT transitive.mounted_root_branch_hash_id, transitive.reversed_mount_path || direct.reversed_mount_path
|
||||
FROM name_lookup_mounts direct
|
||||
JOIN name_lookup_mounts transitive on direct.mounted_root_branch_hash_id = transitive.parent_root_branch_hash_id
|
||||
WHERE direct.parent_root_branch_hash_id = :rootBranchHashId
|
||||
UNION ALL
|
||||
SELECT mount.mounted_root_branch_hash_id, mount.reversed_mount_path || rec.reversed_mount_path
|
||||
FROM name_lookup_mounts mount
|
||||
INNER JOIN transitive_dependency_mounts rec ON mount.parent_root_branch_hash_id = rec.root_branch_hash_id
|
||||
)
|
||||
|]
|
||||
|
||||
-- | NOTE: requires that the codebase has an up-to-date name lookup index. As of writing, this
|
||||
-- is only true on Share.
|
||||
@ -3960,3 +4043,32 @@ setMostRecentNamespace namespace =
|
||||
json :: Text
|
||||
json =
|
||||
Text.Lazy.toStrict (Aeson.encodeToLazyText namespace)
|
||||
|
||||
-- | Get the causal hash result from squashing the provided branch hash if we've squashed it
|
||||
-- at some point in the past.
|
||||
tryGetSquashResult :: BranchHashId -> Transaction (Maybe CausalHashId)
|
||||
tryGetSquashResult bhId = do
|
||||
queryMaybeCol
|
||||
[sql|
|
||||
SELECT
|
||||
squashed_causal_hash_id
|
||||
FROM
|
||||
squash_results
|
||||
WHERE
|
||||
branch_hash_id = :bhId
|
||||
|]
|
||||
|
||||
-- | Save the result of running a squash on the provided branch hash id.
|
||||
saveSquashResult :: BranchHashId -> CausalHashId -> Transaction ()
|
||||
saveSquashResult bhId chId =
|
||||
execute
|
||||
[sql|
|
||||
INSERT INTO squash_results (
|
||||
branch_hash_id,
|
||||
squashed_causal_hash_id)
|
||||
VALUES (
|
||||
:bhId,
|
||||
:chId
|
||||
)
|
||||
ON CONFLICT DO NOTHING
|
||||
|]
|
||||
|
10
codebase2/codebase-sqlite/sql/009-add-squash-cache-table.sql
Normal file
10
codebase2/codebase-sqlite/sql/009-add-squash-cache-table.sql
Normal file
@ -0,0 +1,10 @@
|
||||
-- A table for tracking the results of squashes we've performed.
|
||||
-- This is used to avoid re-squashing the same branch multiple times.
|
||||
CREATE TABLE "squash_results" (
|
||||
-- The branch hash of the namespace to be squashed.
|
||||
-- There should only ever be one result for each unsquashed value hash.
|
||||
branch_hash_id INTEGER PRIMARY KEY NOT NULL REFERENCES hash(id),
|
||||
|
||||
-- The causal hash id which is the result of squashing the 'branch_hash_id's causal.'
|
||||
squashed_causal_hash_id INTEGER NOT NULL REFERENCES causal(self_hash_id)
|
||||
) WITHOUT ROWID;
|
@ -18,6 +18,7 @@ extra-source-files:
|
||||
sql/006-most-recent-branch-table.sql
|
||||
sql/007-add-name-lookup-mounts.sql
|
||||
sql/008-add-most-recent-namespace-table.sql
|
||||
sql/009-add-squash-cache-table.sql
|
||||
sql/create.sql
|
||||
|
||||
source-repository head
|
||||
@ -27,6 +28,7 @@ source-repository head
|
||||
library
|
||||
exposed-modules:
|
||||
U.Codebase.Branch
|
||||
U.Codebase.Causal.Squash
|
||||
U.Codebase.Sqlite.Branch.Diff
|
||||
U.Codebase.Sqlite.Branch.Format
|
||||
U.Codebase.Sqlite.Branch.Full
|
||||
|
@ -18,34 +18,7 @@ On startup, Unison prints a url for the codebase UI. If you did step 3 above, th
|
||||
|
||||
## Autoformatting your code with Ormolu
|
||||
|
||||
We use 0.5.0.1 of Ormolu and CI will fail if your code isn't properly formatted.
|
||||
|
||||
```
|
||||
ghcup install ghc 9.2.7 # if not already installed
|
||||
ghcup install cabal # if not already installed
|
||||
cabal unpack ormolu-0.5.0.1
|
||||
cd ormolu-0.5.0.1
|
||||
cabal install -w ghc-9.2.7
|
||||
```
|
||||
|
||||
You can then add the following to `.git/hooks/pre-commit` to make sure all your commits get formatted:
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [[ -z "${SKIP_FORMATTING}" ]]; then
|
||||
ormolu -i $(git diff --cached --name-only | grep '\.hs$')
|
||||
git add $(git diff --cached --name-only)
|
||||
fi
|
||||
```
|
||||
|
||||
If you've got an existing PR that somehow hasn't been formatted correctly, you can install the correct version of Ormolu locally, then do:
|
||||
|
||||
```
|
||||
ormolu -i $(git ls-files | grep '\.hs$')
|
||||
```
|
||||
We use 0.5.0.1 of Ormolu and CI will add an extra commit, if needed, to autoformat your code.
|
||||
|
||||
Also note that you can always wrap a comment around some code you don't want Ormolu to touch, using:
|
||||
|
||||
|
@ -875,7 +875,8 @@ ioBuiltins =
|
||||
( "IO.tryEval",
|
||||
forall1 "a" $ \a ->
|
||||
(unit --> io a) --> Type.effect () [Type.builtinIO (), DD.exceptionType ()] a
|
||||
)
|
||||
),
|
||||
("IO.randomBytes", nat --> io bytes)
|
||||
]
|
||||
|
||||
mvarBuiltins :: [(Text, Type)]
|
||||
|
@ -78,7 +78,8 @@ migrations getDeclType termBuffer declBuffer rootCodebasePath =
|
||||
sqlMigration 10 Q.addProjectTables,
|
||||
sqlMigration 11 Q.addMostRecentBranchTable,
|
||||
(12, migrateSchema11To12),
|
||||
sqlMigration 13 Q.addMostRecentNamespaceTable
|
||||
sqlMigration 13 Q.addMostRecentNamespaceTable,
|
||||
sqlMigration 14 Q.addSquashResultTable
|
||||
]
|
||||
where
|
||||
sqlMigration :: SchemaVersion -> Sqlite.Transaction () -> (SchemaVersion, Sqlite.Transaction ())
|
||||
|
@ -1,7 +1,8 @@
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE UnicodeSyntax #-}
|
||||
|
||||
module Unison.FileParsers where
|
||||
module Unison.FileParsers
|
||||
( parseAndSynthesizeFile,
|
||||
synthesizeFile',
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Lens
|
||||
import Control.Monad.State (evalStateT)
|
||||
@ -50,8 +51,6 @@ type Type v = Type.Type v Ann
|
||||
|
||||
type UnisonFile v = UF.UnisonFile v Ann
|
||||
|
||||
type Result' v = Result (Seq (Note v Ann))
|
||||
|
||||
debug :: Bool
|
||||
debug = False
|
||||
|
||||
|
@ -37,6 +37,7 @@ import Control.Monad.Reader (ReaderT (..), ask, runReaderT)
|
||||
import Control.Monad.State.Strict (State, execState, modify)
|
||||
import Crypto.Hash qualified as Hash
|
||||
import Crypto.MAC.HMAC qualified as HMAC
|
||||
import Crypto.Random (getRandomBytes)
|
||||
import Data.Bits (shiftL, shiftR, (.|.))
|
||||
import Data.ByteArray qualified as BA
|
||||
import Data.ByteString (hGet, hGetSome, hPut)
|
||||
@ -2384,7 +2385,7 @@ declareForeigns = do
|
||||
|
||||
declareForeign Tracked "IO.listen.impl.v3" boxToEF0
|
||||
. mkForeignIOF
|
||||
$ \sk -> SYS.listenSock sk 2
|
||||
$ \sk -> SYS.listenSock sk 2048
|
||||
|
||||
declareForeign Tracked "IO.clientSocket.impl.v3" boxBoxToEFBox
|
||||
. mkForeignIOF
|
||||
@ -2742,6 +2743,9 @@ declareForeigns = do
|
||||
declareForeign Untracked "Universal.murmurHash" murmur'hash . mkForeign $
|
||||
pure . asWord64 . hash64 . serializeValueLazy
|
||||
|
||||
declareForeign Tracked "IO.randomBytes" natToBox . mkForeign $
|
||||
\n -> Bytes.fromArray <$> getRandomBytes @IO @ByteString n
|
||||
|
||||
declareForeign Untracked "Bytes.zlib.compress" boxDirect . mkForeign $ pure . Bytes.zlibCompress
|
||||
declareForeign Untracked "Bytes.gzip.compress" boxDirect . mkForeign $ pure . Bytes.gzipCompress
|
||||
declareForeign Untracked "Bytes.zlib.decompress" boxToEBoxBox . mkForeign $ \bs ->
|
||||
|
@ -1,6 +1,6 @@
|
||||
cabal-version: 1.12
|
||||
|
||||
-- This file has been generated from package.yaml by hpack version 0.35.1.
|
||||
-- This file has been generated from package.yaml by hpack version 0.35.2.
|
||||
--
|
||||
-- see: https://github.com/sol/hpack
|
||||
|
||||
|
@ -3,7 +3,8 @@
|
||||
racket/string
|
||||
racket/file
|
||||
rnrs/io/ports-6
|
||||
(only-in racket empty?)
|
||||
(only-in rnrs standard-error-port standard-input-port standard-output-port vector-map)
|
||||
(only-in racket empty? with-output-to-string system/exit-code system false?)
|
||||
compatibility/mlist
|
||||
(only-in unison/boot data-case define-unison)
|
||||
unison/data
|
||||
@ -28,15 +29,21 @@
|
||||
unison/concurrent
|
||||
)
|
||||
|
||||
|
||||
(provide
|
||||
unison-FOp-IO.stdHandle
|
||||
(prefix-out
|
||||
builtin-IO.
|
||||
(combine-out
|
||||
seekHandle.impl.v3
|
||||
getLine.impl.v1
|
||||
getSomeBytes.impl.v1
|
||||
getBuffering.impl.v3
|
||||
setBuffering.impl.v3
|
||||
getEcho.impl.v1
|
||||
setEcho.impl.v1
|
||||
getArgs.impl.v1
|
||||
getEnv.impl.v1
|
||||
process.call
|
||||
))
|
||||
|
||||
; Still to implement:
|
||||
@ -46,10 +53,6 @@
|
||||
; ready.impl.v1
|
||||
; isFileOpen.impl.v3
|
||||
; isFileEOF.impl.v3
|
||||
; setEcho.impl.v1
|
||||
; getEcho.impl.v1
|
||||
; - unsafe-port->file-descriptor
|
||||
|
||||
)
|
||||
|
||||
(define either-id (bytevector 6 15 103 128 65 126 44 164 169 154 106 164 187 86 33 156 155 89 79 64 71 158 119 151 142 79 121 206 247 92 41 13 151 250 243 205 13 193 134 218 198 145 193 96 55 87 92 215 34 52 161 162 226 22 169 43 228 184 86 77 149 58 66 125))
|
||||
@ -83,20 +86,31 @@
|
||||
(Right (string->chunked-string line))
|
||||
)))
|
||||
|
||||
(define-unison (getSomeBytes.impl.v1 handle bytes)
|
||||
(let* ([buffer (make-bytes bytes)]
|
||||
[line (read-bytes-avail! buffer handle)])
|
||||
(if (eof-object? line)
|
||||
(Right (bytes->chunked-bytes #""))
|
||||
(Right (bytes->chunked-bytes buffer))
|
||||
)))
|
||||
|
||||
(define BufferMode
|
||||
(data 'Reference 1 (data 'Id 0 (bytevector 107 13 114 185 126 64 211 42 13 102 196 109 125 88 217 3 36 251 159 9 35 172 24 16 54 158 72 167 2 22 248 214 77 251 43 81 18 154 173 92 126 242 69 233 142 79 137 22 152 161 71 175 85 193 31 162 82 54 3 70 220 161 142 37) 0)))
|
||||
|
||||
(define BlockBuffering (data BufferMode 2))
|
||||
(define LineBuffering (data BufferMode 1))
|
||||
(define NoBuffering (data BufferMode 0))
|
||||
(define Boolean (data 'Reference 0 (string->chunked-string "Boolean")))
|
||||
(define True (data Boolean 1))
|
||||
(define False (data Boolean 0))
|
||||
|
||||
(define-unison (getBuffering.impl.v3 handle)
|
||||
(case (file-stream-buffer-mode handle)
|
||||
[(none) (Right NoBuffering)]
|
||||
[(line) (Right LineBuffering)]
|
||||
[(block) (Right BlockBuffering)]
|
||||
[(#f) (Exception 'IO "Unable to determine buffering mode of handle")]
|
||||
[else (Exception 'IO "Unexpected response from file-stream-buffer-mode")]))
|
||||
[(#f) (Exception 'IO "Unable to determine buffering mode of handle" '())]
|
||||
[else (Exception 'IO "Unexpected response from file-stream-buffer-mode" '())]))
|
||||
|
||||
(define-unison (setBuffering.impl.v3 handle mode)
|
||||
(data-case mode
|
||||
@ -110,5 +124,65 @@
|
||||
(file-stream-buffer-mode handle 'block)
|
||||
(Right none))
|
||||
(3 (size)
|
||||
(Exception 'IO "Sized block buffering not supported"))))
|
||||
(Exception 'IO "Sized block buffering not supported" '()))))
|
||||
|
||||
(define (with-buffer-mode port mode)
|
||||
(file-stream-buffer-mode port mode)
|
||||
port)
|
||||
|
||||
(define stdin (with-buffer-mode (standard-input-port) 'none))
|
||||
(define stdout (with-buffer-mode (standard-output-port) 'line))
|
||||
(define stderr (with-buffer-mode (standard-error-port) 'line))
|
||||
|
||||
(define (unison-FOp-IO.stdHandle n)
|
||||
(case n
|
||||
[(0) stdin]
|
||||
[(1) stdout]
|
||||
[(2) stderr]))
|
||||
|
||||
(define-unison (getEcho.impl.v1 handle)
|
||||
(if (eq? handle stdin)
|
||||
(Right (if (get-stdin-echo) True False))
|
||||
(Exception 'IO "getEcho only supported on stdin" '())))
|
||||
|
||||
(define-unison (setEcho.impl.v1 handle echo)
|
||||
(if (eq? handle stdin)
|
||||
(begin
|
||||
(data-case echo
|
||||
(1 () (system "stty echo"))
|
||||
(0 () (system "stty -echo")))
|
||||
(Right none))
|
||||
(Exception 'IO "setEcho only supported on stdin" '())))
|
||||
|
||||
(define (get-stdin-echo)
|
||||
(let ([current (with-output-to-string (lambda () (system "stty -a")))])
|
||||
(string-contains? current " echo ")))
|
||||
|
||||
(define-unison (getArgs.impl.v1 unit)
|
||||
(Right (vector->chunked-list
|
||||
(vector-map string->chunked-string (current-command-line-arguments)))))
|
||||
|
||||
(define-unison (getEnv.impl.v1 key)
|
||||
(let ([value (environment-variables-ref (current-environment-variables) (string->bytes/utf-8 (chunked-string->string key)))])
|
||||
(if (false? value)
|
||||
(Exception 'IO "environmental variable not found" key)
|
||||
(Right (string->chunked-string (bytes->string/utf-8 value))))))
|
||||
|
||||
;; From https://github.com/sorawee/shlex/blob/5de06500e8c831cfc8dffb99d57a76decc02c569/main.rkt (MIT License)
|
||||
;; with is a port of https://github.com/python/cpython/blob/bf2f76ec0976c09de79c8827764f30e3b6fba776/Lib/shlex.py#L325
|
||||
(define unsafe-pattern #rx"[^a-zA-Z0-9_@%+=:,./-]")
|
||||
(define (quote-arg s)
|
||||
(if (non-empty-string? s)
|
||||
(if (regexp-match unsafe-pattern s)
|
||||
(string-append "'" (string-replace s "'" "'\"'\"'") "'")
|
||||
s)
|
||||
"''"))
|
||||
|
||||
(define-unison (process.call command arguments)
|
||||
(system/exit-code
|
||||
(string-join (cons
|
||||
(chunked-string->string command)
|
||||
(map (lambda (arg) (quote-arg (chunked-string->string arg)))
|
||||
(vector->list
|
||||
(chunked-list->vector arguments))))
|
||||
" ")))
|
||||
|
@ -36,6 +36,8 @@
|
||||
builtin-Int.signum
|
||||
builtin-Nat.increment
|
||||
builtin-Nat.toFloat
|
||||
builtin-Text.indexOf
|
||||
builtin-IO.randomBytes
|
||||
|
||||
unison-FOp-internal.dataTag
|
||||
unison-FOp-Char.toText
|
||||
@ -48,8 +50,14 @@
|
||||
unison-FOp-IO.getBytes.impl.v3
|
||||
builtin-IO.seekHandle.impl.v3
|
||||
builtin-IO.getLine.impl.v1
|
||||
builtin-IO.getSomeBytes.impl.v1
|
||||
builtin-IO.setBuffering.impl.v3
|
||||
builtin-IO.getBuffering.impl.v3
|
||||
builtin-IO.setEcho.impl.v1
|
||||
builtin-IO.process.call
|
||||
builtin-IO.getEcho.impl.v1
|
||||
builtin-IO.getArgs.impl.v1
|
||||
builtin-IO.getEnv.impl.v1
|
||||
unison-FOp-IO.getFileSize.impl.v3
|
||||
unison-FOp-IO.getFileTimestamp.impl.v3
|
||||
unison-FOp-IO.fileExists.impl.v3
|
||||
@ -350,6 +358,8 @@
|
||||
exn:fail:contract?
|
||||
file-stream-buffer-mode
|
||||
with-handlers
|
||||
match
|
||||
regexp-match-positions
|
||||
sequence-ref
|
||||
vector-copy!
|
||||
bytes-copy!)
|
||||
@ -357,6 +367,7 @@
|
||||
(unison arithmetic)
|
||||
(unison bytevector)
|
||||
(unison core)
|
||||
(only (unison boot) define-unison)
|
||||
(unison data)
|
||||
(unison math)
|
||||
(unison chunked-seq)
|
||||
@ -371,7 +382,21 @@
|
||||
(unison tcp)
|
||||
(unison gzip)
|
||||
(unison zlib)
|
||||
(unison concurrent))
|
||||
(unison concurrent)
|
||||
(racket random))
|
||||
|
||||
; NOTE: this is just a temporary stopgap until the real function is
|
||||
; done. I accidentally pulled in too new a version of base in the
|
||||
; project version of the unison compiler and it broke the jit tests.
|
||||
(define-unison (builtin-Text.indexOf s t)
|
||||
(let ([ss (chunked-string->string s)]
|
||||
[tt (chunked-string->string t)])
|
||||
(match (regexp-match-positions ss tt)
|
||||
[#f (data 'Optional 1)] ; none
|
||||
[(cons (cons i j) r) (data 'Optional 0 i)]))) ; some
|
||||
|
||||
(define-unison (builtin-IO.randomBytes n)
|
||||
(bytes->chunked-bytes (crypto-random-bytes n)))
|
||||
|
||||
(define (unison-POp-UPKB bs)
|
||||
(build-chunked-list
|
||||
@ -579,20 +604,6 @@
|
||||
|
||||
(define (unison-FOp-Char.toText c) (string->chunked-string (string (integer->char c))))
|
||||
|
||||
(define (with-buffer-mode port mode)
|
||||
(file-stream-buffer-mode port mode)
|
||||
port)
|
||||
|
||||
(define stdin (with-buffer-mode (standard-input-port) 'none))
|
||||
(define stdout (with-buffer-mode (standard-output-port) 'line))
|
||||
(define stderr (with-buffer-mode (standard-error-port) 'line))
|
||||
|
||||
(define (unison-FOp-IO.stdHandle n)
|
||||
(case n
|
||||
[(0) stdin]
|
||||
[(1) stdout]
|
||||
[(2) stderr]))
|
||||
|
||||
(define (unison-FOp-IO.getArgs.impl.v1)
|
||||
(sum 1 (cdr (command-line))))
|
||||
|
||||
|
@ -56,11 +56,11 @@ test = do
|
||||
expectExitCode ExitSuccess ucm ["transcript.fork", transcriptFile, "--codebase-create", tempCodebase] "",
|
||||
-- , expectExitCode ExitSuccess ucm ["headless"] "" -- ?
|
||||
-- options
|
||||
expectExitCode ExitSuccess ucm ["--port", "8000", "--codebase-create", tempCodebase, "--no-base"] "exit",
|
||||
expectExitCode ExitSuccess ucm ["--host", "localhost", "--codebase-create", tempCodebase, "--no-base"] "exit",
|
||||
expectExitCode ExitSuccess ucm ["--token", "MY_TOKEN", "--codebase-create", tempCodebase, "--no-base"] "exit", -- ?
|
||||
expectExitCode ExitSuccess ucm ["--codebase-create", tempCodebase, "--no-base"] "exit",
|
||||
expectExitCode ExitSuccess ucm ["--ui", tempCodebase, "--codebase-create", tempCodebase, "--no-base"] "exit",
|
||||
expectExitCode ExitSuccess ucm ["--port", "8000", "--codebase-create", tempCodebase] "exit",
|
||||
expectExitCode ExitSuccess ucm ["--host", "localhost", "--codebase-create", tempCodebase] "exit",
|
||||
expectExitCode ExitSuccess ucm ["--token", "MY_TOKEN", "--codebase-create", tempCodebase] "exit", -- ?
|
||||
expectExitCode ExitSuccess ucm ["--codebase-create", tempCodebase] "exit",
|
||||
expectExitCode ExitSuccess ucm ["--ui", tempCodebase, "--codebase-create", tempCodebase] "exit",
|
||||
scope "can compile, then run compiled artifact" $
|
||||
tests
|
||||
[ expectExitCode ExitSuccess ucm ["transcript", transcriptFile] "",
|
||||
@ -78,7 +78,7 @@ expectExitCode expected cmd args stdin = scope (intercalate " " (cmd : args)) do
|
||||
expectEqual code expected
|
||||
|
||||
defaultArgs :: [String]
|
||||
defaultArgs = ["--codebase-create", tempCodebase, "--no-base"]
|
||||
defaultArgs = ["--codebase-create", tempCodebase]
|
||||
|
||||
clearTempCodebase :: () -> IO ()
|
||||
clearTempCodebase _ =
|
||||
|
@ -189,6 +189,7 @@ default-extensions:
|
||||
- InstanceSigs
|
||||
- LambdaCase
|
||||
- MultiParamTypeClasses
|
||||
- MultiWayIf
|
||||
- NamedFieldPuns
|
||||
- NumericUnderscores
|
||||
- OverloadedLabels
|
||||
|
35
unison-cli/src/Unison/Cli/ServantClientUtils.hs
Normal file
35
unison-cli/src/Unison/Cli/ServantClientUtils.hs
Normal file
@ -0,0 +1,35 @@
|
||||
-- | servant-client utilities
|
||||
module Unison.Cli.ServantClientUtils
|
||||
( ConnectionError (..),
|
||||
classifyConnectionError,
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Exception (fromException)
|
||||
import Network.HTTP.Client qualified as HttpClient
|
||||
import System.IO.Error (isDoesNotExistError)
|
||||
import Unison.Prelude
|
||||
|
||||
data ConnectionError
|
||||
= ConnectionError'Offline
|
||||
| ConnectionError'SomethingElse HttpClient.HttpExceptionContent
|
||||
| ConnectionError'SomethingEntirelyUnexpected SomeException
|
||||
|
||||
-- | Given a 'SomeException' from a @servant-client@ 'ClientError', attempt to classify what happened.
|
||||
classifyConnectionError :: SomeException -> ConnectionError
|
||||
classifyConnectionError exception0 =
|
||||
case fromException exception0 of
|
||||
Just (HttpClient.HttpExceptionRequest _request content) ->
|
||||
fromMaybe (ConnectionError'SomethingElse content) do
|
||||
case content of
|
||||
HttpClient.ConnectionFailure exception1 -> do
|
||||
ioException <- fromException @IOException exception1
|
||||
if
|
||||
| -- This may not be 100% accurate... but if the initial `getAddrInfo` request fails it will indeed throw
|
||||
-- a "does not exist" error. It seems in order to *know* that `getAddrInfo` was the cause of this
|
||||
-- exception, we'd have to parse the `show` output, which is preposterous.
|
||||
isDoesNotExistError ioException ->
|
||||
Just ConnectionError'Offline
|
||||
| otherwise -> Nothing
|
||||
_ -> Nothing
|
||||
_ -> ConnectionError'SomethingEntirelyUnexpected exception0
|
@ -14,10 +14,12 @@ module Unison.Cli.Share.Projects
|
||||
-- * API functions
|
||||
getProjectById,
|
||||
getProjectByName,
|
||||
getProjectByName',
|
||||
createProject,
|
||||
GetProjectBranchResponse (..),
|
||||
getProjectBranchById,
|
||||
getProjectBranchByName,
|
||||
getProjectBranchByName',
|
||||
createProjectBranch,
|
||||
SetProjectBranchHeadResponse (..),
|
||||
setProjectBranchHead,
|
||||
@ -35,6 +37,7 @@ import Network.URI (URI)
|
||||
import Network.URI qualified as URI
|
||||
import Servant.API ((:<|>) (..), (:>))
|
||||
import Servant.Client
|
||||
import Servant.Client qualified as Servant
|
||||
import U.Codebase.Sqlite.DbId (RemoteProjectBranchId (..), RemoteProjectId (..))
|
||||
import U.Codebase.Sqlite.Queries qualified as Queries
|
||||
import Unison.Auth.HTTPClient qualified as Auth
|
||||
@ -54,16 +57,22 @@ import Unison.Share.Types (codeserverBaseURL)
|
||||
-- On success, update the `remote_project` table.
|
||||
getProjectById :: RemoteProjectId -> Cli (Maybe RemoteProject)
|
||||
getProjectById (RemoteProjectId projectId) = do
|
||||
response <- servantClientToCli (getProject0 (Just projectId) Nothing)
|
||||
response <- servantClientToCli (getProject0 (Just projectId) Nothing) & onLeftM servantClientError
|
||||
onGetProjectResponse response
|
||||
|
||||
-- | Get a project by name.
|
||||
--
|
||||
-- On success, update the `remote_project` table.
|
||||
getProjectByName :: ProjectName -> Cli (Maybe RemoteProject)
|
||||
getProjectByName projectName = do
|
||||
response <- servantClientToCli (getProject0 Nothing (Just (into @Text projectName)))
|
||||
onGetProjectResponse response
|
||||
getProjectByName projectName =
|
||||
getProjectByName' projectName & onLeftM servantClientError
|
||||
|
||||
-- | Variant of 'getProjectByName' that returns servant client errors.
|
||||
getProjectByName' :: ProjectName -> Cli (Either Servant.ClientError (Maybe RemoteProject))
|
||||
getProjectByName' projectName = do
|
||||
servantClientToCli (getProject0 Nothing (Just (into @Text projectName))) >>= \case
|
||||
Left err -> pure (Left err)
|
||||
Right response -> Right <$> onGetProjectResponse response
|
||||
|
||||
-- | Create a new project. Kinda weird: returns `Nothing` if the user handle part of the project doesn't exist.
|
||||
--
|
||||
@ -72,9 +81,10 @@ createProject :: ProjectName -> Cli (Maybe RemoteProject)
|
||||
createProject projectName = do
|
||||
let request = Share.API.CreateProjectRequest {projectName = into @Text projectName}
|
||||
servantClientToCli (createProject0 request) >>= \case
|
||||
Share.API.CreateProjectResponseNotFound {} -> pure Nothing
|
||||
Share.API.CreateProjectResponseUnauthorized x -> unauthorized x
|
||||
Share.API.CreateProjectResponseSuccess project -> Just <$> onGotProject project
|
||||
Left err -> servantClientError err
|
||||
Right (Share.API.CreateProjectResponseNotFound {}) -> pure Nothing
|
||||
Right (Share.API.CreateProjectResponseUnauthorized x) -> unauthorized x
|
||||
Right (Share.API.CreateProjectResponseSuccess project) -> Just <$> onGotProject project
|
||||
|
||||
data GetProjectBranchResponse
|
||||
= GetProjectBranchResponseBranchNotFound
|
||||
@ -86,7 +96,7 @@ data GetProjectBranchResponse
|
||||
-- On success, update the `remote_project_branch` table.
|
||||
getProjectBranchById :: ProjectAndBranch RemoteProjectId RemoteProjectBranchId -> Cli GetProjectBranchResponse
|
||||
getProjectBranchById (ProjectAndBranch (RemoteProjectId projectId) (RemoteProjectBranchId branchId)) = do
|
||||
response <- servantClientToCli (getProjectBranch0 projectId (Just branchId) Nothing)
|
||||
response <- servantClientToCli (getProjectBranch0 projectId (Just branchId) Nothing) & onLeftM servantClientError
|
||||
onGetProjectBranchResponse response
|
||||
|
||||
-- | Get a project branch by name.
|
||||
@ -94,19 +104,31 @@ getProjectBranchById (ProjectAndBranch (RemoteProjectId projectId) (RemoteProjec
|
||||
-- On success, update the `remote_project_branch` table.
|
||||
getProjectBranchByName :: ProjectAndBranch RemoteProjectId ProjectBranchName -> Cli GetProjectBranchResponse
|
||||
getProjectBranchByName (ProjectAndBranch (RemoteProjectId projectId) branchName) = do
|
||||
response <- servantClientToCli (getProjectBranch0 projectId Nothing (Just (into @Text branchName)))
|
||||
response <-
|
||||
servantClientToCli (getProjectBranch0 projectId Nothing (Just (into @Text branchName)))
|
||||
& onLeftM servantClientError
|
||||
onGetProjectBranchResponse response
|
||||
|
||||
-- | Variant of 'getProjectBranchByName' that returns servant client errors.
|
||||
getProjectBranchByName' ::
|
||||
ProjectAndBranch RemoteProjectId ProjectBranchName ->
|
||||
Cli (Either Servant.ClientError GetProjectBranchResponse)
|
||||
getProjectBranchByName' (ProjectAndBranch (RemoteProjectId projectId) branchName) = do
|
||||
servantClientToCli (getProjectBranch0 projectId Nothing (Just (into @Text branchName))) >>= \case
|
||||
Left err -> pure (Left err)
|
||||
Right response -> Right <$> onGetProjectBranchResponse response
|
||||
|
||||
-- | Create a new project branch.
|
||||
--
|
||||
-- On success, update the `remote_project_branch` table.
|
||||
createProjectBranch :: Share.API.CreateProjectBranchRequest -> Cli (Maybe RemoteProjectBranch)
|
||||
createProjectBranch request =
|
||||
servantClientToCli (createProjectBranch0 request) >>= \case
|
||||
Share.API.CreateProjectBranchResponseMissingCausalHash hash -> bugRemoteMissingCausalHash hash
|
||||
Share.API.CreateProjectBranchResponseNotFound {} -> pure Nothing
|
||||
Share.API.CreateProjectBranchResponseUnauthorized x -> unauthorized x
|
||||
Share.API.CreateProjectBranchResponseSuccess branch -> Just <$> onGotProjectBranch branch
|
||||
Left err -> servantClientError err
|
||||
Right (Share.API.CreateProjectBranchResponseMissingCausalHash hash) -> bugRemoteMissingCausalHash hash
|
||||
Right (Share.API.CreateProjectBranchResponseNotFound {}) -> pure Nothing
|
||||
Right (Share.API.CreateProjectBranchResponseUnauthorized x) -> unauthorized x
|
||||
Right (Share.API.CreateProjectBranchResponseSuccess branch) -> Just <$> onGotProjectBranch branch
|
||||
|
||||
data SetProjectBranchHeadResponse
|
||||
= SetProjectBranchHeadResponseNotFound
|
||||
@ -121,14 +143,15 @@ data SetProjectBranchHeadResponse
|
||||
setProjectBranchHead :: Share.API.SetProjectBranchHeadRequest -> Cli SetProjectBranchHeadResponse
|
||||
setProjectBranchHead request =
|
||||
servantClientToCli (setProjectBranchHead0 request) >>= \case
|
||||
Share.API.SetProjectBranchHeadResponseUnauthorized x -> unauthorized x
|
||||
Share.API.SetProjectBranchHeadResponseNotFound _ -> pure SetProjectBranchHeadResponseNotFound
|
||||
Share.API.SetProjectBranchHeadResponseMissingCausalHash hash -> bugRemoteMissingCausalHash hash
|
||||
Share.API.SetProjectBranchHeadResponseExpectedCausalHashMismatch expected actual ->
|
||||
Left err -> servantClientError err
|
||||
Right (Share.API.SetProjectBranchHeadResponseUnauthorized x) -> unauthorized x
|
||||
Right (Share.API.SetProjectBranchHeadResponseNotFound _) -> pure SetProjectBranchHeadResponseNotFound
|
||||
Right (Share.API.SetProjectBranchHeadResponseMissingCausalHash hash) -> bugRemoteMissingCausalHash hash
|
||||
Right (Share.API.SetProjectBranchHeadResponseExpectedCausalHashMismatch expected actual) ->
|
||||
pure (SetProjectBranchHeadResponseExpectedCausalHashMismatch expected actual)
|
||||
Share.API.SetProjectBranchHeadResponsePublishedReleaseIsImmutable -> pure SetProjectBranchHeadResponsePublishedReleaseIsImmutable
|
||||
Share.API.SetProjectBranchHeadResponseDeprecatedReleaseIsImmutable -> pure SetProjectBranchHeadResponseDeprecatedReleaseIsImmutable
|
||||
Share.API.SetProjectBranchHeadResponseSuccess -> pure SetProjectBranchHeadResponseSuccess
|
||||
Right (Share.API.SetProjectBranchHeadResponsePublishedReleaseIsImmutable) -> pure SetProjectBranchHeadResponsePublishedReleaseIsImmutable
|
||||
Right (Share.API.SetProjectBranchHeadResponseDeprecatedReleaseIsImmutable) -> pure SetProjectBranchHeadResponseDeprecatedReleaseIsImmutable
|
||||
Right (Share.API.SetProjectBranchHeadResponseSuccess) -> pure SetProjectBranchHeadResponseSuccess
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
-- Database manipulation callbacks
|
||||
@ -152,8 +175,9 @@ onGotProject :: Share.API.Project -> Cli RemoteProject
|
||||
onGotProject project = do
|
||||
let projectId = RemoteProjectId (project ^. #projectId)
|
||||
projectName <- validateProjectName (project ^. #projectName)
|
||||
let latestRelease = (project ^. #latestRelease) >>= eitherToMaybe . tryFrom @Text
|
||||
Cli.runTransaction (Queries.ensureRemoteProject projectId hardCodedUri projectName)
|
||||
pure RemoteProject {projectId, projectName}
|
||||
pure RemoteProject {projectId, projectName, latestRelease}
|
||||
|
||||
onGotProjectBranch :: Share.API.ProjectBranch -> Cli RemoteProjectBranch
|
||||
onGotProjectBranch branch = do
|
||||
@ -186,6 +210,10 @@ validateBranchName branchName =
|
||||
tryInto @ProjectBranchName branchName & onLeft \_ ->
|
||||
Cli.returnEarly (Output.InvalidProjectBranchName branchName)
|
||||
|
||||
servantClientError :: Servant.ClientError -> Cli void
|
||||
servantClientError =
|
||||
Cli.returnEarly . Output.ServantClientError
|
||||
|
||||
unauthorized :: Share.API.Unauthorized -> Cli void
|
||||
unauthorized (Share.API.Unauthorized message) =
|
||||
Cli.returnEarly (Output.Unauthorized message)
|
||||
@ -210,7 +238,7 @@ hardCodedUri =
|
||||
Nothing -> error ("BaseUrl is an invalid URI: " ++ showBaseUrl hardCodedBaseUrl)
|
||||
Just uri -> uri
|
||||
|
||||
servantClientToCli :: ClientM a -> Cli a
|
||||
servantClientToCli :: ClientM a -> Cli (Either Servant.ClientError a)
|
||||
servantClientToCli action = do
|
||||
Cli.Env {authHTTPClient = Auth.AuthenticatedHttpClient httpManager} <- ask
|
||||
|
||||
@ -218,8 +246,7 @@ servantClientToCli action = do
|
||||
clientEnv =
|
||||
mkClientEnv httpManager hardCodedBaseUrl
|
||||
|
||||
liftIO (runClientM action clientEnv) & onLeftM \err ->
|
||||
Cli.returnEarly (Output.ServantClientError err)
|
||||
liftIO (runClientM action clientEnv)
|
||||
|
||||
getProject0 :: Maybe Text -> Maybe Text -> ClientM Share.API.GetProjectResponse
|
||||
createProject0 :: Share.API.CreateProjectRequest -> ClientM Share.API.CreateProjectResponse
|
||||
|
@ -9,13 +9,14 @@ where
|
||||
|
||||
import U.Codebase.Sqlite.DbId (RemoteProjectBranchId (..), RemoteProjectId (..))
|
||||
import Unison.Prelude
|
||||
import Unison.Project (ProjectBranchName, ProjectName)
|
||||
import Unison.Project (ProjectBranchName, ProjectName, Semver)
|
||||
import Unison.Share.API.Hash qualified as Share.API
|
||||
|
||||
-- | A remote project.
|
||||
data RemoteProject = RemoteProject
|
||||
{ projectId :: RemoteProjectId,
|
||||
projectName :: ProjectName
|
||||
projectName :: ProjectName,
|
||||
latestRelease :: Maybe Semver
|
||||
}
|
||||
deriving stock (Eq, Generic, Show)
|
||||
|
||||
|
@ -2,6 +2,7 @@ module Unison.Cli.TypeCheck
|
||||
( typecheck,
|
||||
typecheckHelper,
|
||||
typecheckFile,
|
||||
typecheckFile',
|
||||
typecheckTerm,
|
||||
)
|
||||
where
|
||||
|
@ -106,7 +106,7 @@ import Unison.Codebase.Editor.Input qualified as Input
|
||||
import Unison.Codebase.Editor.Output
|
||||
import Unison.Codebase.Editor.Output qualified as Output
|
||||
import Unison.Codebase.Editor.Output.DumpNamespace qualified as Output.DN
|
||||
import Unison.Codebase.Editor.RemoteRepo (ReadRemoteNamespace (..), ReadShareLooseCode (..), ShareUserHandle (..))
|
||||
import Unison.Codebase.Editor.RemoteRepo (ReadRemoteNamespace (..))
|
||||
import Unison.Codebase.Editor.RemoteRepo qualified as RemoteRepo
|
||||
import Unison.Codebase.Editor.Slurp qualified as Slurp
|
||||
import Unison.Codebase.Editor.SlurpResult qualified as SlurpResult
|
||||
@ -144,6 +144,7 @@ import Unison.HashQualified qualified as HQ
|
||||
import Unison.HashQualified' qualified as HQ'
|
||||
import Unison.HashQualified' qualified as HashQualified
|
||||
import Unison.Hashing.V2.Convert qualified as Hashing
|
||||
import Unison.JitInfo qualified as JitInfo
|
||||
import Unison.LabeledDependency (LabeledDependency)
|
||||
import Unison.LabeledDependency qualified as LD
|
||||
import Unison.LabeledDependency qualified as LabeledDependency
|
||||
@ -215,6 +216,7 @@ import Unison.Var (Var)
|
||||
import Unison.Var qualified as Var
|
||||
import Unison.WatchKind qualified as WK
|
||||
import Web.Browser (openBrowser)
|
||||
import Witch (unsafeFrom)
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
-- Main loop
|
||||
@ -1291,7 +1293,8 @@ loop e = do
|
||||
CompileSchemeI output main -> doCompileScheme output main
|
||||
ExecuteSchemeI main args -> doRunAsScheme main args
|
||||
GenSchemeLibsI -> doGenerateSchemeBoot True Nothing
|
||||
FetchSchemeCompilerI name -> doFetchCompiler name
|
||||
FetchSchemeCompilerI name branch ->
|
||||
doFetchCompiler name branch
|
||||
IOTestI main -> handleIOTest main
|
||||
-- UpdateBuiltinsI -> do
|
||||
-- stepAt updateBuiltins
|
||||
@ -1357,7 +1360,7 @@ loop e = do
|
||||
externalDependencies <-
|
||||
Cli.runTransaction (NamespaceDependencies.namespaceDependencies codebase (Branch.head b))
|
||||
ppe <- PPE.unsuffixifiedPPE <$> currentPrettyPrintEnvDecl Backend.Within
|
||||
Cli.respond $ ListNamespaceDependencies ppe path externalDependencies
|
||||
Cli.respondNumbered $ ListNamespaceDependencies ppe path externalDependencies
|
||||
DebugNumberedArgsI -> do
|
||||
numArgs <- use #numberedArgs
|
||||
Cli.respond (DumpNumberedArgs numArgs)
|
||||
@ -1472,7 +1475,7 @@ loop e = do
|
||||
handleDiffNamespaceToPatch description diffNamespaceToPatchInput
|
||||
ProjectRenameI name -> handleProjectRename name
|
||||
ProjectSwitchI name -> projectSwitch name
|
||||
ProjectCreateI name -> projectCreate name
|
||||
ProjectCreateI tryDownloadingBase name -> projectCreate tryDownloadingBase name
|
||||
ProjectsI -> handleProjects
|
||||
BranchI source name -> handleBranch source name
|
||||
BranchRenameI name -> handleBranchRename name
|
||||
@ -1624,7 +1627,8 @@ inputDescription input =
|
||||
<> Text.unwords (fmap Text.pack args)
|
||||
CompileSchemeI fi nm -> pure ("compile.native " <> HQ.toText nm <> " " <> Text.pack fi)
|
||||
GenSchemeLibsI -> pure "compile.native.genlibs"
|
||||
FetchSchemeCompilerI name -> pure ("compile.native.fetch" <> Text.pack name)
|
||||
FetchSchemeCompilerI name branch ->
|
||||
pure ("compile.native.fetch" <> Text.pack name <> " " <> Text.pack branch)
|
||||
CreateAuthorI (NameSegment id) name -> pure ("create.author " <> id <> " " <> name)
|
||||
RemoveTermReplacementI src p0 -> do
|
||||
p <- opatch p0
|
||||
@ -2436,24 +2440,25 @@ compilerPath = Path.Path' {Path.unPath' = Left abs}
|
||||
rootPath = Path.Path {Path.toSeq = Seq.fromList segs}
|
||||
abs = Path.Absolute {Path.unabsolute = rootPath}
|
||||
|
||||
doFetchCompiler :: String -> Cli ()
|
||||
doFetchCompiler username =
|
||||
doFetchCompiler :: String -> String -> Cli ()
|
||||
doFetchCompiler username branch =
|
||||
doPullRemoteBranch sourceTarget SyncMode.Complete Input.PullWithoutHistory Verbosity.Silent
|
||||
where
|
||||
-- fetching info
|
||||
ns =
|
||||
ReadShareLooseCode
|
||||
{ server = RemoteRepo.DefaultCodeserver,
|
||||
repo = ShareUserHandle (Text.pack username),
|
||||
path =
|
||||
Path.fromList $ NameSegment <$> ["public", "internal", "trunk"]
|
||||
}
|
||||
sourceTarget = PullSourceTarget2 (ReadShare'LooseCode ns) (This compilerPath)
|
||||
prj =
|
||||
These
|
||||
(unsafeFrom $ "@" <> Text.pack username <> "/internal")
|
||||
(unsafeFrom $ Text.pack branch)
|
||||
|
||||
sourceTarget =
|
||||
PullSourceTarget2
|
||||
(ReadShare'ProjectBranch prj)
|
||||
(This compilerPath)
|
||||
|
||||
ensureCompilerExists :: Cli ()
|
||||
ensureCompilerExists =
|
||||
Cli.branchExistsAtPath' compilerPath
|
||||
>>= flip unless (doFetchCompiler "unison")
|
||||
>>= flip unless (doFetchCompiler "unison" JitInfo.currentRelease)
|
||||
|
||||
getCacheDir :: Cli String
|
||||
getCacheDir = liftIO $ getXdgDirectory XdgCache "unisonlanguage"
|
||||
|
@ -4,6 +4,9 @@ module Unison.Codebase.Editor.HandleInput.ProjectCreate
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Lens (over, (^.))
|
||||
import Control.Monad.Reader (ask)
|
||||
import Data.Map.Strict qualified as Map
|
||||
import Data.Text qualified as Text
|
||||
import Data.UUID.V4 qualified as UUID
|
||||
import System.Random.Shuffle qualified as RandomShuffle
|
||||
@ -14,12 +17,19 @@ import Unison.Cli.Monad (Cli)
|
||||
import Unison.Cli.Monad qualified as Cli
|
||||
import Unison.Cli.MonadUtils qualified as Cli (stepAt)
|
||||
import Unison.Cli.ProjectUtils (projectBranchPath)
|
||||
import Unison.Cli.Share.Projects qualified as Share
|
||||
import Unison.Codebase qualified as Codebase
|
||||
import Unison.Codebase.Branch qualified as Branch
|
||||
import Unison.Codebase.Editor.HandleInput.Pull qualified as Pull
|
||||
import Unison.Codebase.Editor.Output qualified as Output
|
||||
import Unison.Codebase.Path qualified as Path
|
||||
import Unison.Name qualified as Name
|
||||
import Unison.NameSegment (NameSegment (NameSegment))
|
||||
import Unison.Prelude
|
||||
import Unison.Project (ProjectAndBranch (..), ProjectBranchName, ProjectName)
|
||||
import Unison.Share.API.Hash qualified as Share.API
|
||||
import Unison.Sqlite qualified as Sqlite
|
||||
import Unison.Sync.Common qualified as Sync.Common
|
||||
import Witch (unsafeFrom)
|
||||
|
||||
-- | Create a new project.
|
||||
@ -48,8 +58,8 @@ import Witch (unsafeFrom)
|
||||
--
|
||||
-- For now, it doesn't seem worth it to do (1) or (2), since we want to do (3) eventually, and we'd rather not waste too
|
||||
-- much time getting everything perfectly correct before we get there.
|
||||
projectCreate :: Maybe ProjectName -> Cli ()
|
||||
projectCreate maybeProjectName = do
|
||||
projectCreate :: Bool -> Maybe ProjectName -> Cli ()
|
||||
projectCreate tryDownloadingBase maybeProjectName = do
|
||||
projectId <- liftIO (ProjectId <$> UUID.nextRandom)
|
||||
branchId <- liftIO (ProjectBranchId <$> UUID.nextRandom)
|
||||
|
||||
@ -78,10 +88,71 @@ projectCreate maybeProjectName = do
|
||||
True -> pure (Left (Output.ProjectNameAlreadyExists projectName))
|
||||
|
||||
let path = projectBranchPath ProjectAndBranch {project = projectId, branch = branchId}
|
||||
Cli.stepAt "project.create" (Path.unabsolute path, const Branch.empty0)
|
||||
Cli.respond (Output.CreatedProject (isNothing maybeProjectName) projectName)
|
||||
Cli.cd path
|
||||
|
||||
maybeBaseLatestReleaseBranchObject <-
|
||||
if tryDownloadingBase
|
||||
then do
|
||||
Cli.respond Output.FetchingLatestReleaseOfBase
|
||||
|
||||
-- Make an effort to pull the latest release of base, which can go wrong in a number of ways, the most likely of
|
||||
-- which is that the user is offline.
|
||||
maybeBaseLatestReleaseBranchObject <-
|
||||
Cli.label \done -> do
|
||||
baseProject <-
|
||||
Share.getProjectByName' (unsafeFrom @Text "@unison/base") >>= \case
|
||||
Right (Just baseProject) -> pure baseProject
|
||||
_ -> done Nothing
|
||||
ver <- baseProject ^. #latestRelease & onNothing (done Nothing)
|
||||
let baseProjectId = baseProject ^. #projectId
|
||||
let baseLatestReleaseBranchName = unsafeFrom @Text ("releases/" <> into @Text ver)
|
||||
response <-
|
||||
Share.getProjectBranchByName' (ProjectAndBranch baseProjectId baseLatestReleaseBranchName)
|
||||
& onLeftM \_err -> done Nothing
|
||||
baseLatestReleaseBranch <-
|
||||
case response of
|
||||
Share.GetProjectBranchResponseBranchNotFound -> done Nothing
|
||||
Share.GetProjectBranchResponseProjectNotFound -> done Nothing
|
||||
Share.GetProjectBranchResponseSuccess branch -> pure branch
|
||||
Pull.downloadShareProjectBranch baseLatestReleaseBranch
|
||||
Cli.Env {codebase} <- ask
|
||||
baseLatestReleaseBranchObject <-
|
||||
liftIO $
|
||||
Codebase.expectBranchForHash
|
||||
codebase
|
||||
(Sync.Common.hash32ToCausalHash (Share.API.hashJWTHash (baseLatestReleaseBranch ^. #branchHead)))
|
||||
pure (Just baseLatestReleaseBranchObject)
|
||||
when (isNothing maybeBaseLatestReleaseBranchObject) do
|
||||
Cli.respond Output.FailedToFetchLatestReleaseOfBase
|
||||
pure maybeBaseLatestReleaseBranchObject
|
||||
else pure Nothing
|
||||
|
||||
let projectBranchObject =
|
||||
case maybeBaseLatestReleaseBranchObject of
|
||||
Nothing -> Branch.empty0
|
||||
Just baseLatestReleaseBranchObject ->
|
||||
let -- lib.base
|
||||
projectBranchLibBaseObject =
|
||||
over
|
||||
Branch.children
|
||||
(Map.insert (NameSegment "base") baseLatestReleaseBranchObject)
|
||||
Branch.empty0
|
||||
projectBranchLibObject = Branch.cons projectBranchLibBaseObject Branch.empty
|
||||
in over
|
||||
Branch.children
|
||||
(Map.insert Name.libSegment projectBranchLibObject)
|
||||
Branch.empty0
|
||||
|
||||
Cli.stepAt reflogDescription (Path.unabsolute path, const projectBranchObject)
|
||||
|
||||
Cli.respond Output.HappyCoding
|
||||
where
|
||||
reflogDescription =
|
||||
case maybeProjectName of
|
||||
Nothing -> "project.create"
|
||||
Just projectName -> "project.create " <> into @Text projectName
|
||||
|
||||
insertProjectAndBranch :: ProjectId -> ProjectName -> ProjectBranchId -> ProjectBranchName -> Sqlite.Transaction ()
|
||||
insertProjectAndBranch projectId projectName branchId branchName = do
|
||||
Queries.insertProject projectId projectName
|
||||
|
@ -5,6 +5,7 @@ module Unison.Codebase.Editor.HandleInput.Pull
|
||||
loadPropagateDiffDefaultPatch,
|
||||
mergeBranchAndPropagateDefaultPatch,
|
||||
propagatePatch,
|
||||
downloadShareProjectBranch,
|
||||
withEntitiesDownloadedProgressCallback,
|
||||
)
|
||||
where
|
||||
@ -180,23 +181,28 @@ loadRemoteNamespaceIntoMemory syncMode pullMode remoteNamespace = do
|
||||
Cli.returnEarly (Output.GitError err)
|
||||
ReadShare'LooseCode repo -> loadShareLooseCodeIntoMemory repo
|
||||
ReadShare'ProjectBranch remoteBranch -> do
|
||||
let repoInfo = Share.RepoInfo (into @Text (ProjectAndBranch (remoteBranch ^. #projectName) remoteProjectBranchName))
|
||||
causalHash = Common.hash32ToCausalHash . Share.hashJWTHash $ causalHashJwt
|
||||
causalHashJwt = remoteBranch ^. #branchHead
|
||||
remoteProjectBranchName = remoteBranch ^. #branchName
|
||||
(result, numDownloaded) <-
|
||||
Cli.with withEntitiesDownloadedProgressCallback \(downloadedCallback, getNumDownloaded) -> do
|
||||
result <- Share.downloadEntities Share.hardCodedBaseUrl repoInfo causalHashJwt downloadedCallback
|
||||
numDownloaded <- liftIO getNumDownloaded
|
||||
pure (result, numDownloaded)
|
||||
case result of
|
||||
Left err0 ->
|
||||
(Cli.returnEarly . Output.ShareError) case err0 of
|
||||
Share.SyncError err -> Output.ShareErrorDownloadEntities err
|
||||
Share.TransportError err -> Output.ShareErrorTransport err
|
||||
Right () -> do
|
||||
Cli.respond (Output.DownloadedEntities numDownloaded)
|
||||
liftIO (Codebase.expectBranchForHash codebase causalHash)
|
||||
downloadShareProjectBranch remoteBranch
|
||||
let causalHash = Common.hash32ToCausalHash (Share.hashJWTHash (remoteBranch ^. #branchHead))
|
||||
liftIO (Codebase.expectBranchForHash codebase causalHash)
|
||||
|
||||
-- | @downloadShareProjectBranch branch@ downloads the given branch.
|
||||
downloadShareProjectBranch :: Share.RemoteProjectBranch -> Cli ()
|
||||
downloadShareProjectBranch branch = do
|
||||
let repoInfo = Share.RepoInfo (into @Text (ProjectAndBranch (branch ^. #projectName) remoteProjectBranchName))
|
||||
causalHashJwt = branch ^. #branchHead
|
||||
remoteProjectBranchName = branch ^. #branchName
|
||||
exists <- Cli.runTransaction (Queries.causalExistsByHash32 (Share.hashJWTHash causalHashJwt))
|
||||
when (not exists) do
|
||||
(result, numDownloaded) <-
|
||||
Cli.with withEntitiesDownloadedProgressCallback \(downloadedCallback, getNumDownloaded) -> do
|
||||
result <- Share.downloadEntities Share.hardCodedBaseUrl repoInfo causalHashJwt downloadedCallback
|
||||
numDownloaded <- liftIO getNumDownloaded
|
||||
pure (result, numDownloaded)
|
||||
result & onLeft \err0 -> do
|
||||
(Cli.returnEarly . Output.ShareError) case err0 of
|
||||
Share.SyncError err -> Output.ShareErrorDownloadEntities err
|
||||
Share.TransportError err -> Output.ShareErrorTransport err
|
||||
Cli.respond (Output.DownloadedEntities numDownloaded)
|
||||
|
||||
loadShareLooseCodeIntoMemory :: ReadShareLooseCode -> Cli (Branch IO)
|
||||
loadShareLooseCodeIntoMemory rrn@(ReadShareLooseCode {server, repo, path}) = do
|
||||
|
@ -178,8 +178,8 @@ data Input
|
||||
CompileSchemeI String (HQ.HashQualified Name)
|
||||
| -- generate scheme libraries
|
||||
GenSchemeLibsI
|
||||
| -- fetch scheme compiler from a given username
|
||||
FetchSchemeCompilerI String
|
||||
| -- fetch scheme compiler from a given username and branch
|
||||
FetchSchemeCompilerI String String
|
||||
| TestI TestInput
|
||||
| -- metadata
|
||||
-- `link metadata definitions` (adds metadata to all of `definitions`)
|
||||
@ -226,7 +226,7 @@ data Input
|
||||
| AuthLoginI
|
||||
| VersionI
|
||||
| DiffNamespaceToPatchI DiffNamespaceToPatchInput
|
||||
| ProjectCreateI (Maybe ProjectName)
|
||||
| ProjectCreateI Bool {- try downloading base? -} (Maybe ProjectName)
|
||||
| ProjectRenameI ProjectName
|
||||
| ProjectSwitchI ProjectAndBranchNames
|
||||
| ProjectsI
|
||||
|
@ -131,6 +131,11 @@ data NumberedOutput
|
||||
| ListBranches ProjectName [(ProjectBranchName, [(URI, ProjectName, ProjectBranchName)])]
|
||||
| AmbiguousSwitch ProjectName (ProjectAndBranch ProjectName ProjectBranchName)
|
||||
| AmbiguousReset AmbiguousReset'Argument (ProjectAndBranch Sqlite.Project Sqlite.ProjectBranch, Path.Path) (ProjectAndBranch ProjectName ProjectBranchName)
|
||||
| -- | List all direct dependencies which don't have any names in the current branch
|
||||
ListNamespaceDependencies
|
||||
PPE.PrettyPrintEnv -- PPE containing names for everything from the root namespace.
|
||||
Path.Absolute -- The namespace we're checking dependencies for.
|
||||
(Map LabeledDependency (Set Name)) -- Mapping of external dependencies to their local dependents.
|
||||
|
||||
data AmbiguousReset'Argument
|
||||
= AmbiguousReset'Hash
|
||||
@ -296,11 +301,6 @@ data Output
|
||||
| ListDependencies PPE.PrettyPrintEnv (Set LabeledDependency) [HQ.HashQualified Name] [HQ.HashQualified Name] -- types, terms
|
||||
| -- | List dependents of a type or term.
|
||||
ListDependents PPE.PrettyPrintEnv (Set LabeledDependency) [HQ.HashQualified Name] [HQ.HashQualified Name] -- types, terms
|
||||
| -- | List all direct dependencies which don't have any names in the current branch
|
||||
ListNamespaceDependencies
|
||||
PPE.PrettyPrintEnv -- PPE containing names for everything from the root namespace.
|
||||
Path.Absolute -- The namespace we're checking dependencies for.
|
||||
(Map LabeledDependency (Set Name)) -- Mapping of external dependencies to their local dependents.
|
||||
| DumpNumberedArgs NumberedArgs
|
||||
| DumpBitBooster CausalHash (Map CausalHash [CausalHash])
|
||||
| DumpUnisonFileHashes Int [(Name, Reference.Id)] [(Name, Reference.Id)] [(Name, Reference.Id)]
|
||||
@ -373,6 +373,9 @@ data Output
|
||||
| RenamedProject ProjectName ProjectName
|
||||
| RenamedProjectBranch ProjectName ProjectBranchName ProjectBranchName
|
||||
| CantRenameBranchTo ProjectBranchName
|
||||
| FetchingLatestReleaseOfBase
|
||||
| FailedToFetchLatestReleaseOfBase
|
||||
| HappyCoding
|
||||
|
||||
-- | What did we create a project branch from?
|
||||
--
|
||||
@ -535,7 +538,6 @@ isFailure o = case o of
|
||||
NoOp -> False
|
||||
ListDependencies {} -> False
|
||||
ListDependents {} -> False
|
||||
ListNamespaceDependencies {} -> False
|
||||
TermMissingType {} -> True
|
||||
DumpUnisonFileHashes _ x y z -> x == mempty && y == mempty && z == mempty
|
||||
NamespaceEmpty {} -> True
|
||||
@ -588,6 +590,9 @@ isFailure o = case o of
|
||||
RenamedProject {} -> False
|
||||
RenamedProjectBranch {} -> False
|
||||
CantRenameBranchTo {} -> True
|
||||
FetchingLatestReleaseOfBase {} -> False
|
||||
FailedToFetchLatestReleaseOfBase {} -> True
|
||||
HappyCoding {} -> False
|
||||
|
||||
isNumberedFailure :: NumberedOutput -> Bool
|
||||
isNumberedFailure = \case
|
||||
@ -610,4 +615,5 @@ isNumberedFailure = \case
|
||||
ShowDiffAfterPull {} -> False
|
||||
ShowDiffAfterUndo {} -> False
|
||||
ShowDiffNamespace {} -> False
|
||||
ListNamespaceDependencies {} -> False
|
||||
TodoOutput _ todo -> TO.todoScore todo > 0 || not (TO.noConflicts todo)
|
||||
|
@ -5,17 +5,16 @@ module Unison.Codebase.Editor.Propagate
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Error.Util (hush)
|
||||
import Control.Lens
|
||||
import Control.Monad.Reader (ask)
|
||||
import Data.Graph qualified as Graph
|
||||
import Data.Map qualified as Map
|
||||
import Data.Set qualified as Set
|
||||
import U.Codebase.Sqlite.Queries qualified as Queries
|
||||
import Unison.Builtin qualified as Builtin
|
||||
import Unison.Cli.Monad (Cli)
|
||||
import Unison.Cli.Monad qualified as Cli
|
||||
import Unison.Cli.MonadUtils qualified as Cli
|
||||
import Unison.Cli.TypeCheck qualified as Cli (typecheckFile')
|
||||
import Unison.Codebase (Codebase)
|
||||
import Unison.Codebase qualified as Codebase
|
||||
import Unison.Codebase.Branch (Branch0 (..))
|
||||
@ -33,7 +32,6 @@ import Unison.Codebase.TypeEdit qualified as TypeEdit
|
||||
import Unison.ConstructorReference (GConstructorReference (..))
|
||||
import Unison.DataDeclaration (Decl)
|
||||
import Unison.DataDeclaration qualified as Decl
|
||||
import Unison.FileParsers (synthesizeFile')
|
||||
import Unison.Hash (Hash)
|
||||
import Unison.Hashing.V2.Convert qualified as Hashing
|
||||
import Unison.Name (Name)
|
||||
@ -555,21 +553,12 @@ propagate patch b = case validatePatch patch of
|
||||
)
|
||||
)
|
||||
mempty
|
||||
typecheckResult <- typecheckFile codebase [] file
|
||||
(runIdentity (Result.toMaybe typecheckResult) >>= hush)
|
||||
typecheckResult <- Cli.typecheckFile' codebase [] file
|
||||
runIdentity (Result.toMaybe typecheckResult)
|
||||
& fmap UF.hashTerms
|
||||
& (fmap . fmap) (\(_ann, ref, wk, tm, tp) -> (ref, wk, tm, tp))
|
||||
& pure
|
||||
|
||||
typecheckFile ::
|
||||
Codebase m Symbol Ann ->
|
||||
[Type Symbol Ann] ->
|
||||
UF.UnisonFile Symbol Ann ->
|
||||
Sqlite.Transaction (Result.Result (Seq (Result.Note Symbol Ann)) (Either x (UF.TypecheckedUnisonFile Symbol Ann)))
|
||||
typecheckFile codebase ambient file = do
|
||||
typeLookup <- Codebase.typeLookupForDependencies codebase (UF.dependencies file)
|
||||
pure . fmap Right $ synthesizeFile' ambient (typeLookup <> Builtin.typeLookup) file
|
||||
|
||||
-- TypecheckFile file ambient -> liftIO $ typecheck' ambient codebase file
|
||||
unhashTypeComponent :: Reference -> Sqlite.Transaction (Map Symbol (Reference, Decl Symbol Ann))
|
||||
unhashTypeComponent r = case Reference.toId r of
|
||||
|
@ -1,47 +0,0 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Unison.Codebase.Editor.VersionParser where
|
||||
|
||||
import Data.Text (Text)
|
||||
import Data.Text qualified as Text
|
||||
import Data.Void (Void)
|
||||
import Text.Megaparsec
|
||||
import Text.Megaparsec.Char
|
||||
import Unison.Codebase.Editor.RemoteRepo
|
||||
import Unison.Codebase.Path qualified as Path
|
||||
|
||||
-- | Parse git version strings into valid unison namespaces.
|
||||
--
|
||||
-- >>> parseMaybe defaultBaseLib "release/M4"
|
||||
-- >>> parseMaybe defaultBaseLib "release/M4b"
|
||||
-- >>> parseMaybe defaultBaseLib "release/M4c.2"
|
||||
-- Just (ReadShareLooseCode {server = DefaultCodeserver, repo = "unison", path = public.base.releases.M4})
|
||||
-- Just (ReadShareLooseCode {server = DefaultCodeserver, repo = "unison", path = public.base.releases.M4b})
|
||||
-- Just (ReadShareLooseCode {server = DefaultCodeserver, repo = "unison", path = public.base.releases.M4c_2})
|
||||
|
||||
-- >>> parseMaybe defaultBaseLib "dev/M4-1-g22ccb0b3b"
|
||||
-- Just (ReadShareLooseCode {server = DefaultCodeserver, repo = "unison", path = public.base.main})
|
||||
|
||||
-- A version with the 'dirty' flag
|
||||
-- >>> parseMaybe defaultBaseLib "dev/M3-409-gbcdf68db3'"
|
||||
-- Just (ReadShareLooseCode {server = DefaultCodeserver, repo = "unison", path = public.base.main})
|
||||
defaultBaseLib :: Parsec Void Text ReadShareLooseCode
|
||||
defaultBaseLib = fmap makeNS $ release <|> unknown
|
||||
where
|
||||
unknown, release, milestoneVersion :: Parsec Void Text Text
|
||||
unknown = pure "main" <* takeWhileP Nothing (const True) <* eof
|
||||
release = fmap ("releases." <>) $ "release/" *> milestoneVersion <* eof
|
||||
-- Parses the milestone of the current version; e.g. M4a -> M4
|
||||
milestoneVersion = do
|
||||
m <- char 'M'
|
||||
milestoneVersion <- some digitChar
|
||||
_minor <- many (alphaNumChar <|> ('_' <$ oneOf ['.', '_', '-']))
|
||||
_dirty <- optional (char '\'')
|
||||
pure . Text.pack $ m : milestoneVersion
|
||||
makeNS :: Text -> ReadShareLooseCode
|
||||
makeNS t =
|
||||
ReadShareLooseCode
|
||||
{ server = DefaultCodeserver,
|
||||
repo = ShareUserHandle "unison",
|
||||
path = "public" Path.:< "base" Path.:< Path.fromText t
|
||||
}
|
@ -8,17 +8,19 @@ import Control.Lens.Cons qualified as Cons
|
||||
import Data.List (intercalate)
|
||||
import Data.List.NonEmpty qualified as NE
|
||||
import Data.Map qualified as Map
|
||||
import Data.Maybe (fromJust)
|
||||
import Data.Proxy (Proxy (..))
|
||||
import Data.Set qualified as Set
|
||||
import Data.Text qualified as Text
|
||||
import Data.These (These (..))
|
||||
import Network.URI qualified as URI
|
||||
import System.Console.Haskeline.Completion (Completion (Completion))
|
||||
import System.Console.Haskeline.Completion qualified as Haskeline
|
||||
import Text.Megaparsec qualified as P
|
||||
import U.Codebase.Sqlite.DbId (ProjectBranchId, ProjectId)
|
||||
import U.Codebase.Sqlite.Project qualified as Sqlite
|
||||
import U.Codebase.Sqlite.Queries qualified as Queries
|
||||
import Unison.Cli.Pretty (prettyProjectNameSlash, prettySlashProjectBranchName)
|
||||
import Unison.Cli.Pretty (prettyProjectNameSlash, prettySlashProjectBranchName, prettyURI)
|
||||
import Unison.Cli.ProjectUtils qualified as ProjectUtils
|
||||
import Unison.Codebase (Codebase)
|
||||
import Unison.Codebase qualified as Codebase
|
||||
@ -44,6 +46,7 @@ import Unison.CommandLine.Globbing qualified as Globbing
|
||||
import Unison.CommandLine.InputPattern (ArgumentType (..), InputPattern (InputPattern), IsOptional (..))
|
||||
import Unison.CommandLine.InputPattern qualified as I
|
||||
import Unison.HashQualified qualified as HQ
|
||||
import Unison.JitInfo qualified as JitInfo
|
||||
import Unison.Name (Name)
|
||||
import Unison.NameSegment qualified as NameSegment
|
||||
import Unison.Prelude
|
||||
@ -722,7 +725,7 @@ deleteProject =
|
||||
InputPattern
|
||||
{ patternName = "delete.project",
|
||||
aliases = ["project.delete"],
|
||||
visibility = I.Hidden,
|
||||
visibility = I.Visible,
|
||||
argTypes = [(Required, projectNameArg)],
|
||||
help =
|
||||
P.wrapColumn2
|
||||
@ -740,7 +743,7 @@ deleteBranch =
|
||||
InputPattern
|
||||
{ patternName = "delete.branch",
|
||||
aliases = ["branch.delete"],
|
||||
visibility = I.Hidden,
|
||||
visibility = I.Visible,
|
||||
argTypes = [(Required, projectBranchNameWithOptionalProjectNameArg)],
|
||||
help =
|
||||
P.wrapColumn2
|
||||
@ -1666,7 +1669,8 @@ helpTopicsMap =
|
||||
("filestatus", fileStatusMsg),
|
||||
("messages.disallowedAbsolute", disallowedAbsoluteMsg),
|
||||
("remotes", remotesMsg),
|
||||
("namespaces", pathnamesMsg)
|
||||
("namespaces", pathnamesMsg),
|
||||
("projects", projectsMsg)
|
||||
]
|
||||
where
|
||||
blankline = ("", "")
|
||||
@ -1790,6 +1794,30 @@ helpTopicsMap =
|
||||
<> "If the project was created locally then the relationship will be established on"
|
||||
<> "the first `push`."
|
||||
]
|
||||
projectsMsg =
|
||||
P.lines $
|
||||
[ P.wrap $
|
||||
"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.",
|
||||
"",
|
||||
P.column2
|
||||
[ (patternName projectCreate, "create a new project"),
|
||||
(patternName projectsInputPattern, "list all your projects"),
|
||||
(patternName branchInputPattern, "create a new workstream"),
|
||||
(patternName branchesInputPattern, "list all your branches"),
|
||||
(patternName mergeLocal, "merge one branch into another"),
|
||||
(patternName projectSwitch, "switch to a project or branch"),
|
||||
(patternName push, "upload your changes to Unison Share"),
|
||||
(patternName pull, "download code(/changes/updates) from Unison Share"),
|
||||
(patternName clone, "download a Unison Share project or branch for contribution")
|
||||
],
|
||||
"",
|
||||
tip ("Use" <> makeExample help [patternName projectCreate] <> "to learn more."),
|
||||
"",
|
||||
P.wrap $
|
||||
"For full documentation, see"
|
||||
<> prettyURI (fromJust (URI.parseURI "https://unison-lang.org/learn/projects"))
|
||||
]
|
||||
|
||||
help :: InputPattern
|
||||
help =
|
||||
@ -1806,10 +1834,24 @@ help =
|
||||
"\n\n"
|
||||
showPatternHelp
|
||||
visibleInputs
|
||||
[isHelp -> Just msg] -> Left msg
|
||||
[cmd] -> case Map.lookup cmd commandsByName of
|
||||
Nothing -> Left . warn $ "I don't know of that command. Try `help`."
|
||||
Just pat -> Left $ showPatternHelp pat
|
||||
[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
|
||||
-- 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 $
|
||||
showPatternHelp pat
|
||||
<> P.newline
|
||||
<> P.newline
|
||||
<> ( tip $
|
||||
"To read more about"
|
||||
<> P.group (P.string cmd <> ",")
|
||||
<> "use"
|
||||
<> makeExample helpTopics [P.string cmd]
|
||||
)
|
||||
_ -> Left $ warn "Use `help <cmd>` or `help`."
|
||||
)
|
||||
where
|
||||
@ -2300,22 +2342,36 @@ fetchScheme =
|
||||
[]
|
||||
( P.wrapColumn2
|
||||
[ ( makeExample fetchScheme [],
|
||||
"Fetches the unison library for compiling to scheme.\n\n\
|
||||
\This is done automatically when"
|
||||
<> P.group (makeExample compileScheme [])
|
||||
<> "is run\
|
||||
\ if the library is not already in the standard location\
|
||||
\ (unison.internal). However, this command will force\
|
||||
\ a pull even if the library already exists. You can also specify\
|
||||
\ a username to pull from (the default is `unison`) to use an alternate\
|
||||
\ implementation of the scheme compiler. It will attempt to fetch\
|
||||
\ [username].public.internal.trunk for use."
|
||||
P.lines . fmap P.wrap $
|
||||
[ "Fetches the unison library for compiling to scheme.",
|
||||
"This is done automatically when"
|
||||
<> P.group (makeExample compileScheme [])
|
||||
<> "is run if the library is not already in the\
|
||||
\ standard location (unison.internal). However,\
|
||||
\ this command will force a pull even if the\
|
||||
\ library already exists.",
|
||||
"You can also specify a user and branch name to pull\
|
||||
\ from in order to use an alternate version of the\
|
||||
\ unison compiler (for development purposes, for\
|
||||
\ example).",
|
||||
"The default user is `unison`. The default branch\
|
||||
\ for the `unison` user is a specified latest\
|
||||
\ version of the compiler for stability. The\
|
||||
\ default branch for other uses is `main`. The\
|
||||
\ command fetches code from a project:",
|
||||
P.indentN 2 ("@user/internal/branch")
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
( \case
|
||||
[] -> pure (Input.FetchSchemeCompilerI "unison")
|
||||
[name] -> pure (Input.FetchSchemeCompilerI name)
|
||||
[] -> pure (Input.FetchSchemeCompilerI "unison" JitInfo.currentRelease)
|
||||
[name] -> pure (Input.FetchSchemeCompilerI name branch)
|
||||
where
|
||||
branch
|
||||
| name == "unison" = JitInfo.currentRelease
|
||||
| otherwise = "main"
|
||||
[name, branch] -> pure (Input.FetchSchemeCompilerI name branch)
|
||||
_ -> Left $ showPatternHelp fetchScheme
|
||||
)
|
||||
|
||||
@ -2430,7 +2486,7 @@ projectCreate =
|
||||
InputPattern
|
||||
{ patternName = "project.create",
|
||||
aliases = ["create.project"],
|
||||
visibility = I.Hidden,
|
||||
visibility = I.Visible,
|
||||
argTypes = [],
|
||||
help =
|
||||
P.wrapColumn2
|
||||
@ -2441,8 +2497,28 @@ projectCreate =
|
||||
[name] ->
|
||||
case tryInto @ProjectName (Text.pack name) of
|
||||
Left _ -> Left "Invalid project name."
|
||||
Right name1 -> Right (Input.ProjectCreateI (Just name1))
|
||||
_ -> Right (Input.ProjectCreateI Nothing)
|
||||
Right name1 -> Right (Input.ProjectCreateI True (Just name1))
|
||||
_ -> Right (Input.ProjectCreateI True Nothing)
|
||||
}
|
||||
|
||||
projectCreateEmptyInputPattern :: InputPattern
|
||||
projectCreateEmptyInputPattern =
|
||||
InputPattern
|
||||
{ patternName = "project.create-empty",
|
||||
aliases = ["create.empty-project"],
|
||||
visibility = I.Hidden,
|
||||
argTypes = [],
|
||||
help =
|
||||
P.wrapColumn2
|
||||
[ ("`project.create-empty`", "creates an empty project with a random name"),
|
||||
("`project.create-empty foo`", "creates an empty project named `foo`")
|
||||
],
|
||||
parse = \case
|
||||
[name] ->
|
||||
case tryInto @ProjectName (Text.pack name) of
|
||||
Left _ -> Left "Invalid project name."
|
||||
Right name1 -> Right (Input.ProjectCreateI False (Just name1))
|
||||
_ -> Right (Input.ProjectCreateI False Nothing)
|
||||
}
|
||||
|
||||
projectRenameInputPattern :: InputPattern
|
||||
@ -2450,7 +2526,7 @@ projectRenameInputPattern =
|
||||
InputPattern
|
||||
{ patternName = "project.rename",
|
||||
aliases = ["rename.project"],
|
||||
visibility = I.Hidden,
|
||||
visibility = I.Visible,
|
||||
argTypes = [],
|
||||
help =
|
||||
P.wrapColumn2
|
||||
@ -2466,7 +2542,7 @@ projectSwitch =
|
||||
InputPattern
|
||||
{ patternName = "switch",
|
||||
aliases = [],
|
||||
visibility = I.Hidden,
|
||||
visibility = I.Visible,
|
||||
argTypes = [(Required, projectAndBranchNamesArg False)],
|
||||
help =
|
||||
P.wrapColumn2
|
||||
@ -2487,7 +2563,7 @@ projectsInputPattern =
|
||||
InputPattern
|
||||
{ patternName = "projects",
|
||||
aliases = ["list.project", "ls.project", "project.list"],
|
||||
visibility = I.Hidden,
|
||||
visibility = I.Visible,
|
||||
argTypes = [],
|
||||
help = P.wrap "List projects.",
|
||||
parse = \_ -> Right Input.ProjectsI
|
||||
@ -2498,7 +2574,7 @@ branchesInputPattern =
|
||||
InputPattern
|
||||
{ patternName = "branches",
|
||||
aliases = ["list.branch", "ls.branch", "branch.list"],
|
||||
visibility = I.Hidden,
|
||||
visibility = I.Visible,
|
||||
argTypes = [],
|
||||
help =
|
||||
P.wrapColumn2
|
||||
@ -2516,7 +2592,7 @@ branchInputPattern =
|
||||
InputPattern
|
||||
{ patternName = "branch",
|
||||
aliases = ["branch.create", "create.branch"],
|
||||
visibility = I.Hidden,
|
||||
visibility = I.Visible,
|
||||
argTypes = [],
|
||||
help =
|
||||
P.wrapColumn2
|
||||
@ -2547,7 +2623,7 @@ branchEmptyInputPattern =
|
||||
InputPattern
|
||||
{ patternName = "branch.empty",
|
||||
aliases = ["branch.create-empty", "create.empty-branch"],
|
||||
visibility = I.Hidden,
|
||||
visibility = I.Visible,
|
||||
argTypes = [],
|
||||
help = P.wrap "Create a new empty branch.",
|
||||
parse = \case
|
||||
@ -2563,7 +2639,7 @@ branchRenameInputPattern =
|
||||
InputPattern
|
||||
{ patternName = "branch.rename",
|
||||
aliases = ["rename.branch"],
|
||||
visibility = I.Hidden,
|
||||
visibility = I.Visible,
|
||||
argTypes = [],
|
||||
help =
|
||||
P.wrapColumn2
|
||||
@ -2579,7 +2655,7 @@ clone =
|
||||
InputPattern
|
||||
{ patternName = "clone",
|
||||
aliases = [],
|
||||
visibility = I.Hidden,
|
||||
visibility = I.Visible,
|
||||
argTypes = [],
|
||||
help =
|
||||
P.wrapColumn2
|
||||
@ -2620,7 +2696,7 @@ releaseDraft =
|
||||
InputPattern
|
||||
{ patternName = "release.draft",
|
||||
aliases = ["draft.release"],
|
||||
visibility = I.Hidden,
|
||||
visibility = I.Visible,
|
||||
argTypes = [],
|
||||
help = P.wrap "Draft a release.",
|
||||
parse = \case
|
||||
@ -2711,6 +2787,7 @@ validInputs =
|
||||
previewUpdate,
|
||||
printVersion,
|
||||
projectCreate,
|
||||
projectCreateEmptyInputPattern,
|
||||
projectRenameInputPattern,
|
||||
projectSwitch,
|
||||
projectsInputPattern,
|
||||
|
@ -156,8 +156,7 @@ main dir welcome initialPath config initialInputs runtime sbRuntime codebase ser
|
||||
loop currentRoot
|
||||
loop Nothing
|
||||
eventQueue <- Q.newIO
|
||||
welcomeEvents <- Welcome.run codebase welcome
|
||||
initialInputsRef <- newIORef $ welcomeEvents ++ initialInputs
|
||||
initialInputsRef <- newIORef $ Welcome.run welcome ++ initialInputs
|
||||
pageOutput <- newIORef True
|
||||
cancelFileSystemWatch <- case shouldWatchFiles of
|
||||
ShouldNotWatchFiles -> pure (pure ())
|
||||
|
@ -29,11 +29,7 @@ import Network.HTTP.Types qualified as Http
|
||||
import Servant.Client qualified as Servant
|
||||
import System.Console.ANSI qualified as ANSI
|
||||
import System.Console.Haskeline.Completion qualified as Completion
|
||||
import System.Directory
|
||||
( canonicalizePath,
|
||||
doesFileExist,
|
||||
getHomeDirectory,
|
||||
)
|
||||
import System.Directory (canonicalizePath, doesFileExist, getHomeDirectory)
|
||||
import U.Codebase.Branch (NamespaceStats (..))
|
||||
import U.Codebase.Branch.Diff (NameChanges (..))
|
||||
import U.Codebase.HashTags (CausalHash (..))
|
||||
@ -43,6 +39,7 @@ import Unison.Auth.Types qualified as Auth
|
||||
import Unison.Builtin.Decls qualified as DD
|
||||
import Unison.Cli.Pretty
|
||||
import Unison.Cli.ProjectUtils qualified as ProjectUtils
|
||||
import Unison.Cli.ServantClientUtils qualified as ServantClientUtils
|
||||
import Unison.Codebase.Editor.DisplayObject (DisplayObject (BuiltinObject, MissingObject, UserObject))
|
||||
import Unison.Codebase.Editor.Input qualified as Input
|
||||
import Unison.Codebase.Editor.Output
|
||||
@ -490,6 +487,48 @@ notifyNumbered = \case
|
||||
reset = IP.makeExample IP.reset
|
||||
relPath0 = prettyPath' (Path.toPath' path)
|
||||
absPath0 = review ProjectUtils.projectBranchPathPrism (ProjectAndBranch (pn0 ^. #projectId) (bn0 ^. #branchId), path)
|
||||
ListNamespaceDependencies _ppe _path Empty -> ("This namespace has no external dependencies.", mempty)
|
||||
ListNamespaceDependencies ppe path' externalDependencies ->
|
||||
( P.column2Header (P.hiBlack "External dependency") ("Dependents in " <> prettyAbsolute path') $
|
||||
List.intersperse spacer (externalDepsTable externalDependencies),
|
||||
numberedArgs
|
||||
)
|
||||
where
|
||||
spacer = ("", "")
|
||||
(nameNumbers, numberedArgs) = numberedDependents externalDependencies
|
||||
getNameNumber name = fromMaybe (error "ListNamespaceDependencies: name is missing number") (Map.lookup name nameNumbers)
|
||||
numberedDependents :: Map LabeledDependency (Set Name) -> (Map Name Int, NumberedArgs)
|
||||
numberedDependents deps =
|
||||
deps
|
||||
& Map.elems
|
||||
& List.foldl'
|
||||
( \(nextNum, (nameToNum, args)) names ->
|
||||
let unnumberedNames = Set.toList $ Set.difference names (Map.keysSet nameToNum)
|
||||
newNextNum = nextNum + length unnumberedNames
|
||||
in ( newNextNum,
|
||||
( nameToNum <> (Map.fromList (zip unnumberedNames [nextNum ..])),
|
||||
args <> fmap Name.toString unnumberedNames
|
||||
)
|
||||
)
|
||||
)
|
||||
(1, (mempty, mempty))
|
||||
& snd
|
||||
externalDepsTable :: Map LabeledDependency (Set Name) -> [(P.Pretty P.ColorText, P.Pretty P.ColorText)]
|
||||
externalDepsTable = ifoldMap $ \ld dependents ->
|
||||
[(prettyLD ld, prettyDependents dependents)]
|
||||
prettyLD :: LabeledDependency -> P.Pretty P.ColorText
|
||||
prettyLD =
|
||||
P.syntaxToColor
|
||||
. prettyHashQualified
|
||||
. LD.fold
|
||||
(PPE.typeName ppe)
|
||||
(PPE.termName ppe)
|
||||
prettyDependents :: Set Name -> P.Pretty P.ColorText
|
||||
prettyDependents refs =
|
||||
refs
|
||||
& Set.toList
|
||||
& fmap (\name -> formatNum (getNameNumber name) <> prettyName name)
|
||||
& P.lines
|
||||
where
|
||||
absPathToBranchId = Right
|
||||
|
||||
@ -1657,28 +1696,6 @@ notifyUser dir = \case
|
||||
pure $ listDependentsOrDependencies ppe "Dependents" "dependents" lds types terms
|
||||
ListDependencies ppe lds types terms ->
|
||||
pure $ listDependentsOrDependencies ppe "Dependencies" "dependencies" lds types terms
|
||||
ListNamespaceDependencies _ppe _path Empty -> pure $ "This namespace has no external dependencies."
|
||||
ListNamespaceDependencies ppe path' externalDependencies -> do
|
||||
let spacer = ("", "")
|
||||
pure . P.column2Header (P.hiBlack "External dependency") ("Dependents in " <> prettyAbsolute path') $
|
||||
List.intersperse spacer (externalDepsTable externalDependencies)
|
||||
where
|
||||
externalDepsTable :: Map LabeledDependency (Set Name) -> [(P.Pretty P.ColorText, P.Pretty P.ColorText)]
|
||||
externalDepsTable = ifoldMap $ \ld dependents ->
|
||||
[(prettyLD ld, prettyDependents dependents)]
|
||||
prettyLD :: LabeledDependency -> P.Pretty P.ColorText
|
||||
prettyLD =
|
||||
P.syntaxToColor
|
||||
. prettyHashQualified
|
||||
. LD.fold
|
||||
(PPE.typeName ppe)
|
||||
(PPE.termName ppe)
|
||||
prettyDependents :: Set Name -> P.Pretty P.ColorText
|
||||
prettyDependents refs =
|
||||
refs
|
||||
& Set.toList
|
||||
& fmap prettyName
|
||||
& P.lines
|
||||
DumpUnisonFileHashes hqLength datas effects terms ->
|
||||
pure . P.syntaxToColor . P.lines $
|
||||
( effects <&> \(n, r) ->
|
||||
@ -1944,7 +1961,13 @@ notifyUser dir = \case
|
||||
P.text ("Unauthorized: " <> message)
|
||||
ServantClientError err ->
|
||||
pure case err of
|
||||
Servant.ConnectionError _exception -> P.wrap "Something went wrong with the connection. Try again?"
|
||||
Servant.ConnectionError exception ->
|
||||
P.wrap $
|
||||
fromMaybe "Something went wrong with the connection. Try again?" do
|
||||
case ServantClientUtils.classifyConnectionError exception of
|
||||
ServantClientUtils.ConnectionError'Offline -> Just "You appear to be offline."
|
||||
ServantClientUtils.ConnectionError'SomethingElse _ -> Nothing
|
||||
ServantClientUtils.ConnectionError'SomethingEntirelyUnexpected _ -> Nothing
|
||||
Servant.DecodeFailure message response ->
|
||||
P.wrap "Huh, I failed to decode a response from the server."
|
||||
<> P.newline
|
||||
@ -2092,6 +2115,34 @@ notifyUser dir = \case
|
||||
CantRenameBranchTo branch ->
|
||||
pure . P.wrap $
|
||||
"You can't rename a branch to" <> P.group (prettyProjectBranchName branch <> ".")
|
||||
FetchingLatestReleaseOfBase ->
|
||||
pure . P.wrap $
|
||||
"I'll now fetch the latest version of the base Unison library..."
|
||||
FailedToFetchLatestReleaseOfBase ->
|
||||
pure . P.wrap $ "Sorry something went wrong while fetching the library."
|
||||
HappyCoding -> do
|
||||
pure $
|
||||
P.wrap "🎨 Type `ui` to explore this project's code in your browser."
|
||||
<> P.newline
|
||||
<> P.wrap ("🔭 Discover libraries at https://share.unison-lang.org")
|
||||
<> P.newline
|
||||
<> P.wrap "📖 Use `help-topic projects` to learn more about projects."
|
||||
<> P.newline
|
||||
<> P.newline
|
||||
<> P.wrap "Write your first Unison code with UCM:"
|
||||
<> P.newline
|
||||
<> P.newline
|
||||
<> P.indentN
|
||||
2
|
||||
( P.wrap "1. Open scratch.u."
|
||||
<> P.newline
|
||||
<> P.wrap "2. Write some Unison code and save the file."
|
||||
<> P.newline
|
||||
<> P.wrap "3. In UCM, type `add` to save it to your new project."
|
||||
)
|
||||
<> P.newline
|
||||
<> P.newline
|
||||
<> P.wrap "🎉 🥳 Happy coding!"
|
||||
where
|
||||
_nameChange _cmd _pastTenseCmd _oldName _newName _r = error "todo"
|
||||
|
||||
|
@ -1,35 +1,22 @@
|
||||
module Unison.CommandLine.Welcome where
|
||||
module Unison.CommandLine.Welcome
|
||||
( CodebaseInitStatus (..),
|
||||
Welcome (..),
|
||||
asciiartUnison,
|
||||
run,
|
||||
welcome,
|
||||
)
|
||||
where
|
||||
|
||||
import Data.Sequence (singleton)
|
||||
import Data.These (These (..))
|
||||
import System.Random (randomRIO)
|
||||
import Unison.Codebase (Codebase)
|
||||
import Unison.Codebase qualified as Codebase
|
||||
import Unison.Codebase.Editor.Input
|
||||
import Unison.Codebase.Editor.RemoteRepo (ReadRemoteNamespace (..), ReadShareLooseCode (..))
|
||||
import Unison.Codebase.Path (Path)
|
||||
import Unison.Codebase.Path qualified as Path
|
||||
import Unison.Codebase.SyncMode qualified as SyncMode
|
||||
import Unison.Codebase.Verbosity qualified as Verbosity
|
||||
import Unison.CommandLine.Types (ShouldWatchFiles (..))
|
||||
import Unison.NameSegment (NameSegment (NameSegment))
|
||||
import Unison.Prelude
|
||||
import Unison.Util.Pretty qualified as P
|
||||
import Prelude hiding (readFile, writeFile)
|
||||
|
||||
data Welcome = Welcome
|
||||
{ onboarding :: Onboarding, -- Onboarding States
|
||||
downloadBase :: DownloadBase,
|
||||
watchDir :: FilePath,
|
||||
unisonVersion :: Text,
|
||||
shouldWatchFiles :: ShouldWatchFiles
|
||||
unisonVersion :: Text
|
||||
}
|
||||
|
||||
data DownloadBase
|
||||
= DownloadBase ReadShareLooseCode
|
||||
| DontDownloadBase
|
||||
deriving (Show, Eq)
|
||||
|
||||
-- Previously Created is different from Previously Onboarded because a user can
|
||||
-- 1.) create a new codebase
|
||||
-- 2.) decide not to go through the onboarding flow until later and exit
|
||||
@ -40,80 +27,44 @@ data CodebaseInitStatus
|
||||
deriving (Show, Eq)
|
||||
|
||||
data Onboarding
|
||||
= Init CodebaseInitStatus -- Can transition to [DownloadingBase, Author, Finished, PreviouslyOnboarded]
|
||||
| DownloadingBase ReadShareLooseCode -- Can transition to [Author, Finished]
|
||||
= Init CodebaseInitStatus -- Can transition to [Author, Finished, PreviouslyOnboarded]
|
||||
| Author -- Can transition to [Finished]
|
||||
-- End States
|
||||
| Finished
|
||||
| PreviouslyOnboarded
|
||||
deriving (Show, Eq)
|
||||
|
||||
welcome :: CodebaseInitStatus -> DownloadBase -> FilePath -> Text -> ShouldWatchFiles -> Welcome
|
||||
welcome initStatus downloadBase filePath unisonVersion shouldWatchFiles =
|
||||
Welcome (Init initStatus) downloadBase filePath unisonVersion shouldWatchFiles
|
||||
welcome :: CodebaseInitStatus -> Text -> Welcome
|
||||
welcome initStatus unisonVersion =
|
||||
Welcome (Init initStatus) unisonVersion
|
||||
|
||||
pullBase :: ReadShareLooseCode -> Either Event Input
|
||||
pullBase ns =
|
||||
let seg = NameSegment "base"
|
||||
rootPath = Path.Path {Path.toSeq = singleton seg}
|
||||
abs = Path.Absolute {Path.unabsolute = rootPath}
|
||||
pullRemote =
|
||||
PullRemoteBranchI
|
||||
( PullSourceTarget2
|
||||
(ReadShare'LooseCode ns)
|
||||
(This (Path.Path' {Path.unPath' = Left abs}))
|
||||
)
|
||||
SyncMode.Complete
|
||||
PullWithHistory
|
||||
Verbosity.Silent
|
||||
in Right pullRemote
|
||||
|
||||
run :: Codebase IO v a -> Welcome -> IO [Either Event Input]
|
||||
run codebase Welcome {onboarding = onboarding, downloadBase = downloadBase, watchDir = dir, unisonVersion = version, shouldWatchFiles} = do
|
||||
run :: Welcome -> [Either Event Input]
|
||||
run Welcome {onboarding = onboarding, unisonVersion = version} = do
|
||||
go onboarding []
|
||||
where
|
||||
go :: Onboarding -> [Either Event Input] -> IO [Either Event Input]
|
||||
go :: Onboarding -> [Either Event Input] -> [Either Event Input]
|
||||
go onboarding acc =
|
||||
case onboarding of
|
||||
Init NewlyCreatedCodebase -> do
|
||||
determineFirstStep downloadBase codebase >>= \step -> go step (headerMsg : acc)
|
||||
go PreviouslyOnboarded (headerMsg : acc)
|
||||
where
|
||||
headerMsg = toInput (header version)
|
||||
Init PreviouslyCreatedCodebase -> do
|
||||
go PreviouslyOnboarded (headerMsg : acc)
|
||||
where
|
||||
headerMsg = toInput (header version)
|
||||
DownloadingBase ns@(ReadShareLooseCode {path}) ->
|
||||
go Author ([pullBaseInput, downloadMsg] ++ acc)
|
||||
where
|
||||
downloadMsg = Right $ CreateMessage (downloading path)
|
||||
pullBaseInput = pullBase ns
|
||||
Author ->
|
||||
go Finished (authorMsg : acc)
|
||||
where
|
||||
authorMsg = toInput authorSuggestion
|
||||
-- These are our two terminal Welcome conditions, at the end we reverse the order of the desired input commands otherwise they come out backwards
|
||||
Finished -> do
|
||||
startMsg <- getStarted shouldWatchFiles dir
|
||||
pure $ reverse (toInput startMsg : acc)
|
||||
PreviouslyOnboarded -> do
|
||||
startMsg <- getStarted shouldWatchFiles dir
|
||||
pure $ reverse (toInput startMsg : acc)
|
||||
Finished -> reverse (toInput getStarted : acc)
|
||||
PreviouslyOnboarded -> reverse (toInput getStarted : acc)
|
||||
|
||||
toInput :: P.Pretty P.ColorText -> Either Event Input
|
||||
toInput pretty =
|
||||
Right $ CreateMessage pretty
|
||||
|
||||
determineFirstStep :: DownloadBase -> Codebase IO v a -> IO Onboarding
|
||||
determineFirstStep downloadBase codebase = do
|
||||
isEmptyCodebase <- Codebase.runTransaction codebase Codebase.getRootBranchExists
|
||||
case downloadBase of
|
||||
DownloadBase ns
|
||||
| isEmptyCodebase ->
|
||||
pure $ DownloadingBase ns
|
||||
_ ->
|
||||
pure PreviouslyOnboarded
|
||||
|
||||
asciiartUnison :: P.Pretty P.ColorText
|
||||
asciiartUnison =
|
||||
P.red " _____"
|
||||
@ -139,20 +90,6 @@ asciiartUnison =
|
||||
<> P.cyan "|___|"
|
||||
<> P.purple "_|_|"
|
||||
|
||||
downloading :: Path -> P.Pretty P.ColorText
|
||||
downloading path =
|
||||
P.lines
|
||||
[ P.group (P.wrap "🐣 Since this is a fresh codebase, let me download the base library for you." <> P.newline),
|
||||
P.wrap
|
||||
( "🕐 Downloading"
|
||||
<> P.blue (P.string (show path))
|
||||
<> "of the"
|
||||
<> P.bold "base library"
|
||||
<> "into"
|
||||
<> P.group (P.blue ".base" <> ", this may take a minute...")
|
||||
)
|
||||
]
|
||||
|
||||
header :: Text -> P.Pretty P.ColorText
|
||||
header version =
|
||||
asciiartUnison
|
||||
@ -173,22 +110,9 @@ authorSuggestion =
|
||||
P.wrap $ P.blue "https://www.unison-lang.org/learn/tooling/configuration/"
|
||||
]
|
||||
|
||||
getStarted :: ShouldWatchFiles -> FilePath -> IO (P.Pretty P.ColorText)
|
||||
getStarted shouldWatchFiles dir = do
|
||||
earth <- (["🌎", "🌍", "🌏"] !!) <$> randomRIO (0, 2)
|
||||
|
||||
pure $
|
||||
P.linesSpaced
|
||||
[ P.wrap "Get started:",
|
||||
P.indentN 2 $
|
||||
P.column2
|
||||
( [ ("📖", "Type " <> P.hiBlue "help" <> " to list all commands, or " <> P.hiBlue "help <cmd>" <> " to view help for one command"),
|
||||
("🎨", "Type " <> P.hiBlue "ui" <> " to open the Codebase UI in your default browser"),
|
||||
("📚", "Read the official docs at " <> P.blue "https://www.unison-lang.org/learn/"),
|
||||
(earth, "Visit Unison Share at " <> P.blue "https://share.unison-lang.org" <> " to discover libraries")
|
||||
]
|
||||
<> case shouldWatchFiles of
|
||||
ShouldWatchFiles -> [("👀", "I'm watching for changes to " <> P.bold ".u" <> " files under " <> (P.group . P.blue $ P.string dir))]
|
||||
ShouldNotWatchFiles -> [("📝", "File watching is disabled, use the 'load' command to parse and typecheck unison files.")]
|
||||
)
|
||||
]
|
||||
getStarted :: P.Pretty P.ColorText
|
||||
getStarted =
|
||||
P.wrap "📚 Read the official docs at https://www.unison-lang.org/learn/"
|
||||
<> P.newline
|
||||
<> P.newline
|
||||
<> P.wrap "Type 'project.create' to get started."
|
||||
|
4
unison-cli/src/Unison/JitInfo.hs
Normal file
4
unison-cli/src/Unison/JitInfo.hs
Normal file
@ -0,0 +1,4 @@
|
||||
module Unison.JitInfo (currentRelease) where
|
||||
|
||||
currentRelease :: String
|
||||
currentRelease = "releases/0.0.1"
|
@ -9,7 +9,6 @@ import Unison.Test.Cli.Monad qualified as Cli.Monad
|
||||
import Unison.Test.GitSync qualified as GitSync
|
||||
import Unison.Test.LSP qualified as LSP
|
||||
import Unison.Test.UriParser qualified as UriParser
|
||||
import Unison.Test.VersionParser qualified as VersionParser
|
||||
|
||||
test :: Test ()
|
||||
test =
|
||||
@ -18,8 +17,7 @@ test =
|
||||
ClearCache.test,
|
||||
Cli.Monad.test,
|
||||
GitSync.test,
|
||||
UriParser.test,
|
||||
VersionParser.test
|
||||
UriParser.test
|
||||
]
|
||||
|
||||
main :: IO ()
|
||||
|
@ -1,37 +0,0 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Unison.Test.VersionParser where
|
||||
|
||||
import Control.Error.Safe (rightMay)
|
||||
import Data.Text
|
||||
import EasyTest
|
||||
import Text.Megaparsec
|
||||
import Unison.Codebase.Editor.RemoteRepo
|
||||
import Unison.Codebase.Editor.VersionParser
|
||||
import Unison.Codebase.Path qualified as Path
|
||||
|
||||
test :: Test ()
|
||||
test =
|
||||
scope "versionparser" . tests . fmap makeTest $
|
||||
[ ("latest-abc", "main"),
|
||||
("dev/M4", "main"), -- or should this be "releases.M4"?
|
||||
("dev/M4-1-g22ccb0b3b", "main"), -- and should this also be "releases.m4"?
|
||||
-- All non-dev releases should pull from the most recent major milestone
|
||||
("release/M4", "releases.M4"),
|
||||
("release/M2i_3", "releases.M2"),
|
||||
("release/M2i-HOTFIX", "releases.M2")
|
||||
]
|
||||
|
||||
makeTest :: (Text, Text) -> Test ()
|
||||
makeTest (version, path) =
|
||||
scope (unpack version) $
|
||||
expectEqual
|
||||
(rightMay $ runParser defaultBaseLib "versionparser" version)
|
||||
( Just
|
||||
( ReadShareLooseCode
|
||||
{ server = DefaultCodeserver,
|
||||
repo = ShareUserHandle "unison",
|
||||
path = Path.fromList ["public", "base"] <> Path.fromText path
|
||||
}
|
||||
)
|
||||
)
|
@ -37,6 +37,7 @@ library
|
||||
Unison.Cli.Pretty
|
||||
Unison.Cli.PrettyPrintUtils
|
||||
Unison.Cli.ProjectUtils
|
||||
Unison.Cli.ServantClientUtils
|
||||
Unison.Cli.Share.Projects
|
||||
Unison.Cli.Share.Projects.Types
|
||||
Unison.Cli.TypeCheck
|
||||
@ -75,7 +76,6 @@ library
|
||||
Unison.Codebase.Editor.TodoOutput
|
||||
Unison.Codebase.Editor.UCMVersion
|
||||
Unison.Codebase.Editor.UriParser
|
||||
Unison.Codebase.Editor.VersionParser
|
||||
Unison.Codebase.TranscriptParser
|
||||
Unison.CommandLine
|
||||
Unison.CommandLine.Completion
|
||||
@ -88,6 +88,7 @@ library
|
||||
Unison.CommandLine.OutputMessages
|
||||
Unison.CommandLine.Types
|
||||
Unison.CommandLine.Welcome
|
||||
Unison.JitInfo
|
||||
Unison.LSP
|
||||
Unison.LSP.CancelRequest
|
||||
Unison.LSP.CodeAction
|
||||
@ -132,6 +133,7 @@ library
|
||||
InstanceSigs
|
||||
LambdaCase
|
||||
MultiParamTypeClasses
|
||||
MultiWayIf
|
||||
NamedFieldPuns
|
||||
NumericUnderscores
|
||||
OverloadedLabels
|
||||
@ -261,6 +263,7 @@ executable cli-integration-tests
|
||||
InstanceSigs
|
||||
LambdaCase
|
||||
MultiParamTypeClasses
|
||||
MultiWayIf
|
||||
NamedFieldPuns
|
||||
NumericUnderscores
|
||||
OverloadedLabels
|
||||
@ -390,6 +393,7 @@ executable transcripts
|
||||
InstanceSigs
|
||||
LambdaCase
|
||||
MultiParamTypeClasses
|
||||
MultiWayIf
|
||||
NamedFieldPuns
|
||||
NumericUnderscores
|
||||
OverloadedLabels
|
||||
@ -523,6 +527,7 @@ executable unison
|
||||
InstanceSigs
|
||||
LambdaCase
|
||||
MultiParamTypeClasses
|
||||
MultiWayIf
|
||||
NamedFieldPuns
|
||||
NumericUnderscores
|
||||
OverloadedLabels
|
||||
@ -638,7 +643,6 @@ test-suite cli-tests
|
||||
Unison.Test.LSP
|
||||
Unison.Test.Ucm
|
||||
Unison.Test.UriParser
|
||||
Unison.Test.VersionParser
|
||||
hs-source-dirs:
|
||||
tests
|
||||
default-extensions:
|
||||
@ -662,6 +666,7 @@ test-suite cli-tests
|
||||
InstanceSigs
|
||||
LambdaCase
|
||||
MultiParamTypeClasses
|
||||
MultiWayIf
|
||||
NamedFieldPuns
|
||||
NumericUnderscores
|
||||
OverloadedLabels
|
||||
|
@ -80,11 +80,6 @@ data ShouldForkCodebase
|
||||
| DontFork
|
||||
deriving (Show, Eq)
|
||||
|
||||
data ShouldDownloadBase
|
||||
= ShouldDownloadBase
|
||||
| ShouldNotDownloadBase
|
||||
deriving (Show, Eq)
|
||||
|
||||
data ShouldSaveCodebase
|
||||
= SaveCodebase (Maybe FilePath)
|
||||
| DontSaveCodebase
|
||||
@ -109,7 +104,6 @@ data Command
|
||||
= Launch
|
||||
IsHeadless
|
||||
CodebaseServerOpts
|
||||
ShouldDownloadBase
|
||||
-- Starting path
|
||||
(Maybe Path.Absolute)
|
||||
ShouldWatchFiles
|
||||
@ -359,10 +353,9 @@ launchParser :: CodebaseServerOpts -> IsHeadless -> Parser Command
|
||||
launchParser envOpts isHeadless = do
|
||||
-- ApplicativeDo
|
||||
codebaseServerOpts <- codebaseServerOptsParser envOpts
|
||||
downloadBase <- downloadBaseFlag
|
||||
startingPath <- startingPathOption
|
||||
shouldWatchFiles <- noFileWatchFlag
|
||||
pure (Launch isHeadless codebaseServerOpts downloadBase startingPath shouldWatchFiles)
|
||||
pure (Launch isHeadless codebaseServerOpts startingPath shouldWatchFiles)
|
||||
|
||||
initParser :: Parser Command
|
||||
initParser = pure Init
|
||||
@ -421,18 +414,6 @@ saveCodebaseToFlag = do
|
||||
_ -> DontSaveCodebase
|
||||
)
|
||||
|
||||
downloadBaseFlag :: Parser ShouldDownloadBase
|
||||
downloadBaseFlag =
|
||||
flag
|
||||
ShouldDownloadBase
|
||||
ShouldNotDownloadBase
|
||||
( long "no-base"
|
||||
<> help downloadBaseHelp
|
||||
<> noGlobal
|
||||
)
|
||||
where
|
||||
downloadBaseHelp = "if set, a new codebase will be created without downloading the base library, otherwise the new codebase will download base"
|
||||
|
||||
startingPathOption :: Parser (Maybe Path.Absolute)
|
||||
startingPathOption =
|
||||
let meta =
|
||||
|
@ -7,7 +7,10 @@
|
||||
{-# LANGUAGE ViewPatterns #-}
|
||||
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
|
||||
|
||||
module Main where
|
||||
module Main
|
||||
( main,
|
||||
)
|
||||
where
|
||||
|
||||
import ArgParse
|
||||
( CodebasePathOption (..),
|
||||
@ -15,7 +18,6 @@ import ArgParse
|
||||
GlobalOptions (GlobalOptions, codebasePathOption, exitOption),
|
||||
IsHeadless (Headless, WithCLI),
|
||||
RunSource (..),
|
||||
ShouldDownloadBase (..),
|
||||
ShouldExit (DoNotExit, Exit),
|
||||
ShouldForkCodebase (..),
|
||||
ShouldSaveCodebase (..),
|
||||
@ -25,7 +27,6 @@ import ArgParse
|
||||
import Compat (defaultInterruptHandler, withInterruptHandler)
|
||||
import Control.Concurrent (newEmptyMVar, runInUnboundThread, takeMVar)
|
||||
import Control.Concurrent.STM
|
||||
import Control.Error.Safe (rightMay)
|
||||
import Control.Exception (evaluate)
|
||||
import Data.ByteString.Lazy qualified as BL
|
||||
import Data.Configurator.Types (Config)
|
||||
@ -37,13 +38,11 @@ import Data.Text.IO qualified as Text
|
||||
import GHC.Conc (setUncaughtExceptionHandler)
|
||||
import GHC.Conc qualified
|
||||
import Ki qualified
|
||||
import Language.Haskell.TH qualified as TH
|
||||
import Language.Haskell.TH.Syntax qualified as TH
|
||||
import Network.HTTP.Client qualified as HTTP
|
||||
import Network.HTTP.Client.TLS qualified as HTTP
|
||||
import Stats (recordRtsStats)
|
||||
import System.Directory (canonicalizePath, getCurrentDirectory, removeDirectoryRecursive)
|
||||
import System.Environment (getProgName, lookupEnv, withArgs)
|
||||
import System.Environment (getProgName, withArgs)
|
||||
import System.Exit qualified as Exit
|
||||
import System.FilePath qualified as FP
|
||||
import System.IO (stderr)
|
||||
@ -51,16 +50,12 @@ import System.IO.CodePage (withCP65001)
|
||||
import System.IO.Error (catchIOError)
|
||||
import System.IO.Temp qualified as Temp
|
||||
import System.Path qualified as Path
|
||||
import Text.Megaparsec (runParser)
|
||||
import Text.Pretty.Simple (pHPrint)
|
||||
import U.Codebase.Sqlite.Queries qualified as Queries
|
||||
import Unison.Codebase (Codebase, CodebasePath)
|
||||
import Unison.Codebase qualified as Codebase
|
||||
import Unison.Codebase.Branch (Branch)
|
||||
import Unison.Codebase.Editor.Input qualified as Input
|
||||
import Unison.Codebase.Editor.RemoteRepo (ReadShareLooseCode)
|
||||
import Unison.Codebase.Editor.UriParser (parseReadShareLooseCode)
|
||||
import Unison.Codebase.Editor.VersionParser qualified as VP
|
||||
import Unison.Codebase.Execute (execute)
|
||||
import Unison.Codebase.Init (CodebaseInitOptions (..), InitError (..), InitResult (..), SpecifiedCodebase (..))
|
||||
import Unison.Codebase.Init qualified as CodebaseInit
|
||||
@ -147,7 +142,6 @@ main = withCP65001 . runInUnboundThread . Ki.scoped $ \scope -> do
|
||||
[Left fileEvent, Right $ Input.ExecuteI mainName args, Right Input.QuitI]
|
||||
serverUrl
|
||||
startPath
|
||||
ShouldNotDownloadBase
|
||||
initRes
|
||||
noOpRootNotifier
|
||||
noOpPathNotifier
|
||||
@ -173,7 +167,6 @@ main = withCP65001 . runInUnboundThread . Ki.scoped $ \scope -> do
|
||||
[Left fileEvent, Right $ Input.ExecuteI mainName args, Right Input.QuitI]
|
||||
serverUrl
|
||||
startPath
|
||||
ShouldNotDownloadBase
|
||||
initRes
|
||||
noOpRootNotifier
|
||||
noOpPathNotifier
|
||||
@ -247,7 +240,7 @@ main = withCP65001 . runInUnboundThread . Ki.scoped $ \scope -> do
|
||||
case mrtsStatsFp of
|
||||
Nothing -> action
|
||||
Just fp -> recordRtsStats fp action
|
||||
Launch isHeadless codebaseServerOpts downloadBase mayStartingPath shouldWatchFiles -> do
|
||||
Launch isHeadless codebaseServerOpts mayStartingPath shouldWatchFiles -> do
|
||||
getCodebaseOrExit mCodePathOption (SC.MigrateAfterPrompt SC.Backup SC.Vacuum) \(initRes, _, theCodebase) -> do
|
||||
withRuntimes RTI.Persistent \(runtime, sbRuntime) -> do
|
||||
startingPath <- case isHeadless of
|
||||
@ -308,7 +301,6 @@ main = withCP65001 . runInUnboundThread . Ki.scoped $ \scope -> do
|
||||
[]
|
||||
(Just baseUrl)
|
||||
(Just startingPath)
|
||||
downloadBase
|
||||
initRes
|
||||
notifyOnRootChanges
|
||||
notifyOnPathChanges
|
||||
@ -479,22 +471,18 @@ launch ::
|
||||
[Either Input.Event Input.Input] ->
|
||||
Maybe Server.BaseUrl ->
|
||||
Maybe Path.Absolute ->
|
||||
ShouldDownloadBase ->
|
||||
InitResult ->
|
||||
(Branch IO -> STM ()) ->
|
||||
(Path.Absolute -> STM ()) ->
|
||||
CommandLine.ShouldWatchFiles ->
|
||||
IO ()
|
||||
launch dir config runtime sbRuntime codebase inputs serverBaseUrl mayStartingPath shouldDownloadBase initResult notifyRootChange notifyPathChange shouldWatchFiles =
|
||||
let downloadBase = case defaultBaseLib of
|
||||
Just remoteNS | shouldDownloadBase == ShouldDownloadBase -> Welcome.DownloadBase remoteNS
|
||||
_ -> Welcome.DontDownloadBase
|
||||
isNewCodebase = case initResult of
|
||||
CreatedCodebase {} -> NewlyCreatedCodebase
|
||||
_ -> PreviouslyCreatedCodebase
|
||||
launch dir config runtime sbRuntime codebase inputs serverBaseUrl mayStartingPath initResult notifyRootChange notifyPathChange shouldWatchFiles =
|
||||
let isNewCodebase = case initResult of
|
||||
CreatedCodebase -> NewlyCreatedCodebase
|
||||
OpenedCodebase -> PreviouslyCreatedCodebase
|
||||
|
||||
(ucmVersion, _date) = Version.gitDescribe
|
||||
welcome = Welcome.welcome isNewCodebase downloadBase dir ucmVersion shouldWatchFiles
|
||||
welcome = Welcome.welcome isNewCodebase ucmVersion
|
||||
in CommandLine.main
|
||||
dir
|
||||
welcome
|
||||
@ -521,27 +509,9 @@ markdownFile md = case FP.takeExtension md of
|
||||
isDotU :: String -> Bool
|
||||
isDotU file = FP.takeExtension file == ".u"
|
||||
|
||||
-- so we can do `ucm --help`, `ucm -help` or `ucm help` (I hate
|
||||
-- having to remember which one is supported)
|
||||
isFlag :: String -> String -> Bool
|
||||
isFlag f arg = arg == f || arg == "-" ++ f || arg == "--" ++ f
|
||||
|
||||
getConfigFilePath :: Maybe FilePath -> IO FilePath
|
||||
getConfigFilePath mcodepath = (FP.</> ".unisonConfig") <$> Codebase.getCodebaseDir mcodepath
|
||||
|
||||
defaultBaseLib :: Maybe ReadShareLooseCode
|
||||
defaultBaseLib =
|
||||
let mayBaseSharePath =
|
||||
$( do
|
||||
mayPath <- TH.runIO (lookupEnv "UNISON_BASE_PATH")
|
||||
TH.lift mayPath
|
||||
)
|
||||
in mayBaseSharePath & \case
|
||||
Just s -> eitherToMaybe $ parseReadShareLooseCode "UNISON_BASE_PATH" s
|
||||
Nothing -> rightMay $ runParser VP.defaultBaseLib "version" gitRef
|
||||
where
|
||||
(gitRef, _date) = Version.gitDescribe
|
||||
|
||||
getCodebaseOrExit :: Maybe CodebasePathOption -> SC.MigrationStrategy -> ((InitResult, CodebasePath, Codebase IO Symbol Ann) -> IO r) -> IO r
|
||||
getCodebaseOrExit codebasePathOption migrationStrategy action = do
|
||||
initOptions <- argsToCodebaseInitOptions codebasePathOption
|
||||
|
@ -96,3 +96,4 @@ default-extensions:
|
||||
- TypeApplications
|
||||
- TypeOperators
|
||||
- ViewPatterns
|
||||
- ImportQualifiedPost
|
||||
|
@ -31,7 +31,7 @@ module Unison.Server.Backend
|
||||
displayType,
|
||||
docsInBranchToHtmlFiles,
|
||||
expandShortCausalHash,
|
||||
findDocInBranchAndRender,
|
||||
findDocInBranch,
|
||||
formatSuffixedType,
|
||||
getCurrentParseNames,
|
||||
getCurrentPrettyNames,
|
||||
@ -454,25 +454,16 @@ lsAtPath codebase mayRootBranch absPath = do
|
||||
b <- Codebase.runTransaction codebase (Codebase.getShallowBranchAtPath (Path.unabsolute absPath) mayRootBranch)
|
||||
lsBranch codebase b
|
||||
|
||||
findDocInBranchAndRender ::
|
||||
findDocInBranch ::
|
||||
Set NameSegment ->
|
||||
Width ->
|
||||
Rt.Runtime Symbol ->
|
||||
Codebase IO Symbol Ann ->
|
||||
PPED.PrettyPrintEnvDecl ->
|
||||
V2Branch.Branch m ->
|
||||
Backend IO (Maybe Doc.Doc)
|
||||
findDocInBranchAndRender names _width runtime codebase ppe namespaceBranch =
|
||||
let renderReadme :: PPED.PrettyPrintEnvDecl -> Reference -> IO Doc.Doc
|
||||
renderReadme ppe docReference = do
|
||||
doc <- evalDocRef runtime codebase docReference <&> Doc.renderDoc ppe
|
||||
pure doc
|
||||
|
||||
-- choose the first term (among conflicted terms) matching any of these names, in this order.
|
||||
Maybe TermReference
|
||||
findDocInBranch names namespaceBranch =
|
||||
let -- choose the first term (among conflicted terms) matching any of these names, in this order.
|
||||
-- we might later want to return all of them to let the front end decide
|
||||
toCheck = Set.toList names
|
||||
readme :: Maybe Reference
|
||||
readme = listToMaybe $ do
|
||||
readmeRef :: Maybe Reference
|
||||
readmeRef = listToMaybe $ do
|
||||
name <- toCheck
|
||||
term <- toList $ Map.lookup name termsMap
|
||||
k <- Map.keys term
|
||||
@ -482,8 +473,7 @@ findDocInBranchAndRender names _width runtime codebase ppe namespaceBranch =
|
||||
V2Referent.Ref ref -> pure $ Cv.reference2to1 ref
|
||||
where
|
||||
termsMap = V2Branch.terms namespaceBranch
|
||||
in liftIO $ do
|
||||
traverse (renderReadme ppe) readme
|
||||
in readmeRef
|
||||
|
||||
isDoc :: Codebase m Symbol Ann -> Referent.Referent -> Sqlite.Transaction Bool
|
||||
isDoc codebase ref = do
|
||||
|
@ -11,11 +11,9 @@
|
||||
module Unison.Server.Local.Endpoints.NamespaceDetails where
|
||||
|
||||
import Control.Monad.Except
|
||||
import Data.Aeson
|
||||
import Data.OpenApi (ToSchema)
|
||||
import Data.Set qualified as Set
|
||||
import Servant (Capture, QueryParam, (:>))
|
||||
import Servant.Docs (DocCapture (..), ToCapture (..), ToSample (..))
|
||||
import Servant.Docs (DocCapture (..), ToCapture (..))
|
||||
import Servant.OpenApi ()
|
||||
import U.Codebase.Causal qualified as V2Causal
|
||||
import U.Codebase.HashTags (CausalHash)
|
||||
@ -28,11 +26,10 @@ import Unison.Parser.Ann (Ann)
|
||||
import Unison.Prelude
|
||||
import Unison.Server.Backend
|
||||
import Unison.Server.Backend qualified as Backend
|
||||
import Unison.Server.Doc (Doc)
|
||||
import Unison.Server.Doc qualified as Doc
|
||||
import Unison.Server.Types
|
||||
( APIGet,
|
||||
UnisonHash,
|
||||
mayDefaultWidth,
|
||||
NamespaceDetails (..),
|
||||
v2CausalBranchToUnisonHash,
|
||||
)
|
||||
import Unison.Symbol (Symbol)
|
||||
@ -51,34 +48,6 @@ instance ToCapture (Capture "namespace" Text) where
|
||||
"namespace"
|
||||
"The fully qualified name of a namespace. The leading `.` is optional."
|
||||
|
||||
instance ToSample NamespaceDetails where
|
||||
toSamples _ =
|
||||
[ ( "When no value is provided for `namespace`, the root namespace `.` is "
|
||||
<> "listed by default",
|
||||
NamespaceDetails
|
||||
Path.empty
|
||||
"#gjlk0dna8dongct6lsd19d1o9hi5n642t8jttga5e81e91fviqjdffem0tlddj7ahodjo5"
|
||||
Nothing
|
||||
)
|
||||
]
|
||||
|
||||
data NamespaceDetails = NamespaceDetails
|
||||
{ fqn :: Path.Path,
|
||||
hash :: UnisonHash,
|
||||
readme :: Maybe Doc
|
||||
}
|
||||
deriving (Generic, Show)
|
||||
|
||||
instance ToJSON NamespaceDetails where
|
||||
toJSON NamespaceDetails {..} =
|
||||
object
|
||||
[ "fqn" .= fqn,
|
||||
"hash" .= hash,
|
||||
"readme" .= readme
|
||||
]
|
||||
|
||||
deriving instance ToSchema NamespaceDetails
|
||||
|
||||
namespaceDetails ::
|
||||
Rt.Runtime Symbol ->
|
||||
Codebase IO Symbol Ann ->
|
||||
@ -86,33 +55,26 @@ namespaceDetails ::
|
||||
Maybe (Either ShortCausalHash CausalHash) ->
|
||||
Maybe Width ->
|
||||
Backend IO NamespaceDetails
|
||||
namespaceDetails runtime codebase namespacePath mayRoot mayWidth =
|
||||
let width = mayDefaultWidth mayWidth
|
||||
in do
|
||||
(rootCausal, namespaceCausal, shallowBranch) <-
|
||||
Backend.hoistBackend (Codebase.runTransaction codebase) do
|
||||
rootCausalHash <-
|
||||
case mayRoot of
|
||||
Nothing -> Backend.resolveRootBranchHashV2 Nothing
|
||||
Just (Left sch) -> Backend.resolveRootBranchHashV2 (Just sch)
|
||||
Just (Right ch) -> lift $ Backend.resolveCausalHashV2 (Just ch)
|
||||
-- lift (Backend.resolveCausalHashV2 rootCausalHash)
|
||||
namespaceCausal <- lift $ Codebase.getShallowCausalAtPath namespacePath (Just rootCausalHash)
|
||||
shallowBranch <- lift $ V2Causal.value namespaceCausal
|
||||
pure (rootCausalHash, namespaceCausal, shallowBranch)
|
||||
namespaceDetails <- do
|
||||
(_localNamesOnly, ppe) <- Backend.scopedNamesForBranchHash codebase (Just rootCausal) namespacePath
|
||||
readme <-
|
||||
Backend.findDocInBranchAndRender
|
||||
readmeNames
|
||||
width
|
||||
runtime
|
||||
codebase
|
||||
ppe
|
||||
shallowBranch
|
||||
let causalHash = v2CausalBranchToUnisonHash namespaceCausal
|
||||
pure $ NamespaceDetails namespacePath causalHash readme
|
||||
|
||||
pure $ namespaceDetails
|
||||
namespaceDetails runtime codebase namespacePath mayRoot _mayWidth = do
|
||||
(rootCausal, namespaceCausal, shallowBranch) <-
|
||||
Backend.hoistBackend (Codebase.runTransaction codebase) do
|
||||
rootCausalHash <-
|
||||
case mayRoot of
|
||||
Nothing -> Backend.resolveRootBranchHashV2 Nothing
|
||||
Just (Left sch) -> Backend.resolveRootBranchHashV2 (Just sch)
|
||||
Just (Right ch) -> lift $ Backend.resolveCausalHashV2 (Just ch)
|
||||
-- lift (Backend.resolveCausalHashV2 rootCausalHash)
|
||||
namespaceCausal <- lift $ Codebase.getShallowCausalAtPath namespacePath (Just rootCausalHash)
|
||||
shallowBranch <- lift $ V2Causal.value namespaceCausal
|
||||
pure (rootCausalHash, namespaceCausal, shallowBranch)
|
||||
namespaceDetails <- do
|
||||
(_localNamesOnly, ppe) <- Backend.scopedNamesForBranchHash codebase (Just rootCausal) namespacePath
|
||||
let mayReadmeRef = Backend.findDocInBranch readmeNames shallowBranch
|
||||
renderedReadme <- for mayReadmeRef \readmeRef -> do
|
||||
eDoc <- liftIO $ evalDocRef runtime codebase readmeRef
|
||||
pure $ Doc.renderDoc ppe eDoc
|
||||
let causalHash = v2CausalBranchToUnisonHash namespaceCausal
|
||||
pure $ NamespaceDetails namespacePath causalHash renderedReadme
|
||||
pure $ namespaceDetails
|
||||
where
|
||||
readmeNames = Set.fromList ["README", "Readme", "ReadMe", "readme"]
|
||||
|
38
unison-share-api/src/Unison/Server/Share/NamespaceDetails.hs
Normal file
38
unison-share-api/src/Unison/Server/Share/NamespaceDetails.hs
Normal file
@ -0,0 +1,38 @@
|
||||
module Unison.Server.Share.NamespaceDetails (namespaceDetails) where
|
||||
|
||||
import Control.Monad.Except
|
||||
import Data.Set qualified as Set
|
||||
import Servant.OpenApi ()
|
||||
import U.Codebase.HashTags (CausalHash)
|
||||
import Unison.Codebase (Codebase)
|
||||
import Unison.Codebase qualified as Codebase
|
||||
import Unison.Codebase.Path qualified as Path
|
||||
import Unison.Codebase.Runtime qualified as Rt
|
||||
import Unison.Parser.Ann (Ann)
|
||||
import Unison.Server.Backend
|
||||
import Unison.Server.Backend qualified as Backend
|
||||
import Unison.Server.Share.RenderDoc qualified as RenderDoc
|
||||
import Unison.Server.Types
|
||||
( NamespaceDetails (..),
|
||||
v2CausalBranchToUnisonHash,
|
||||
)
|
||||
import Unison.Symbol (Symbol)
|
||||
import Unison.Util.Pretty (Width)
|
||||
|
||||
namespaceDetails ::
|
||||
Rt.Runtime Symbol ->
|
||||
Codebase IO Symbol Ann ->
|
||||
Path.Path ->
|
||||
CausalHash ->
|
||||
Maybe Width ->
|
||||
Backend IO NamespaceDetails
|
||||
namespaceDetails runtime codebase namespacePath rootCausalHash mayWidth = do
|
||||
causalHashAtPath <- liftIO $ Codebase.runTransaction codebase do
|
||||
causalBranch <- Backend.resolveCausalHashV2 (Just rootCausalHash)
|
||||
namespaceCausal <- Codebase.getShallowCausalAtPath namespacePath (Just causalBranch)
|
||||
let causalHashAtPath = v2CausalBranchToUnisonHash namespaceCausal
|
||||
pure causalHashAtPath
|
||||
mayReadme <- RenderDoc.findAndRenderDoc readmeNames runtime codebase namespacePath rootCausalHash mayWidth
|
||||
pure $ NamespaceDetails namespacePath causalHashAtPath mayReadme
|
||||
where
|
||||
readmeNames = Set.fromList ["README", "Readme", "ReadMe", "readme"]
|
@ -11,55 +11,52 @@
|
||||
module Unison.Server.Share.RenderDoc where
|
||||
|
||||
import Control.Monad.Except
|
||||
import Data.Set qualified as Set
|
||||
import Servant.OpenApi ()
|
||||
import U.Codebase.Causal qualified as V2Causal
|
||||
import U.Codebase.HashTags (CausalHash)
|
||||
import U.Codebase.Sqlite.NameLookups (PathSegments (..))
|
||||
import U.Codebase.Sqlite.Operations qualified as Ops
|
||||
import Unison.Codebase (Codebase)
|
||||
import Unison.Codebase qualified as Codebase
|
||||
import Unison.Codebase.Path qualified as Path
|
||||
import Unison.Codebase.Runtime qualified as Rt
|
||||
import Unison.Codebase.ShortCausalHash (ShortCausalHash)
|
||||
import Unison.NameSegment (NameSegment)
|
||||
import Unison.LabeledDependency qualified as LD
|
||||
import Unison.NameSegment (NameSegment (..))
|
||||
import Unison.Parser.Ann (Ann)
|
||||
import Unison.Prelude
|
||||
import Unison.PrettyPrintEnvDecl.Sqlite qualified as PPESqlite
|
||||
import Unison.Server.Backend
|
||||
import Unison.Server.Backend qualified as Backend
|
||||
import Unison.Server.Doc (Doc)
|
||||
import Unison.Server.Types
|
||||
( mayDefaultWidth,
|
||||
)
|
||||
import Unison.Server.Doc qualified as Doc
|
||||
import Unison.Symbol (Symbol)
|
||||
import Unison.Util.Pretty (Width)
|
||||
|
||||
renderDoc ::
|
||||
-- | Find, eval, and render the first doc we find with any of the provided names within the given namespace
|
||||
-- If no doc is found, return Nothing
|
||||
--
|
||||
-- Requires Name Lookups, currently only usable on Share.
|
||||
findAndRenderDoc ::
|
||||
Set NameSegment ->
|
||||
Rt.Runtime Symbol ->
|
||||
Codebase IO Symbol Ann ->
|
||||
Path.Path ->
|
||||
Maybe (Either ShortCausalHash CausalHash) ->
|
||||
CausalHash ->
|
||||
Maybe Width ->
|
||||
Backend IO (Maybe Doc)
|
||||
renderDoc docNames runtime codebase namespacePath mayRoot mayWidth =
|
||||
let width = mayDefaultWidth mayWidth
|
||||
in do
|
||||
(rootCausal, shallowBranch) <-
|
||||
Backend.hoistBackend (Codebase.runTransaction codebase) do
|
||||
rootCausalHash <-
|
||||
case mayRoot of
|
||||
Nothing -> Backend.resolveRootBranchHashV2 Nothing
|
||||
Just (Left sch) -> Backend.resolveRootBranchHashV2 (Just sch)
|
||||
Just (Right ch) -> lift $ Backend.resolveCausalHashV2 (Just ch)
|
||||
-- lift (Backend.resolveCausalHashV2 rootCausalHash)
|
||||
namespaceCausal <- lift $ Codebase.getShallowCausalAtPath namespacePath (Just rootCausalHash)
|
||||
shallowBranch <- lift $ V2Causal.value namespaceCausal
|
||||
pure (rootCausalHash, shallowBranch)
|
||||
(_localNamesOnly, ppe) <- Backend.scopedNamesForBranchHash codebase (Just rootCausal) namespacePath
|
||||
renderedDoc <-
|
||||
Backend.findDocInBranchAndRender
|
||||
docNames
|
||||
width
|
||||
runtime
|
||||
codebase
|
||||
ppe
|
||||
shallowBranch
|
||||
pure renderedDoc
|
||||
findAndRenderDoc docNames runtime codebase namespacePath rootCausalHash _mayWidth = do
|
||||
(shallowBranchAtNamespace, namesPerspective) <-
|
||||
liftIO . (Codebase.runTransaction codebase) $ do
|
||||
rootCausal <- Backend.resolveCausalHashV2 (Just rootCausalHash)
|
||||
let rootBranchHash = V2Causal.valueHash rootCausal
|
||||
namespaceCausal <- Codebase.getShallowCausalAtPath namespacePath (Just rootCausal)
|
||||
shallowBranchAtNamespace <- V2Causal.value namespaceCausal
|
||||
namesPerspective <- Ops.namesPerspectiveForRootAndPath rootBranchHash (coerce . Path.toList $ namespacePath)
|
||||
pure (shallowBranchAtNamespace, namesPerspective)
|
||||
let mayDocRef = Backend.findDocInBranch docNames shallowBranchAtNamespace
|
||||
for mayDocRef \docRef -> do
|
||||
eDoc <- liftIO $ evalDocRef runtime codebase docRef
|
||||
let docDeps = Doc.dependencies eDoc <> Set.singleton (LD.TermReference docRef)
|
||||
docPPE <- liftIO $ Codebase.runTransaction codebase $ PPESqlite.ppedForReferences namesPerspective docDeps
|
||||
pure $ Doc.renderDoc docPPE eDoc
|
||||
|
@ -39,6 +39,7 @@ import Unison.Codebase.Branch qualified as Branch
|
||||
import Unison.Codebase.Editor.DisplayObject
|
||||
( DisplayObject,
|
||||
)
|
||||
import Unison.Codebase.Path qualified as Path
|
||||
import Unison.Hash qualified as Hash
|
||||
import Unison.HashQualified qualified as HQ
|
||||
import Unison.HashQualified' qualified as HQ'
|
||||
@ -71,6 +72,34 @@ type UnisonName = Text
|
||||
|
||||
type UnisonHash = Text
|
||||
|
||||
data NamespaceDetails = NamespaceDetails
|
||||
{ fqn :: Path.Path,
|
||||
hash :: UnisonHash,
|
||||
readme :: Maybe Doc
|
||||
}
|
||||
deriving (Generic, Show)
|
||||
|
||||
instance Docs.ToSample NamespaceDetails where
|
||||
toSamples _ =
|
||||
[ ( "When no value is provided for `namespace`, the root namespace `.` is "
|
||||
<> "listed by default",
|
||||
NamespaceDetails
|
||||
Path.empty
|
||||
"#gjlk0dna8dongct6lsd19d1o9hi5n642t8jttga5e81e91fviqjdffem0tlddj7ahodjo5"
|
||||
Nothing
|
||||
)
|
||||
]
|
||||
|
||||
instance ToJSON NamespaceDetails where
|
||||
toJSON NamespaceDetails {..} =
|
||||
object
|
||||
[ "fqn" .= fqn,
|
||||
"hash" .= hash,
|
||||
"readme" .= readme
|
||||
]
|
||||
|
||||
deriving instance ToSchema NamespaceDetails
|
||||
|
||||
-- | A hash qualified name, unlike HashQualified, the hash is required
|
||||
data ExactName name ref = ExactName
|
||||
{ name :: name,
|
||||
|
@ -1,6 +1,6 @@
|
||||
cabal-version: 1.12
|
||||
|
||||
-- This file has been generated from package.yaml by hpack version 0.35.1.
|
||||
-- This file has been generated from package.yaml by hpack version 0.35.2.
|
||||
--
|
||||
-- see: https://github.com/sol/hpack
|
||||
|
||||
@ -42,6 +42,7 @@ library
|
||||
Unison.Server.Share
|
||||
Unison.Server.Share.Definitions
|
||||
Unison.Server.Share.FuzzyFind
|
||||
Unison.Server.Share.NamespaceDetails
|
||||
Unison.Server.Share.RenderDoc
|
||||
Unison.Server.Syntax
|
||||
Unison.Server.Types
|
||||
@ -80,6 +81,7 @@ library
|
||||
TypeApplications
|
||||
TypeOperators
|
||||
ViewPatterns
|
||||
ImportQualifiedPost
|
||||
ghc-options: -Wall
|
||||
build-depends:
|
||||
NanoID
|
||||
|
@ -5,6 +5,6 @@ Thus, make sure the contents of this file define the contents of the cache
|
||||
(e.g. don't pull `latest`.)
|
||||
|
||||
```ucm
|
||||
.> pull @unison/base/releases/2.0.0 .base
|
||||
.> pull @unison/base/releases/2.2.0 .base
|
||||
.> compile.native.fetch
|
||||
```
|
||||
|
@ -5,9 +5,9 @@ Thus, make sure the contents of this file define the contents of the cache
|
||||
(e.g. don't pull `latest`.)
|
||||
|
||||
```ucm
|
||||
.> pull @unison/base/releases/2.0.0 .base
|
||||
.> pull @unison/base/releases/2.2.0 .base
|
||||
|
||||
Downloaded 11939 entities.
|
||||
Downloaded 12209 entities.
|
||||
|
||||
✅
|
||||
|
||||
@ -15,11 +15,11 @@ Thus, make sure the contents of this file define the contents of the cache
|
||||
|
||||
.> compile.native.fetch
|
||||
|
||||
Downloaded 65927 entities.
|
||||
Downloaded 1255 entities.
|
||||
|
||||
✅
|
||||
|
||||
Successfully updated .unison.internal from
|
||||
unison.public.internal.trunk.
|
||||
@unison/internal/releases/0.0.1.
|
||||
|
||||
```
|
||||
|
@ -64,6 +64,7 @@ to `Tests.check` and `Tests.checkEqual`).
|
||||
```
|
||||
|
||||
```ucm:hide
|
||||
.> alias.term ##IO.randomBytes IO.randomBytes
|
||||
.> load unison-src/builtin-tests/io-tests.u
|
||||
.> add
|
||||
```
|
||||
|
@ -1,13 +1,18 @@
|
||||
|
||||
io.tests = Tests.main do
|
||||
!test_getFileSize
|
||||
!test_getFileSize_err
|
||||
!test_getFileSize_err
|
||||
!test_getFileTimestamp
|
||||
!test_getFileTimestamp_err
|
||||
!io.test.seek.absolute
|
||||
!io.test.seek.relative
|
||||
!io.test.getLine
|
||||
!io.test.getsetBuffering
|
||||
!io.test_getEcho
|
||||
!io.test_getArgs
|
||||
!io.test_getEnv
|
||||
!io.test.getRandomBytes
|
||||
!io.test_getSomeBytes
|
||||
|
||||
testFile = do
|
||||
fp = FilePath ((FilePath.toText !getTempDirectory) ++ "/unison-test")
|
||||
@ -47,7 +52,7 @@ test_getFileTimestamp = do
|
||||
Tests.fail "File timestamp is too late" ((Int.toText ts) ++ " vs " ++ (Int.toText after))
|
||||
else
|
||||
Tests.pass "File timestamp is reasonable"
|
||||
|
||||
|
||||
test_getFileTimestamp_err = do
|
||||
expectError' "File timestamp of missing file" ["does not exist", "error getting"] '(FilePath.getTimestamp !testFile)
|
||||
|
||||
@ -104,3 +109,34 @@ io.test.getsetBuffering = do
|
||||
checkEqual "Line" b2 LineBuffering
|
||||
checkEqual "No" b3 NoBuffering
|
||||
|
||||
is_a_tty = do
|
||||
exitCode = call "test" ["-t", "0"]
|
||||
exitCode == 0
|
||||
|
||||
io.test_getEcho = do
|
||||
if is_a_tty () then
|
||||
prev = getEcho stdIn
|
||||
setEcho stdIn false
|
||||
checkEqual "echo turned off" (getEcho stdIn) false
|
||||
setEcho stdIn true
|
||||
checkEqual "echo turned back on" (getEcho stdIn) true
|
||||
setEcho stdIn prev
|
||||
else
|
||||
()
|
||||
|
||||
io.test_getArgs = do
|
||||
checkEqual "cli args" !getArgs []
|
||||
|
||||
io.test_getEnv = do
|
||||
checkEqual "HOME env variable" (startsWith "/" (getEnv "HOME")) true
|
||||
|
||||
io.test.getRandomBytes = do
|
||||
bs = IO.randomBytes 10
|
||||
checkEqual "get 10 random bytes" 10 (base.Bytes.size bs)
|
||||
|
||||
io.test_getSomeBytes = do
|
||||
fp = !testFile
|
||||
_ = writeFile fp "one\ntwo\nthree"
|
||||
h = open fp Read
|
||||
one = getSomeBytes h 3
|
||||
checkEqual "get some bytes" one (toUtf8 "one")
|
||||
|
@ -66,6 +66,7 @@ to `Tests.check` and `Tests.checkEqual`).
|
||||
```
|
||||
|
||||
```ucm:hide
|
||||
.> alias.term ##IO.randomBytes IO.randomBytes
|
||||
.> load unison-src/builtin-tests/io-tests.u
|
||||
.> add
|
||||
```
|
||||
|
@ -26,6 +26,7 @@ Tests.main suite = do
|
||||
|
||||
Tests.run : '{IO,Exception,Tests} () ->{IO,Exception} Boolean
|
||||
Tests.run suite =
|
||||
use Nat +
|
||||
h passed failed = cases
|
||||
{ _ } -> (passed, failed)
|
||||
{ pass msg -> k } ->
|
||||
|
@ -41,7 +41,7 @@ chainClient portPromise toSend =
|
||||
tlsock = Tls.handshake tls
|
||||
TlsSocket.send tlsock (toUtf8 toSend)
|
||||
-- res = fromUtf8 (TlsSocket.receive tlsock)
|
||||
TlsSocket.close tlsock
|
||||
TlsSocket.terminate tlsock
|
||||
-- res
|
||||
|
||||
-- server receives then sends
|
||||
@ -61,7 +61,7 @@ chainServer portPromise toSend =
|
||||
tlsock = net.Tls.handshake tls
|
||||
res = fromUtf8 (TlsSocket.receive tlsock)
|
||||
-- TlsSocket.send tlsock (toUtf8 toSend)
|
||||
TlsSocket.close tlsock
|
||||
TlsSocket.terminate tlsock
|
||||
res
|
||||
|
||||
tlsChainTest = do
|
||||
|
@ -66,7 +66,7 @@ tls.example.com = do
|
||||
conn = base.IO.net.Tls.handshake tls
|
||||
TlsSocket.send conn (toUtf8 "GET /index.html HTTP/1.0\r\nHost: example.com\r\n\r\n")
|
||||
response = TlsSocket.receive conn
|
||||
TlsSocket.close conn
|
||||
TlsSocket.terminate conn
|
||||
contains "HTTP/1.0 200 OK" (fromUtf8 response)
|
||||
|
||||
testConnectSelfSigned = do
|
||||
@ -123,7 +123,7 @@ serverThread portPromise toSend =
|
||||
tls = Tls.newServer tlsconfig sock'
|
||||
tlsock = net.Tls.handshake tls
|
||||
TlsSocket.send tlsock (toUtf8 toSend)
|
||||
TlsSocket.close tlsock
|
||||
TlsSocket.terminate tlsock
|
||||
|
||||
testClient : Optional SignedCert -> Text -> Promise Nat -> '{IO} Either Failure Text
|
||||
testClient cert hostname portVar _ = catch do
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -33,16 +33,16 @@ hasMetadata = 3
|
||||
.dependencies> namespace.dependencies
|
||||
|
||||
External dependency Dependents in .dependencies
|
||||
builtin.Int dependsOnInt
|
||||
builtin.Int 1. dependsOnInt
|
||||
|
||||
builtin.Nat dependsOnIntAndNat
|
||||
dependsOnNat
|
||||
hasMetadata
|
||||
builtin.Nat 2. dependsOnIntAndNat
|
||||
3. dependsOnNat
|
||||
4. hasMetadata
|
||||
|
||||
builtin.Text hasMetadata
|
||||
builtin.Text 4. hasMetadata
|
||||
|
||||
builtin.Nat.drop dependsOnIntAndNat
|
||||
builtin.Nat.drop 2. dependsOnIntAndNat
|
||||
|
||||
metadata.myMetadata hasMetadata
|
||||
metadata.myMetadata 4. hasMetadata
|
||||
|
||||
```
|
||||
|
@ -337,364 +337,365 @@ Let's try it!
|
||||
251. io2.IO.putBytes.impl : Handle
|
||||
-> Bytes
|
||||
->{IO} Either Failure ()
|
||||
252. io2.IO.ready.impl : Handle ->{IO} Either Failure Boolean
|
||||
253. io2.IO.ref : a ->{IO} Ref {IO} a
|
||||
254. io2.IO.removeDirectory.impl : Text
|
||||
252. io2.IO.randomBytes : Nat ->{IO} Bytes
|
||||
253. io2.IO.ready.impl : Handle ->{IO} Either Failure Boolean
|
||||
254. io2.IO.ref : a ->{IO} Ref {IO} a
|
||||
255. io2.IO.removeDirectory.impl : Text
|
||||
->{IO} Either Failure ()
|
||||
255. io2.IO.removeFile.impl : Text ->{IO} Either Failure ()
|
||||
256. io2.IO.renameDirectory.impl : Text
|
||||
256. io2.IO.removeFile.impl : Text ->{IO} Either Failure ()
|
||||
257. io2.IO.renameDirectory.impl : Text
|
||||
-> Text
|
||||
->{IO} Either Failure ()
|
||||
257. io2.IO.renameFile.impl : Text
|
||||
258. io2.IO.renameFile.impl : Text
|
||||
-> Text
|
||||
->{IO} Either Failure ()
|
||||
258. io2.IO.seekHandle.impl : Handle
|
||||
259. io2.IO.seekHandle.impl : Handle
|
||||
-> SeekMode
|
||||
-> Int
|
||||
->{IO} Either Failure ()
|
||||
259. io2.IO.serverSocket.impl : Optional Text
|
||||
260. io2.IO.serverSocket.impl : Optional Text
|
||||
-> Text
|
||||
->{IO} Either Failure Socket
|
||||
260. io2.IO.setBuffering.impl : Handle
|
||||
261. io2.IO.setBuffering.impl : Handle
|
||||
-> BufferMode
|
||||
->{IO} Either Failure ()
|
||||
261. io2.IO.setCurrentDirectory.impl : Text
|
||||
262. io2.IO.setCurrentDirectory.impl : Text
|
||||
->{IO} Either
|
||||
Failure ()
|
||||
262. io2.IO.setEcho.impl : Handle
|
||||
263. io2.IO.setEcho.impl : Handle
|
||||
-> Boolean
|
||||
->{IO} Either Failure ()
|
||||
263. io2.IO.socketAccept.impl : Socket
|
||||
264. io2.IO.socketAccept.impl : Socket
|
||||
->{IO} Either Failure Socket
|
||||
264. io2.IO.socketPort.impl : Socket ->{IO} Either Failure Nat
|
||||
265. io2.IO.socketReceive.impl : Socket
|
||||
265. io2.IO.socketPort.impl : Socket ->{IO} Either Failure Nat
|
||||
266. io2.IO.socketReceive.impl : Socket
|
||||
-> Nat
|
||||
->{IO} Either Failure Bytes
|
||||
266. io2.IO.socketSend.impl : Socket
|
||||
267. io2.IO.socketSend.impl : Socket
|
||||
-> Bytes
|
||||
->{IO} Either Failure ()
|
||||
267. io2.IO.stdHandle : StdHandle -> Handle
|
||||
268. io2.IO.systemTime.impl : '{IO} Either Failure Nat
|
||||
269. io2.IO.systemTimeMicroseconds : '{IO} Int
|
||||
270. io2.IO.tryEval : '{IO} a ->{IO, Exception} a
|
||||
271. unique type io2.IOError
|
||||
272. io2.IOError.AlreadyExists : IOError
|
||||
273. io2.IOError.EOF : IOError
|
||||
274. io2.IOError.IllegalOperation : IOError
|
||||
275. io2.IOError.NoSuchThing : IOError
|
||||
276. io2.IOError.PermissionDenied : IOError
|
||||
277. io2.IOError.ResourceBusy : IOError
|
||||
278. io2.IOError.ResourceExhausted : IOError
|
||||
279. io2.IOError.UserError : IOError
|
||||
280. unique type io2.IOFailure
|
||||
281. unique type io2.MiscFailure
|
||||
282. builtin type io2.MVar
|
||||
283. io2.MVar.isEmpty : MVar a ->{IO} Boolean
|
||||
284. io2.MVar.new : a ->{IO} MVar a
|
||||
285. io2.MVar.newEmpty : '{IO} MVar a
|
||||
286. io2.MVar.put.impl : MVar a -> a ->{IO} Either Failure ()
|
||||
287. io2.MVar.read.impl : MVar a ->{IO} Either Failure a
|
||||
288. io2.MVar.swap.impl : MVar a -> a ->{IO} Either Failure a
|
||||
289. io2.MVar.take.impl : MVar a ->{IO} Either Failure a
|
||||
290. io2.MVar.tryPut.impl : MVar a
|
||||
268. io2.IO.stdHandle : StdHandle -> Handle
|
||||
269. io2.IO.systemTime.impl : '{IO} Either Failure Nat
|
||||
270. io2.IO.systemTimeMicroseconds : '{IO} Int
|
||||
271. io2.IO.tryEval : '{IO} a ->{IO, Exception} a
|
||||
272. unique type io2.IOError
|
||||
273. io2.IOError.AlreadyExists : IOError
|
||||
274. io2.IOError.EOF : IOError
|
||||
275. io2.IOError.IllegalOperation : IOError
|
||||
276. io2.IOError.NoSuchThing : IOError
|
||||
277. io2.IOError.PermissionDenied : IOError
|
||||
278. io2.IOError.ResourceBusy : IOError
|
||||
279. io2.IOError.ResourceExhausted : IOError
|
||||
280. io2.IOError.UserError : IOError
|
||||
281. unique type io2.IOFailure
|
||||
282. unique type io2.MiscFailure
|
||||
283. builtin type io2.MVar
|
||||
284. io2.MVar.isEmpty : MVar a ->{IO} Boolean
|
||||
285. io2.MVar.new : a ->{IO} MVar a
|
||||
286. io2.MVar.newEmpty : '{IO} MVar a
|
||||
287. io2.MVar.put.impl : MVar a -> a ->{IO} Either Failure ()
|
||||
288. io2.MVar.read.impl : MVar a ->{IO} Either Failure a
|
||||
289. io2.MVar.swap.impl : MVar a -> a ->{IO} Either Failure a
|
||||
290. io2.MVar.take.impl : MVar a ->{IO} Either Failure a
|
||||
291. io2.MVar.tryPut.impl : MVar a
|
||||
-> a
|
||||
->{IO} Either Failure Boolean
|
||||
291. io2.MVar.tryRead.impl : MVar a
|
||||
292. io2.MVar.tryRead.impl : MVar a
|
||||
->{IO} Either
|
||||
Failure (Optional a)
|
||||
292. io2.MVar.tryTake : MVar a ->{IO} Optional a
|
||||
293. builtin type io2.ProcessHandle
|
||||
294. builtin type io2.Promise
|
||||
295. io2.Promise.new : '{IO} Promise a
|
||||
296. io2.Promise.read : Promise a ->{IO} a
|
||||
297. io2.Promise.tryRead : Promise a ->{IO} Optional a
|
||||
298. io2.Promise.write : Promise a -> a ->{IO} Boolean
|
||||
299. io2.Ref.cas : Ref {IO} a -> Ticket a -> a ->{IO} Boolean
|
||||
300. io2.Ref.readForCas : Ref {IO} a ->{IO} Ticket a
|
||||
301. builtin type io2.Ref.Ticket
|
||||
302. io2.Ref.Ticket.read : Ticket a -> a
|
||||
303. unique type io2.RuntimeFailure
|
||||
304. unique type io2.SeekMode
|
||||
305. io2.SeekMode.AbsoluteSeek : SeekMode
|
||||
306. io2.SeekMode.RelativeSeek : SeekMode
|
||||
307. io2.SeekMode.SeekFromEnd : SeekMode
|
||||
308. builtin type io2.Socket
|
||||
309. unique type io2.StdHandle
|
||||
310. io2.StdHandle.StdErr : StdHandle
|
||||
311. io2.StdHandle.StdIn : StdHandle
|
||||
312. io2.StdHandle.StdOut : StdHandle
|
||||
313. builtin type io2.STM
|
||||
314. io2.STM.atomically : '{STM} a ->{IO} a
|
||||
315. io2.STM.retry : '{STM} a
|
||||
316. unique type io2.STMFailure
|
||||
317. builtin type io2.ThreadId
|
||||
318. unique type io2.ThreadKilledFailure
|
||||
319. builtin type io2.Tls
|
||||
320. builtin type io2.Tls.Cipher
|
||||
321. builtin type io2.Tls.ClientConfig
|
||||
322. io2.Tls.ClientConfig.certificates.set : [SignedCert]
|
||||
293. io2.MVar.tryTake : MVar a ->{IO} Optional a
|
||||
294. builtin type io2.ProcessHandle
|
||||
295. builtin type io2.Promise
|
||||
296. io2.Promise.new : '{IO} Promise a
|
||||
297. io2.Promise.read : Promise a ->{IO} a
|
||||
298. io2.Promise.tryRead : Promise a ->{IO} Optional a
|
||||
299. io2.Promise.write : Promise a -> a ->{IO} Boolean
|
||||
300. io2.Ref.cas : Ref {IO} a -> Ticket a -> a ->{IO} Boolean
|
||||
301. io2.Ref.readForCas : Ref {IO} a ->{IO} Ticket a
|
||||
302. builtin type io2.Ref.Ticket
|
||||
303. io2.Ref.Ticket.read : Ticket a -> a
|
||||
304. unique type io2.RuntimeFailure
|
||||
305. unique type io2.SeekMode
|
||||
306. io2.SeekMode.AbsoluteSeek : SeekMode
|
||||
307. io2.SeekMode.RelativeSeek : SeekMode
|
||||
308. io2.SeekMode.SeekFromEnd : SeekMode
|
||||
309. builtin type io2.Socket
|
||||
310. unique type io2.StdHandle
|
||||
311. io2.StdHandle.StdErr : StdHandle
|
||||
312. io2.StdHandle.StdIn : StdHandle
|
||||
313. io2.StdHandle.StdOut : StdHandle
|
||||
314. builtin type io2.STM
|
||||
315. io2.STM.atomically : '{STM} a ->{IO} a
|
||||
316. io2.STM.retry : '{STM} a
|
||||
317. unique type io2.STMFailure
|
||||
318. builtin type io2.ThreadId
|
||||
319. unique type io2.ThreadKilledFailure
|
||||
320. builtin type io2.Tls
|
||||
321. builtin type io2.Tls.Cipher
|
||||
322. builtin type io2.Tls.ClientConfig
|
||||
323. io2.Tls.ClientConfig.certificates.set : [SignedCert]
|
||||
-> ClientConfig
|
||||
-> ClientConfig
|
||||
323. io2.TLS.ClientConfig.ciphers.set : [Cipher]
|
||||
324. io2.TLS.ClientConfig.ciphers.set : [Cipher]
|
||||
-> ClientConfig
|
||||
-> ClientConfig
|
||||
324. io2.Tls.ClientConfig.default : Text
|
||||
325. io2.Tls.ClientConfig.default : Text
|
||||
-> Bytes
|
||||
-> ClientConfig
|
||||
325. io2.Tls.ClientConfig.versions.set : [Version]
|
||||
326. io2.Tls.ClientConfig.versions.set : [Version]
|
||||
-> ClientConfig
|
||||
-> ClientConfig
|
||||
326. io2.Tls.decodeCert.impl : Bytes
|
||||
327. io2.Tls.decodeCert.impl : Bytes
|
||||
-> Either Failure SignedCert
|
||||
327. io2.Tls.decodePrivateKey : Bytes -> [PrivateKey]
|
||||
328. io2.Tls.encodeCert : SignedCert -> Bytes
|
||||
329. io2.Tls.encodePrivateKey : PrivateKey -> Bytes
|
||||
330. io2.Tls.handshake.impl : Tls ->{IO} Either Failure ()
|
||||
331. io2.Tls.newClient.impl : ClientConfig
|
||||
328. io2.Tls.decodePrivateKey : Bytes -> [PrivateKey]
|
||||
329. io2.Tls.encodeCert : SignedCert -> Bytes
|
||||
330. io2.Tls.encodePrivateKey : PrivateKey -> Bytes
|
||||
331. io2.Tls.handshake.impl : Tls ->{IO} Either Failure ()
|
||||
332. io2.Tls.newClient.impl : ClientConfig
|
||||
-> Socket
|
||||
->{IO} Either Failure Tls
|
||||
332. io2.Tls.newServer.impl : ServerConfig
|
||||
333. io2.Tls.newServer.impl : ServerConfig
|
||||
-> Socket
|
||||
->{IO} Either Failure Tls
|
||||
333. builtin type io2.Tls.PrivateKey
|
||||
334. io2.Tls.receive.impl : Tls ->{IO} Either Failure Bytes
|
||||
335. io2.Tls.send.impl : Tls -> Bytes ->{IO} Either Failure ()
|
||||
336. builtin type io2.Tls.ServerConfig
|
||||
337. io2.Tls.ServerConfig.certificates.set : [SignedCert]
|
||||
334. builtin type io2.Tls.PrivateKey
|
||||
335. io2.Tls.receive.impl : Tls ->{IO} Either Failure Bytes
|
||||
336. io2.Tls.send.impl : Tls -> Bytes ->{IO} Either Failure ()
|
||||
337. builtin type io2.Tls.ServerConfig
|
||||
338. io2.Tls.ServerConfig.certificates.set : [SignedCert]
|
||||
-> ServerConfig
|
||||
-> ServerConfig
|
||||
338. io2.Tls.ServerConfig.ciphers.set : [Cipher]
|
||||
339. io2.Tls.ServerConfig.ciphers.set : [Cipher]
|
||||
-> ServerConfig
|
||||
-> ServerConfig
|
||||
339. io2.Tls.ServerConfig.default : [SignedCert]
|
||||
340. io2.Tls.ServerConfig.default : [SignedCert]
|
||||
-> PrivateKey
|
||||
-> ServerConfig
|
||||
340. io2.Tls.ServerConfig.versions.set : [Version]
|
||||
341. io2.Tls.ServerConfig.versions.set : [Version]
|
||||
-> ServerConfig
|
||||
-> ServerConfig
|
||||
341. builtin type io2.Tls.SignedCert
|
||||
342. io2.Tls.terminate.impl : Tls ->{IO} Either Failure ()
|
||||
343. builtin type io2.Tls.Version
|
||||
344. unique type io2.TlsFailure
|
||||
345. builtin type io2.TVar
|
||||
346. io2.TVar.new : a ->{STM} TVar a
|
||||
347. io2.TVar.newIO : a ->{IO} TVar a
|
||||
348. io2.TVar.read : TVar a ->{STM} a
|
||||
349. io2.TVar.readIO : TVar a ->{IO} a
|
||||
350. io2.TVar.swap : TVar a -> a ->{STM} a
|
||||
351. io2.TVar.write : TVar a -> a ->{STM} ()
|
||||
352. io2.validateSandboxed : [Term] -> a -> Boolean
|
||||
353. unique type IsPropagated
|
||||
354. IsPropagated.IsPropagated : IsPropagated
|
||||
355. unique type IsTest
|
||||
356. IsTest.IsTest : IsTest
|
||||
357. unique type Link
|
||||
358. builtin type Link.Term
|
||||
359. Link.Term : Term -> Link
|
||||
360. Link.Term.toText : Term -> Text
|
||||
361. builtin type Link.Type
|
||||
362. Link.Type : Type -> Link
|
||||
363. builtin type List
|
||||
364. List.++ : [a] -> [a] -> [a]
|
||||
365. List.+: : a -> [a] -> [a]
|
||||
366. List.:+ : [a] -> a -> [a]
|
||||
367. List.at : Nat -> [a] -> Optional a
|
||||
368. List.cons : a -> [a] -> [a]
|
||||
369. List.drop : Nat -> [a] -> [a]
|
||||
370. List.empty : [a]
|
||||
371. List.size : [a] -> Nat
|
||||
372. List.snoc : [a] -> a -> [a]
|
||||
373. List.take : Nat -> [a] -> [a]
|
||||
374. metadata.isPropagated : IsPropagated
|
||||
375. metadata.isTest : IsTest
|
||||
376. builtin type MutableArray
|
||||
377. MutableArray.copyTo! : MutableArray g a
|
||||
342. builtin type io2.Tls.SignedCert
|
||||
343. io2.Tls.terminate.impl : Tls ->{IO} Either Failure ()
|
||||
344. builtin type io2.Tls.Version
|
||||
345. unique type io2.TlsFailure
|
||||
346. builtin type io2.TVar
|
||||
347. io2.TVar.new : a ->{STM} TVar a
|
||||
348. io2.TVar.newIO : a ->{IO} TVar a
|
||||
349. io2.TVar.read : TVar a ->{STM} a
|
||||
350. io2.TVar.readIO : TVar a ->{IO} a
|
||||
351. io2.TVar.swap : TVar a -> a ->{STM} a
|
||||
352. io2.TVar.write : TVar a -> a ->{STM} ()
|
||||
353. io2.validateSandboxed : [Term] -> a -> Boolean
|
||||
354. unique type IsPropagated
|
||||
355. IsPropagated.IsPropagated : IsPropagated
|
||||
356. unique type IsTest
|
||||
357. IsTest.IsTest : IsTest
|
||||
358. unique type Link
|
||||
359. builtin type Link.Term
|
||||
360. Link.Term : Term -> Link
|
||||
361. Link.Term.toText : Term -> Text
|
||||
362. builtin type Link.Type
|
||||
363. Link.Type : Type -> Link
|
||||
364. builtin type List
|
||||
365. List.++ : [a] -> [a] -> [a]
|
||||
366. List.+: : a -> [a] -> [a]
|
||||
367. List.:+ : [a] -> a -> [a]
|
||||
368. List.at : Nat -> [a] -> Optional a
|
||||
369. List.cons : a -> [a] -> [a]
|
||||
370. List.drop : Nat -> [a] -> [a]
|
||||
371. List.empty : [a]
|
||||
372. List.size : [a] -> Nat
|
||||
373. List.snoc : [a] -> a -> [a]
|
||||
374. List.take : Nat -> [a] -> [a]
|
||||
375. metadata.isPropagated : IsPropagated
|
||||
376. metadata.isTest : IsTest
|
||||
377. builtin type MutableArray
|
||||
378. MutableArray.copyTo! : MutableArray g a
|
||||
-> Nat
|
||||
-> MutableArray g a
|
||||
-> Nat
|
||||
-> Nat
|
||||
->{g, Exception} ()
|
||||
378. MutableArray.freeze : MutableArray g a
|
||||
379. MutableArray.freeze : MutableArray g a
|
||||
-> Nat
|
||||
-> Nat
|
||||
->{g} ImmutableArray a
|
||||
379. MutableArray.freeze! : MutableArray g a
|
||||
380. MutableArray.freeze! : MutableArray g a
|
||||
->{g} ImmutableArray a
|
||||
380. MutableArray.read : MutableArray g a
|
||||
381. MutableArray.read : MutableArray g a
|
||||
-> Nat
|
||||
->{g, Exception} a
|
||||
381. MutableArray.size : MutableArray g a -> Nat
|
||||
382. MutableArray.write : MutableArray g a
|
||||
382. MutableArray.size : MutableArray g a -> Nat
|
||||
383. MutableArray.write : MutableArray g a
|
||||
-> Nat
|
||||
-> a
|
||||
->{g, Exception} ()
|
||||
383. builtin type MutableByteArray
|
||||
384. MutableByteArray.copyTo! : MutableByteArray g
|
||||
384. builtin type MutableByteArray
|
||||
385. MutableByteArray.copyTo! : MutableByteArray g
|
||||
-> Nat
|
||||
-> MutableByteArray g
|
||||
-> Nat
|
||||
-> Nat
|
||||
->{g, Exception} ()
|
||||
385. MutableByteArray.freeze : MutableByteArray g
|
||||
386. MutableByteArray.freeze : MutableByteArray g
|
||||
-> Nat
|
||||
-> Nat
|
||||
->{g} ImmutableByteArray
|
||||
386. MutableByteArray.freeze! : MutableByteArray g
|
||||
387. MutableByteArray.freeze! : MutableByteArray g
|
||||
->{g} ImmutableByteArray
|
||||
387. MutableByteArray.read16be : MutableByteArray g
|
||||
388. MutableByteArray.read16be : MutableByteArray g
|
||||
-> Nat
|
||||
->{g, Exception} Nat
|
||||
388. MutableByteArray.read24be : MutableByteArray g
|
||||
389. MutableByteArray.read24be : MutableByteArray g
|
||||
-> Nat
|
||||
->{g, Exception} Nat
|
||||
389. MutableByteArray.read32be : MutableByteArray g
|
||||
390. MutableByteArray.read32be : MutableByteArray g
|
||||
-> Nat
|
||||
->{g, Exception} Nat
|
||||
390. MutableByteArray.read40be : MutableByteArray g
|
||||
391. MutableByteArray.read40be : MutableByteArray g
|
||||
-> Nat
|
||||
->{g, Exception} Nat
|
||||
391. MutableByteArray.read64be : MutableByteArray g
|
||||
392. MutableByteArray.read64be : MutableByteArray g
|
||||
-> Nat
|
||||
->{g, Exception} Nat
|
||||
392. MutableByteArray.read8 : MutableByteArray g
|
||||
393. MutableByteArray.read8 : MutableByteArray g
|
||||
-> Nat
|
||||
->{g, Exception} Nat
|
||||
393. MutableByteArray.size : MutableByteArray g -> Nat
|
||||
394. MutableByteArray.write16be : MutableByteArray g
|
||||
394. MutableByteArray.size : MutableByteArray g -> Nat
|
||||
395. MutableByteArray.write16be : MutableByteArray g
|
||||
-> Nat
|
||||
-> Nat
|
||||
->{g, Exception} ()
|
||||
395. MutableByteArray.write32be : MutableByteArray g
|
||||
396. MutableByteArray.write32be : MutableByteArray g
|
||||
-> Nat
|
||||
-> Nat
|
||||
->{g, Exception} ()
|
||||
396. MutableByteArray.write64be : MutableByteArray g
|
||||
397. MutableByteArray.write64be : MutableByteArray g
|
||||
-> Nat
|
||||
-> Nat
|
||||
->{g, Exception} ()
|
||||
397. MutableByteArray.write8 : MutableByteArray g
|
||||
398. MutableByteArray.write8 : MutableByteArray g
|
||||
-> Nat
|
||||
-> Nat
|
||||
->{g, Exception} ()
|
||||
398. builtin type Nat
|
||||
399. Nat.* : Nat -> Nat -> Nat
|
||||
400. Nat.+ : Nat -> Nat -> Nat
|
||||
401. Nat./ : Nat -> Nat -> Nat
|
||||
402. Nat.and : Nat -> Nat -> Nat
|
||||
403. Nat.complement : Nat -> Nat
|
||||
404. Nat.drop : Nat -> Nat -> Nat
|
||||
405. Nat.eq : Nat -> Nat -> Boolean
|
||||
406. Nat.fromText : Text -> Optional Nat
|
||||
407. Nat.gt : Nat -> Nat -> Boolean
|
||||
408. Nat.gteq : Nat -> Nat -> Boolean
|
||||
409. Nat.increment : Nat -> Nat
|
||||
410. Nat.isEven : Nat -> Boolean
|
||||
411. Nat.isOdd : Nat -> Boolean
|
||||
412. Nat.leadingZeros : Nat -> Nat
|
||||
413. Nat.lt : Nat -> Nat -> Boolean
|
||||
414. Nat.lteq : Nat -> Nat -> Boolean
|
||||
415. Nat.mod : Nat -> Nat -> Nat
|
||||
416. Nat.or : Nat -> Nat -> Nat
|
||||
417. Nat.popCount : Nat -> Nat
|
||||
418. Nat.pow : Nat -> Nat -> Nat
|
||||
419. Nat.shiftLeft : Nat -> Nat -> Nat
|
||||
420. Nat.shiftRight : Nat -> Nat -> Nat
|
||||
421. Nat.sub : Nat -> Nat -> Int
|
||||
422. Nat.toFloat : Nat -> Float
|
||||
423. Nat.toInt : Nat -> Int
|
||||
424. Nat.toText : Nat -> Text
|
||||
425. Nat.trailingZeros : Nat -> Nat
|
||||
426. Nat.xor : Nat -> Nat -> Nat
|
||||
427. structural type Optional a
|
||||
428. Optional.None : Optional a
|
||||
429. Optional.Some : a -> Optional a
|
||||
430. builtin type Pattern
|
||||
431. Pattern.capture : Pattern a -> Pattern a
|
||||
432. Pattern.isMatch : Pattern a -> a -> Boolean
|
||||
433. Pattern.join : [Pattern a] -> Pattern a
|
||||
434. Pattern.many : Pattern a -> Pattern a
|
||||
435. Pattern.or : Pattern a -> Pattern a -> Pattern a
|
||||
436. Pattern.replicate : Nat -> Nat -> Pattern a -> Pattern a
|
||||
437. Pattern.run : Pattern a -> a -> Optional ([a], a)
|
||||
438. builtin type Ref
|
||||
439. Ref.read : Ref g a ->{g} a
|
||||
440. Ref.write : Ref g a -> a ->{g} ()
|
||||
441. builtin type Request
|
||||
442. builtin type Scope
|
||||
443. Scope.array : Nat ->{Scope s} MutableArray (Scope s) a
|
||||
444. Scope.arrayOf : a
|
||||
399. builtin type Nat
|
||||
400. Nat.* : Nat -> Nat -> Nat
|
||||
401. Nat.+ : Nat -> Nat -> Nat
|
||||
402. Nat./ : Nat -> Nat -> Nat
|
||||
403. Nat.and : Nat -> Nat -> Nat
|
||||
404. Nat.complement : Nat -> Nat
|
||||
405. Nat.drop : Nat -> Nat -> Nat
|
||||
406. Nat.eq : Nat -> Nat -> Boolean
|
||||
407. Nat.fromText : Text -> Optional Nat
|
||||
408. Nat.gt : Nat -> Nat -> Boolean
|
||||
409. Nat.gteq : Nat -> Nat -> Boolean
|
||||
410. Nat.increment : Nat -> Nat
|
||||
411. Nat.isEven : Nat -> Boolean
|
||||
412. Nat.isOdd : Nat -> Boolean
|
||||
413. Nat.leadingZeros : Nat -> Nat
|
||||
414. Nat.lt : Nat -> Nat -> Boolean
|
||||
415. Nat.lteq : Nat -> Nat -> Boolean
|
||||
416. Nat.mod : Nat -> Nat -> Nat
|
||||
417. Nat.or : Nat -> Nat -> Nat
|
||||
418. Nat.popCount : Nat -> Nat
|
||||
419. Nat.pow : Nat -> Nat -> Nat
|
||||
420. Nat.shiftLeft : Nat -> Nat -> Nat
|
||||
421. Nat.shiftRight : Nat -> Nat -> Nat
|
||||
422. Nat.sub : Nat -> Nat -> Int
|
||||
423. Nat.toFloat : Nat -> Float
|
||||
424. Nat.toInt : Nat -> Int
|
||||
425. Nat.toText : Nat -> Text
|
||||
426. Nat.trailingZeros : Nat -> Nat
|
||||
427. Nat.xor : Nat -> Nat -> Nat
|
||||
428. structural type Optional a
|
||||
429. Optional.None : Optional a
|
||||
430. Optional.Some : a -> Optional a
|
||||
431. builtin type Pattern
|
||||
432. Pattern.capture : Pattern a -> Pattern a
|
||||
433. Pattern.isMatch : Pattern a -> a -> Boolean
|
||||
434. Pattern.join : [Pattern a] -> Pattern a
|
||||
435. Pattern.many : Pattern a -> Pattern a
|
||||
436. Pattern.or : Pattern a -> Pattern a -> Pattern a
|
||||
437. Pattern.replicate : Nat -> Nat -> Pattern a -> Pattern a
|
||||
438. Pattern.run : Pattern a -> a -> Optional ([a], a)
|
||||
439. builtin type Ref
|
||||
440. Ref.read : Ref g a ->{g} a
|
||||
441. Ref.write : Ref g a -> a ->{g} ()
|
||||
442. builtin type Request
|
||||
443. builtin type Scope
|
||||
444. Scope.array : Nat ->{Scope s} MutableArray (Scope s) a
|
||||
445. Scope.arrayOf : a
|
||||
-> Nat
|
||||
->{Scope s} MutableArray (Scope s) a
|
||||
445. Scope.bytearray : Nat
|
||||
446. Scope.bytearray : Nat
|
||||
->{Scope s} MutableByteArray (Scope s)
|
||||
446. Scope.bytearrayOf : Nat
|
||||
447. Scope.bytearrayOf : Nat
|
||||
-> Nat
|
||||
->{Scope s} MutableByteArray
|
||||
(Scope s)
|
||||
447. Scope.ref : a ->{Scope s} Ref {Scope s} a
|
||||
448. Scope.run : (∀ s. '{g, Scope s} r) ->{g} r
|
||||
449. structural type SeqView a b
|
||||
450. SeqView.VElem : a -> b -> SeqView a b
|
||||
451. SeqView.VEmpty : SeqView a b
|
||||
452. Socket.toText : Socket -> Text
|
||||
453. unique type Test.Result
|
||||
454. Test.Result.Fail : Text -> Result
|
||||
455. Test.Result.Ok : Text -> Result
|
||||
456. builtin type Text
|
||||
457. Text.!= : Text -> Text -> Boolean
|
||||
458. Text.++ : Text -> Text -> Text
|
||||
459. Text.drop : Nat -> Text -> Text
|
||||
460. Text.empty : Text
|
||||
461. Text.eq : Text -> Text -> Boolean
|
||||
462. Text.fromCharList : [Char] -> Text
|
||||
463. Text.fromUtf8.impl : Bytes -> Either Failure Text
|
||||
464. Text.gt : Text -> Text -> Boolean
|
||||
465. Text.gteq : Text -> Text -> Boolean
|
||||
466. Text.indexOf : Text -> Text -> Optional Nat
|
||||
467. Text.lt : Text -> Text -> Boolean
|
||||
468. Text.lteq : Text -> Text -> Boolean
|
||||
469. Text.patterns.anyChar : Pattern Text
|
||||
470. Text.patterns.char : Class -> Pattern Text
|
||||
471. Text.patterns.charIn : [Char] -> Pattern Text
|
||||
472. Text.patterns.charRange : Char -> Char -> Pattern Text
|
||||
473. Text.patterns.digit : Pattern Text
|
||||
474. Text.patterns.eof : Pattern Text
|
||||
475. Text.patterns.letter : Pattern Text
|
||||
476. Text.patterns.literal : Text -> Pattern Text
|
||||
477. Text.patterns.notCharIn : [Char] -> Pattern Text
|
||||
478. Text.patterns.notCharRange : Char -> Char -> Pattern Text
|
||||
479. Text.patterns.punctuation : Pattern Text
|
||||
480. Text.patterns.space : Pattern Text
|
||||
481. Text.repeat : Nat -> Text -> Text
|
||||
482. Text.reverse : Text -> Text
|
||||
483. Text.size : Text -> Nat
|
||||
484. Text.take : Nat -> Text -> Text
|
||||
485. Text.toCharList : Text -> [Char]
|
||||
486. Text.toLowercase : Text -> Text
|
||||
487. Text.toUppercase : Text -> Text
|
||||
488. Text.toUtf8 : Text -> Bytes
|
||||
489. Text.uncons : Text -> Optional (Char, Text)
|
||||
490. Text.unsnoc : Text -> Optional (Text, Char)
|
||||
491. ThreadId.toText : ThreadId -> Text
|
||||
492. todo : a -> b
|
||||
493. structural type Tuple a b
|
||||
494. Tuple.Cons : a -> b -> Tuple a b
|
||||
495. structural type Unit
|
||||
496. Unit.Unit : ()
|
||||
497. Universal.< : a -> a -> Boolean
|
||||
498. Universal.<= : a -> a -> Boolean
|
||||
499. Universal.== : a -> a -> Boolean
|
||||
500. Universal.> : a -> a -> Boolean
|
||||
501. Universal.>= : a -> a -> Boolean
|
||||
502. Universal.compare : a -> a -> Int
|
||||
503. Universal.murmurHash : a -> Nat
|
||||
504. unsafe.coerceAbilities : (a ->{e1} b) -> a ->{e2} b
|
||||
505. builtin type Value
|
||||
506. Value.dependencies : Value -> [Term]
|
||||
507. Value.deserialize : Bytes -> Either Text Value
|
||||
508. Value.load : Value ->{IO} Either [Term] a
|
||||
509. Value.serialize : Value -> Bytes
|
||||
510. Value.value : a -> Value
|
||||
448. Scope.ref : a ->{Scope s} Ref {Scope s} a
|
||||
449. Scope.run : (∀ s. '{g, Scope s} r) ->{g} r
|
||||
450. structural type SeqView a b
|
||||
451. SeqView.VElem : a -> b -> SeqView a b
|
||||
452. SeqView.VEmpty : SeqView a b
|
||||
453. Socket.toText : Socket -> Text
|
||||
454. unique type Test.Result
|
||||
455. Test.Result.Fail : Text -> Result
|
||||
456. Test.Result.Ok : Text -> Result
|
||||
457. builtin type Text
|
||||
458. Text.!= : Text -> Text -> Boolean
|
||||
459. Text.++ : Text -> Text -> Text
|
||||
460. Text.drop : Nat -> Text -> Text
|
||||
461. Text.empty : Text
|
||||
462. Text.eq : Text -> Text -> Boolean
|
||||
463. Text.fromCharList : [Char] -> Text
|
||||
464. Text.fromUtf8.impl : Bytes -> Either Failure Text
|
||||
465. Text.gt : Text -> Text -> Boolean
|
||||
466. Text.gteq : Text -> Text -> Boolean
|
||||
467. Text.indexOf : Text -> Text -> Optional Nat
|
||||
468. Text.lt : Text -> Text -> Boolean
|
||||
469. Text.lteq : Text -> Text -> Boolean
|
||||
470. Text.patterns.anyChar : Pattern Text
|
||||
471. Text.patterns.char : Class -> Pattern Text
|
||||
472. Text.patterns.charIn : [Char] -> Pattern Text
|
||||
473. Text.patterns.charRange : Char -> Char -> Pattern Text
|
||||
474. Text.patterns.digit : Pattern Text
|
||||
475. Text.patterns.eof : Pattern Text
|
||||
476. Text.patterns.letter : Pattern Text
|
||||
477. Text.patterns.literal : Text -> Pattern Text
|
||||
478. Text.patterns.notCharIn : [Char] -> Pattern Text
|
||||
479. Text.patterns.notCharRange : Char -> Char -> Pattern Text
|
||||
480. Text.patterns.punctuation : Pattern Text
|
||||
481. Text.patterns.space : Pattern Text
|
||||
482. Text.repeat : Nat -> Text -> Text
|
||||
483. Text.reverse : Text -> Text
|
||||
484. Text.size : Text -> Nat
|
||||
485. Text.take : Nat -> Text -> Text
|
||||
486. Text.toCharList : Text -> [Char]
|
||||
487. Text.toLowercase : Text -> Text
|
||||
488. Text.toUppercase : Text -> Text
|
||||
489. Text.toUtf8 : Text -> Bytes
|
||||
490. Text.uncons : Text -> Optional (Char, Text)
|
||||
491. Text.unsnoc : Text -> Optional (Text, Char)
|
||||
492. ThreadId.toText : ThreadId -> Text
|
||||
493. todo : a -> b
|
||||
494. structural type Tuple a b
|
||||
495. Tuple.Cons : a -> b -> Tuple a b
|
||||
496. structural type Unit
|
||||
497. Unit.Unit : ()
|
||||
498. Universal.< : a -> a -> Boolean
|
||||
499. Universal.<= : a -> a -> Boolean
|
||||
500. Universal.== : a -> a -> Boolean
|
||||
501. Universal.> : a -> a -> Boolean
|
||||
502. Universal.>= : a -> a -> Boolean
|
||||
503. Universal.compare : a -> a -> Int
|
||||
504. Universal.murmurHash : a -> Nat
|
||||
505. unsafe.coerceAbilities : (a ->{e1} b) -> a ->{e2} b
|
||||
506. builtin type Value
|
||||
507. Value.dependencies : Value -> [Term]
|
||||
508. Value.deserialize : Bytes -> Either Text Value
|
||||
509. Value.load : Value ->{IO} Either [Term] a
|
||||
510. Value.serialize : Value -> Bytes
|
||||
511. Value.value : a -> Value
|
||||
|
||||
|
||||
.builtin> alias.many 94-104 .mylib
|
||||
|
@ -2,8 +2,8 @@ The `branch` command creates a new branch.
|
||||
|
||||
```ucm:hide
|
||||
.> builtins.merge
|
||||
.> project.create foo
|
||||
.> project.create bar
|
||||
.> project.create-empty foo
|
||||
.> project.create-empty bar
|
||||
```
|
||||
|
||||
First, we'll just create a loose code namespace with a term in it for later.
|
||||
|
@ -74,7 +74,7 @@ The `builtins.merge` command adds the known builtins to a `builtin` subnamespace
|
||||
63. Value/ (5 terms)
|
||||
64. bug (a -> b)
|
||||
65. crypto/ (13 terms, 1 type)
|
||||
66. io2/ (132 terms, 32 types)
|
||||
66. io2/ (133 terms, 32 types)
|
||||
67. metadata/ (2 terms)
|
||||
68. todo (a -> b)
|
||||
69. unsafe/ (1 term)
|
||||
|
@ -2,7 +2,7 @@ Deleting the branch you are on takes you to its parent (though this is impossibl
|
||||
your working directory with each command).
|
||||
|
||||
```ucm
|
||||
.> project.create foo
|
||||
.> project.create-empty foo
|
||||
foo/main> branch topic
|
||||
foo/topic> delete.branch /topic
|
||||
```
|
||||
|
@ -2,10 +2,22 @@ Deleting the branch you are on takes you to its parent (though this is impossibl
|
||||
your working directory with each command).
|
||||
|
||||
```ucm
|
||||
.> project.create foo
|
||||
.> project.create-empty foo
|
||||
|
||||
🎉 I've created the project foo.
|
||||
|
||||
🎨 Type `ui` to explore this project's code in your browser.
|
||||
🔭 Discover libraries at https://share.unison-lang.org
|
||||
📖 Use `help-topic projects` to learn more about projects.
|
||||
|
||||
Write your first Unison code with UCM:
|
||||
|
||||
1. Open scratch.u.
|
||||
2. Write some Unison code and save the file.
|
||||
3. In UCM, type `add` to save it to your new project.
|
||||
|
||||
🎉 🥳 Happy coding!
|
||||
|
||||
foo/main> branch topic
|
||||
|
||||
Done. I've created the topic branch based off of main.
|
||||
|
@ -1,8 +1,8 @@
|
||||
# delete.project
|
||||
|
||||
```ucm
|
||||
.> project.create foo
|
||||
.> project.create bar
|
||||
.> project.create-empty foo
|
||||
.> project.create-empty bar
|
||||
.> projects
|
||||
foo/main> delete.project foo
|
||||
.> projects
|
||||
|
@ -1,16 +1,40 @@
|
||||
# delete.project
|
||||
|
||||
```ucm
|
||||
.> project.create foo
|
||||
.> project.create-empty foo
|
||||
|
||||
🎉 I've created the project foo.
|
||||
|
||||
🎨 Type `ui` to explore this project's code in your browser.
|
||||
🔭 Discover libraries at https://share.unison-lang.org
|
||||
📖 Use `help-topic projects` to learn more about projects.
|
||||
|
||||
Write your first Unison code with UCM:
|
||||
|
||||
1. Open scratch.u.
|
||||
2. Write some Unison code and save the file.
|
||||
3. In UCM, type `add` to save it to your new project.
|
||||
|
||||
🎉 🥳 Happy coding!
|
||||
|
||||
☝️ The namespace . is empty.
|
||||
|
||||
.> project.create bar
|
||||
.> project.create-empty bar
|
||||
|
||||
🎉 I've created the project bar.
|
||||
|
||||
🎨 Type `ui` to explore this project's code in your browser.
|
||||
🔭 Discover libraries at https://share.unison-lang.org
|
||||
📖 Use `help-topic projects` to learn more about projects.
|
||||
|
||||
Write your first Unison code with UCM:
|
||||
|
||||
1. Open scratch.u.
|
||||
2. Write some Unison code and save the file.
|
||||
3. In UCM, type `add` to save it to your new project.
|
||||
|
||||
🎉 🥳 Happy coding!
|
||||
|
||||
☝️ The namespace . is empty.
|
||||
|
||||
.> projects
|
||||
|
@ -23,7 +23,7 @@ Technically, the definitions all exist, but they have no names. `builtins.merge`
|
||||
|
||||
.foo> ls
|
||||
|
||||
1. builtin/ (444 terms, 66 types)
|
||||
1. builtin/ (445 terms, 66 types)
|
||||
|
||||
```
|
||||
And for a limited time, you can get even more builtin goodies:
|
||||
@ -35,7 +35,7 @@ And for a limited time, you can get even more builtin goodies:
|
||||
|
||||
.foo> ls
|
||||
|
||||
1. builtin/ (616 terms, 84 types)
|
||||
1. builtin/ (617 terms, 84 types)
|
||||
|
||||
```
|
||||
More typically, you'd start out by pulling `base.
|
||||
|
@ -407,3 +407,19 @@ testTimeZone = do
|
||||
.> run testTimeZone
|
||||
```
|
||||
|
||||
### Get some random bytes
|
||||
|
||||
```unison:hide
|
||||
testRandom : '{io2.IO} [Result]
|
||||
testRandom = do
|
||||
test = do
|
||||
bytes = IO.randomBytes 10
|
||||
check "randomBytes returns the right number of bytes" (size bytes == 10)
|
||||
runTest test
|
||||
```
|
||||
|
||||
```ucm
|
||||
.> add
|
||||
.> io.test testGetEnv
|
||||
```
|
||||
|
||||
|
@ -675,3 +675,33 @@ testTimeZone = do
|
||||
()
|
||||
|
||||
```
|
||||
### Get some random bytes
|
||||
|
||||
```unison
|
||||
testRandom : '{io2.IO} [Result]
|
||||
testRandom = do
|
||||
test = do
|
||||
bytes = IO.randomBytes 10
|
||||
check "randomBytes returns the right number of bytes" (size bytes == 10)
|
||||
runTest test
|
||||
```
|
||||
|
||||
```ucm
|
||||
.> add
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
||||
testRandom : '{IO} [Result]
|
||||
|
||||
.> io.test testGetEnv
|
||||
|
||||
New test results:
|
||||
|
||||
◉ testGetEnv PATH environent variable should be set
|
||||
◉ testGetEnv DOESNTEXIST didn't exist
|
||||
|
||||
✅ 2 test(s) passing
|
||||
|
||||
Tip: Use view testGetEnv to view the source of a test.
|
||||
|
||||
```
|
||||
|
@ -115,13 +115,13 @@ it's still in the `history` of the parent namespace and can be resurrected at an
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #f6od7ck7o9
|
||||
⊙ 1. #sch8ktifgr
|
||||
|
||||
- Deletes:
|
||||
|
||||
feature1.y
|
||||
|
||||
⊙ 2. #heefa0k2c2
|
||||
⊙ 2. #ith4t7v4vg
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
@ -132,26 +132,26 @@ it's still in the `history` of the parent namespace and can be resurrected at an
|
||||
Original name New name(s)
|
||||
feature1.y master.y
|
||||
|
||||
⊙ 3. #ch6bfhmr01
|
||||
⊙ 3. #n3o88a18gi
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
feature1.y
|
||||
|
||||
⊙ 4. #ipqe7pdtbj
|
||||
⊙ 4. #6ko53cmfad
|
||||
|
||||
> Moves:
|
||||
|
||||
Original name New name
|
||||
x master.x
|
||||
|
||||
⊙ 5. #aupi617lfm
|
||||
⊙ 5. #ciekcpjcg5
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
x
|
||||
|
||||
□ 6. #okls7hes5i (start of history)
|
||||
□ 6. #iog2oo140r (start of history)
|
||||
|
||||
```
|
||||
To resurrect an old version of a namespace, you can learn its hash via the `history` command, then use `fork #namespacehash .newname`.
|
||||
|
@ -269,7 +269,7 @@ I should be able to move the root into a sub-namespace
|
||||
|
||||
.> ls
|
||||
|
||||
1. root/ (621 terms, 85 types)
|
||||
1. root/ (622 terms, 85 types)
|
||||
|
||||
.> history
|
||||
|
||||
@ -278,13 +278,13 @@ I should be able to move the root into a sub-namespace
|
||||
|
||||
|
||||
|
||||
□ 1. #d7nl0iepe9 (start of history)
|
||||
□ 1. #u3bfr3r2ei (start of history)
|
||||
|
||||
```
|
||||
```ucm
|
||||
.> ls .root.at.path
|
||||
|
||||
1. builtin/ (616 terms, 84 types)
|
||||
1. builtin/ (617 terms, 84 types)
|
||||
2. existing/ (1 term)
|
||||
3. happy/ (3 terms, 1 type)
|
||||
4. history/ (1 term)
|
||||
@ -294,7 +294,7 @@ I should be able to move the root into a sub-namespace
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #u5b78mseu5
|
||||
⊙ 1. #kq43nl1o04
|
||||
|
||||
- Deletes:
|
||||
|
||||
@ -305,7 +305,7 @@ I should be able to move the root into a sub-namespace
|
||||
Original name New name
|
||||
existing.a.termInA existing.b.termInA
|
||||
|
||||
⊙ 2. #l536jkmva1
|
||||
⊙ 2. #4ukqhpj1ih
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
@ -317,26 +317,26 @@ I should be able to move the root into a sub-namespace
|
||||
happy.b.termInA existing.a.termInA
|
||||
history.b.termInA existing.a.termInA
|
||||
|
||||
⊙ 3. #l3c9t29mk5
|
||||
⊙ 3. #l2cn17ai85
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
existing.a.termInA existing.b.termInB
|
||||
|
||||
⊙ 4. #6qe2efg2ej
|
||||
⊙ 4. #3rbcejtv6q
|
||||
|
||||
> Moves:
|
||||
|
||||
Original name New name
|
||||
history.a.termInA history.b.termInA
|
||||
|
||||
⊙ 5. #n2pk3n46k1
|
||||
⊙ 5. #3ne1c2n3ob
|
||||
|
||||
- Deletes:
|
||||
|
||||
history.b.termInB
|
||||
|
||||
⊙ 6. #fe8hescuc7
|
||||
⊙ 6. #ui7k5bt5gd
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
@ -347,13 +347,13 @@ I should be able to move the root into a sub-namespace
|
||||
Original name New name(s)
|
||||
happy.b.termInA history.a.termInA
|
||||
|
||||
⊙ 7. #902pi46cvk
|
||||
⊙ 7. #5mcatjsb8n
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
history.a.termInA history.b.termInB
|
||||
|
||||
⊙ 8. #h3soer49rq
|
||||
⊙ 8. #74jssi3o9e
|
||||
|
||||
> Moves:
|
||||
|
||||
@ -363,7 +363,7 @@ I should be able to move the root into a sub-namespace
|
||||
happy.a.T.T2 happy.b.T.T2
|
||||
happy.a.termInA happy.b.termInA
|
||||
|
||||
⊙ 9. #gn938smc7r
|
||||
⊙ 9. #esu945u1md
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
@ -373,7 +373,7 @@ I should be able to move the root into a sub-namespace
|
||||
|
||||
happy.a.T.T
|
||||
|
||||
⊙ 10. #nkng97evbr
|
||||
⊙ 10. #cas2jteq60
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
@ -385,7 +385,7 @@ I should be able to move the root into a sub-namespace
|
||||
|
||||
⠇
|
||||
|
||||
⊙ 11. #8pvqa03j6q
|
||||
⊙ 11. #gdutne6b5t
|
||||
|
||||
|
||||
```
|
||||
|
@ -1106,361 +1106,363 @@ d = c + 10
|
||||
394. builtin.Char.Class.punctuation : Class
|
||||
395. builtin.Text.patterns.punctuation : Pattern
|
||||
Text
|
||||
396. builtin.Char.Class.range : Char
|
||||
396. builtin.io2.IO.randomBytes : Nat
|
||||
->{IO} Bytes
|
||||
397. builtin.Char.Class.range : Char
|
||||
-> Char
|
||||
-> Class
|
||||
397. builtin.ImmutableArray.read : ImmutableArray
|
||||
398. builtin.ImmutableArray.read : ImmutableArray
|
||||
a
|
||||
-> Nat
|
||||
->{Exception} a
|
||||
398. builtin.MutableArray.read : MutableArray
|
||||
399. builtin.MutableArray.read : MutableArray
|
||||
g a
|
||||
-> Nat
|
||||
->{g,
|
||||
Exception} a
|
||||
399. builtin.io2.Promise.read : Promise
|
||||
400. builtin.io2.Promise.read : Promise
|
||||
a
|
||||
->{IO} a
|
||||
400. builtin.Ref.read : Ref g a
|
||||
401. builtin.Ref.read : Ref g a
|
||||
->{g} a
|
||||
401. builtin.io2.TVar.read : TVar a
|
||||
402. builtin.io2.TVar.read : TVar a
|
||||
->{STM} a
|
||||
402. builtin.io2.Ref.Ticket.read : Ticket
|
||||
403. builtin.io2.Ref.Ticket.read : Ticket
|
||||
a
|
||||
-> a
|
||||
403. builtin.ImmutableByteArray.read16be : ImmutableByteArray
|
||||
404. builtin.ImmutableByteArray.read16be : ImmutableByteArray
|
||||
-> Nat
|
||||
->{Exception} Nat
|
||||
404. builtin.MutableByteArray.read16be : MutableByteArray
|
||||
405. builtin.MutableByteArray.read16be : MutableByteArray
|
||||
g
|
||||
-> Nat
|
||||
->{g,
|
||||
Exception} Nat
|
||||
405. builtin.ImmutableByteArray.read24be : ImmutableByteArray
|
||||
406. builtin.ImmutableByteArray.read24be : ImmutableByteArray
|
||||
-> Nat
|
||||
->{Exception} Nat
|
||||
406. builtin.MutableByteArray.read24be : MutableByteArray
|
||||
407. builtin.MutableByteArray.read24be : MutableByteArray
|
||||
g
|
||||
-> Nat
|
||||
->{g,
|
||||
Exception} Nat
|
||||
407. builtin.ImmutableByteArray.read32be : ImmutableByteArray
|
||||
408. builtin.ImmutableByteArray.read32be : ImmutableByteArray
|
||||
-> Nat
|
||||
->{Exception} Nat
|
||||
408. builtin.MutableByteArray.read32be : MutableByteArray
|
||||
409. builtin.MutableByteArray.read32be : MutableByteArray
|
||||
g
|
||||
-> Nat
|
||||
->{g,
|
||||
Exception} Nat
|
||||
409. builtin.ImmutableByteArray.read40be : ImmutableByteArray
|
||||
410. builtin.ImmutableByteArray.read40be : ImmutableByteArray
|
||||
-> Nat
|
||||
->{Exception} Nat
|
||||
410. builtin.MutableByteArray.read40be : MutableByteArray
|
||||
411. builtin.MutableByteArray.read40be : MutableByteArray
|
||||
g
|
||||
-> Nat
|
||||
->{g,
|
||||
Exception} Nat
|
||||
411. builtin.ImmutableByteArray.read64be : ImmutableByteArray
|
||||
412. builtin.ImmutableByteArray.read64be : ImmutableByteArray
|
||||
-> Nat
|
||||
->{Exception} Nat
|
||||
412. builtin.MutableByteArray.read64be : MutableByteArray
|
||||
413. builtin.MutableByteArray.read64be : MutableByteArray
|
||||
g
|
||||
-> Nat
|
||||
->{g,
|
||||
Exception} Nat
|
||||
413. builtin.ImmutableByteArray.read8 : ImmutableByteArray
|
||||
414. builtin.ImmutableByteArray.read8 : ImmutableByteArray
|
||||
-> Nat
|
||||
->{Exception} Nat
|
||||
414. builtin.MutableByteArray.read8 : MutableByteArray
|
||||
415. builtin.MutableByteArray.read8 : MutableByteArray
|
||||
g
|
||||
-> Nat
|
||||
->{g,
|
||||
Exception} Nat
|
||||
415. builtin.io2.Ref.readForCas : Ref
|
||||
416. builtin.io2.Ref.readForCas : Ref
|
||||
{IO} a
|
||||
->{IO} Ticket
|
||||
a
|
||||
416. builtin.io2.TVar.readIO : TVar a
|
||||
417. builtin.io2.TVar.readIO : TVar a
|
||||
->{IO} a
|
||||
417. builtin.io2.Clock.internals.realtime : '{IO} Either
|
||||
418. builtin.io2.Clock.internals.realtime : '{IO} Either
|
||||
Failure
|
||||
TimeSpec
|
||||
418. builtin.io2.IO.ref : a
|
||||
419. builtin.io2.IO.ref : a
|
||||
->{IO} Ref
|
||||
{IO} a
|
||||
419. builtin.Scope.ref : a
|
||||
420. builtin.Scope.ref : a
|
||||
->{Scope
|
||||
s} Ref
|
||||
{Scope
|
||||
s}
|
||||
a
|
||||
420. builtin.Text.repeat : Nat
|
||||
421. builtin.Text.repeat : Nat
|
||||
-> Text
|
||||
-> Text
|
||||
421. builtin.Pattern.replicate : Nat
|
||||
422. builtin.Pattern.replicate : Nat
|
||||
-> Nat
|
||||
-> Pattern
|
||||
a
|
||||
-> Pattern
|
||||
a
|
||||
422. builtin.io2.STM.retry : '{STM} a
|
||||
423. builtin.Text.reverse : Text
|
||||
423. builtin.io2.STM.retry : '{STM} a
|
||||
424. builtin.Text.reverse : Text
|
||||
-> Text
|
||||
424. builtin.Float.round : Float
|
||||
425. builtin.Float.round : Float
|
||||
-> Int
|
||||
425. builtin.Pattern.run : Pattern
|
||||
426. builtin.Pattern.run : Pattern
|
||||
a
|
||||
-> a
|
||||
-> Optional
|
||||
( [a],
|
||||
a)
|
||||
426. builtin.Scope.run : (∀ s.
|
||||
427. builtin.Scope.run : (∀ s.
|
||||
'{g,
|
||||
Scope s} r)
|
||||
->{g} r
|
||||
427. builtin.io2.Clock.internals.sec : TimeSpec
|
||||
428. builtin.io2.Clock.internals.sec : TimeSpec
|
||||
-> Int
|
||||
428. builtin.Char.Class.separator : Class
|
||||
429. builtin.Code.serialize : Code
|
||||
429. builtin.Char.Class.separator : Class
|
||||
430. builtin.Code.serialize : Code
|
||||
-> Bytes
|
||||
430. builtin.Value.serialize : Value
|
||||
431. builtin.Value.serialize : Value
|
||||
-> Bytes
|
||||
431. builtin.io2.Tls.ClientConfig.certificates.set : [SignedCert]
|
||||
432. builtin.io2.Tls.ClientConfig.certificates.set : [SignedCert]
|
||||
-> ClientConfig
|
||||
-> ClientConfig
|
||||
432. builtin.io2.Tls.ServerConfig.certificates.set : [SignedCert]
|
||||
433. builtin.io2.Tls.ServerConfig.certificates.set : [SignedCert]
|
||||
-> ServerConfig
|
||||
-> ServerConfig
|
||||
433. builtin.io2.TLS.ClientConfig.ciphers.set : [Cipher]
|
||||
434. builtin.io2.TLS.ClientConfig.ciphers.set : [Cipher]
|
||||
-> ClientConfig
|
||||
-> ClientConfig
|
||||
434. builtin.io2.Tls.ServerConfig.ciphers.set : [Cipher]
|
||||
435. builtin.io2.Tls.ServerConfig.ciphers.set : [Cipher]
|
||||
-> ServerConfig
|
||||
-> ServerConfig
|
||||
435. builtin.io2.Tls.ClientConfig.versions.set : [Version]
|
||||
436. builtin.io2.Tls.ClientConfig.versions.set : [Version]
|
||||
-> ClientConfig
|
||||
-> ClientConfig
|
||||
436. builtin.io2.Tls.ServerConfig.versions.set : [Version]
|
||||
437. builtin.io2.Tls.ServerConfig.versions.set : [Version]
|
||||
-> ServerConfig
|
||||
-> ServerConfig
|
||||
437. builtin.Int.shiftLeft : Int
|
||||
438. builtin.Int.shiftLeft : Int
|
||||
-> Nat
|
||||
-> Int
|
||||
438. builtin.Nat.shiftLeft : Nat
|
||||
439. builtin.Nat.shiftLeft : Nat
|
||||
-> Nat
|
||||
-> Nat
|
||||
439. builtin.Int.shiftRight : Int
|
||||
440. builtin.Int.shiftRight : Int
|
||||
-> Nat
|
||||
-> Int
|
||||
440. builtin.Nat.shiftRight : Nat
|
||||
441. builtin.Nat.shiftRight : Nat
|
||||
-> Nat
|
||||
-> Nat
|
||||
441. builtin.Int.signum : Int
|
||||
442. builtin.Int.signum : Int
|
||||
-> Int
|
||||
442. builtin.Float.sin : Float
|
||||
443. builtin.Float.sin : Float
|
||||
-> Float
|
||||
443. builtin.Float.sinh : Float
|
||||
444. builtin.Float.sinh : Float
|
||||
-> Float
|
||||
444. builtin.Bytes.size : Bytes
|
||||
445. builtin.Bytes.size : Bytes
|
||||
-> Nat
|
||||
445. builtin.ImmutableArray.size : ImmutableArray
|
||||
446. builtin.ImmutableArray.size : ImmutableArray
|
||||
a
|
||||
-> Nat
|
||||
446. builtin.ImmutableByteArray.size : ImmutableByteArray
|
||||
447. builtin.ImmutableByteArray.size : ImmutableByteArray
|
||||
-> Nat
|
||||
447. builtin.List.size : [a]
|
||||
448. builtin.List.size : [a]
|
||||
-> Nat
|
||||
448. builtin.MutableArray.size : MutableArray
|
||||
449. builtin.MutableArray.size : MutableArray
|
||||
g a
|
||||
-> Nat
|
||||
449. builtin.MutableByteArray.size : MutableByteArray
|
||||
450. builtin.MutableByteArray.size : MutableByteArray
|
||||
g
|
||||
-> Nat
|
||||
450. builtin.Text.size : Text
|
||||
451. builtin.Text.size : Text
|
||||
-> Nat
|
||||
451. builtin.Text.patterns.space : Pattern
|
||||
452. builtin.Text.patterns.space : Pattern
|
||||
Text
|
||||
452. builtin.Float.sqrt : Float
|
||||
453. builtin.Float.sqrt : Float
|
||||
-> Float
|
||||
453. builtin.io2.IO.process.start : Text
|
||||
454. builtin.io2.IO.process.start : Text
|
||||
-> [Text]
|
||||
->{IO} ( Handle,
|
||||
Handle,
|
||||
Handle,
|
||||
ProcessHandle)
|
||||
454. builtin.io2.IO.stdHandle : StdHandle
|
||||
455. builtin.io2.IO.stdHandle : StdHandle
|
||||
-> Handle
|
||||
455. builtin.Nat.sub : Nat
|
||||
456. builtin.Nat.sub : Nat
|
||||
-> Nat
|
||||
-> Int
|
||||
456. builtin.io2.TVar.swap : TVar a
|
||||
457. builtin.io2.TVar.swap : TVar a
|
||||
-> a
|
||||
->{STM} a
|
||||
457. builtin.Char.Class.symbol : Class
|
||||
458. builtin.io2.IO.systemTimeMicroseconds : '{IO} Int
|
||||
459. builtin.io2.Clock.internals.systemTimeZone : Int
|
||||
458. builtin.Char.Class.symbol : Class
|
||||
459. builtin.io2.IO.systemTimeMicroseconds : '{IO} Int
|
||||
460. builtin.io2.Clock.internals.systemTimeZone : Int
|
||||
->{IO} ( Int,
|
||||
Nat,
|
||||
Text)
|
||||
460. builtin.Bytes.take : Nat
|
||||
461. builtin.Bytes.take : Nat
|
||||
-> Bytes
|
||||
-> Bytes
|
||||
461. builtin.List.take : Nat
|
||||
462. builtin.List.take : Nat
|
||||
-> [a]
|
||||
-> [a]
|
||||
462. builtin.Text.take : Nat
|
||||
463. builtin.Text.take : Nat
|
||||
-> Text
|
||||
-> Text
|
||||
463. builtin.Float.tan : Float
|
||||
464. builtin.Float.tan : Float
|
||||
-> Float
|
||||
464. builtin.Float.tanh : Float
|
||||
465. builtin.Float.tanh : Float
|
||||
-> Float
|
||||
465. builtin.io2.Clock.internals.threadCPUTime : '{IO} Either
|
||||
466. builtin.io2.Clock.internals.threadCPUTime : '{IO} Either
|
||||
Failure
|
||||
TimeSpec
|
||||
466. builtin.Bytes.toBase16 : Bytes
|
||||
467. builtin.Bytes.toBase16 : Bytes
|
||||
-> Bytes
|
||||
467. builtin.Bytes.toBase32 : Bytes
|
||||
468. builtin.Bytes.toBase32 : Bytes
|
||||
-> Bytes
|
||||
468. builtin.Bytes.toBase64 : Bytes
|
||||
469. builtin.Bytes.toBase64 : Bytes
|
||||
-> Bytes
|
||||
469. builtin.Bytes.toBase64UrlUnpadded : Bytes
|
||||
470. builtin.Bytes.toBase64UrlUnpadded : Bytes
|
||||
-> Bytes
|
||||
470. builtin.Text.toCharList : Text
|
||||
471. builtin.Text.toCharList : Text
|
||||
-> [Char]
|
||||
471. builtin.Int.toFloat : Int
|
||||
472. builtin.Int.toFloat : Int
|
||||
-> Float
|
||||
472. builtin.Nat.toFloat : Nat
|
||||
473. builtin.Nat.toFloat : Nat
|
||||
-> Float
|
||||
473. builtin.Nat.toInt : Nat
|
||||
474. builtin.Nat.toInt : Nat
|
||||
-> Int
|
||||
474. builtin.Bytes.toList : Bytes
|
||||
475. builtin.Bytes.toList : Bytes
|
||||
-> [Nat]
|
||||
475. builtin.Text.toLowercase : Text
|
||||
476. builtin.Text.toLowercase : Text
|
||||
-> Text
|
||||
476. builtin.Char.toNat : Char
|
||||
477. builtin.Char.toNat : Char
|
||||
-> Nat
|
||||
477. builtin.Float.toRepresentation : Float
|
||||
478. builtin.Float.toRepresentation : Float
|
||||
-> Nat
|
||||
478. builtin.Int.toRepresentation : Int
|
||||
479. builtin.Int.toRepresentation : Int
|
||||
-> Nat
|
||||
479. builtin.Char.toText : Char
|
||||
480. builtin.Char.toText : Char
|
||||
-> Text
|
||||
480. builtin.Debug.toText : a
|
||||
481. builtin.Debug.toText : a
|
||||
-> Optional
|
||||
(Either
|
||||
Text
|
||||
Text)
|
||||
481. builtin.Float.toText : Float
|
||||
482. builtin.Float.toText : Float
|
||||
-> Text
|
||||
482. builtin.Handle.toText : Handle
|
||||
483. builtin.Handle.toText : Handle
|
||||
-> Text
|
||||
483. builtin.Int.toText : Int
|
||||
484. builtin.Int.toText : Int
|
||||
-> Text
|
||||
484. builtin.Nat.toText : Nat
|
||||
485. builtin.Nat.toText : Nat
|
||||
-> Text
|
||||
485. builtin.Socket.toText : Socket
|
||||
486. builtin.Socket.toText : Socket
|
||||
-> Text
|
||||
486. builtin.Link.Term.toText : Term
|
||||
487. builtin.Link.Term.toText : Term
|
||||
-> Text
|
||||
487. builtin.ThreadId.toText : ThreadId
|
||||
488. builtin.ThreadId.toText : ThreadId
|
||||
-> Text
|
||||
488. builtin.Text.toUppercase : Text
|
||||
489. builtin.Text.toUppercase : Text
|
||||
-> Text
|
||||
489. builtin.Text.toUtf8 : Text
|
||||
490. builtin.Text.toUtf8 : Text
|
||||
-> Bytes
|
||||
490. builtin.todo : a -> b
|
||||
491. builtin.Debug.trace : Text
|
||||
491. builtin.todo : a -> b
|
||||
492. builtin.Debug.trace : Text
|
||||
-> a
|
||||
-> ()
|
||||
492. builtin.Int.trailingZeros : Int
|
||||
493. builtin.Int.trailingZeros : Int
|
||||
-> Nat
|
||||
493. builtin.Nat.trailingZeros : Nat
|
||||
494. builtin.Nat.trailingZeros : Nat
|
||||
-> Nat
|
||||
494. builtin.Float.truncate : Float
|
||||
495. builtin.Float.truncate : Float
|
||||
-> Int
|
||||
495. builtin.Int.truncate0 : Int
|
||||
496. builtin.Int.truncate0 : Int
|
||||
-> Nat
|
||||
496. builtin.io2.IO.tryEval : '{IO} a
|
||||
497. builtin.io2.IO.tryEval : '{IO} a
|
||||
->{IO,
|
||||
Exception} a
|
||||
497. builtin.io2.Promise.tryRead : Promise
|
||||
498. builtin.io2.Promise.tryRead : Promise
|
||||
a
|
||||
->{IO} Optional
|
||||
a
|
||||
498. builtin.io2.MVar.tryTake : MVar a
|
||||
499. builtin.io2.MVar.tryTake : MVar a
|
||||
->{IO} Optional
|
||||
a
|
||||
499. builtin.Text.uncons : Text
|
||||
500. builtin.Text.uncons : Text
|
||||
-> Optional
|
||||
( Char,
|
||||
Text)
|
||||
500. builtin.Any.unsafeExtract : Any
|
||||
501. builtin.Any.unsafeExtract : Any
|
||||
-> a
|
||||
501. builtin.Text.unsnoc : Text
|
||||
502. builtin.Text.unsnoc : Text
|
||||
-> Optional
|
||||
( Text,
|
||||
Char)
|
||||
502. builtin.Char.Class.upper : Class
|
||||
503. builtin.Code.validate : [( Term,
|
||||
503. builtin.Char.Class.upper : Class
|
||||
504. builtin.Code.validate : [( Term,
|
||||
Code)]
|
||||
->{IO} Optional
|
||||
Failure
|
||||
504. builtin.io2.validateSandboxed : [Term]
|
||||
505. builtin.io2.validateSandboxed : [Term]
|
||||
-> a
|
||||
-> Boolean
|
||||
505. builtin.Value.value : a
|
||||
506. builtin.Value.value : a
|
||||
-> Value
|
||||
506. builtin.io2.IO.process.wait : ProcessHandle
|
||||
507. builtin.io2.IO.process.wait : ProcessHandle
|
||||
->{IO} Nat
|
||||
507. builtin.Debug.watch : Text
|
||||
508. builtin.Debug.watch : Text
|
||||
-> a
|
||||
-> a
|
||||
508. builtin.Char.Class.whitespace : Class
|
||||
509. builtin.MutableArray.write : MutableArray
|
||||
509. builtin.Char.Class.whitespace : Class
|
||||
510. builtin.MutableArray.write : MutableArray
|
||||
g a
|
||||
-> Nat
|
||||
-> a
|
||||
->{g,
|
||||
Exception} ()
|
||||
510. builtin.io2.Promise.write : Promise
|
||||
511. builtin.io2.Promise.write : Promise
|
||||
a
|
||||
-> a
|
||||
->{IO} Boolean
|
||||
511. builtin.Ref.write : Ref g a
|
||||
512. builtin.Ref.write : Ref g a
|
||||
-> a
|
||||
->{g} ()
|
||||
512. builtin.io2.TVar.write : TVar a
|
||||
513. builtin.io2.TVar.write : TVar a
|
||||
-> a
|
||||
->{STM} ()
|
||||
513. builtin.MutableByteArray.write16be : MutableByteArray
|
||||
514. builtin.MutableByteArray.write16be : MutableByteArray
|
||||
g
|
||||
-> Nat
|
||||
-> Nat
|
||||
->{g,
|
||||
Exception} ()
|
||||
514. builtin.MutableByteArray.write32be : MutableByteArray
|
||||
515. builtin.MutableByteArray.write32be : MutableByteArray
|
||||
g
|
||||
-> Nat
|
||||
-> Nat
|
||||
->{g,
|
||||
Exception} ()
|
||||
515. builtin.MutableByteArray.write64be : MutableByteArray
|
||||
516. builtin.MutableByteArray.write64be : MutableByteArray
|
||||
g
|
||||
-> Nat
|
||||
-> Nat
|
||||
->{g,
|
||||
Exception} ()
|
||||
516. builtin.MutableByteArray.write8 : MutableByteArray
|
||||
517. builtin.MutableByteArray.write8 : MutableByteArray
|
||||
g
|
||||
-> Nat
|
||||
-> Nat
|
||||
->{g,
|
||||
Exception} ()
|
||||
517. builtin.Int.xor : Int
|
||||
518. builtin.Int.xor : Int
|
||||
-> Int
|
||||
-> Int
|
||||
518. builtin.Nat.xor : Nat
|
||||
519. builtin.Nat.xor : Nat
|
||||
-> Nat
|
||||
-> Nat
|
||||
|
||||
|
@ -10,7 +10,7 @@ zonk = 0
|
||||
|
||||
```ucm
|
||||
.foo> add
|
||||
.> project.create foo
|
||||
.> project.create-empty foo
|
||||
.> merge foo foo/main
|
||||
```
|
||||
|
||||
@ -23,7 +23,7 @@ foo/main> add
|
||||
```
|
||||
|
||||
```ucm
|
||||
.> project.create bar
|
||||
.> project.create-empty bar
|
||||
bar/main> merge foo/main
|
||||
bar/main> branch /topic
|
||||
```
|
||||
|
@ -30,10 +30,22 @@ zonk = 0
|
||||
|
||||
zonk : Nat
|
||||
|
||||
.> project.create foo
|
||||
.> project.create-empty foo
|
||||
|
||||
🎉 I've created the project foo.
|
||||
|
||||
🎨 Type `ui` to explore this project's code in your browser.
|
||||
🔭 Discover libraries at https://share.unison-lang.org
|
||||
📖 Use `help-topic projects` to learn more about projects.
|
||||
|
||||
Write your first Unison code with UCM:
|
||||
|
||||
1. Open scratch.u.
|
||||
2. Write some Unison code and save the file.
|
||||
3. In UCM, type `add` to save it to your new project.
|
||||
|
||||
🎉 🥳 Happy coding!
|
||||
|
||||
.> merge foo foo/main
|
||||
|
||||
Here's what's changed in foo/main after the merge:
|
||||
@ -74,10 +86,22 @@ foo/main> add
|
||||
|
||||
```
|
||||
```ucm
|
||||
.> project.create bar
|
||||
.> project.create-empty bar
|
||||
|
||||
🎉 I've created the project bar.
|
||||
|
||||
🎨 Type `ui` to explore this project's code in your browser.
|
||||
🔭 Discover libraries at https://share.unison-lang.org
|
||||
📖 Use `help-topic projects` to learn more about projects.
|
||||
|
||||
Write your first Unison code with UCM:
|
||||
|
||||
1. Open scratch.u.
|
||||
2. Write some Unison code and save the file.
|
||||
3. In UCM, type `add` to save it to your new project.
|
||||
|
||||
🎉 🥳 Happy coding!
|
||||
|
||||
bar/main> merge foo/main
|
||||
|
||||
Here's what's changed in the current namespace after the
|
||||
|
@ -59,17 +59,17 @@ y = 2
|
||||
most recent, along with the command that got us there. Try:
|
||||
|
||||
`fork 2 .old`
|
||||
`fork #sfboh4r465 .old` to make an old namespace
|
||||
`fork #3amtojjv8u .old` to make an old namespace
|
||||
accessible again,
|
||||
|
||||
`reset-root #sfboh4r465` to reset the root namespace and
|
||||
`reset-root #3amtojjv8u` to reset the root namespace and
|
||||
its history to that of the
|
||||
specified namespace.
|
||||
|
||||
When Root Hash Action
|
||||
1. now #6oglurikek add
|
||||
2. now #sfboh4r465 add
|
||||
3. now #t4v947uir6 builtins.merge
|
||||
1. now #8hu49338cf add
|
||||
2. now #3amtojjv8u add
|
||||
3. now #fhvlkucguq builtins.merge
|
||||
4. #sg60bvjo91 history starts here
|
||||
|
||||
Tip: Use `diff.namespace 1 7` to compare namespaces between
|
||||
|
@ -11,7 +11,7 @@ someterm = 18
|
||||
```
|
||||
|
||||
```ucm
|
||||
.> project.create foo
|
||||
.> project.create-empty foo
|
||||
foo/main> add
|
||||
```
|
||||
|
||||
|
@ -18,10 +18,22 @@ someterm = 18
|
||||
|
||||
```
|
||||
```ucm
|
||||
.> project.create foo
|
||||
.> project.create-empty foo
|
||||
|
||||
🎉 I've created the project foo.
|
||||
|
||||
🎨 Type `ui` to explore this project's code in your browser.
|
||||
🔭 Discover libraries at https://share.unison-lang.org
|
||||
📖 Use `help-topic projects` to learn more about projects.
|
||||
|
||||
Write your first Unison code with UCM:
|
||||
|
||||
1. Open scratch.u.
|
||||
2. Write some Unison code and save the file.
|
||||
3. In UCM, type `add` to save it to your new project.
|
||||
|
||||
🎉 🥳 Happy coding!
|
||||
|
||||
foo/main> add
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
@ -29,7 +29,7 @@ foo.a = 5
|
||||
# reset branch
|
||||
|
||||
```ucm
|
||||
.> project.create foo
|
||||
.> project.create-empty foo
|
||||
foo/main> history
|
||||
```
|
||||
|
||||
|
@ -26,13 +26,13 @@ a = 5
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #d31cd19hmj
|
||||
⊙ 1. #9o9nce99ll
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
a
|
||||
|
||||
□ 2. #t4v947uir6 (start of history)
|
||||
□ 2. #fhvlkucguq (start of history)
|
||||
|
||||
.> reset 2
|
||||
|
||||
@ -45,7 +45,7 @@ a = 5
|
||||
|
||||
|
||||
|
||||
□ 1. #t4v947uir6 (start of history)
|
||||
□ 1. #fhvlkucguq (start of history)
|
||||
|
||||
```
|
||||
```unison
|
||||
@ -79,13 +79,13 @@ foo.a = 5
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #fnbh3f6bi4
|
||||
⊙ 1. #6q9qb5j7he
|
||||
|
||||
+ Adds / updates:
|
||||
|
||||
foo.a
|
||||
|
||||
□ 2. #t4v947uir6 (start of history)
|
||||
□ 2. #fhvlkucguq (start of history)
|
||||
|
||||
.> reset 1 foo
|
||||
|
||||
@ -99,10 +99,22 @@ foo.a = 5
|
||||
# reset branch
|
||||
|
||||
```ucm
|
||||
.> project.create foo
|
||||
.> project.create-empty foo
|
||||
|
||||
🎉 I've created the project foo.
|
||||
|
||||
🎨 Type `ui` to explore this project's code in your browser.
|
||||
🔭 Discover libraries at https://share.unison-lang.org
|
||||
📖 Use `help-topic projects` to learn more about projects.
|
||||
|
||||
Write your first Unison code with UCM:
|
||||
|
||||
1. Open scratch.u.
|
||||
2. Write some Unison code and save the file.
|
||||
3. In UCM, type `add` to save it to your new project.
|
||||
|
||||
🎉 🥳 Happy coding!
|
||||
|
||||
foo/main> history
|
||||
|
||||
☝️ The namespace is empty.
|
||||
|
@ -13,7 +13,7 @@ Let's look at some examples. We'll start with a namespace with just the builtins
|
||||
|
||||
|
||||
|
||||
□ 1. #lcn24e0a6c (start of history)
|
||||
□ 1. #vpkls27v13 (start of history)
|
||||
|
||||
.> fork builtin builtin2
|
||||
|
||||
@ -42,21 +42,21 @@ Now suppose we `fork` a copy of builtin, then rename `Nat.+` to `frobnicate`, th
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #ps6sgdb6eb
|
||||
⊙ 1. #gtktavsknb
|
||||
|
||||
> Moves:
|
||||
|
||||
Original name New name
|
||||
Nat.frobnicate Nat.+
|
||||
|
||||
⊙ 2. #pmj762mtub
|
||||
⊙ 2. #tfkgj5mep6
|
||||
|
||||
> Moves:
|
||||
|
||||
Original name New name
|
||||
Nat.+ Nat.frobnicate
|
||||
|
||||
□ 3. #lcn24e0a6c (start of history)
|
||||
□ 3. #vpkls27v13 (start of history)
|
||||
|
||||
```
|
||||
If we merge that back into `builtin`, we get that same chain of history:
|
||||
@ -73,21 +73,21 @@ If we merge that back into `builtin`, we get that same chain of history:
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #ps6sgdb6eb
|
||||
⊙ 1. #gtktavsknb
|
||||
|
||||
> Moves:
|
||||
|
||||
Original name New name
|
||||
Nat.frobnicate Nat.+
|
||||
|
||||
⊙ 2. #pmj762mtub
|
||||
⊙ 2. #tfkgj5mep6
|
||||
|
||||
> Moves:
|
||||
|
||||
Original name New name
|
||||
Nat.+ Nat.frobnicate
|
||||
|
||||
□ 3. #lcn24e0a6c (start of history)
|
||||
□ 3. #vpkls27v13 (start of history)
|
||||
|
||||
```
|
||||
Let's try again, but using a `merge.squash` (or just `squash`) instead. The history will be unchanged:
|
||||
@ -108,7 +108,7 @@ Let's try again, but using a `merge.squash` (or just `squash`) instead. The hist
|
||||
|
||||
|
||||
|
||||
□ 1. #lcn24e0a6c (start of history)
|
||||
□ 1. #vpkls27v13 (start of history)
|
||||
|
||||
```
|
||||
The churn that happened in `mybuiltin` namespace ended up back in the same spot, so the squash merge of that namespace with our original namespace had no effect.
|
||||
@ -499,13 +499,13 @@ This checks to see that squashing correctly preserves deletions:
|
||||
Note: The most recent namespace hash is immediately below this
|
||||
message.
|
||||
|
||||
⊙ 1. #9hnba2qr13
|
||||
⊙ 1. #nd5hkv52vo
|
||||
|
||||
- Deletes:
|
||||
|
||||
Nat.* Nat.+
|
||||
|
||||
□ 2. #lcn24e0a6c (start of history)
|
||||
□ 2. #vpkls27v13 (start of history)
|
||||
|
||||
```
|
||||
Notice that `Nat.+` and `Nat.*` are deleted by the squash, and we see them deleted in one atomic step in the history.
|
||||
|
@ -11,8 +11,8 @@ someterm = 18
|
||||
```
|
||||
|
||||
```ucm
|
||||
.> project.create foo
|
||||
.> project.create bar
|
||||
.> project.create-empty foo
|
||||
.> project.create-empty bar
|
||||
foo/main> add
|
||||
foo/main> branch bar
|
||||
foo/main> branch topic
|
||||
|
@ -18,14 +18,38 @@ someterm = 18
|
||||
|
||||
```
|
||||
```ucm
|
||||
.> project.create foo
|
||||
.> project.create-empty foo
|
||||
|
||||
🎉 I've created the project foo.
|
||||
|
||||
.> project.create bar
|
||||
🎨 Type `ui` to explore this project's code in your browser.
|
||||
🔭 Discover libraries at https://share.unison-lang.org
|
||||
📖 Use `help-topic projects` to learn more about projects.
|
||||
|
||||
Write your first Unison code with UCM:
|
||||
|
||||
1. Open scratch.u.
|
||||
2. Write some Unison code and save the file.
|
||||
3. In UCM, type `add` to save it to your new project.
|
||||
|
||||
🎉 🥳 Happy coding!
|
||||
|
||||
.> project.create-empty bar
|
||||
|
||||
🎉 I've created the project bar.
|
||||
|
||||
🎨 Type `ui` to explore this project's code in your browser.
|
||||
🔭 Discover libraries at https://share.unison-lang.org
|
||||
📖 Use `help-topic projects` to learn more about projects.
|
||||
|
||||
Write your first Unison code with UCM:
|
||||
|
||||
1. Open scratch.u.
|
||||
2. Write some Unison code and save the file.
|
||||
3. In UCM, type `add` to save it to your new project.
|
||||
|
||||
🎉 🥳 Happy coding!
|
||||
|
||||
foo/main> add
|
||||
|
||||
⍟ I've added these definitions:
|
||||
|
Loading…
Reference in New Issue
Block a user