Get / set character and line coordinate of the selection in the text editor

Hi everybody,

I want to insert some text according to a multiline selection in the text editor .
There are some handy attribute that could help, but there’s a critical one missing ! (maybe I dont see something obvious…)

Here is a list if these attributes (in a text datablock D.texts['Text']) :

current_character # character position (at selection character start)

current_line # line object where cursor is (at selection start)

current_line_index # index where cursor is (at selection start)


select_end_character # character position at selection end

select_end_line # line object where selection end

#!! MISSING !! : select_end_line_index (impossible to know where the selection end !)

So it’s Impossible to determine where the selection has stopped at line level.
The only super ugly workaround I see is using bpy.ops.text.copy() and count the ‘\n’ in the clipboard to know how many line were selected…

Is there another way to get this ?

Also, is there a way to set cursor position on line and character ? current_character and such are read_only and the only things I found is moving to the very start/end of line with some ops (bpy.ops.text.move(override, type='LINE_END') but not at specific character position.

Thank you for your attention.

You can create your own index function.

def sell_idx(text):
    for idx, line in enumerate(text.lines):
        if line == text.select_end_line:
            return idx

select_end_line_index = sell_idx(text)

If you don’t want to deal with a function:
select_end_line_index = text.lines[:].index(text.select_end_line)

Setting cursor can be done by either

bpy.ops.text.cursor_set() or
bpy.ops.text.move().

The former takes pixel coordinates and is meant to be used in conjunction with context.space_data.region_location_from_cursor(line, column), the latter requires that you write your own function that moves the cursor to a given position.

I used the latter one because I need the ability to set multi-line selections as well. You can see how I set the cursor and selection in text_toggle_comment.py.

If you just need to set the caret position (no selection), the former involves less code.

import bpy

def run():
    st = bpy.context.space_data
    index = st.text.lines[:].index

    line_index = index(st.text.select_end_line)

    x, y = st.region_location_from_cursor(line_index, 0)

    # add 10 to y, since there's some misalignment
    bpy.ops.text.cursor_set(x=x, y=y + 10)

if __name__ == '__main__':
    run()
1 Like

Thank you for the help.

I posted the same question about “get_selected_text” on blender.dev (here : https://developer.blender.org/T66317).

Dalai Felinto linked to an addon he had made with a function that does exactly that (even if its outdated).