Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple carets, selections, insertion points and paste #1141

Open
mprz1024 opened this issue Jul 15, 2016 · 36 comments
Open

Multiple carets, selections, insertion points and paste #1141

mprz1024 opened this issue Jul 15, 2016 · 36 comments

Comments

@mprz1024
Copy link

mprz1024 commented Jul 15, 2016

It would be great to have the ability to create multiple carets, select multiple pieces, or progressively clone a selection of a word to the next identical match creating multiple selections, not necessarily square, and then be able to type, delete, replace, etc. using the multiple carets until Esc is hit, pasting into all carets with Ctrl-V, and so on.

Here's an animated demonstration of these features: https://www.sublimetext.com/

This is a killer feature of software like Sublime Text, TextMate or Ultra Edit, and this would put Geany closer to some of the most reputed, feature rich commercial multiplatform editors, while still being free software. I believe there's support for this in Scintilla, at least to some extent.

This supersets #850 and #625.

@elextr
Copy link
Member

elextr commented Jul 15, 2016

This is a significant change, pull requests are welcome.

@b4n
Copy link
Member

b4n commented Jul 15, 2016

Scintilla (the editing component Geany uses) can do that. So it's a "mere matter" of adding UI capability to Geany (and design how it should actually work from a UI perspective).

And it possibly requires enhancing several parts of Geany so it plays nicely with multiple selections (I'm afraid a lot of our code was written carelessly to that regard, or even way before the feature even existed in Scintilla).

@elextr
Copy link
Member

elextr commented Jul 15, 2016

And it possibly requires enhancing several parts of Geany so it plays nicely with multiple selections (I'm afraid a lot of our code was written carelessly to that regard, or even way before the feature even existed in Scintilla).

Which is why its a significant change.

Carelessly is probably harsh, it was simple written with no intention of handling multiple selections.

@AdamDanischewski
Copy link

It looks like the multi-select copy/paste insert portion of this request was added as of 1.23.1.

@elextr
Copy link
Member

elextr commented Aug 22, 2016

@AdamDanischewski its definitely only possible to have one selection still, you havn't confused it with rectangular selection have you?

@Ryan1729
Copy link

Ryan1729 commented Nov 12, 2017

This feature is just about the only thing holding me back from switching away from another editor for everything, so I thought I would take a stab at it. I cloned master and added a wrapper for SCI_SETMULTIPLESELECTION in sciwrappers.c and unconditionally called it in create_new_sci, (presumably the final version should be behind a checkbox or something.) But that didn't appear to do anything, (specifically I tried Ctrl-clicking to place multiple cursors.) Just by searching "geany ctrl click" I found this discussion thread that mentions that Ctrl-clicking is hardcoded to goto-tag and find-matching-brace depending where you click. So I found the part of the code that does that and removed it. But Ctrl-clicking still doesn't work. Per comments above I expected some parts not to play nicely with multiple selections, but I hoped what I did would be enough to get it working some of the time! I managed to make the small changes I did by just grepping trough the code and checking that functions were called when I thought they were being called. Does anyone else with more knowledge of the codebase have any ideas what else might cause Ctrl-clicking not to work?

FWIW, further on in that discussion I linked to, an enable-multiselection branch was mentioned. Now I don't know the history of this project, but that discussion is from 2012. Is there any chance that branch would be even slightly relevant to the current codebase, assuming the author still has it and can be contacted?

@elextr
Copy link
Member

elextr commented Nov 13, 2017

@Ryan1729 good on you for trying.

One thought on why it does nothing is that something has to do the selection, are you sure Scintilla has a default binding for ctrl+click that does multiple selection? If not you need to add it, or add it to Geany in place of the code you deleted.

Per comments above I expected some parts not to play nicely with multiple selections

I would expect everything to simply ignore multiple selections, and just read the main selection and operate on that. And thats where the "significant change" part above comes in.

The enable-multiselection branch is not in the Geany repository, or any PR (AFAICT) so it a private one at best in that persons github repository.

PS removed the backticks around your link so it would work, markup is ignored inside backticks.

@Ryan1729
Copy link

I had assumed that it was built in to Scintilla since that docs page I mentioned before [1] seems to be about Scintilla only and it explicitly mentions Ctrl in conjunction with the mouse. I had also tried Ctrl-click in SciTE and that worked as expected. After a cursory grep through the latest Scintilla and SciTE, I didn't find Ctrl-click logic in either of them. There's some kind of autogenerated interface in SciTE which makes things like this hard to search for there, though. I did stumble across the logic for the selection adding behaviour bound to Ctrl-D in Sublime Text. Altogether that suggests to me that the Ctrl-click behaviour is probably in SciTE, not built-in`to Scintilla.

So I've now tried calling SCI_ADDSELECTION on Ctrl-click, in the same place I removed the code from, but it still doesn't seem to do anything. I've confirmed it makes it to the right part of the big switch statement in the local copy of Scintilla though.

Here's the diff.

[1] Regarding the link, I meant to do something like this. I've put the backticks inside the square brackets this time. I knew there was a way that it worked.

@elextr
Copy link
Member

elextr commented Nov 13, 2017

I had also tried Ctrl-click in SciTE and that worked as expected.

What exactly is expected, I can't get Scite to do anything interesting on crtl+click. The version in my distro is kind of old (3.6.0) and maybe it was added after that.

How do you know it didn't work? IIUC multiple selections have a separate styling from the main selection, and since Geany doesn't set that style they may not be visible?

@AdamDanischewski
Copy link

How do you know it didn't work?

Ryan by Ctrl-click do you mean Ctrl + Shift Click? If you haven't tried that, give it a shot I think that provides the functionality that is referred to in the API documents.

@elextr
Copy link
Member

elextr commented Nov 13, 2017

@AdamDanischewski as noted in reply to your previous post above, ctrl+shift+click makes a rectangular selection, not a multiple selection, this is not the same thing.

@AdamDanischewski
Copy link

@elextr It sounds like you want something like crtrl-click multipositional multiselect
Can you describe in words what you mean by the missing functionality? (or better yet post an animated Gif from it working on another editor)

@elextr
Copy link
Member

elextr commented Nov 13, 2017

@AdamDanischewski read the OP (and its not me that wants it :)

@AdamDanischewski
Copy link

Lol, yea I was only scrolling up only to his new comment for some reason - disregard the clarification request. I see what you are looking for now, best of luck. I developed the first patch for the multiselect functionality that's working now. I didn't implement it ultimately in Geany because of the user interface complexity. What I did was simply hook the functionality to an existing loaded user interface component for testing - to make sure it was turned on. That way you don't have to worry about the user interface - you can just turn on the functionality and test that it works then upload what you have and ask a developer to integrate it into the user interface.

As far as the Scintilla functions, I think these may be the ones you want to play around with:
SCI_SWAPMAINANCHORCARET moves the caret to the opposite end of the main selection. SCI_ROTATESELECTION makes the next selection be the main selection.
SCI_MULTIPLESELECTADDNEXT adds the next occurrence of the main selection within the target to the set of selections as main. If the current selection is empty then select word around caret. The current searchFlags are used so the application may choose case sensitivity and word search options.
SCI_MULTIPLESELECTADDEACH is similar to SCI_MULTIPLESELECTADDNEXT but adds multiple occurrences instead of just one.

Look in the Geany code where SCI_SETMULTIPLESELECTION is set, to see how to turn on these on then look at the keybindings code to see if you can remap them to buttons (easier for testing). Try to focus on one thing that you can see working or not to get it going then ramp it up the full functionality.

@Ryan1729
Copy link

Just to be absolutely clear what we're talking about, here's a gif recording of an unconfigured SciTE 4.0.2:

scite_multiple_selections

In the gif I Ctrl-click twice (unfortunately you can't see my mouse,) to make two additional selections, perform some edits, then simply left click to go back to a single selection.

I guess I was assuming Scintila handled more of the GUI, rather than, as appears to be the case, just managing the editor state.

@AdamDanischewski Those seem like good suggestions. assuming extra selections are actually working, just not showing in the UI, SCI_ROTATESELECTION should allow a quick demonstration that will actually show up. I'll get started on that.

@Ryan1729
Copy link

I've got a branch here that callsSCI_ADDSELECTION on ctrl-click, and calls SCI_ROTATESELECTION on ctrl-right-click. Mysteriously, if you ctrl-click then ctrl-right-click somewhere else, by the time the right click happens, the number of selections is back down to 1. So I also quickly co-opted the dubug mode for the SSM macro to print out the selection count when every message is sent to Scintilla, (though that macro anyway.) Surprisingly, the selection count goes back to 1 before the first other message is sent! I find this extremely odd since the only ways to remove the other selections with the Scintilla API, as far as I can tell, are in the section which I only added wrappers for in that branch.

Unless someone knows some weird thing the code is doing that wold cause this, (setting the selection outside the Scintilla API?!) I suppose I'll have to try getting GDB working.

@elextr
Copy link
Member

elextr commented Nov 14, 2017

Maybe something is overwriting your multiple select setting so its back to single?

@Ryan1729
Copy link

I just tried adding the result of SCI_GETMULTIPLESELECTION to the printouts, and once it's set it to true, it remains true.

@elextr
Copy link
Member

elextr commented Nov 15, 2017

Dunno, can only suggest looking at one of the scintilla based apps that does what you want and steal, erm reuse, their algorithms.

@diohja
Copy link

diohja commented Nov 17, 2017

Textadept (https://foicica.com/textadept/) has this feature and I believe it uses Scintilla. I am not a programmer, so I have no idea how to search Textadepts's code and adapt the feature to Geany. But maybe someone with the skills can give it a try. This is the only feature I really miss in Geany and it would be great to have it.

PS: The feature I'm talking about is the "multi-caret editing", as displayed by Ryan1729. Textadept doesn't have the "column/retangular multipaste" feature.

@AdamDanischewski
Copy link

@diohja Textadept does seem to have the feature yet it doesn't look like it's really using Scintilla. It includes ScintillaLua a lexer for Scintilla. The Scintilla functionality appears to have been recreated in Lua.

@elextr
Copy link
Member

elextr commented Nov 17, 2017

Textadept appears to use ScintillaGTK, not Scintilla directly, so it comes in a library rather than included source code. That also means the API may be different.

@AdamDanischewski
Copy link

AdamDanischewski commented Nov 17, 2017

@elextr It does say that it uses Scintilla as the core text editing component, when I first browsed the code it looked like mainly lua, looking closer I see some calls that create a Scintilla document. See textadept.c line no. 1355.

/**
 * Creates a new Scintilla document and adds it to the Lua state.
 * Generates 'buffer_before_switch' and 'buffer_new' events.
 * @param doc Almost always zero, except for the first Scintilla view created,
 *   in which its doc pointer would be given here since it already has a
 *   pre-created buffer.
 * @see lL_adddoc
 */
static void new_buffer(sptr_t doc) {
  if (!doc) {
    doc = SS(focused_view, SCI_CREATEDOCUMENT, 0, 0); // create the new document
    lL_event(lua, "buffer_before_switch", -1);
    lL_adddoc(lua, doc);
    lL_gotodoc(lua, focused_view, -1, FALSE);
  } else lL_adddoc(lua, doc), SS(focused_view, SCI_ADDREFDOCUMENT, 0, doc);
#if GTK
...

https://foicica.com/textadept/TECHNOLOGY.html

See here for the Textadept API, the mapping from Textadept to Scintilla happens in the buffer object: https://foicica.com/textadept/api.html#buffer

@AdamDanischewski
Copy link

AdamDanischewski commented Nov 17, 2017

Kind of like textadept now that I've played around with it, you have to a hack a colorizer (theme) to get the color scheme to Geany though. Copy and modify a theme in the themes directory under the source directory (exploded tar ball).

Presuming you named your cloned theme to be your-new-theme.lua

Add this to your ~/.textadept/init.lua file: ui.set_theme(not CURSES and 'your-new-theme')

Then modify the colors and type Ctrl-e for a command window in textadept and enter: reset()

Keep modifying it to your preference (hint you can choose more than the colors listed (e.g. color.red works), once you get the color scheme you like it's not that different from Geany, and it seems a lot faster.

Here is my pseudo-Bash colorizer clone I just put together - it's not an exact match yet it works for me:

-- Colors theme for Textadept (http://foicica.com/textadept/)
-- Theme author: mrmrs (http://clrs.cc)
-- Base16 (https://github.com/chriskempson/base16)
-- Build with Base16 Builder (https://github.com/chriskempson/base16-builder)
-- Repository: https://github.com/rgieseke/ta-themes

local buffer = buffer
local property, property_int = buffer.property, buffer.property_int

property['color.base00'] = 0x111111
property['color.base01'] = 0x333333
property['color.base02'] = 0x555555
property['color.base03'] = 0x777777
property['color.base04'] = 0x999999
property['color.base05'] = 0xbbbbbb
property['color.base06'] = 0xdddddd
property['color.base07'] = 0xffffff
property['color.base08'] = 0x3641ff
property['color.base09'] = 0x1b85ff
property['color.base0A'] = 0x00dcff
property['color.base0B'] = 0x40cc2e
property['color.base0C'] = 0xffdb7f
property['color.base0D'] = 0xd97400
property['color.base0E'] = 0xc90db1
property['color.base0F'] = 0x4b1485
property['color.base10'] = 0xff0000

-- Default font.
property['font'], property['fontsize'] = 'Bitstream Vera Sans Mono', 10
if WIN32 then
  property['font'] = 'Courier New'
elseif OSX then
  property['font'], property['fontsize'] = 'Monaco', 12
end

-- Predefined styles.
property['style.default'] = 'font:%(font),size:%(fontsize),'..
                            'fore:%(color.base02),back:%(color.base07)'
property['style.linenumber'] = 'fore:%(color.base05),back:%(color.base07)'
property['style.bracelight'] = 'fore:%(color.base0C),underlined'
property['style.bracebad'] = 'fore:%(color.base08)'
property['style.controlchar'] = '%(style.nothing)'
property['style.indentguide'] = 'fore:%(color.base03)'
property['style.calltip'] = 'fore:%(color.base05),back:%(color.base00)'

-- Token styles.
property['style.class'] = 'fore:%(color.base08)'
property['style.comment'] = 'fore:%(color.red)'
property['style.constant'] = 'fore:%(color.base09)'
property['style.embedded'] = 'fore:%(color.base0F),back:%(color.base06)'
property['style.error'] = 'fore:%(color.base08),italics'
property['style.function'] = 'fore:%(color.base09)'
property['style.identifier'] = ''
property['style.keyword'] = 'fore:%(color.base0D)'
property['style.label'] = 'fore:%(color.base09)'
property['style.number'] = 'fore:%(color.base0C)'
property['style.operator'] = 'fore:%(color.base0E)'
property['style.preprocessor'] = 'fore:%(color.base0A)'
property['style.regex'] = 'fore:%(color.base0C)'
property['style.string'] = 'fore:%(color.base0B)'
property['style.type'] = 'fore:%(color.base0E)'
property['style.variable'] = 'fore:%(color.base0D)'
property['style.whitespace'] = ''

-- Multiple Selection and Virtual Space.
--buffer.additional_sel_alpha =
--buffer.additional_sel_fore =
--buffer.additional_sel_back =
--buffer.additional_caret_fore =

-- Caret and Selection Styles.
buffer:set_sel_fore(true, property_int['color.base07'])
buffer:set_sel_back(true, property_int['color.base02'])
--buffer.sel_alpha =
buffer.caret_fore = property_int['color.base00']
buffer.caret_line_back = property_int['color.base06']
--buffer.caret_line_back_alpha =

-- Fold Margin.
buffer:set_fold_margin_colour(true, property_int['color.base07'])
buffer:set_fold_margin_hi_colour(true, property_int['color.base07'])

-- Markers.
local MARK_BOOKMARK, t_run = textadept.bookmarks.MARK_BOOKMARK, textadept.run
--buffer.marker_fore[MARK_BOOKMARK] = property_int['color.base05']
buffer.marker_back[MARK_BOOKMARK] = property_int['color.base0D']
--buffer.marker_fore[t_run.MARK_WARNING] = property_int['color.base05']
buffer.marker_back[t_run.MARK_WARNING] = property_int['color.base0A']
--buffer.marker_fore[t_run.MARK_ERROR] = property_int['color.base05']
buffer.marker_back[t_run.MARK_ERROR] = property_int['color.base08']
for i = 25, 31 do -- fold margin markers
  buffer.marker_fore[i] = property_int['color.base07']
  buffer.marker_back[i] = property_int['color.base04']
  buffer.marker_back_selected[i] = property_int['color.base05']
end

-- Indicators.
local INDIC_BRACEMATCH = textadept.editing.INDIC_BRACEMATCH
buffer.indic_fore[INDIC_BRACEMATCH] = property_int['color.base02']
local INDIC_HIGHLIGHT = textadept.editing.INDIC_HIGHLIGHT
buffer.indic_fore[INDIC_HIGHLIGHT] = property_int['color.base0A']
buffer.indic_alpha[INDIC_HIGHLIGHT] = 255

-- Long Lines.
buffer.edge_colour = property_int['color.base06']

-- Add red and green for diff lexer.
property['color.red'] = property['color.base08']
property['color.green'] = property['color.base0B']
property['color.yellow'] = property['color.base0D']

@diohja
Copy link

diohja commented Nov 17, 2017

Textadept is blazing fast, but I miss two features:

  1. a "word/character counter" (not just for the file but also for a selection)
  2. a "find and mark-all" (preferentially like Geany's Ctrl+shift+M)

I currently use Visual Studio Code, because it has all the features I use and has many useful extensions. The downside is that its not as fast as Geany or Textadept. But its faster than any other text editor with similar functions.

@Ryan1729
Copy link

I've now got ctrl-click multiple selections working, (I can make multiple selections and type into all of them at once) on my debugging branch. Note that that branch simply deletes the old ctrl-click functionality, (and has a bunch of printouts besides), so it' is not suitable to add to the main codebase, but it works as a proof of concept.

So the question now seems to be how should the settings for ctrl-clicking be handled? The natural thing to do right now seems (to me) to be a set of radio buttons, (and a corresponding enum) that allows selecting between the old functionality (goto-tag and find-matching-brace), adding a selection, and not doing anything on ctrl-click at all. However, that old discussion thread mentioned the idea of mouse bindings, (so the user could bind arbitrary actions to mouse inputs,) which seems like a reasonable idea. If that's ever going to happen, then we should probably think about that when deciding how this setting works. If we go with my enum proposal then later mouse bindings get added, then either user's configuration files break or we have one of two undesirable situations : this enum overrides the keybindings, meaning the user might set mouse bindings and not understand why they need to set the enum to "None" or an additional setting of "Allow keybinding", or the other situation where the keybindings override the enum and if a user binds something to ctrl-shift-click and is surprised that ctrl-click stops doing what they expect.

Then again, would not having either setting override each other be best? If a user is surprised that ctrl-clicking adds a selection, in addition to whatever they set it to do, then hopefully that would prompt them to look in the settings to turn that off? Maybe someone else has a better idea that avoids even that problem?

@AdamDanischewski
Copy link

Since the current default behavior is different, it may be argued to not make it a default. Yet the functionality seems to be much better and I personally would prefer to see Geany remain consistent with other editors that offer this same functionality. It is a quirk in my opinion that Geany using Scintilla defaults to a different functionality than what the other Scintilla editors have as standard with regards to multi-caret on Ctrl-click.

I vote to make the new Ctrl-click functionality standard in accordance with the other Scintilla editors.

Btw: you are in the same situation, I was in, with regards to fixing it yet not being able to add it to the user interface. Hopefully elextr knows how to route this to the appropriate parties for implementation.

@elextr
Copy link
Member

elextr commented Nov 18, 2017

IMO a few things are need to be resolved for this to progress:

1. As @AdamDanischewski said, some UI control is needed. The prefect solution IMO is to extend the keybindings UI to allow binding to mouse buttons (with modifiers) as well, so called "clickbindings".

Some mice have many buttons and these could be bound by the user to suit their use-case, while other users may keep the current ctrl-click and bind the multiple select elsewhere and others go for interapp compatibility. Giving the user control takes the heat out of the debate about backward compatibility vs interapp commonality.

This would need a bit of work because the current keybindings are based on gtk_accellerator which does not handle clicks IIUC, but I think its just MMOP to have the click handler use bindings instead of being hard coded and to store and retrieve click to action mappings, eg in clickbindings.conf like keybindings.conf.

2. A plan is needed to introduce multiple select into Geany. As has been said elsewhere, none of Geany is written to support multiple selects. It would be my recommendation that multiple selects be introduced progressively instead of as one big lump. In practice the project does poorly with big lumps because it doesn't have the effort available to review and test them.

But before any multiple select capability is introduced it must be checked that no other Geany and core plugin functionality is affected by their presence and any problems fixed.

Then the basic ability to make multiple selections and type in them, as @Ryan1729 has here, can be added and contributions solicited for making other Geany functions multiple select aware when it makes sense for that.

3. The ability to style the secondary selections can be added, Scintilla can do it, so the settings "just" need to be added to Geany and appropriate colour schemes.

@sagarchalise
Copy link

@Ryan1729 is it possible to embed this feature to may be https://github.com/geany/geany-plugins/tree/master/geanyextrasel ?

This is just a personal opinion but may be the workflow would be multi edit mode selection via menu similar to how column mode currently works on that plugin. While on multi edit mode disable other functionality related to extrasel plugin.

@Ryan1729
Copy link

@sagarchalise That plugin relies on geany providing the functions sci_set_selection_mode and sci_get_selection_mode, that is geany already supporting rectangle selections. I suppose geany could expose the underlying functionality from scintilla for plugins and just not in its own GUI and let a plugin handle it. This might actually be a good way to get testing for multiple selection corner cases: users can opt-in by installing the plugin, with the expectation that some things might be weird/broken. Eventually multi-edit-mode could be moved into geany proper.

I'm not sure how to handle the mouse portion in this scenario though.

@elextr
Copy link
Member

elextr commented Dec 22, 2017

Enabling Scintilla multiple selections is easy, but everybody seems to have missed the following:

Geany and plugins are not written to handle multiple selects, its is unknown what will happen in Geany or plugin functions if there is a multiple selection. In the best case it will "just work" on the main selection and ignore the rest, in the worse case who knows, crash maybe.

Geany handles rectangular selections, but they are provided by Scintilla as a single selection, not multiple selections.

No plugin can change this as its in Geany and other plugins code.

Until the plan for introducing multiple selects addresses this it is likely to go nowhere.

@AdamDanischewski
Copy link

@Ryan1729 That sounds like a reasonable plan to move forward -- since it is unknown what the effects will be, just make it an option to let those who want to use it, give it a shot and they can report if there are issues - fixing them where possible (although it probably will require an overhaul for handling selects at some point).

@jp-pulga
Copy link

jp-pulga commented Jan 4, 2019

Any news in this? I will like to see this feature in Geany

@Ryan1729
Copy link

Ryan1729 commented Jan 5, 2019 via email

@wonkawilly
Copy link

+1 for this feature: hope will be implemented.

@elextr
Copy link
Member

elextr commented Aug 11, 2023

Contributions are welcome, but as the comment above says, the original implementor has stopped working on it, and it appears nobody else is interested/needs it enough.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants