elastic-tabstops.cpp (1631B)
1 #include <iostream> 2 #include <vector> 3 #include <cassert> 4 #include <sstream> 5 #include <memory> 6 7 #if 1 8 #define DIM "\e[2m" 9 #define RESET "\e[m" 10 #define INDENT DIM " >> " RESET 11 #define PADDING DIM " ยป" RESET 12 #else 13 #define INDENT " " 14 #define PADDING " " 15 #endif 16 17 using namespace std; 18 19 struct column 20 { 21 size_t width; 22 bool is_indent; 23 }; 24 25 struct cell 26 { 27 string str; 28 shared_ptr<column> column_ref; 29 }; 30 31 struct line 32 { 33 vector<cell> cells; 34 string tail; 35 }; 36 37 vector<line> backlog; 38 39 void flush_backlog() 40 { 41 for (auto& line : backlog) 42 { 43 for (auto& c : line.cells) 44 { 45 if (c.column_ref->is_indent) 46 cout << INDENT; 47 else 48 { 49 c.str.resize(c.column_ref->width, ' '); 50 cout << c.str << PADDING; 51 } 52 } 53 cout << line.tail << endl; 54 } 55 backlog.clear(); 56 } 57 58 int main() 59 { 60 string buf; 61 vector<size_t> chunk_stack; 62 vector<shared_ptr<column>> columns; 63 64 while (getline(cin, buf)) 65 { 66 struct line l; 67 istringstream in2(move(buf)); 68 69 while (getline(in2, buf, '\t')) 70 l.cells.push_back({move(buf), {}}); 71 72 if (l.cells.size()) 73 { 74 l.tail = move(l.cells.back().str); 75 l.cells.pop_back(); 76 } 77 78 columns.resize(l.cells.size()); 79 80 bool indenting = true; 81 for (size_t i = 0; i < columns.size(); ++i) 82 { 83 auto& p = columns[i]; 84 auto width = l.cells[i].str.size(); 85 86 if (width) 87 indenting = false; 88 89 if (p) 90 { 91 p->width = max(p->width, width); 92 p->is_indent &= indenting; 93 } else 94 p = make_shared<column>(column{width, indenting}); 95 96 l.cells[i].column_ref = p; 97 } 98 99 backlog.push_back(move(l)); 100 auto& C = backlog.back().cells; 101 102 if (C.empty()) 103 flush_backlog(); 104 } 105 flush_backlog(); 106 }