smallcloudai/refact-chat-js

Applying Diffs

Closed this issue · 2 comments

refact-lsp smallcloudai/refact-lsp#226 gives you support for applying diffs to local files!

It's presented by 2 handlers:

  • v1/diff-apply
  • v1/diff-state

How to use it:

  1. call v1/diff-state to find out which chunks can be applied and which ones cannot. Disable in GUI those that cannot be applied
  2. modify apply field in requests for v1/diff-apply to set a desired state of chunks

to use v1/diff-apply follow the format:

{
    "apply": [true, false],
    "chunks": [
        {
            "file_name": "some_file.txt",
            "file_action": "edit",
            "line1": 1,
            "line2": 4,
            "lines_remove": "...",
            "lines_add": "...",
        },
        {
            "file_name": "some_file.txt",
            "file_action": "edit",
            "line1": 9,
            "line2": 10,
            "lines_remove": "...",
            "lines_add": "...",
        }
    ]
}

Please note:

  • len(apply) must be equal to len(chunks)
  • chunks must be unchanged when calling v1/diff-apply, the only thing you should modify is the apply array.
  • you can apply multiple chunks simultaneously.
  • it won't panic if you will apply what is already applied

⚠️ apply got a new behaviour:
apply represents a desired state of chunks -- those which are true will be applied, false will be un-applied or untouched. For example, if you want to undo everything pass an array full of false.

Output:

{
  "fuzzy_results": [
    {
      "chunk_id": 0,
      "fuzzy_n_used": 0
    }
  ],
  "state": [
    1,
    0,
    0,
    0,
    0
  ]
}

fuzzy_results is what you could ignore rn 😀, but here is what it is:
fuzzy_n_used is a number -- by how many lines did we need to widen our search window to find the chunk in the text. When line1 and line2 match exactly the position in the file fuzzy_n_used is equal to 0. The maximum fuzzy_n_used allowed is 10. fuzzy_n_used = 1 means, that the search window was made bigger by 1 line on top and 1 line on bottom.

state on the other hand is quite useful!

  • state is a list of usize (0 -- not applied, 1 -- applied or 2 -- failed to apply); len(state) is equal to len(chunks) from the input.
  • you can get the current state as a field in response of v1/diff-apply or when calling v1/diff-state

To use v1/diff-state follow the format:

{
    "chunks": [
        {
            "file_name": "some_file.txt",
            "file_action": "edit",
            "line1": 1,
            "line2": 4,
            "lines_remove": "...",
            "lines_add": "...",
        },
        {
            "file_name": "some_file.txt",
            "file_action": "edit",
            "line1": 9,
            "line2": 10,
            "lines_remove": "...",
            "lines_add": "...",
        }
    ]
}

Output:

{
"id": 16402438028794706325, 
"state": [false, false, false, false], 
"can_apply": [true, true, true, true]
}

state says which chunks are applied and which aren't
can_apply checks if chunks from request can be applied to the current state of the file.

A few words on how we store state in refact-lsp:
we take chunks from the request and hash them into u64. That's why chunks shouldn't ever be modified during calls apply otherwise we won't be able to get the state and will fail to apply/undo.

file_name in chunks could be absolute or relative. If relative, refact-lsp will try to complete it if it's present in index, otherwise it will try to respond with a meaningful error text

I think it's better to separate "apply": true from the chunks list, because it's not part of chat history.

Also, I'm not sure why we have integer in double quotes over there:

"chat_id": "1",
"message_id": "1",

Is it a string or an integer after all?

These handlers have been removed now it works through the patch api and the ide.