Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calculate the width of each displayed character #185

Merged
merged 2 commits into from
Apr 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
AUTOMAKE_OPTIONS=foreign

AM_CFLAGS=-pedantic -Wall -Werror -Wextra
AM_CPPFLAGS=-D_GNU_SOURCE

bin_PROGRAMS=pick
dist_pick_SOURCES=pick.c compat.h compat.c
Expand All @@ -19,8 +20,6 @@ T_LOG_COMPILER=$(top_srcdir)/tests/pick-test.sh
check_PROGRAMS=tests/pick-test
tests_pick_test_SOURCES=tests/pick-test.c
tests_pick_test_CFLAGS=$(AM_CFLAGS)
# Required by posix_openpt on Linux.
tests_pick_test_CFLAGS+=-D_XOPEN_SOURCE=600

EXTRA_DIST=INSTALL.md INSTALL.md.in LICENSE README.md tests/pick-test.sh $(TESTS)

Expand Down
112 changes: 71 additions & 41 deletions pick.c
Original file line number Diff line number Diff line change
Expand Up @@ -667,65 +667,95 @@ tty_restore(void)
}

void
print_line(const char *string, size_t length, int so, ssize_t ulso, ssize_t uleo)
print_line(const char *str, size_t len, int standout,
ssize_t enter_underline, ssize_t exit_underline)
{
size_t i;
int c, col, tabwidth;
int in_esc_seq = 0;
int non_printable = 0;
wchar_t wc;
int col, in_esc_seq, nbytes, width;

if (so)
if (standout)
tty_putp(enter_standout_mode, 1);

for (col = i = 0; i < length && col < columns; i++) {
if (i == (size_t)ulso)
col = i = in_esc_seq = 0;
while (col < columns) {
if (enter_underline == (ssize_t)i)
tty_putp(enter_underline_mode, 1);
else if (exit_underline == (ssize_t)i)
tty_putp(exit_underline_mode, 1);
if (i == len)
break;

if (str[i] == '\t') {
width = 8 - (col & 7); /* ceil to multiple of 8 */
if (col + width > columns)
break;
for (; width > 0; width--)
if (tty_putc(' ') == ERR)
err(1, "tty_putc");

i++, col += width;
continue;
}

/*
* Count the number of outputted ANSI escape sequences
* in order to adjust the column count since they do not
* occupy any screen real-estate.
* A NUL will be present prior the NUL-terminator if
* descriptions are enabled.
*/
if (in_esc_seq) {
non_printable++;
if (string[i] >= '@' && string[i] <= '~')
in_esc_seq = 0;
} else if (i > 0 && string[i - 1] == '\033'
&& string[i] == '[') {
in_esc_seq = 1;
non_printable = 2;
if (str[i] == '\0') {
if (tty_putc(' ') == ERR)
err(1, "tty_putc");

i++, col++;
continue;
}

c = string[i];
if (c == '\t') {
/* Ceil column count to multiple of 8. */
col += tabwidth = 8 - (col & 7);
while (tabwidth-- > 0)
if (tty_putc(' ') == ERR)
err(1, "tty_putc");
} else {
/*
* Due to the explicit NUL-check above, the case where
* mbtowc(3) returns 0 is not handled here.
*/
if ((nbytes = mbtowc(&wc, &str[i], MB_CUR_MAX)) == -1) {
mbtowc(NULL, NULL, MB_CUR_MAX);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this for resetting internal state of mbtowc?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct

i++;
continue;
}

width = 0;
if (i > 0 && str[i - 1] == '\033' && str[i] == '[')
/*
* A null character will be present prior the
* terminating null character if descriptions is
* enabled.
* Start of ANSI escape sequence. The previous
* ESC-character already has a zero width but any
* following characters will not consume any columns
* once displayed.
*/
if (c == '\0')
c = ' ';
if (!isu8cont(c))
col++;
if (tty_putc(c) == EOF)
err(1, "tty_putc");
}
in_esc_seq = 1;
else if (!in_esc_seq && (width = wcwidth(wc)) < 0)
/*
* The character is not printable. However, it could be
* an ESC-character marking the the beginning an escape
* sequence so make sure to display every valid
* characters.
*/
width = 0;
else if (str[i] >= '@' && str[i] <= '~')
in_esc_seq = 0;

if (i + 1 == (size_t)uleo)
tty_putp(exit_underline_mode, 1);
if (col + width > columns)
break;
col += width;

for (; nbytes > 0; nbytes--, i++)
if (tty_putc(str[i]) == EOF)
err(1, "tty_putc");
}
for (col -= non_printable; col < columns; col++)
for (; col < columns; col++)
if (tty_putc(' ') == EOF)
err(1, "tty_putc");

/* If uleo is greater than columns the underline attribute will spill
* over on the next line unless all attributes are exited. */
/*
* If exit_underline is greater than columns the underline attribute
* will spill over on the next line unless all attributes are exited.
*/
tty_putp(exit_attribute_mode, 1);
}

Expand Down