Skip to content

Commit c47d14e

Browse files
committed
Add text wrapping when printing post contents
It seems to handle quotes and complex posts well, but the MAX_COLUMN doesn't fully interact with indentation. This will be fixed in a future commit.
1 parent ada8462 commit c47d14e

1 file changed

Lines changed: 76 additions & 25 deletions

File tree

src/pretty.c

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@
2727
#include "include/util.h"
2828
#include "include/main.h"
2929

30+
/*
31+
* Maximum column for wrapping text in posts.
32+
*/
33+
#define MAX_COLUMN 80
34+
3035
/*
3136
* Number of spaces used for indenting post replies.
3237
*/
@@ -143,7 +148,8 @@ static inline void print_pad(FILE* fp, int amount) {
143148
}
144149

145150
/*
146-
* Print the specified string as if they were the contents of a 4chan post.
151+
* Print the specified string as if they were the contents of a 4chan post,
152+
* wrapping lines at word boundaries if they exceed MAX_COLUMN.
147153
*/
148154
static void print_post_contents(FILE* fp, const char* str, bool use_pad) {
149155
bool in_quote = false; /* >foo */
@@ -153,42 +159,87 @@ static void print_post_contents(FILE* fp, const char* str, bool use_pad) {
153159
XPOST_TEXT, /* >>>/foo/ */
154160
} xpost_state = XPOST_NONE;
155161

156-
for (size_t i = 0; str[i] != '\0'; i++) {
157-
const bool first_of_line = (i == 0 || str[i - 1] == '\n');
162+
/* Position in the string of the last printed newline or space */
163+
size_t last_newline_idx = 0, last_space_idx = 0;
164+
165+
size_t i;
166+
for (i = 0; str[i] != '\0'; i++) {
167+
/*
168+
* Store that we found a space (and optionally a newline) in the current
169+
* iteration.
170+
*/
171+
if (isspace(str[i])) {
172+
last_space_idx = i;
173+
if (str[i] == '\n')
174+
last_newline_idx = i;
175+
continue;
176+
}
177+
178+
if (!isspace(str[i + 1]) && str[i + 1] != '\0')
179+
continue;
180+
181+
const bool is_first_word_of_input_line =
182+
(last_space_idx == 0 || str[last_space_idx] == '\n');
158183

159-
/* Whenever we change line, reset color and quote state */
160-
if (first_of_line) {
184+
/* TODO: Check one-off errors */
185+
if (i - last_newline_idx >= MAX_COLUMN) {
186+
fputc('\n', fp);
187+
last_newline_idx = last_space_idx;
188+
if (use_pad)
189+
print_pad(fp, POST_PAD);
190+
/*
191+
* It shouldn't be necessary to specify the color again, but some
192+
* terminals reset on newline (e.g. when piping to 'less -R').
193+
*/
161194
if (in_quote)
195+
fprintf(fp, COL_QUOTE ">");
196+
} else if (last_space_idx != 0) {
197+
fputc(str[last_space_idx], fp);
198+
}
199+
200+
/* Whenever we change an input line, reset color and quote state */
201+
if (is_first_word_of_input_line) {
202+
if (in_quote || xpost_state != XPOST_NONE)
162203
fprintf(fp, COL_POST);
163204
if (use_pad)
164205
print_pad(fp, POST_PAD);
165-
in_quote = false;
206+
in_quote = false;
207+
xpost_state = XPOST_NONE;
166208
}
167209

168-
/* Check if this character starts a quote, and what kind */
169-
if (str[i] == '>') {
170-
if (str[i + 1] == '>') {
171-
if (isdigit(str[i + 2])) {
172-
xpost_state = XPOST_DIGITS; /* >>123456789 */
173-
fprintf(fp, COL_XPOST);
174-
} else if (str[i + 2] == '>') {
175-
xpost_state = XPOST_TEXT; /* >>>/foo/ */
176-
fprintf(fp, COL_XPOST);
210+
/* Print the last word of the input */
211+
const size_t word_start =
212+
(last_space_idx == 0) ? 0 : last_space_idx + 1;
213+
for (size_t j = word_start; j <= i; j++) {
214+
/* Check if this character starts a quote, and what kind */
215+
if (xpost_state == XPOST_NONE && str[j] == '>') {
216+
if (str[j + 1] == '>') {
217+
if (isdigit(str[j + 2])) {
218+
xpost_state = XPOST_DIGITS; /* >>123456789 */
219+
fprintf(fp, COL_XPOST);
220+
} else if (str[j + 2] == '>') {
221+
xpost_state = XPOST_TEXT; /* >>>/foo/ */
222+
fprintf(fp, COL_XPOST);
223+
}
224+
225+
while (str[j + 1] == '>')
226+
fputc(str[j++], fp);
227+
} else if (is_first_word_of_input_line && !in_quote) {
228+
in_quote = true; /* >foo */
229+
fprintf(fp, COL_QUOTE);
177230
}
178-
} else if (first_of_line && !in_quote) {
179-
in_quote = true; /* >foo */
180-
fprintf(fp, COL_QUOTE);
231+
} else if ((xpost_state == XPOST_DIGITS && !isdigit(str[j])) ||
232+
(xpost_state == XPOST_TEXT && isspace(str[j]))) {
233+
const char* old_color = (in_quote) ? COL_QUOTE : COL_POST;
234+
fprintf(fp, "%s", old_color);
235+
xpost_state = XPOST_NONE;
181236
}
182-
} else if ((xpost_state == XPOST_DIGITS && !isdigit(str[i])) ||
183-
(xpost_state == XPOST_TEXT && isspace(str[i]))) {
184-
const char* old_color = (in_quote) ? COL_QUOTE : COL_POST;
185-
fprintf(fp, "%s", old_color);
186-
xpost_state = XPOST_NONE;
187-
}
188237

189-
fputc(str[i], fp);
238+
fputc(str[j], fp);
239+
}
190240
}
191241

242+
/* Reset terminal color */
192243
fprintf(fp, "%s", COL_NORM);
193244
}
194245

0 commit comments

Comments
 (0)