Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5d370ad
Add annotate command spec
ChrisPenner Sep 24, 2025
98808e3
Add migration for adding change comments
ChrisPenner Sep 24, 2025
925b579
Add queries for annotating a causal
ChrisPenner Sep 24, 2025
d7ae3f7
Start implementing annotation command
ChrisPenner Sep 24, 2025
620cdfb
Implement annotation
ChrisPenner Sep 24, 2025
dfcb6e5
Add optional message argument to annotate
ChrisPenner Sep 24, 2025
4d9776f
Use existing annotation as template when updating
ChrisPenner Sep 24, 2025
348ddf7
Split history command into its own module
ChrisPenner Sep 24, 2025
a83eaac
Remove project ID from comments
ChrisPenner Sep 24, 2025
56c415a
Display comments in history
ChrisPenner Sep 24, 2025
5c30d6d
Add annotation template
ChrisPenner Sep 24, 2025
d527e8a
automatically run ormolu
ChrisPenner Sep 24, 2025
81947a6
Ensure we show messages on the final causal
ChrisPenner Sep 24, 2025
909111c
Remove unusable message argument
ChrisPenner Oct 15, 2025
afc21ae
Add author to comment tables
ChrisPenner Oct 15, 2025
2c30845
Fix schemaVersion
ChrisPenner Oct 23, 2025
166177c
Add preferences table
ChrisPenner Oct 24, 2025
37aba5f
Add Preferences module and queries
ChrisPenner Oct 24, 2025
fa6e5a8
Helpers for preferences module
ChrisPenner Oct 24, 2025
15d7135
Add most of config.set command
ChrisPenner Oct 24, 2025
08a5716
Switch preferences -> config
ChrisPenner Oct 24, 2025
c1f8e82
Fix sql syntax
ChrisPenner Oct 24, 2025
32b3945
Allow multiple args to `config.set`
ChrisPenner Oct 24, 2025
cc80ba8
ormolu
ChrisPenner Oct 24, 2025
38371af
automatically run ormolu
aryairani Oct 24, 2025
d80a002
Re-run CI
ChrisPenner Oct 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions codebase2/codebase-sqlite/U/Codebase/Config.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
module U.Codebase.Config
( AuthorName,
ConfigKey (..),
allKeys,
mkAuthorName,
unAuthorName,
keyToText,
keyFromText,
allKeysText,
)
where

import Data.Text qualified as Text
import Unison.Prelude
import Unison.Sqlite qualified as Sqlite

data ConfigKey = AuthorNameKey
deriving stock (Eq, Enum, Bounded)

instance Show ConfigKey where
show k = Text.unpack . keyToText $ k

allKeys :: [ConfigKey]
allKeys = [minBound .. maxBound]

allKeysText :: [Text]
allKeysText = keyToText <$> allKeys

keyToText :: ConfigKey -> Text
keyToText = \case
AuthorNameKey -> "author.name"

keyFromText :: Text -> Maybe ConfigKey
keyFromText t = case t of
"author.name" -> Just AuthorNameKey
_ -> Nothing

instance Sqlite.ToField ConfigKey where
toField AuthorNameKey = Sqlite.toField (keyToText AuthorNameKey)

mkAuthorName :: Text -> Either Text AuthorName
mkAuthorName name
| Text.null (Text.strip name) = Left "Author name cannot be empty."
| Text.length name > 100 = Left "Author name cannot exceed 100 characters."
| otherwise = Right (AuthorName name)

newtype AuthorName = AuthorName {unAuthorName :: Text}
deriving stock (Eq, Show)
deriving newtype (Sqlite.ToField, Sqlite.FromField)
4 changes: 4 additions & 0 deletions codebase2/codebase-sqlite/U/Codebase/Sqlite/DbId.hs
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,7 @@ instance Show BranchHashId where

instance Show CausalHashId where
show h = "CausalHashId (" ++ show (unCausalHashId h) ++ ")"

newtype ChangeCommentId = ChangeCommentId Word64
deriving (Eq, Ord, Show)
deriving (Num, Real, Enum, Integral, Bits, FromField, ToField) via Word64
86 changes: 85 additions & 1 deletion codebase2/codebase-sqlite/U/Codebase/Sqlite/Queries.hs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ module U.Codebase.Sqlite.Queries
expectCurrentProjectPath,
setCurrentProjectPath,

-- * Annotations
annotateCausal,
getLatestCausalAnnotation,

