class_name TextEditingUtils extends Reference const non_typing_paragraph := "¶" const non_typing_space := "●" const whitespace_chars := [ ord(" "), ord(","), ord(":"), ord("-"), ord(";"), ord("("), ord(")"), ord("."), ord(non_typing_paragraph), ord(non_typing_space), ] static func is_character_whitespace(text : String, idx : int) -> bool: if idx <= 0: return true # Stop at the edges. if idx >= text.length(): return true return text.ord_at(idx) in whitespace_chars static func show_non_typing(text : String) -> String: text = text\ .replace(non_typing_paragraph, "\n")\ .replace(non_typing_space, " ") if text.ends_with("\n"): text = text.left(text.length() - 1) + non_typing_paragraph elif text.ends_with(" "): text = text.left(text.length() - 1) + non_typing_space return text static func revert_non_typing(text : String) -> String: if text.ends_with(non_typing_paragraph): text = text.left(text.length() - 1) + "\n" elif text.ends_with(non_typing_space): text = text.left(text.length() - 1) + " " return text static func multi_erase_right(values : Array, cursor_positions : Array, ctrl_pressed : bool): for i in values.size(): var start_pos = cursor_positions[i] cursor_positions[i] = _step_cursor(values[i], cursor_positions[i], 1, ctrl_pressed) cursor_positions[i] = min( cursor_positions[i], values[i].length() ) values[i] = ( values[i].left(start_pos) + values[i].substr(cursor_positions[i]) ) cursor_positions[i] = start_pos return values static func multi_erase_left(values : Array, cursor_positions : Array, ctrl_pressed): for i in values.size(): var start_pos = cursor_positions[i] cursor_positions[i] = _step_cursor(values[i], cursor_positions[i], -1, ctrl_pressed) values[i] = ( values[i].substr(0, cursor_positions[i]) + values[i].substr(start_pos) ) return values static func multi_move_left(values : Array, cursor_positions : Array, ctrl_pressed): for i in cursor_positions.size(): cursor_positions[i] = _step_cursor(values[i], cursor_positions[i], -1, ctrl_pressed) static func multi_move_right(values : Array, cursor_positions : Array, ctrl_pressed): for i in cursor_positions.size(): cursor_positions[i] = _step_cursor(values[i], cursor_positions[i], 1, ctrl_pressed) static func multi_paste(values : Array, cursor_positions : Array): var pasted_lines := OS.clipboard.split("\n") var paste_each_line := pasted_lines.size() == values.size() for i in values.size(): if paste_each_line: cursor_positions[i] += pasted_lines[i].length() else: cursor_positions[i] += OS.clipboard.length() values[i] = ( values[i].left(cursor_positions[i]) + (pasted_lines[i] if paste_each_line else OS.clipboard) + values[i].substr(cursor_positions[i]) ) return values static func multi_copy(values : Array): for i in values.size(): values[i] = values[i] OS.clipboard = "\n".join(values) static func multi_input(input_char : String, values : Array, cursor_positions : Array): for i in values.size(): values[i] = ( values[i].left(cursor_positions[i]) + input_char + values[i].substr(cursor_positions[i]) ) cursor_positions[i] = min(cursor_positions[i] + 1, values[i].length()) return values static func _step_cursor(text : String, start : int, step : int = 1, ctrl_pressed : bool = false) -> int: while true: start += step if !ctrl_pressed or is_character_whitespace(text, start): if start > text.length(): return text.length() if start < 0: return 0 return start return 0