Skip to content

Commit

Permalink
Add dte -Q option, to allow greater control over terminal queries
Browse files Browse the repository at this point in the history
The previous (undocumented) `$DTE_FULL_QUERY` environment variable
is now replaced by `dte -Q6` (see the added comment for details).
`dte -Q0` disables queries entirely.

Values 1 through 3 correspond to the 3 existing query levels, but
also result in *all* levels between 1 and the selected value being
emitted at startup (instead of conditionally, based on responses to
earlier queries). Values 4 and 5 are reserved for future use and
anything `>= 6` is treated the same way as 6.

Note: this feature has been left undocumented for now, which implies
it may still receive breaking changes in the future.
  • Loading branch information
craigbarnes committed Nov 12, 2024
1 parent 80c14aa commit 9346194
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 23 deletions.
6 changes: 3 additions & 3 deletions src/editor.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,8 @@ void ui_start(EditorState *e)
// Like ui_start(), but to be called only the first time the UI is started.
// Terminal queries are buffered before ui_resize() is called, so that only
// a single term_output_flush() is needed (i.e. as opposed to calling
// ui_start() + term_put_level_1_queries() + term_output_flush()).
void ui_first_start(EditorState *e, bool emit_all_queries)
// ui_start() + term_put_initial_queries() + term_output_flush()).
void ui_first_start(EditorState *e, unsigned int terminal_query_level)
{
BUG_ON(e->status != EDITOR_RUNNING);
Terminal *term = &e->terminal;
Expand All @@ -299,7 +299,7 @@ void ui_first_start(EditorState *e, bool emit_all_queries)
term_use_alt_screen_buffer(term);
term_enable_private_modes(term);

term_put_level_1_queries(term, emit_all_queries);
term_put_initial_queries(term, terminal_query_level);
ui_resize(e);
}

Expand Down
2 changes: 1 addition & 1 deletion src/editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ EditorState *init_editor_state(void) RETURNS_NONNULL;
void free_editor_state(EditorState *e) NONNULL_ARGS;
void any_key(Terminal *term, unsigned int esc_timeout) NONNULL_ARGS;
int main_loop(EditorState *e) NONNULL_ARGS WARN_UNUSED_RESULT;
void ui_first_start(EditorState *e, bool emit_all_queries) NONNULL_ARGS;
void ui_first_start(EditorState *e, unsigned int terminal_query_level) NONNULL_ARGS;
void ui_start(EditorState *e) NONNULL_ARGS;
void ui_end(EditorState *e) NONNULL_ARGS;
void ui_resize(EditorState *e) NONNULL_ARGS;
Expand Down
17 changes: 12 additions & 5 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ static ExitCode lint_syntax(const char *filename, SyntaxLoadFlags flags)
return get_nr_errors() ? EC_DATA_ERROR : EC_OK;
}

