Skip to content

Conversation

@bbarker
Copy link
Contributor

@bbarker bbarker commented Dec 26, 2025

Overview

diff.update allows a user to see inline code diffing within UCM before updating the codebase. This is most helpful for reviewing changes locally.

A simple example (without color; deletions would be in red and additions in green):

scratch/foo1> diff.update diff.update

  Preview of changes that would be made by `update`:

  New definitions:
    + bar : Nat
    + bar =
    +   use Nat +
    +   foo + 1

  Updated definitions:
      foo : Nat
      foo =
        use Nat +
        x = 1
    -   y = 3
    +   y = 4
        x + y

  + (added), - (deleted)

  Run `update` to apply these changes.

scratch/foo1> view foo

  foo : Nat
  foo =
    use Nat +
    x = 1
    y = 3
    x + y

Implementation approach and notes

The implementation reuses existing update infrastructure by leveraging getNamespaceDependentsOf and hydrateRefs
from Cli.UpdateUtils to fetch old definitions from the codebase. It employs an inline diff algorithm using
Data.Algorithm.Diff to compute line-by-line differences between old and new definitions—including terms, structural
types, and abilities. The pretty-print environment includes names from the typechecked file (via UF.typecheckedToNames)
that shadow namespace names, ensuring new references resolve to names rather than hash abbreviations. Following the
existing HandleInput/*.hs pattern, the implementation uses a dedicated DiffUpdate.hs module and exposes the
functionality as a diff-update tool in the MCP server for AI agent access.

Interesting/controversial decisions

The implementation chose an inline diff format over side-by-side comparison, using the -/+ prefix format (like git diff) rather than a side-by-side layout, as this approach is more compact and familiar to developers.

Test coverage

  • 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?

    • Not particularly, though maybe we could go with larger diff examples?

Final checklist

  • 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.
  • Update your PR description if the specifics of the PR have changed over time.
  • Include transcripts or screenshots that demonstrate the changed behavior.
  • If you changed .cabal files, make sure the package.yaml files are up-to-date instead.

@aryairani
Copy link
Contributor

hit me up either here or on discord to help as needed

@aryairani aryairani marked this pull request as draft December 26, 2025 04:36
@bbarker
Copy link
Contributor Author

bbarker commented Jan 3, 2026

Hi @aryairani , I think this could use an initial review now. Thanks!

@aryairani aryairani marked this pull request as ready for review January 5, 2026 17:18
-- | When True, always use raw strings (triple-quoted) for multiline text,
-- even when nested inside other expressions. This is useful for diff output
-- where we want actual newlines for better line-by-line diffing.
forceRawStrings :: !Bool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember offhand, should we not just have this on all the time?
I'm guessing that a multi-line string embedded in some other expression as a single line probably isn't wonderfully readable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, i was thinking that as well (and is indeed why this was added) but left it in in case there might be places where you want to do "\n\n" and just have that displayed as a single line (for instance), but ... no intelligent handling is currently implemented to decide on which alternative to use.

Comment on lines -269 to -270
-- we only use this syntax if we're not wrapped in something else,
-- to avoid possible round trip issues if the text ends at an odd column
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder what this "possible round trip issues if the text ends at an odd column" was; can you remember, @runarorama?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We normally don't keep this file; stuff within unison-src/transcripts/idempotent/ doesn't produce an .output.md when run with transcripts unless there's an error.

(Running stack exec unison transcript unison-src/transcripts/idempotent/diff-update.md will produce the separate output file, but I recommend stack exec transcripts diff-update in this case.)

I'm gonna see if Github will let me delete it easily.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: It did let me delete it easily.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation - would it make sense to add a git ignore rule for *.output.md, or do we want to keep it as is to flag possible issues?

@aryairani
Copy link
Contributor

I'm gonna merge it, but we can still discuss the raw strings thing and consolidate the implementation later if appropriate.

Thanks for the contribution!

@aryairani aryairani merged commit 23b831f into unisonweb:trunk Jan 5, 2026
18 checks passed
@aryairani aryairani changed the title [Draft] Add diff.update to show preview of changes before running update Add diff.update to show preview of changes before running update Jan 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants