long line wrapping: first version v_0 tip
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 19 Feb 2023 02:26:23 +0100
branchv_0
changeset 18 002077ecb17a
parent 17 f67047a1e19e
long line wrapping: first version
src/RecfileHandler.h
--- a/src/RecfileHandler.h	Sun Feb 19 00:36:47 2023 +0100
+++ b/src/RecfileHandler.h	Sun Feb 19 02:26:23 2023 +0100
@@ -111,12 +111,64 @@
 		return escaped.str();
 	}
 
+	integer_t computeWidth(const wchar_t ch) {
+		switch (ch) {
+			case L'\t':
+				// TODO: tabulator width?
+				return 4;
+			case L' ':
+				return 1;
+			default:
+				return std::max(0, wcwidth(ch));
+		}
+	}
+
+	/**
+	 * @param stringValue
+	 * @return the width that would the string occupy on the display (particular characters might be wider than 1 column)
+	 */
+	integer_t computeWidth(const string_t & stringValue) {
+		integer_t width = 0;
+		for (wchar_t ch : stringValue) width += computeWidth(ch);
+		return width;
+	}
+
 	void writeAttribute(const string_t& escapedName, const TypeId& type, const string_t& value) {
 		output << convertor.to_bytes(escapedName) << ": ";
 
-		for (char ch : convertor.to_bytes(value)) {
-			output << ch;
-			if (ch == '\n') output << "+ ";
+		static const integer_t MAX_LINE_WIDTH = 80; // TODO: configuration
+		static const boolean_t unlimited = MAX_LINE_WIDTH == -1;
+
+		integer_t currentWidth = computeWidth(escapedName) + 2; // 2 = ": " separator
+		integer_t valueWidth = computeWidth(value);
+		integer_t remainingWidth = valueWidth;
+
+
+		for (size_t i = 0, limit = value.size(); i < limit; i++) {
+			wchar_t ch = value[i];
+			integer_t characterWidth = computeWidth(ch);
+
+			if (ch == '\n') {
+				output << std::endl << "+ ";
+				currentWidth = 2; // 2 = "+ " prefix
+			} else {
+				if (unlimited || (currentWidth + remainingWidth) <= MAX_LINE_WIDTH) {
+					// all remaining characters fit the in the limit
+					currentWidth += characterWidth;
+					output << convertor.to_bytes(ch);
+				} else if ((currentWidth + characterWidth + 1) <= MAX_LINE_WIDTH) { // 1 = "\"
+					// we will wrap the line, but not yet
+					currentWidth += characterWidth;
+					output << convertor.to_bytes(ch);
+				} else {
+					output << "\\" << std::endl;
+					currentWidth = 0;
+					currentWidth += characterWidth;
+					output << convertor.to_bytes(ch);
+				}
+			}
+
+			remainingWidth -= characterWidth;
 		}
 
 		output << std::endl;