static ExitCode showkey_loop(void)
static ExitCode showkey_loop(unsigned int terminal_query_level)
{
if (!term_mode_init()) {
return ec_error("tcgetattr", EC_IO_ERROR);
Expand All @@ -118,7 +118,7 @@ static ExitCode showkey_loop(void)
term_input_init(ibuf);
term_output_init(obuf);
term_enable_private_modes(&term);
term_put_level_1_queries(&term, !!xgetenv("DTE_FULL_QUERY"));
term_put_initial_queries(&term, terminal_query_level);
term_put_literal(obuf, "Press any key combination, or use Ctrl+D to exit\r\n");
term_output_flush(obuf);

Expand Down Expand Up @@ -401,14 +401,15 @@ static const char usage[] =
// NOLINTNEXTLINE(readability-function-size)
int main(int argc, char *argv[])
{
static const char optstring[] = "hBHKRVS:b:c:t:r:s:";
static const char optstring[] = "hBHKRVQ:S:b:c:t:r:s:";
const char *rc = NULL;
const char *commands[8];
const char *tags[8];
size_t nr_commands = 0;
size_t nr_tags = 0;
bool read_rc = true;
bool load_and_save_history = true;
unsigned int terminal_query_level = 1;
errors_to_stderr(true);

for (int ch; (ch = getopt(argc, argv, optstring)) != -1; ) {
Expand Down Expand Up @@ -443,8 +444,14 @@ int main(int argc, char *argv[])
case 'H':
load_and_save_history = false;
break;
case 'Q':
if (!str_to_uint(optarg, &terminal_query_level)) {
fprintf(stderr, "Error: invalid argument for -Q: '%s'\n", optarg);
return EC_USAGE_ERROR;
}
break;
case 'K':
return showkey_loop();
return showkey_loop(terminal_query_level);
case 'V':
return write_stdout(copyright, sizeof(copyright));
case 'h':
Expand Down Expand Up @@ -550,7 +557,7 @@ int main(int argc, char *argv[])
}

set_view(window_get_first_view(window));
ui_first_start(e, !!xgetenv("DTE_FULL_QUERY"));
ui_first_start(e, terminal_query_level);

for (size_t i = 0; i < nr_commands; i++) {
handle_normal_command(e, commands[i], false);
Expand Down
33 changes: 24 additions & 9 deletions src/terminal/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,21 +195,36 @@ void term_put_str(TermOutputBuffer *obuf, const char *str)
* • https://vt100.net/docs/vt510-rm/DA1.html
* • ECMA-48 §8.3.24
*/
void term_put_level_1_queries(Terminal *term, bool emit_all)
void term_put_initial_queries(Terminal *term, unsigned int level)
{
if (level < 1) {
return;
}

LOG_INFO("sending level 1 queries to terminal");
term_put_literal(&term->obuf, "\033[c"); // ECMA-48 DA (AKA "DA1")

// ECMA-48 DA (Device Attributes; referred to as "DA1" in other contexts)
term_put_literal(&term->obuf, "\033[c");
if (level < 2) {
return;
}

// Level 6 or greater means emit all query levels and also emit even
// conditional queries, i.e. those that are usually omitted when the
// corresponding feature flag was already set by term_init()
bool emit_all = (level >= 6);
if (emit_all) {
LOG_INFO("emit_all set; unconditionally sending all queries");
term_put_level_2_queries(term, true);
term_put_level_3_queries(term, true);
// Set QUERY flags in Terminal::features, so that handle_query_reply()
// doesn't send level 2/3 queries again
term->features |= TFLAG_QUERY_L2 | TFLAG_QUERY_L3;
LOG_INFO("query level set to %u; unconditionally sending all queries", level);
}

term_put_level_2_queries(term, emit_all);
term->features |= TFLAG_QUERY_L2;

if (level < 3) {
return;
}

term_put_level_3_queries(term, emit_all);
term->features |= TFLAG_QUERY_L3;
}

/*
Expand Down
2 changes: 1 addition & 1 deletion src/terminal/output.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ void term_put_byte(TermOutputBuffer *obuf, char ch);
void term_put_bytes(TermOutputBuffer *obuf, const char *str, size_t count);
TermSetBytesMethod term_set_bytes(Terminal *term, char ch, size_t count);
void term_put_str(TermOutputBuffer *obuf, const char *str);
void term_put_level_1_queries(Terminal *term, bool emit_all);
void term_put_initial_queries(Terminal *term, unsigned int level);
void term_put_level_2_queries(Terminal *term, bool emit_all);
void term_put_level_3_queries(Terminal *term, bool emit_all);
void term_use_alt_screen_buffer(Terminal *term);
Expand Down
8 changes: 4 additions & 4 deletions test/terminal.c
Original file line number Diff line number Diff line change
Expand Up @@ -1681,14 +1681,14 @@ static void test_term_put_level_1_queries(TestContext *ctx)
EXPECT_UINT_EQ(term.features, (C256 | BCE | TITLE | OSC52));
EXPECT_EQ(obuf->count, 0);

// Basic level 1 queries (with emit_all=false)
// Basic level 1 queries
static const char level1[] = "\033[c";
term_put_level_1_queries(&term, false);
term_put_initial_queries(&term, 1);
EXPECT_MEMEQ(obuf->buf, obuf->count, level1, sizeof(level1) - 1);

// All queries (forced by emit_all=true)
static const char full[] =
// term_put_level_1_queries()
// term_put_initial_queries()
"\033[c"
// term_put_level_2_queries()
"\033[>c"
Expand Down Expand Up @@ -1720,7 +1720,7 @@ static void test_term_put_level_1_queries(TestContext *ctx)
;

obuf->count = 0;
term_put_level_1_queries(&term, true);
term_put_initial_queries(&term, 6);
EXPECT_MEMEQ(obuf->buf, obuf->count, full, sizeof(full) - 1);

EXPECT_EQ(obuf->scroll_x, 0);
Expand Down

0 comments on commit 9346194

Please sign in to comment.