microsoft / vscode

Visual Studio Code
https://code.visualstudio.com
MIT License
162.23k stars 28.56k forks source link

Replace in files is buggy when multiple changes are made on same line of code #166437

Open avnishbm opened 1 year ago

avnishbm commented 1 year ago

Type: Bug

Hi,

In the Search in files option, when we try to search (say for 'quantity') & replace (say replace with ORDER_FILLED_QUANTITY), and happen to select multiple instances of the search results with more than 1 instances in the same line of code, and then select replace (by right click), the changes made by the editor are incorrect and happen to misplace the text. It appears changes are being done keeping the original position of the search text in mind, where as in the process of replacing for multiple instances in same line, the position of the 2nd (or later) instances of the search text in the line changes, where as editor seems to replace based on the original position of the search text in the line.

e.g. if the original line is: my name is 'quantity' and i exist in second place as well like 'quantity' and it's good

In the search in files option if we search for 'quantity' (with single quotes), for the above line 2 instances will get listed in the search results. We mention replace text as ORDER_FILLED_QUANTITY. Now if we select the 2 instances and right click and select Replace, we will see that the 2nd text replacement is misplaced in the line and some other text has got replaced.

VS Code version: Code 1.73.0 (8fa188b2b301d36553cbc9ce1b0a146ccb93351f, 2022-11-01T15:38:50.881Z) OS version: Darwin x64 21.6.0 Modes: Sandboxed: No

System Info |Item|Value| |---|---| |CPUs|Intel(R) Core(TM) i5-5250U CPU @ 1.60GHz (4 x 1600)| |GPU Status|2d_canvas: enabled
canvas_oop_rasterization: disabled_off
direct_rendering_display_compositor: disabled_off_ok
gpu_compositing: enabled
metal: disabled_off
multiple_raster_threads: enabled_on
opengl: enabled_on
rasterization: enabled
raw_draw: disabled_off_ok
skia_renderer: enabled_on
video_decode: enabled
video_encode: enabled
vulkan: disabled_off
webgl: enabled
webgl2: enabled
webgpu: disabled_off| |Load (avg)|6, 6, 6| |Memory (System)|8.00GB (0.03GB free)| |Process Argv|--crash-reporter-id 2c518836-798d-47b7-b16c-e76bc10fa2b8| |Screen Reader|no| |VM|0%|
Extensions (39) Extension|Author (truncated)|Version ---|---|--- vscode-browser-preview|auc|0.7.2 doxdocgen|csc|1.4.0 dart-code|Dar|3.52.1 flutter|Dar|3.52.0 vscode-eslint|dba|2.2.6 es7-react-js-snippets|dsz|4.4.3 gitlens|eam|13.0.4 prettier-vscode|esb|9.9.0 vscode-firefox-debug|fir|2.9.8 auto-rename-tag|for|0.1.10 go|gol|0.36.0 better-cpp-syntax|jef|1.16.3 cmake-language-support-vscode|jos|0.0.7 vscode-docker|ms-|1.22.2 vscode-dotnet-runtime|ms-|1.6.0 isort|ms-|2022.6.0 python|ms-|2022.18.2 vscode-pylance|ms-|2022.11.20 jupyter|ms-|2022.9.1202862440 jupyter-keymap|ms-|1.0.0 jupyter-renderers|ms-|1.0.12 vscode-jupyter-cell-tags|ms-|0.1.6 vscode-jupyter-slideshow|ms-|0.1.5 remote-containers|ms-|0.262.3 remote-ssh|ms-|0.92.0 remote-ssh-edit|ms-|0.84.0 remote-wsl|ms-|0.72.0 cmake-tools|ms-|1.12.27 cpptools|ms-|1.12.4 cpptools-extension-pack|ms-|1.3.0 remote-explorer|ms-|0.0.2 debugger-for-chrome|msj|4.13.0 vetur|oct|0.36.1 indent-rainbow|ode|8.3.1 LiveServer|rit|5.7.9 mdx|sil|0.1.1 cmake|twx|0.0.17 highlight-matching-tag|vin|0.10.1 volar|Vue|1.0.9 (1 theme extensions excluded)
A/B Experiments ``` vsliv368:30146709 vsreu685:30147344 python383:30185418 vspor879:30202332 vspor708:30202333 vspor363:30204092 vslsvsres303:30308271 pythonvspyl392:30443607 vserr242cf:30382550 pythontb:30283811 vsjup518:30340749 pythonptprofiler:30281270 vshan820:30294714 vstes263:30335439 vscorecescf:30445987 pythondataviewer:30285071 vscod805cf:30301675 binariesv615:30325510 bridge0708:30335490 bridge0723:30353136 cmake_vspar411:30581797 vsaa593cf:30376535 pythonvs932:30410667 cppdebug:30492333 vsclangdc:30486549 c4g48928:30535728 dsvsc012:30540252 azure-dev_surveyone:30548225 vscccc:30566498 pyindex848cf:30577861 nodejswelcome1cf:30587006 fc301958:30595537 282f8724:30602487 gswce1:30605430 3d0df643:30604793 dbltrim-noruby:30604474 ```
VSCodeTriageBot commented 1 year ago

