Compare commits

..

6 Commits

Author SHA1 Message Date
Romain Vimont
d9dbee9993 Adapt help to terminal size
If the error stream is a terminal, and we can retrieve the terminal
size, wrap the lines at terminal boundaries.
2021-11-11 11:34:39 +01:00
Romain Vimont
740445f425 Add util function to get terminal size 2021-11-11 11:34:35 +01:00
Romain Vimont
f849e85e9f Generate getopt params from option structures
Use the option descriptions to generate the optstring and longopts
parameters for the getopt_long() command.

That way, the options are completely described in a single place.
2021-11-11 11:34:35 +01:00
Romain Vimont
628b131741 Structure shortcuts help 2021-11-11 11:34:35 +01:00
Romain Vimont
fb3d6c319b Structure command line options help
It will allow to correctly print the help for the current terminal size
(even if for now it is hardcoded to 80 columns).
2021-11-07 23:08:09 +01:00
Romain Vimont
04b8a6dcda Add line wrapper
Add a tool to wrap lines at words boundaries (spaces) to fit in a
specified number of columns, left-indented by a specified number of
spaces.
2021-11-07 23:08:08 +01:00
6 changed files with 96 additions and 13 deletions

View File

@@ -29,6 +29,7 @@ src = [
'src/util/process.c',
'src/util/strbuf.c',
'src/util/str_util.c',
'src/util/term.c',
'src/util/thread.c',
'src/util/tick.c',
]
@@ -189,6 +190,7 @@ if get_option('buildtype') == 'debug'
'src/options.c',
'src/util/strbuf.c',
'src/util/str_util.c',
'src/util/term.c',
]],
['test_clock', [
'tests/test_clock.c',

View File

@@ -4,12 +4,14 @@
#include <getopt.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "options.h"
#include "util/log.h"
#include "util/strbuf.h"
#include "util/str_util.h"
#include "util/term.h"
#define STR_IMPL_(x) #x
#define STR(x) STR_IMPL_(x)
@@ -312,7 +314,7 @@ static const struct sc_option options[] = {
"\"lsuper\" and \"rsuper\".\n"
"A shortcut can consist in several keys, separated by '+'. "
"Several shortcuts can be specified, separated by ','.\n"
"For example, to use either LCtrl+LAlt or LSuper for scrcpy\n"
"For example, to use either LCtrl+LAlt or LSuper for scrcpy "
"shortcuts, pass \"lctrl+lalt,lsuper\".\n"
"Default is \"lalt,lsuper\" (left-Alt or left-Super).",
},
@@ -680,7 +682,7 @@ error:
static void
print_option_usage(const struct sc_option *opt, unsigned cols) {
assert(cols > 20); // We need some space
assert(cols > 8); // wrap_lines() requires indent < columns
if (!opt->text) {
// Option not documented in help (for example because it is deprecated)
@@ -716,7 +718,7 @@ print_shortcuts_intro(unsigned cols) {
static void
print_shortcut(const struct sc_shortcut *shortcut, unsigned cols) {
assert(cols > 20); // We need some space
assert(cols > 8); // wrap_lines() requires indent < columns
assert(shortcut->shortcuts[0]); // At least one shortcut
assert(shortcut->text);
@@ -740,17 +742,30 @@ print_shortcut(const struct sc_shortcut *shortcut, unsigned cols) {
void
scrcpy_print_usage(const char *arg0) {
#define SC_TERM_COLS_DEFAULT 80
unsigned cols;
if (!isatty(STDERR_FILENO)) {
// Not a tty, use a default value
cols = SC_TERM_COLS_DEFAULT;
} else {
bool ok = sc_term_get_size(NULL, &cols);
if (!ok) {
cols = SC_TERM_COLS_DEFAULT; // default value
}
}
fprintf(stderr, "Usage: %s [options]\n\n"
"Options:\n", arg0);
for (size_t i = 0; i < ARRAY_LEN(options); ++i) {
print_option_usage(&options[i], 80);
print_option_usage(&options[i], cols);
}
// Print shortcuts section
fprintf(stderr, "\nShortcuts:\n\n");
print_shortcuts_intro(80);
print_shortcuts_intro(cols);
for (size_t i = 0; i < ARRAY_LEN(shortcuts); ++i) {
print_shortcut(&shortcuts[i], 80);
print_shortcut(&shortcuts[i], cols);
}
}

View File

@@ -213,6 +213,8 @@ utf8_from_wide_char(const wchar_t *ws) {
#endif
char *wrap_lines(const char *input, unsigned columns, unsigned indent) {
assert(indent < columns);
struct sc_strbuf buf;
// The output string should not be a lot longer than the input string (just
@@ -224,8 +226,6 @@ char *wrap_lines(const char *input, unsigned columns, unsigned indent) {
return false;
}
assert(indent < columns);
#define APPEND(S,N) if (!sc_strbuf_append(&buf, S, N)) goto error
#define APPEND_CHAR(C) if (!sc_strbuf_append_char(&buf, C)) goto error
#define APPEND_N(C,N) if (!sc_strbuf_append_n(&buf, C, N)) goto error
@@ -241,7 +241,12 @@ char *wrap_lines(const char *input, unsigned columns, unsigned indent) {
size_t col = indent;
while (*input) {
size_t sep_idx = strcspn(input, "\n ");
bool wrap = col + sep_idx > columns;
size_t new_col = col + sep_idx;
if (pending == ' ') {
// The pending space counts
++new_col;
}
bool wrap = new_col > columns;
char sep = input[sep_idx];
if (sep == ' ')

51
app/src/util/term.c Normal file
View File

@@ -0,0 +1,51 @@
#include "term.h"
#include <assert.h>
#ifdef _WIN32
# include <windows.h>
#else
# include <unistd.h>
# include <sys/ioctl.h>
#endif
bool
sc_term_get_size(unsigned *rows, unsigned *cols) {
#ifdef _WIN32
CONSOLE_SCREEN_BUFFER_INFO csbi;
bool ok =
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
if (!ok) {
return false;
}
if (rows) {
assert(csbi.srWindow.Bottom >= csbi.srWindow.Top);
*rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
}
if (cols) {
assert(csbi.srWindow.Right >= csbi.srWindow.Left);
*cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
}
return true;
#else
struct winsize ws;
int r = ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
if (r == -1) {
return false;
}
if (rows) {
*rows = ws.ws_row;
}
if (cols) {
*cols = ws.ws_col;
}
return true;
#endif
}

11
app/src/util/term.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef SC_TERM_H
#define SC_TERM_H
#include "common.h"
#include <stdbool.h>
bool
sc_term_get_size(unsigned *rows, unsigned *cols);
#endif

View File

@@ -301,7 +301,7 @@ static void test_strlist_contains(void) {
static void test_wrap_lines(void) {
const char *s = "This is a text to test line wrapping. The lines must be "
"wrapped either at a space or a line break.\n"
"wrapped at a space or a line break.\n"
"\n"
"This rectangle must remains a rectangle because it is "
"drawn in lines having lengths lower than the specified "
@@ -315,9 +315,8 @@ static void test_wrap_lines(void) {
const char *expected = " This is a text to\n"
" test line wrapping.\n"
" The lines must be\n"
" wrapped either at a\n"
" space or a line\n"
" break.\n"
" wrapped at a space\n"
" or a line break.\n"
" \n"
" This rectangle must\n"
" remains a rectangle\n"