You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			150 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			GDScript
		
	
		
		
			
		
	
	
			150 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			GDScript
		
	
| 
											2 years ago
										 | extends RefCounted | ||
|  | 
 | ||
|  | const non_typing_paragraph := "¶" | ||
|  | const non_typing_space := "●" | ||
|  | const whitespace_chars := [ | ||
|  | 	32, # " " | ||
|  | 	44, # "," | ||
|  | 	58, # ":" | ||
|  | 	45, # "-" | ||
|  | 	59, # ";" | ||
|  | 	40, # "(" | ||
|  | 	41, # ")" | ||
|  | 	46, # "." | ||
|  | 	182, # "¶" Linefeed | ||
|  | 	10, # "\n" Actual Linefeed | ||
|  | 	967, # "●" Whitespace | ||
|  | ] | ||
|  | 
 | ||
|  | 
 | ||
|  | 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.unicode_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 : 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) | ||
|  | 		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 : bool): | ||
|  | 	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 : bool): | ||
|  | 	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 := DisplayServer.clipboard_get().replace("\r", "").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] += DisplayServer.clipboard_get().length() | ||
|  | 
 | ||
|  | 		values[i] = ( | ||
|  | 			values[i].left(cursor_positions[i]) | ||
|  | 			+ (pasted_lines[i] if paste_each_line else DisplayServer.clipboard_get()) | ||
|  | 			+ values[i].substr(cursor_positions[i]) | ||
|  | 		) | ||
|  | 
 | ||
|  | 	return values | ||
|  | 
 | ||
|  | 
 | ||
|  | static func multi_copy(values : Array): | ||
|  | 	for i in values.size(): | ||
|  | 		values[i] = values[i] | ||
|  | 	 | ||
|  | 	DisplayServer.clipboard_set("\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: | ||
|  | 	var cur := start | ||
|  | 	if ctrl_pressed and is_character_whitespace(text, cur + step): | ||
|  | 		cur += step | ||
|  | 
 | ||
|  | 	while true: | ||
|  | 		cur += step | ||
|  | 		if !ctrl_pressed or is_character_whitespace(text, cur): | ||
|  | 			if cur > text.length(): | ||
|  | 				return text.length() | ||
|  | 
 | ||
|  | 			if cur <= 0: | ||
|  | 				return 0 | ||
|  | 
 | ||
|  | 			if ctrl_pressed and step < 0: | ||
|  | 				return cur + 1 | ||
|  | 
 | ||
|  | 			return cur | ||
|  | 
 | ||
|  | 	return 0 |