sublimehq / sublime_text

Issue tracker for Sublime Text
https://www.sublimetext.com
809 stars 39 forks source link

Option to change behavior of pasting into multiple selections #1435

Open idleberg opened 8 years ago

idleberg commented 8 years ago

Summary

This is an odd bug and I find it hard to describe. Hopefully the steps to reproduce make it clearer.

When copy & pasting n lines of text into n selections, the result will differ from selections less or greater than n.

Steps to reproduce

1.) Consider the following YAML (just for illustration, can be any syntax)

firstItem:
  -one
  -two
  -three
secondItem:
  -one
  -two
  -three
thirdItem:
  -one
  -two
  -three

2.) Copy two lines of text, e.g.

-new two
-another two

3.) In the YAML file select any of the of the sub-keys, e.g. -two

4.) Press CmdD to select the next instance to -two (= two selections)

6.) Paste the the two lines (or ”Paste and indent”)

Expected behavior

I'm expecting the YAML to look like this (comments added for emphasis)

firstItem:
  -one
  -new two     #
  -another two #
  -three
secondItem:
  -one
  -new two     #
  -another two #
  -three
thirdItem:
  -one
  -two
  -three

I get the expected result when I select all instances of -two or only one (less or greater than number of lines pasted).

Actual behavior

The YAML actually looks like this (comments added for emphasis)

firstItem:
  -one
  -new two #
  -three
secondItem:
  -one
  -another two #
  -three
thirdItem:
  -one
  -two
  -three

This will always be the case when the selections match the number of lines copied

Environment

FichteFoll commented 8 years ago

This is intended, specifically for multi-caret pasting. If you have the same number of lines in your clipboard as you have selections, ST will insert one line for each selection/caret.

It has always been like this and I hardly doubt it will ever be changed.

wbond commented 8 years ago

Yes, this is one of the nicest features of multiple selections, and would be a huge functionality regression if changed.

idleberg commented 8 years ago

I didn't know about that feature, it's a great one. However, I think it's a bad design decision to have one action behave differently depending on context. To someone who doesn't know about it (like me 9 hours ago), it feels erratic. Is there at least an option to override this, so one can still get the “expected result” as mentioned above?

vovkkk commented 8 years ago

Is there at least an option to override this, so one can still get the “expected result” as mentioned above?

You can use Replace… (in Find menu) to get the “expected result”.


I agree that feature is useful and removing it would be regression, but what about confirmation dialogue? I.e. if clipboard contains same amount of lines as view contains selections, then on paste it would ask Do you want to paste line per selection or the whole clipboard to each selection? and there would be another setting to disable dialogue for old-skool-fellows.

alextretyak commented 7 years ago

I firmly believe that additional option/setting is not needed. There are two clearly distinct use cases, depending on the source of clipboard text [i.e. a way with/by which that text was placed into the clipboard]:

So, I would rather fix that @FichteFoll's statement: If you have the same number of lines in your clipboard as you have selections, ST will insert one line for each selection/caret. to something like this: If you have the same number of copied regions/texts in your clipboard as you have selections, ST will insert one copied region/text for each selection/caret.

I suppose that during the initial development of this feature [multi-caret pasting] a developer of SublimeText could not clearly decide what method for separating text regions of multiple selection should be used.

Moreover, as I can see this problem already have beed raised (here and here), and in solution proposed by @adzenith copied text from multiple [regions/]selections is stored in global array variable selection_strings. As an alternative, I would suggest to refuse global variable selection_strings and use some special [ASCII or Unicode] character to separate copied regions (e.g. File Separator Character — "\x1C"). [For now in SublimeText [as it turns out] simple "\n" (Line Feed) character is used as such separator [of multiple copied text regions] character, so multi-line text [i.e. text which contains at least one "\n" character] breaks this "multi-caret pasting" feature.]

idleberg commented 7 years ago

There are two clearly distinct use cases

The use cases are not necessarily distinct. The example given in my initial post was simplified for illustration purposes. Working with 20+ selections can be overwhelming (I actually had cases of hundreds of selections), making it hard to keep track. Predictable behaviour is desirable and to achieve that I'd be fine with any additional keystroke preceding the paste-command, e.g. AnyModifierKey, CmdV on macOS.

alextretyak commented 7 years ago

@idleberg By distinct I mean that your case is clearly distinct from what @FichteFoll is talking about. Because as I understand you copy single selection/region (possibly consisting of multiple lines) into many selections/carets.

adzenith commented 7 years ago

The CopyEdit plugin you mentioned is indeed meant to fix this exact problem. I wrote the plugin because Sublime Text's behavior with multi-line, multi-selection is pretty broken compared to the single-line, multi-selection behavior (as you noted). The latter does exactly what you expect, and it's the behavior that I think @FichteFoll wants to preserve (?). The former does not do what you expect, and it sounds like that's what @idleberg wants to change. The plugin just makes both scenarios behave like the excellent single-line scenario.