-- * migrations
runCreateSql,
addTempEntityTables,
Expand All @@ -254,6 +258,7 @@ module U.Codebase.Sqlite.Queries
addUpdateBranchTable,
addDerivedDependentsByDependencyIndex,
addUpgradeBranchTable,
addChangeComments,

-- ** schema version
currentSchemaVersion,
Expand Down Expand Up @@ -284,6 +289,12 @@ module U.Codebase.Sqlite.Queries
x2cDecl,
checkBranchExistsForCausalHash,

-- * Config
getAuthorName,
setAuthorName,
getConfigValue,
setConfigValue,

-- * Types
TextPathSegments,
JsonParseFailure (..),
Expand Down Expand Up @@ -319,6 +330,8 @@ import Data.Time qualified as Time
import Data.Vector qualified as Vector
import Network.URI (URI)
import U.Codebase.Branch.Type (NamespaceStats (..))
import U.Codebase.Config (AuthorName, ConfigKey)
import U.Codebase.Config qualified as Config
import U.Codebase.Decl qualified as C
import U.Codebase.Decl qualified as C.Decl
import U.Codebase.HashTags (BranchHash (..), CausalHash (..), PatchHash (..))
Expand All @@ -334,6 +347,7 @@ import U.Codebase.Sqlite.DbId
( BranchHashId (..),
BranchObjectId (..),
CausalHashId (..),
ChangeCommentId,
HashId (..),
HashVersion,
ObjectId (..),
Expand Down Expand Up @@ -413,7 +427,7 @@ type TextPathSegments = [Text]
-- * main squeeze

currentSchemaVersion :: SchemaVersion
currentSchemaVersion = 22
currentSchemaVersion = 23

runCreateSql :: Transaction ()
runCreateSql =
Expand Down Expand Up @@ -499,6 +513,10 @@ addUpgradeBranchTable :: Transaction ()
addUpgradeBranchTable =
executeStatements $(embedProjectStringFile "sql/019-add-upgrade-branch-table.sql")

addChangeComments :: Transaction ()
addChangeComments =
executeStatements $(embedProjectStringFile "sql/020-add-change-comments.sql")

schemaVersion :: Transaction SchemaVersion
schemaVersion =
queryOneCol
Expand Down Expand Up @@ -4022,3 +4040,69 @@ saveSquashResult bhId chId =
)
ON CONFLICT DO NOTHING
|]

getLatestCausalAnnotation :: CausalHashId -> Transaction (Maybe (ChangeCommentId, Text))
getLatestCausalAnnotation causalHashId =
queryMaybeRow
[sql|
SELECT cc.id, ccr.contents
FROM change_comments AS cc
JOIN change_comment_revisions AS ccr ON cc.id = ccr.comment_id
WHERE cc.causal_hash_id = :causalHashId
ORDER BY ccr.created_at DESC
LIMIT 1
|]

annotateCausal :: AuthorName -> CausalHashId -> Text -> Transaction ()
annotateCausal authorName causalHashId contents = do
mayExistingCommentId <-
queryMaybeCol @ChangeCommentId
[sql|
SELECT id
FROM change_comments
WHERE causal_hash_id = :causalHashId
|]
commentId <- case mayExistingCommentId of
Nothing ->
queryOneCol @ChangeCommentId
[sql|
INSERT INTO change_comments (author, causal_hash_id, created_at)
VALUES (:authorName, :causalHashId, strftime('%s', 'now', 'subsec'))
RETURNING id
|]
Just cid -> pure cid
execute
[sql|
INSERT INTO change_comment_revisions (comment_id, contents, created_at)
VALUES (:commentId, :contents, strftime('%s', 'now', 'subsec'))
|]

getAuthorName :: Transaction (Maybe AuthorName)
getAuthorName = do
r <- getConfigValue Config.AuthorNameKey <&> fmap Config.mkAuthorName
case r of
Just (Left err) -> error $ "getAuthorName: " <> Text.unpack err
Just (Right authorName) -> pure (Just authorName)
Nothing -> pure Nothing

setAuthorName :: AuthorName -> Transaction ()
setAuthorName authorName =
setConfigValue Config.AuthorNameKey (Config.unAuthorName authorName)

setConfigValue :: ConfigKey -> Text -> Transaction ()
setConfigValue key value =
execute
[sql|
INSERT INTO config (key, value)
VALUES (:key, :value)
ON CONFLICT (key) DO UPDATE SET value = excluded.value
|]

