Quick Refactor destroys existing code
Describe the bug I ask Quick Refactor for some help on a local code position. The source-code replacement destroys existing code.
To Reproduce Steps to reproduce the behavior:
- Use Codestral
- Open the attached file
- Scroll down to mul1 and set the cursor at the beginning of the line
- Request "Quick Refactor"
- Ask for a description
- Code is destroyed
Expected behavior The code should still be intact and a description of the code should be above the method.
Screenrecording https://github.com/user-attachments/assets/c563305d-cb2b-4fd7-ba9f-10daf571bc37
Additional context Concepts_01.zip
Hi, looks interesting. But I suppose this was answer from model. You can check it in log
Ah, ok. You're probably right. I think it is not clear to me, how the Quick Refactor should work. Should I select a code section that should be replaced? Without selection (like in the attached screeen recording) I get a result in the log:
[QodeAssist] Refactoring failed: Refactoring request was cancelled
[QodeAssist] Sending request to llm:
url: https://codestral.mistral.ai/v1/chat/completions
Request body:
{
"max_tokens": 2000,
"messages": [
{
"content": "You are an expert C++, Qt, and QML code completion assistant. Your task is to provideprecise and contextually appropriate code completions to insert depending on user instructions.\n\n\n\nFile information:\nLanguage: text/x-c++src\nFile path: C:/Users/Michael/Documents/Projects/Concepts_01/main.cpp\n\nCode context with position markers:#include <QDebug>\n#include <QString>\n\n// have a concept that requires a type to have a + operator\ntemplate <typename T>\nconcept Addable = requires(T a, T b)\n {\n a + b;\n };\n\n// allow only a type to have a + operator for parameters a and b\n// that returns a type that also has a + operator\nAddable auto add1(Addable auto value1, Addable auto value2)\n {\n return value1 + value2;\n }\n\n// allow only a type to be integral or floating point for parameters a and b.\nauto add2(auto value1, auto value2)\nrequires\n(std::integral<decltype(value1)> || std::floating_point<decltype(value1)>) &&\n(std::integral<decltype(value2)> || std::floating_point<decltype(value2)>)\n {\n return value1 + value2;\n }\n\n// allow only a type to be integral or floating point for parameters a and b.\nauto sub1(auto value1, auto value2)\nrequires\n(std::integral<decltype(value1)> || std::floating_point<decltype(value1)>) &&\n(std::integral<decltype(value2)> || std::floating_point<decltype(value2)>)\n {\n return value1 - value2;\n }\n\n\n<cursor>\nauto mul1(auto value1, auto value2)\nrequires\n(std::integral<decltype(value1)> || std::floating_point<decltype(value1)>) &&\n(std::integral<decltype(value2)> || std::floating_point<decltype(value2)>)\n {\n return value1 * value2;\n }\n\n\n\nint main(int argc, char* argv[])\n {\n add1(1.1, 2);\n add1(1, 2.);\n add1(QString(\"Hello\"), QString(\"world\"));\n // add1(\"Hello\", \"world\"); // this does not work\n\n add2(1.1, 2);\n add2(1, 2.);\n // add2(QString(\"Hello\"), QString(\"world\")); // this does not work\n }\n\n\nOutput format:\n- Generate ONLY the code that should replace the current selection between<selection_start><selection_end> or be inserted at cursor position<cursor>\n- Do not include any explanations, comments about the code, or markdown code block markers\n- The output should be ready to insert directly into the editor\n- Follow the existing code style and indentation patterns",
"role": "system"
},
{
"content": "Add a description to the code.",
"role": "user"
}
],
"model": "codestral-latest",
"stream": true,
"temperature": 0.5
}
[QodeAssist] Refactoring completed successfully. New code to insert:
[QodeAssist] ---------- BEGIN REFACTORED CODE ----------
[QodeAssist] // allow only a type to be integral or floating point for parameters a and b.
auto mul1(auto value1, auto value2)
requires
(std::integral<decltype(value1)> || std::floating_point<decltype(value1)>) &&
(std::integral<decltype(value2)> || std::floating_point<decltype(value2)>)
{
return value1 * value2;
}
[QodeAssist] ----------- END REFACTORED CODE -----------
[QodeAssist] Refactoring completed successfully. New code to insert:
[QodeAssist] ---------- BEGIN REFACTORED CODE ----------
[QodeAssist]
[QodeAssist] ----------- END REFACTORED CODE -----------
[QodeAssist] Request finished successfully
I'm not sure if this is resonable. But it looks like the cursor is filled with the section between new code to insert: BEGIN REFACTORED CODE and END REFACTORED CODE. But then there is a second output: New code to insert: with emptiness. And at the start I always see: Refactoring failed: Refactoring request was cancelled
It's clear, that something is inserted at the position of the cursor.
Sometimes, when I undo (using Ctrl + Z) I don't get the original text, but some other modification. When I press a second time undo (Ctrl + Z) I have the original document again.
Can it be, that there are sometimes two responds?
For Quick refactor is using Chat Assistance settings, and I see you are set Code Completions model for that. For sure this model is very bad understanding human command text. Please try with another Instruct model
For Quick refactor is using Chat Assistance settings, and I see you are set Code Completions model for that. For sure this model is very bad understanding human command text. Please try with another Instruct model
Sorry, I don't get what you say. I looked at the prompt that is generated for the quick refactor and so I decided to select the part that should be refactored.
Please have a look at the new screen recording: https://github.com/user-attachments/assets/7229f8d8-db97-41a9-a3ec-fba59f27da48
You can see that the output generated by Quick Refactor seems to be a reasonable replacement for the selected text:
[QodeAssist] Refactoring failed: Refactoring request was cancelled
[QodeAssist] Sending request to llm:
url: https://codestral.mistral.ai/v1/chat/completions
Request body:
{
"max_tokens": 2000,
"messages": [
{
"content": "You are an expert C++, Qt, and QML code completion assistant. Your task is to provide precise and contextually appropriate code completions to insert depending on user instructions.\n\n\n\nFile information:\nLanguage: text/x-c++src\nFile path: C:/Users/Michael/Documents/Projects/Concepts_01/main.cpp\n\nCode context with position markers:#include <QDebug>\n#include <QString>\n\n// have a concept that requires a type to have a + operator\ntemplate <typename T>\nconcept Addable = requires(T a, T b)\n {\n a + b;\n };\n\n// allow only a type to have a + operator for parameters a and b\n// that returns a type that also has a + operator\nAddable auto add1(Addable auto value1, Addable auto value2)\n {\n return value1 + value2;\n }\n\n// allow only a type to be integral or floating point for parameters a and b.\nauto add2(auto value1, auto value2)\nrequires\n(std::integral<decltype(value1)> || std::floating_point<decltype(value1)>) &&\n(std::integral<decltype(value2)> || std::floating_point<decltype(value2)>)\n {\n return value1 + value2;\n }\n\n// allow only a type to be integral or floating point for parameters a and b.\nauto sub1(auto value1, auto value2)\nrequires\n(std::integral<decltype(value1)> || std::floating_point<decltype(value1)>) &&\n(std::integral<decltype(value2)> || std::floating_point<decltype(value2)>)\n {\n return value1 - value2;\n }\n\n\n<selection_start>auto mul1(auto value1, auto value2)\nrequires\n(std::integral<decltype(value1)> || std::floating_point<decltype(value1)>) &&\n(std::integral<decltype(value2)> || std::floating_point<decltype(value2)>)\n {\n return value1 * value2;\n }\n<selection_end><cursor>\n\nint main(int argc, char* argv[])\n {\n add1(1.1, 2);\n add1(1, 2.);\n add1(QString(\"Hello\"), QString(\"world\"));\n // add1(\"Hello\", \"world\"); // this does not work\n\n add2(1.1, 2);\n add2(1, 2.);\n // add2(QString(\"Hello\"), QString(\"world\")); // this does not work\n }\n\n\nOutput format:\n- Generate ONLY the code that should replace the current selection between<selection_start><selection_end> or be inserted at cursor position<cursor>\n- Do not include any explanations, comments about the code, or markdown code block markers\n- The output should be ready to insert directly into the editor\n- Follow the existing code style and indentation patterns\n\nUser files context:\n",
"role": "system"
},
{
"content": "Add a docygen style documentation to this method.",
"role": "user"
}
],
"model": "codestral-latest",
"stream": true,
"temperature": 0.5
}
[QodeAssist] Refactoring completed successfully. New code to insert:
[QodeAssist] ---------- BEGIN REFACTORED CODE ----------
[QodeAssist] /**
* Multiplies two values if both are integral or floating point types.
*
* @tparam T1 The type of the first value.
* @tparam T2 The type of the second value.
* @param value1 The first value to multiply.
* @param value2 The second value to multiply.
* @return The product of value1 and value2.
*/
auto mul1(auto value1, auto value2)
requires
(std::integral<decltype(value1)> || std::floating_point<decltype(value1)>) &&
(std::integral<decltype(value2)> || std::floating_point<decltype(value2)>)
{
return value1 * value2;
}
[QodeAssist] ----------- END REFACTORED CODE -----------
[QodeAssist] Refactoring completed successfully. New code to insert:
[QodeAssist] ---------- BEGIN REFACTORED CODE ----------
[QodeAssist]
[QodeAssist] ----------- END REFACTORED CODE -----------
[QodeAssist] Request finished successfully
However, only a part is shown in the editor.
Now the "funny" part: If I ask for undo in the editor once, I can see the whole refactored code. If I request "undo" a second time the original code is there again.
So, somehow the refactored code is written twice into the editor to replace the selection?
An additional finding: I use version 0.6.2 with QtC 17.0.1
The effect that is shown in the screen recording in the previous comment (with replacing the selection) is still there, but only if I ask for a "Quick refactor" for the first time after opening Qt Creator:
- after "Qucik refactor" the replacement is garbage (missing the first part of the refactored code)
- press once undo: we have nice refactored text in the editor
- press second time undo: we have the original text again. Why are the two levels of undo, anyway?
But if i repeat the "Quick Refactor" the replacement is exactly what LLM delivered as refactored code. And there is only one level of undo.
So, it looks more like an initialization problem?
Sorry, my last comment was wrong. It now have the same two level undo behavior often... Sorry for this wrong finding.
But what make we wonder is that sometimes I get in the log:
one [QodeAssist] ---------- BEGIN REFACTORED CODE ---------- ... [QodeAssist] ----------- END REFACTORED CODE ----------- pair
and sometimes two for one "Quick Response".
When I get two, the second one seems to have always an empty line...
Thank you for feedback, I agree, the behavior is strange, I'll see if I can quickly fix something, but in general, I'll now finish tool/function calling and mcp and remake quickrefactor into a more convenient feature through the new toolkit
Thanks for having a look.
I added tools to chat for editing files in 0.8.0, please try, I hope it will be helpful while I am fixing quick refactor tool
I refactored Quick Refactor system, now it works via code completion and never remove or destroy your code, also you can add your custom instructions for reuse
I had a look at the Quick Refactor refactoring that you did. I like the new options.
I recorded a try. You can see that it shows the selection that will be replaced. However, the first line of the replacement is shown selected. Somehow this is confusing.
https://github.com/user-attachments/assets/efa2b43f-8bb6-4f78-a992-6c90452b3438
Is there something I do wrong?
Log:
[QodeAssist] MistralAIProvider: Sending request {3d485579-9f9a-4b52-883b-11d842673057} to https://codestral.mistral.ai/v1/chat/completions
[QodeAssist] HttpClient: data: {
"max_tokens": 2000,
"messages": [
{
"content": "You are an expert C++, Qt, and QML code completion assistant. Your task is to provide precise and contextually appropriate code completions to insert depending on user instructions.\n\n\n\nFile information:\nLanguage: text/x-c++src\nFile path: C:/Users/Michael/Documents/Projects/TestedLibrary/FunnyClasses/FunnyClassesLib/catjokes.cpp\n\nCode context with position markers:#include \"catjokes.h\"\n\n<selection_start>CatJokes::CatJokes()\n {\n _jokes.append(\"Meeeeeow\");\n _jokes.append(\"Hoohoo!\");\n _jokes.append(\"Meooowww!\");\n }\n<selection_end><cursor>\nQString CatJokes::joke() const\n {\n // return one of the jokes in the vector\n return _jokes[rand() % _jokes.size()];\n }\n\nunsigned int CatJokes::jokeCount() const\n {\n return _jokes.size();\n }\n\n\nOutput format:\n- Generate ONLY the code that should replace the current selection between<selection_start><selection_end> or be inserted at cursor position<cursor>\n- Do not include any explanations, comments about the code, or markdown code block markers\n- The output should be ready to insert directly into the editor\n- Follow the existing code style and indentation patterns",
"role": "system"
},
{
"content": "Add doxygen comments to the selected code.\nUse the backslash notation.\nFor examples in the code use Whitesmiths indenting.",
"role": "user"
}
],
"model": "codestral-latest",
"stream": true,
"temperature": 0.5
}
[QodeAssist] HttpClient: Added active request: {3d485579-9f9a-4b52-883b-11d842673057}
[QodeAssist] Created NEW OpenAIMessage for Mistral request {3d485579-9f9a-4b52-883b-11d842673057}
[QodeAssist] Cleared accumulated responses for continuation request {3d485579-9f9a-4b52-883b-11d842673057}
[QodeAssist] Starting continuation for request {3d485579-9f9a-4b52-883b-11d842673057}
[QodeAssist] Mistral message marked as complete for {3d485579-9f9a-4b52-883b-11d842673057}
[QodeAssist] HttpClient: Request {3d485579-9f9a-4b52-883b-11d842673057} - HTTP Status: 200
[QodeAssist] Emitting full response for {3d485579-9f9a-4b52-883b-11d842673057}
[QodeAssist] Refactoring completed successfully. New code to insert:
[QodeAssist] ---------- BEGIN REFACTORED CODE ----------
[QodeAssist] /**
* \brief Constructs a CatJokes object.
*
* Initializes the object with a list of cat jokes.
*/
CatJokes::CatJokes()
{
_jokes.append("Meeeeeow");
_jokes.append("Hoohoo!");
_jokes.append("Meooowww!");
}
[QodeAssist] ----------- END REFACTORED CODE -----------
[QodeAssist] Displaying refactoring suggestion with hover handler
[QodeAssist] Cleaning up Mistral request {3d485579-9f9a-4b52-883b-11d842673057}
[QodeAssist] ToolsManager: Cleaned up request {3d485579-9f9a-4b52-883b-11d842673057}
You do everything correct. That looks how code suggestion now works in QtCreator. Even if I try to ideal mapping new changes to old, still problem to showing, need to patch QtCreator
Looking closer to the recorded mp4 and the output of QodeAssist you can see that the first line of the previous code is somehow missing... It looks like the first selection line is replaced by the refactored code. Still this line is selected. Maybe the new lines needs to be inserted before the current selection in you new version?
Sorry, I don't understand. I only see the line where you have the cursor disappearing because it's being considered a line to be replaced. Perhaps you can compensate for some of these issues with instructions for LLM, so it inserts the line after which the thread is replaced, or doesn't take it into account.
This is what was selected to start:
You can see the first line: CatJokes::CatJokes()
After "adding" the refactored code:
The first line is missing in this situation. It looks, as if the first line was replaced by the whole refactored code. Still the first lines is selected.
So, my question was: maybe the first line should not be replaced, but the refactored code should be inserted before the selected code?
aaaaa, got it, maybe, I will try to do like that
unfortunately this is impossible on my side
okay, another idea, what do you think?
https://github.com/user-attachments/assets/5a8f4d85-0bab-44b5-8a30-de4a54da454f
Nice idea.
Questions come me to mind
- no proportional font should be used... better same font es in editor?
- if replacement does not fit on screen.. Are the green and red box contents scrollable?
- do we have a chance for a kind of diff view? Qt creator has some build in... Under tools?
I can't re-use unfortunately but I can reuse class differ from QtCreator API and with some customization it can looks like this
https://github.com/user-attachments/assets/1b3a538d-8d84-453c-90c6-c53afcbc9124
Hey, that looks good.
I'm curious, how the refactored preview looks like, if something was removed by the refactoring.
The font seems to be the same that is used in the editor, nice.
Does the preview window adopt in size, depending on the lenght of the lines? If not, can you scroll?
Changing in the refactoring screen is also nice. How does it look like, if you change in the AI added sections, e.g. change something in the brief section. I was wandering, if the changes, that you did from hand shouldn't be highlighted similar to the ones the AI did. E.g. the "New" you typed in was not highlighted in the same way:
The widget "Show Original" might be sufficiently replaced by a toggle button: "Original" that is highlighted, if the original is shown and not highlighted if not shown. We have this in QtCreator for the side panels:
inactive:
active:
I also find the arrows in the widget not intuitive.
When the original is show, do we have a change to align the source code lines like we would have in the QtCreator diff view? For short sections what you recorded is ok, but for longer ones it might be confusing. With the aligning one could also see, if some lines were removed.
But all in all much better than what we had before. Thanks for your work.
side by side widget for quick refactor in 0.9.2 release, please try, sizes of widget you can change in settings