FichteFoll commented 7 years ago

To re-iterate on my earlier comment: The current behavior is so definitive that I hardly doubt it can be changed. It is very predictable once you understand it and follows a simple rule.

A setting could be added to change the behavior of copying and pasting, but a way more flexible way of changing the behavior would be to just write a plugin since the required functionality is made available through the API.

Imo, the only thing that could be worth adding to the default distribution is a command on a different key binding that does what OP expected.

wbond commented 7 years ago

@alextretyak Using something other than \n for the separator would break integration with other programs.

@adzenith No, I don't believe anything is currently broken with regards to multiple selections. It may not do what you initially thought it would, but I do believe it is functioning as Jon intended.

In summary:

  1. When multiple selections copy or cut to the clipboard, the data is placed on the clipboard with a \n separator for integration with other software on your machine.
  2. When performing editing in multiple selections, if the user cuts and then pastes, the obvious functionality it to cut text from each line and then paste the same text back to where the cursor currently is. This allows you to batch edit lines.

While I understand why you may want to add two line to the clipboard and then paste them in two places, changing the current implementation to achieve that would break the above use cases.

That isn't to say, like @FichteFoll suggests, that a new command could be implemented to support multi-line pasting when there are the same number of cursors and lines on the clipboard.

I would (generally) be opposed to prompting the user in such a situation. A prompt would be useful the first time, and a hindrance all subsequent times. Instead, I'd prefer to add official documentation about the details of multiple cursors and how the clipboard interacts with them.

FichteFoll commented 7 years ago

Instead, I'd prefer to add official documentation about the details of multiple cursors and how the clipboard interacts with them.

If I had more time (or it was paid 😄 ), this would already be part of the unofficial docs, but there's a lot to do.

adzenith commented 7 years ago

@wbond Have you tried the plugin? It works really well, even when copy-pasting to other programs. It puts the data on the clipboard with a \n separator, but internally stores the selections separately. If you paste somewhere else it just works, like normal copying and pasting. That is to say, it meets both criteria that you put forward there.

The change is that it also meets the second criterion for selections with newlines in them. This allows you to actually batch-edit lines, instead of just batch-editing parts of lines. So it adds the feature that @idleberg wants without breaking either of the two features that it sounds like you want, if I'm understanding you correctly.

wbond commented 7 years ago

@adzenith No, I haven't tried the plugin, but then again, I haven't ever run into wanting to change the current behavior.

vovkkk commented 7 years ago

I would (generally) be opposed to prompting the user in such a situation. A prompt would be useful the first time, and a hindrance all subsequent times.

It would be a way to decide which behaviour you need at the moment without thinking about it beforehand. The thing is that user may need both of them in different cases. Currently it is like this: press ctrl+v, see that you got not what you need, press ctrl+z, paste content at each point with single selection or use Replace panel With dialogue it would be: press ctrl+v, see prompt, decide what you need and press Enter (or ctrl+v) for default or Escape for whole content into each selection.

alextretyak commented 7 years ago

@wbond

Using something other than \n for the separator would break integration with other programs.

I agree with that point (though I personally do not need copy/paste multi-region selections between different programs [because the only program on my machine which supports multi-selection is SublimeText ☺], I can easily imagine that this may be needed for some people working with multiple editors with multi-caret/multi-selection support [e.g. Atom and Sublime]).

@FichteFoll I see two advantages of fixing the default distribution:

  1. Prevent confuse subsequent users [as current behaviour is definitely confusing at least for me, for @idleberg, for @adzenith and for a couple of users in the aforementioned topic: Cort3z, ismell, qgates]. (I agree however that this functionality it not needed for all users, but it is certainly needed for some of us [users], and I also agree that fixing the default distribution should not break the existing functionality (referred to by @FichteFoll and @wbond).)
  2. Preserve consistent behaviour of shortcuts (Ctrl+C/V/X etc.) and the standard main menu commands (Edit:Cut/Copy/Paste), because [as far as I know] plug-ins can not override behaviour of particular menu items in SublimeText (but can add new items to main menu).

As a basis solution for this issue I think that @adzenith's plug-in is practically acceptable (though need some polishing).

adzenith commented 7 years ago

If you see places it needs some polishing feel free to open issues (or pull requests!).

alextretyak commented 7 years ago

In the best tradition of TDD, let's begin with writing some tests.

At my fork of @adzenith's CopyEdit I have added this file cut_copy_paste_tests.py, and [with the help of it] I have performed the following tests:

 # CopyEdit_9b68 Sublime by default cut_copy_one
(1) CORRECT CORRECT CORRECT CORRECT
(2) CORRECT CORRECT CORRECT CORRECT
(3) CORRECT WRONG WRONG WRONG
(4) ALSO WRONG WRONG CORRECT CORRECT
(5) CORRECT CORRECT CORRECT CORRECT
(6) WRONG CORRECT CORRECT CORRECT
(7) ALSO WRONG WRONG WRONG INCORRECT
(8) INCORRECT CORRECT CORRECT INCORRECT
(9) INCORRECT INCORRECT INCORRECT INCORRECT