getConfigValue :: ConfigKey -> Transaction (Maybe Text)
getConfigValue key =
queryMaybeCol
[sql|
SELECT value
FROM config
WHERE key = :key
|]
38 changes: 38 additions & 0 deletions codebase2/codebase-sqlite/sql/020-add-change-comments.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
-- A simple table for storing user preferences as key/value pairs.
CREATE TABLE config (
key TEXT NOT NULL PRIMARY KEY,
value TEXT NOT NULL
);

-- Add tables for storing change comments
-- These tables deliberately contain less information than we'll probably need, with the
-- plan that we'll migrate them and add new features on the way.

CREATE TABLE change_comments (
id INTEGER PRIMARY KEY,
causal_hash_id INTEGER REFERENCES hash(id) NOT NULL,
author TEXT NOT NULL,

-- Remember that SQLITE doesn't have any actual 'time' type,
-- This column contains float values constructed
-- using strftime('%s', 'now', 'subsec')
created_at TEXT NOT NULL
);

CREATE INDEX change_comments_by_causal_hash_id ON change_comments(causal_hash_id, created_at DESC);

CREATE TABLE change_comment_revisions (
comment_id INTEGER REFERENCES change_comments(id),
contents TEXT NOT NULL,

-- Remember that SQLITE doesn't have any actual 'time' type,
-- This column contains float values constructed
-- using strftime('%s', 'now', 'subsec')
created_at TEXT NOT NULL,

-- - In a distributed system you really can’t ever truly delete comments,
-- but you can ask to hide them.
hidden BOOL NOT NULL DEFAULT FALSE
);

CREATE INDEX change_comment_revisions_by_comment_id_and_created_at ON change_comment_revisions(comment_id, created_at DESC);
4 changes: 3 additions & 1 deletion codebase2/codebase-sqlite/unison-codebase-sqlite.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 1.12

-- This file has been generated from package.yaml by hpack version 0.36.0.
-- This file has been generated from package.yaml by hpack version 0.38.1.
--
-- see: https://github.com/sol/hpack

Expand Down Expand Up @@ -29,6 +29,7 @@ extra-source-files:
sql/017-add-update-branch-table.sql
sql/018-add-derived-dependents-by-dependency-index.sql
sql/019-add-upgrade-branch-table.sql
sql/020-add-change-comments.sql
sql/create.sql

