Browse Source

Fix strange behavior with list close tags and empty list tags

Fix the first two points in #61621.

Support for two  writing ways: compact or loose. The loose one is designed for easy editing in the editor.
For this, the first blank line (if exists) right after the list tags (`[ol]`, `[/ol]`, `[ul]`, and `[/ul]`)
will be ignored.

Make sure the empty list contains at least one item, that is, an empty list is ultimately a list with one item.
As a reminder here is a list.
Rindbee 3 years ago
parent
commit
a14f7c4027
1 changed files with 62 additions and 6 deletions
  1. 62 6
      scene/gui/rich_text_label.cpp

+ 62 - 6
scene/gui/rich_text_label.cpp

@@ -3369,21 +3369,34 @@ void RichTextLabel::append_text(const String &p_bbcode) {
 
 	bool in_bold = false;
 	bool in_italics = false;
+	bool after_list_open_tag = false;
+	bool after_list_close_tag = false;
 
 	set_process_internal(false);
 
-	while (pos < p_bbcode.length()) {
+	while (pos <= p_bbcode.length()) {
 		int brk_pos = p_bbcode.find("[", pos);
 
 		if (brk_pos < 0) {
 			brk_pos = p_bbcode.length();
 		}
 
-		if (brk_pos > pos) {
-			add_text(p_bbcode.substr(pos, brk_pos - pos));
+		String text = brk_pos > pos ? p_bbcode.substr(pos, brk_pos - pos) : "";
+
+		// Trim the first newline character, it may be added later as needed.
+		if (after_list_close_tag || after_list_open_tag) {
+			text = text.trim_prefix("\n");
 		}
 
 		if (brk_pos == p_bbcode.length()) {
+			// For tags that are not properly closed.
+			if (text.is_empty() && after_list_open_tag) {
+				text = "\n";
+			}
+
+			if (!text.is_empty()) {
+				add_text(text);
+			}
 			break; //nothing else to add
 		}
 
@@ -3391,7 +3404,8 @@ void RichTextLabel::append_text(const String &p_bbcode) {
 
 		if (brk_end == -1) {
 			//no close, add the rest
-			add_text(p_bbcode.substr(brk_pos, p_bbcode.length() - brk_pos));
+			text += p_bbcode.substr(brk_pos, p_bbcode.length() - brk_pos);
+			add_text(text);
 			break;
 		}
 
@@ -3437,18 +3451,60 @@ void RichTextLabel::append_text(const String &p_bbcode) {
 			}
 
 			if (!tag_ok) {
-				add_text("[" + tag);
+				text += "[" + tag;
+				add_text(text);
+				after_list_open_tag = false;
+				after_list_close_tag = false;
 				pos = brk_end;
 				continue;
 			}
 
+			if (text.is_empty() && after_list_open_tag) {
+				text = "\n"; // Make empty list have at least one item.
+			}
+			after_list_open_tag = false;
+
+			if (tag == "/ol" || tag == "/ul") {
+				if (!text.is_empty()) {
+					// Make sure text ends with a newline character, that is, the last item
+					// will wrap at the end of block.
+					if (!text.ends_with("\n")) {
+						text += "\n";
+					}
+				} else if (!after_list_close_tag) {
+					text = "\n"; // Make the innermost list item wrap at the end of lists.
+				}
+				after_list_close_tag = true;
+			} else {
+				after_list_close_tag = false;
+			}
+
+			if (!text.is_empty()) {
+				add_text(text);
+			}
+
 			tag_stack.pop_front();
 			pos = brk_end + 1;
 			if (tag != "/img" && tag != "/dropcap") {
 				pop();
 			}
+			continue;
+		}
+
+		if (tag == "ol" || tag.begins_with("ol ") || tag == "ul" || tag.begins_with("ul ")) {
+			if (text.is_empty() && after_list_open_tag) {
+				text = "\n"; // Make each list have at least one item at the beginning.
+			}
+			after_list_open_tag = true;
+		} else {
+			after_list_open_tag = false;
+		}
+		if (!text.is_empty()) {
+			add_text(text);
+		}
+		after_list_close_tag = false;
 
-		} else if (tag == "b") {
+		if (tag == "b") {
 			//use bold font
 			in_bold = true;
 			if (in_italics) {