P.S. cut_copy_one is a simple [plugin/]command from that my comment with added just this EventListener code (to override Cut/Copy commands in all places, even in menu Edit:Cut/Copy):

class cut_copy_one_listener(sublime_plugin.EventListener):
    def on_text_command(self, view, command_name, args):
        if command_name in ["cut", "copy"]:
            return ("cut_copy_one", {"command": command_name})
wbond commented 7 years ago

@alextretyak I read through the tests, however we seem to disagree about what is the correct and wrong/incorrect.

For number 4, IMO, Sublime Text is CORRECT here. If you copy multiple values, you should never throw one away.

For number 7 and 9, I can't see how we should assume when pasting contents with the cursor in the middle of a line that the values should instead be pasted at the beginning.

The only one that seems it would be unintuitive to me with the current Sublime Text implementation is number 3.

alextretyak commented 7 years ago

I have fixed behaivour of CopyEdit plugin to "correctly" pass all my tests and already added a pull request for it, but... looking at the comment of @wbond it seems that I was a bit hurried ☺.

alextretyak commented 7 years ago

@wbond Test (4) was added specifically to resolve this issue #1461 and has real practical application (simple refactoring/renaming some identifier via Alt+F3). Also I'd like to note that pasting single selection region into multiple cursor positions works correctly (and totally symmetrically) in this case, so I doesn't feel any problem with it. May be you have some real example when this behaviour is undesirable?

alextretyak commented 7 years ago

I can't see how we should assume when pasting contents with the cursor in the middle of a line that the values should instead be pasted at the beginning.

Just like how now Sublime assume/handle this for single caret case (I have already mentioned that under the hood Sublime already have some nontrivial logic to handle this correctly.)

keith-hall commented 7 years ago

Something similar has also been mentioned at https://github.com/SublimeTextIssues/Core/issues/173

titoBouzout commented 5 years ago

This may be the default, but a way to use it "normally" would be welcome. Just because was designed that way does not mean it couldn't be extended for when you need a normal paste (CTRL+SHIFT+V or CTRL+ALT+V or whatever). I found this issue like a week ago.

FichteFoll commented 5 years ago

Note that a custom command to ignore the selection-splitting behavior is as simple as this:

import sublime
import sublime_plugin

class PasteRawCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        clip = sublime.get_clipboard()
        for region in self.view.sel():
            self.view.replace(edit, region, clip)
keith-hall commented 5 years ago

presumably you want to iterate the regions in reverse though

FichteFoll commented 5 years ago

sublime.Selection is a lazy iterable and updates live when iterated. Iterating in reverse is only necessary when you prefetch the regions and intend to change the contents later.

trollfred commented 5 years ago

I wanna throw my two cents here - I'd really like there is a some form of command+option+control+shift+V which ignores multi-caret pasting and the rest is left as it is

trss commented 5 years ago

I totally love the current behavior except when at times the number of lines copied doesn't match the number of selections into which it's pasted.

Following have been my usecases IIRC.

In the "most common" case, if the number of lines don't match, it accidentally results in the "almost never" case which becomes a mess. But it's possible to quickly recover from it by undoing.

The only issue for me is when the number of selections in the "most common" case is as large as 1000's of lines and it accidentally triggers the "almost never" case. Sublime Text freezes for a while since it explodes quadratically into a million lines. It'll be good if this is solved.

A confirmation alert I feel will make sense here. Because I think it's fair to assume that nobody would want to paste too many lines into too many places. At least not commonly so. Since it may be difficult to decide how many is too many it could be applied to even one newline if there's a consensus on the usecases perhaps.

Perhaps this warrants a separate issue since it potentially introduces a third behavior for the same action which is the opposite of the original issue in this thread which complains about the already existing two behaviors. About this complaint, I was tripped by it too, but that was years ago. And I feel it's just a small learning curve which is well worth it.

Sainan commented 3 years ago

Yes, this is one of the nicest features of multiple selections, and would be a huge functionality regression if changed.

Haha. I regret upgrading to ST 4.

FichteFoll commented 3 years ago

Would you mind clarifying on this? The behavior is unchanged in ST4 compared to ST3 (or ST2 for that matter).

Unless you meant to imply that it specifically hasn't been addressed.

Sainan commented 3 years ago

I swear some things are not working in ST4 anymore that did work in ST3, tho I can't remember now what it was anymore.

tablatronix commented 1 year ago

Is this the same issue?, it IS indeed new and is very annoying, no idea if its an osx update or st4. on OSX If you copy into buffer, it gets overwritten constantly, if you select anything it goes into buffer, If i highlight something and find next thats now in the buffer and my copy is gone, if I goto find and replace and click on something in there, now that! is in my paste buffer... oh and undo seems to also affect the copy buffer sometimes?