source-repository head
Expand All @@ -39,6 +40,7 @@ library
exposed-modules:
U.Codebase.Branch
U.Codebase.Causal.Squash
U.Codebase.Config
U.Codebase.Sqlite.Branch.Diff
U.Codebase.Sqlite.Branch.Format
U.Codebase.Sqlite.Branch.Full
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ migrations regionVar getDeclType termBuffer declBuffer rootCodebasePath =
sqlMigration 19 Q.addMergeBranchTables,
sqlMigration 20 Q.addUpdateBranchTable,
sqlMigration 21 Q.addDerivedDependentsByDependencyIndex,
sqlMigration 22 Q.addUpgradeBranchTable
sqlMigration 22 Q.addUpgradeBranchTable,
sqlMigration 23 Q.addChangeComments
]
where
runT :: Sqlite.Transaction () -> Sqlite.Connection -> IO ()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ createSchema = do
Q.addUpdateBranchTable
Q.addDerivedDependentsByDependencyIndex
Q.addUpgradeBranchTable
Q.addChangeComments
(_, emptyCausalHashId) <- emptyCausalHash
(_, ProjectBranchRow {projectId, branchId}) <-
insertProjectAndBranch scratchProjectName scratchBranchName emptyCausalHashId
Expand Down
34 changes: 11 additions & 23 deletions unison-cli/src/Unison/Codebase/Editor/HandleInput.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ import Unison.Codebase.Causal qualified as Causal
import Unison.Codebase.Editor.AuthorInfo (AuthorInfo (..))
import Unison.Codebase.Editor.AuthorInfo qualified as AuthorInfo
import Unison.Codebase.Editor.HandleInput.AddRun (handleAddRun)
import Unison.Codebase.Editor.HandleInput.Annotate (handleAnnotate)
import Unison.Codebase.Editor.HandleInput.AuthLogin (authLogin)
import Unison.Codebase.Editor.HandleInput.Branch (handleBranch)
import Unison.Codebase.Editor.HandleInput.BranchRename (handleBranchRename)
import Unison.Codebase.Editor.HandleInput.BranchSquash (handleBranchSquash)
import Unison.Codebase.Editor.HandleInput.Branches (handleBranches)
import Unison.Codebase.Editor.HandleInput.Cancel (handleCancel)
import Unison.Codebase.Editor.HandleInput.ConfigSet (handleConfigSet)
import Unison.Codebase.Editor.HandleInput.DebugDefinition qualified as DebugDefinition
import Unison.Codebase.Editor.HandleInput.DebugFoldRanges qualified as DebugFoldRanges
import Unison.Codebase.Editor.HandleInput.DebugSynhashTerm (handleDebugSynhashTerm)
Expand All @@ -64,6 +66,7 @@ import Unison.Codebase.Editor.HandleInput.EditNamespace (handleEditNamespace)
import Unison.Codebase.Editor.HandleInput.FindAndReplace (handleStructuredFindI, handleStructuredFindReplaceI, handleTextFindI)
import Unison.Codebase.Editor.HandleInput.FormatFile qualified as Format
import Unison.Codebase.Editor.HandleInput.Global qualified as Global
import Unison.Codebase.Editor.HandleInput.History (handleHistory)
import Unison.Codebase.Editor.HandleInput.InstallLib (handleInstallLib, handleInstallLocalLib)
import Unison.Codebase.Editor.HandleInput.LSPDebug qualified as LSPDebug
import Unison.Codebase.Editor.HandleInput.Load (EvalMode (Sandboxed), evalUnisonFile, handleLoad, loadUnisonFile)
Expand Down Expand Up @@ -297,29 +300,9 @@ loop e = do
success <- Cli.popd
when (not success) (Cli.respond StartOfCurrentPathHistory)
HistoryI resultsCap diffCap from -> do
branch <-
case from of
BranchAtSCH hash -> Cli.resolveShortCausalHash hash
BranchAtPath path' -> do
pp <- Cli.resolvePath' path'
Cli.getBranchFromProjectPath pp
BranchAtProjectPath pp -> Cli.getBranchFromProjectPath pp
schLength <- Cli.runTransaction Codebase.branchHashLength
history <- liftIO (doHistory schLength 0 branch [])
Cli.respondNumbered history
where
doHistory :: Int -> Int -> Branch IO -> [(CausalHash, Names.Diff)] -> IO NumberedOutput
doHistory schLength !n b acc =
if maybe False (n >=) resultsCap
then pure (History diffCap schLength acc (PageEnd (Branch.headHash b) n))
else case Branch._history b of
Causal.One {} -> pure (History diffCap schLength acc (EndOfLog $ Branch.headHash b))
Causal.Merge _ _ _ tails ->
pure (History diffCap schLength acc (MergeTail (Branch.headHash b) $ Map.keys tails))
Causal.Cons _ _ _ tail -> do
b' <- fmap Branch.Branch $ snd tail
let elem = (Branch.headHash b, Branch.namesDiff b' b)
doHistory schLength (n + 1) b' (elem : acc)
handleHistory resultsCap diffCap from
AnnotateI toAnnotate -> do
handleAnnotate toAnnotate
UndoI -> do
rootBranch <- Cli.getCurrentProjectRoot
(_, prev) <-
Expand Down Expand Up @@ -736,6 +719,7 @@ loop e = do
BranchRenameI name -> handleBranchRename name
BranchesI name -> handleBranches name
CloneI remoteNames localNames -> handleClone remoteNames localNames
ConfigSetI key value -> handleConfigSet key value
BranchSquashI branchToSquash destBranch -> handleBranchSquash branchToSquash destBranch
ReleaseDraftI semver -> handleReleaseDraft semver
UpgradeI old new -> handleUpgrade old new
Expand Down Expand Up @@ -817,6 +801,7 @@ inputDescription input =
BranchesI {} -> wat
ClearI {} -> wat
CloneI {} -> wat
ConfigSetI {} -> wat
CreateMessage {} -> wat
DebugClearWatchI {} -> wat
DebugDoctorI {} -> wat
Expand All @@ -842,6 +827,9 @@ inputDescription input =
HistoryI {} -> wat
IOTestAllI -> wat
IOTestI {} -> wat
AnnotateI mayBranchId -> do
hashTxt <- traverse bid2 mayBranchId
pure $ "annotate" <> fromMaybe "" hashTxt
LibInstallI {} -> wat
LibInstallLocalI {} -> wat
ListDependenciesI {} -> wat
Expand Down
Loading
Loading