compute proper width of strings (characters might be wider than 1 column on display) v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 17 Nov 2019 17:51:13 +0100
branchv_0
changeset 26 32824e833b89
parent 25 d841e5ac15c0
child 27 f03e1f9cfcb6
compute proper width of strings (characters might be wider than 1 column on display) Before: $ echo hello 🐭 | relpipe-in-csv wide string | relpipe-out-tabular wide: ╭─────────────────╮ │ string (string) │ ├─────────────────┤ │ hello 🐭 │ ╰─────────────────╯ Record count: 1 After: $ echo hello 🐭 | relpipe-in-csv wide string | relpipe-out-tabular wide: ╭─────────────────╮ │ string (string) │ ├─────────────────┤ │ hello 🐭 │ ╰─────────────────╯ Record count: 1
src/TabularPrefetchingHandler.h
--- a/src/TabularPrefetchingHandler.h	Wed Oct 30 16:47:43 2019 +0100
+++ b/src/TabularPrefetchingHandler.h	Sun Nov 17 17:51:13 2019 +0100
@@ -98,6 +98,16 @@
 		return result.str();
 	}
 
+	/**
+	 * @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 += std::max(0, wcwidth(ch));
+		return width;
+	}
+
 	void printHorizontalLine(const string_t &left, const string_t &middle, const string_t &right) {
 		const string_t bar = L"─";
 		// TODO: support also ASCII nostalgia:
@@ -148,7 +158,7 @@
 			integer_t columnIndex = i % columnCount;
 			if (columnIndex == 0) output << INDENT << ESC_BORDER << "│" << ESC_RESET;
 			string_t stringValue = values[i];
-			integer_t padding = columnWidths[columnIndex] - stringValue.size();
+			integer_t padding = columnWidths[columnIndex] - computeWidth(stringValue);
 			boolean_t alignRight = columnTypes[columnIndex] == TypeId::BOOLEAN || columnTypes[columnIndex] == TypeId::INTEGER;
 
 			if (alignRight) for (integer_t p = 0; p < padding; p++) output << " ";
@@ -190,7 +200,7 @@
 	void attribute(const string_t& value) override {
 		integer_t i = values.size() % columnCount;
 		values.push_back(value);
-		columnWidths[i] = max(columnWidths[i], value.length());
+		columnWidths[i] = max(columnWidths[i], computeWidth(value));
 	}
 
 	void endOfPipe() {