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

delete_word_left and delete_word_right unexpected behaviour #3186

Open
wohltat opened this issue May 4, 2024 · 1 comment
Open

delete_word_left and delete_word_right unexpected behaviour #3186

wohltat opened this issue May 4, 2024 · 1 comment

Comments

@wohltat
Copy link

wohltat commented May 4, 2024

When deleting a word with delete_word_left (ctrl+backspace) or delete_word_right (ctrl+delete) the behavior is not like in other editor and in my opinion faulty.

  • When deleting back over a linebreak with multiple lines, it deletes all the whitespace + linebreak + the previous word. In sublime text for example this would be 3 steps.
  • Strange behavior around brackets
    • It sometimes stops before the last bracket. When there is a word in the bracket like [foo]
    • deletion of adjacent brackets is also strange. For example deleting back in foo bar []() gives foo even though there is a space in between.
    • When there are brackets as first characters in the console command line, then they cannot be deleted at all
@wohltat
Copy link
Author

wohltat commented May 4, 2024

This was bothering me quite a lot. So i had to do something.

Here is an algorithm where i tried to copy the behavior of sublime text:
As far as i tested it, it is identical.

Basic idea is that there are 3 character groups. As long as the next character is of the same group the deletion continues. One preceding white-space is skipped so that it is removed together with the word.

import tkinter as tk

example_text = """

    start_index = text_widget.search(r'\w*\W?', cursor_index, backwards=True, regexp=True, stopindex='1.0')

    # If start_index is at the beginning of the text, move it to the beginning of the line
    if start_index == '':
        start_index = '1.0'
    else:
        start_index = text_widget.index(start_index + "+1c")

    # Delete text between start of the word and cursor position
    text_widget.delete(start_index, cursor_index)

# Example usage:
def on_ctrl_backspace(event):
    delete_word_left(text_widget)
    asdasdf
        aaaaa\tasdf\t \tfsdf\t\tsdksd\t     
    .)(=.,)[]$&/()''""....{} asdf§sadf
"""

def char_group(c):
    # group 1 = whitespaces, group 2 = symbols, group 3 = alphanum
    group2_chars = '!"#$%&\'()*+,-./:;<=>?@[\\]^`{|}~'
    if c.isspace(): return 1
    if c in group2_chars: return 2
    return 3

def delete_word_left(text_widget):
    # Get current cursor position
    cursor_index = text_widget.index(tk.INSERT)
    line_start_index = text_widget.index(cursor_index + " linestart")

    # get the current line and search from the end
    line = text_widget.get(line_start_index, tk.INSERT)
    cur_index = len(line)-1

    # step at least one whitespace at the beginning
    if line and line[cur_index].isspace():	
        cur_index -= 1 

    last_char_group = None 
    for cur_char in reversed(line[:cur_index+1]):
        cur_char_group = char_group(cur_char)
        if last_char_group and last_char_group != cur_char_group:
            break
        last_char_group = cur_char_group
        cur_index -= 1

    start_index = text_widget.index(line_start_index +  f" + {cur_index+2} chars")
    text_widget.delete(start_index, cursor_index)

def delete_word_right(text_widget):
    # Get current cursor position
    cursor_index = text_widget.index(tk.INSERT)
    line_end_index = text_widget.index(cursor_index + " lineend")

    # get the current line and search from the end
    line = text_widget.get(tk.INSERT, line_end_index)
    cur_index = 0

    # step at least one whitespace at the beginning
    if line and line[cur_index].isspace():	
        cur_index += 1 

    last_char_group = None 
    for cur_char in line[cur_index:]:
        cur_char_group = char_group(cur_char)
        # print(f'{cur_index=} {cur_char=} {cur_char_group=} {last_char_group=}')
        if last_char_group and last_char_group != cur_char_group:
            break
        last_char_group = cur_char_group
        cur_index += 1

    end_index = text_widget.index(cursor_index +  f" + {cur_index-1} chars")
    text_widget.delete(cursor_index, end_index)

def on_ctrl_backspace(event):
    delete_word_left(text_widget)

def on_ctrl_delete(event):
    delete_word_right(text_widget)

root = tk.Tk() 
text_widget = tk.Text(root)
text_widget.insert(tk.END, example_text)
text_widget.pack()
text_widget.focus()
text_widget.bind("<Control-BackSpace>", on_ctrl_backspace)
text_widget.bind("<Control-Delete>", on_ctrl_delete)

root.mainloop()

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

No branches or pull requests

1 participant