Thanks for creating this issue! It looks like you may be using an old version of VS Code, the latest stable release is 1.73.1. Please try upgrading to the latest version and checking whether this issue remains.

Happy Coding!

avnishbm commented 1 year ago

Upgraded to latest stable version 1.73.1 and tried, the issue still persists.

ArturoDent commented 1 year ago

I can see this too when selecting multiple lines in the results and choosing replace from their context menu. Here is a gif to show the steps.

replaceSelect

avnishbm commented 1 year ago

cool, thanks for the demonstration!

Niko-O commented 2 months ago

I just ran into the same problem and would like to add some more info:

Latest "stable" setup according to the official download page

Version: 1.90.2 (user setup) Commit: 5437499feb04f7a586f677b155b039bc2b3669eb Date: 2024-06-18T22:34:26.404Z Electron: 29.4.0 ElectronBuildId: 9728852 Chromium: 122.0.6261.156 Node.js: 20.9.0 V8: 12.2.281.27-electron.0 OS: Windows_NT x64 10.0.19045

settings.json and keybindings.json are empty (except for the root array/object).
There are no extensions installed.

Steps to reproduce:

  1. Create a folder "Test"
  2. Open VS Code..
  3. Drag the folder onto VS code. Trust the author if prompted.
  4. Create a file "Example.txt" via the Explorer panel.
  5. Type Foo Foo Foo Foo in the file and save it.
  6. Press Ctrl+Shift+H to open the search panel.
  7. Enter Foo in the search box.
  8. Enter Bartholomew in the replace box and hit Enter.
  9. Single-left-click the first search result, then hold Shift while single-left-clicking the third search result. (Make sure to not accidentally click on any buttons that appear when hovering over search results.)
  10. Things should look like this: grafik
  11. There are three buttons labeled "A" in the screenshot above. Click on the one of the first search result.

What should happen: The resulting file should contain Bartholomew Bartholomew Bartholomew Foo.

What actually happens: The resulting file contains BartBartBartholomewomewomew Foo Foo Foo.

Alternative steps (each considered individually as deviations from the above steps to reproduce):

It seems that the code that loops over the selected search results simply does something along the lines of (pseudo-code): For Each SearchResult: Document.Replace(Line: SearchResult.Line, From: SearchResult.StartIndex, Length: SearchResult.Length, With: ReplacementText), without taking into account that the start index of subsequent search results in the same line must be adjusted if the replacement text has a different length than the original text.

Why I think this is important: Replacing only a subset of all search results is a somewhat common task. While replacing each occurrence individually is possible, it becomes tedious when there are many search results, especially when there are blocks of similar results that can be quickly identified as "all of those need to be replaced". The in-editor search and replace requires holding the Enter key down with precise timing, or hitting it many times. The global search and replace makes it easy to quickly select a chunk of search results and apply the replacement with a single click. But this bug makes that function dangerous to use.
This bug can silently corrupt files, which is always a bad time. The corruption might not be immediately obvious, especially if the file was not yet opened (performing the replacements won't open it in an editor).