Skip to content

Commit

Permalink
Move all RPROMPT code from readline into Clink.
Browse files Browse the repository at this point in the history
This cleans out the Readline modifications for RPROMPT support.
I abandoned the goal of contributing RPROMPT support back into Readline
because its display code has limitations that created troublesome edge
cases.  And since Clink abandoned Readline's display code altogether, I
don't have a good way to test whether the RPROMPT implementation would
work properly in bash.
  • Loading branch information
chrisant996 committed Nov 10, 2024
1 parent 407e654 commit eb37b0e
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 110 deletions.
1 change: 0 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ _This todo list describes ChrisAnt996's current intended roadmap for Clink's fut

## Normal Priority
- Randomly hit `assert(group == m_prev_group || group == m_catch_group);` upon `Ctrl-Space`. It left input in a weird state with `clink-select-complete` still active but not handling input. Could not repro again after I got out of the state. It seems likely to be a long-standing issue in some obscure edge case.
- Finish removing the RPROMPT stuff from Readline, moving it entirely into Clink code. The only part of Readline that actually needs it is the stuff for clearing to the end of the line, which is mostly omitted now anyway. Most of it can be moved easily, but one spot will need special consideration (maybe a callback?): `_rl_erase_entire_line()` inside `_rl_internal_char_cleanup()`.
- Event handler enhancements:
- Allow setting an optional `priority` when registering event handlers? So that scripts can control the precedence of `onbeginedit`, `onendedit`, and so on.
- Allow adding a ONE-TIME event handler which automatically removes itself upon firing? And `clink-diagnostics` would need to show any ONE-TIME event handlers until the next beginedit.
Expand Down
3 changes: 3 additions & 0 deletions clink/lib/include/lib/display_readline.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
class line_buffer;
typedef struct _history_expansion history_expansion;

extern char* rl_rprompt;
void rl_set_rprompt(const char* rprompt);

extern "C" void reset_display_readline(void);
void refresh_terminal_size();
void clear_to_end_of_screen_on_next_display();
Expand Down
65 changes: 63 additions & 2 deletions clink/lib/src/display_readline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,14 @@ extern int rl_get_forced_display(void);
extern void rl_set_forced_display(int force);

extern int _rl_last_v_pos;
extern int _rl_rprompt_shown_len;

int _rl_rprompt_shown_len = 0;
} // extern "C"

// rl_prompt is the right-justified prompt string, if any. It is set by
// rl_set_rprompt(), and should not be assigned to directly.
char* rl_rprompt = nullptr;
int32 rl_visible_rprompt_length = 0;

#ifndef HANDLE_MULTIBYTE
#error HANDLE_MULTIBYTE is required.
#endif
Expand Down Expand Up @@ -2771,6 +2775,63 @@ extern "C" void _rl_refresh_line(void)
rl_keep_mark_active();
}

//------------------------------------------------------------------------------
extern "C" void _rl_clear_to_eol(int32 count)
{
if (_rl_last_v_pos == 0)
{
// If the cursor is on the first line of the input buffer, then flag
// that the right side prompt is not shown, so it can be redisplayed
// later as appropriate.
_rl_rprompt_shown_len = 0;
}

assert(_rl_term_clreol);
assert(*_rl_term_clreol);
tputs(_rl_term_clreol);
}

//------------------------------------------------------------------------------
static char* expand_rprompt(const char* pmt)
{
const uint32 l = str_len(pmt);
char* ret = (char*)xmalloc(l + 1);
bool newlines = false;

// Strip the invisible character string markers RL_PROMPT_START_IGNORE and
// RL_PROMPT_END_IGNORE.
char* r = ret;
for (const char* p = pmt; *p; ++p)
{
if (*p == '\r' || *p == '\n')
newlines = true;
if (*p != RL_PROMPT_START_IGNORE && *p != RL_PROMPT_END_IGNORE)
*(r++) = *p;
}
*r = '\0';

if (newlines)
{
free(ret);
ret = nullptr;
}

return ret;
}

//------------------------------------------------------------------------------
void rl_set_rprompt(const char* rprompt)
{
free(rl_rprompt);

if (rprompt && *rprompt)
rl_rprompt = expand_rprompt(rprompt);
else
rl_rprompt = nullptr;

rl_visible_rprompt_length = rl_rprompt ? cell_count(rl_rprompt) : 0;
}

//------------------------------------------------------------------------------
void refresh_terminal_size()
{
Expand Down
4 changes: 1 addition & 3 deletions clink/lua/src/rl_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <lib/rl_integration.h>
#include <lib/matches.h>
#include <lib/match_colors.h>
#include <lib/display_readline.h>
#include "match_builder_lua.h"
#include "prompt.h"

Expand All @@ -30,9 +31,6 @@ extern "C" {
#include <readline/history.h>
#include <readline/rldefs.h>
#include <readline/rlprivate.h>
extern int _rl_completion_case_map;
extern const char* rl_readline_name;
extern int _rl_last_v_pos;
}

// TODO: Clean up extern.
Expand Down
105 changes: 15 additions & 90 deletions readline/readline/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,7 @@ static void norm_face (char *, int);

#if !defined (OMIT_DEFAULT_DISPLAY_READLINE)
static void update_line (char *, char *, char *, char *, int, int, int, int);
#endif /* !OMIT_DEFAULT_DISPLAY_READLINE */
static void space_to_eol (int);
#if !defined (OMIT_DEFAULT_DISPLAY_READLINE)
static void delete_chars (int);
static void insert_some_chars (char *, int, int);
static void open_some_spaces (int);
Expand All @@ -89,7 +87,6 @@ static void _rl_move_cursor_relative (int, const char *, const char *);

/* Values for FLAGS */
#define PMT_MULTILINE 0x01
#define PMT_RPROMPT 0x02

/* begin_clink_change */
//static char *expand_prompt (char *, int, int *, int *, int *, int *);
Expand Down Expand Up @@ -220,13 +217,6 @@ int rl_display_fixed = 0;
This is usually pointing to rl_prompt. */
char *rl_display_prompt = (char *)NULL;

/* begin_clink_change */
/* The right side prompt, if any. This is displayed on the first
line of the input text, if there is room past the input text. */
char *rl_display_rprompt = (char *)NULL;
int _rl_rprompt_shown_len = 0;
/* end_clink_change */

/* Variables used to include the editing mode in the prompt. */
char *_rl_emacs_mode_str;
int _rl_emacs_modestr_len;
Expand Down Expand Up @@ -402,7 +392,6 @@ prompt_modestr (int *lenp)

/* Possible values for FLAGS:
PMT_MULTILINE caller indicates that this is part of a multiline prompt
PMT_RPROMPT caller indicates that this is the right side prompt
*/

/* This approximates the number of lines the prompt will take when displayed */
Expand Down Expand Up @@ -466,15 +455,10 @@ expand_prompt (const char *pmt, int flags, int *lp, int *lip, int *niflp, int *v
if (vlp)
*vlp = l;

/* begin_clink_change */
if (!(flags & PMT_RPROMPT))
/* end_clink_change */
{
local_prompt_newlines = (int *) xrealloc (local_prompt_newlines, sizeof (int) * 2);
local_prompt_invis_chars = (int *) xrealloc (local_prompt_invis_chars, sizeof (int) * 2);
local_prompt_newlines[0] = local_prompt_invis_chars[0] = 0;
local_prompt_newlines[1] = -1;
}
local_prompt_newlines = (int *) xrealloc (local_prompt_newlines, sizeof (int) * 2);
local_prompt_invis_chars = (int *) xrealloc (local_prompt_invis_chars, sizeof (int) * 2);
local_prompt_newlines[0] = local_prompt_invis_chars[0] = 0;
local_prompt_newlines[1] = -1;

return r;
}
Expand All @@ -486,19 +470,14 @@ expand_prompt (const char *pmt, int flags, int *lp, int *lip, int *niflp, int *v
/* Guess at how many screen lines the prompt will take to size the array that
keeps track of where the line wraps happen */
newlines_guess = (_rl_screenwidth > 0) ? APPROX_DIV(l, _rl_screenwidth) : APPROX_DIV(l, 80);
/* begin_clink_change */
if (!(flags & PMT_RPROMPT))
/* end_clink_change */
local_prompt_newlines = (int *) xrealloc (local_prompt_newlines, sizeof (int) * (newlines_guess + 1));
local_prompt_newlines[newlines = 0] = 0;
local_prompt_invis_chars = (int *) xrealloc (local_prompt_invis_chars, sizeof (int) * (newlines_guess + 1));
local_prompt_invis_chars[0] = 0;
for (rl = 1; rl <= newlines_guess; rl++)
{
local_prompt_newlines = (int *) xrealloc (local_prompt_newlines, sizeof (int) * (newlines_guess + 1));
local_prompt_newlines[newlines = 0] = 0;
local_prompt_invis_chars = (int *) xrealloc (local_prompt_invis_chars, sizeof (int) * (newlines_guess + 1));
local_prompt_invis_chars[0] = 0;
for (rl = 1; rl <= newlines_guess; rl++)
{
local_prompt_newlines[rl] = -1;
local_prompt_invis_chars[rl] = 0;
}
local_prompt_newlines[rl] = -1;
local_prompt_invis_chars[rl] = 0;
}

rl = physchars = 0; /* mode string now part of nprompt */
Expand Down Expand Up @@ -594,12 +573,7 @@ expand_prompt (const char *pmt, int flags, int *lp, int *lip, int *niflp, int *v
invflset = 1;
}

/* begin_clink_change */
//if (physchars >= (bound = (newlines + 1) * _rl_screenwidth) && local_prompt_newlines[newlines+1] == -1)
if (!(flags & PMT_RPROMPT) &&
physchars >= (bound = (newlines + 1) * _rl_screenwidth) &&
local_prompt_newlines[newlines+1] == -1)
/* end_clink_change */
if (physchars >= (bound = (newlines + 1) * _rl_screenwidth) && local_prompt_newlines[newlines+1] == -1)
{
int new;
if (physchars > bound) /* should rarely happen */
Expand All @@ -625,11 +599,8 @@ expand_prompt (const char *pmt, int flags, int *lp, int *lip, int *niflp, int *v
code that wraps before the physical screen width if the character
width would exceed it, but it needs to be checked against this
code and local_prompt_newlines[]. */
/* begin_clink_change */
//if (ignoring == 0)
if (!(flags & PMT_RPROMPT) && ignoring == 0)
/* end_clink_change */
can_add_invis = (physchars == bound);
if (ignoring == 0)
can_add_invis = (physchars == bound);
}
}

Expand All @@ -652,23 +623,6 @@ expand_prompt (const char *pmt, int flags, int *lp, int *lip, int *niflp, int *v
if (nprompt != pmt)
xfree (nprompt);

/* begin_clink_change */
/* Right side prompt is restricted to one line. */
if ((flags & PMT_RPROMPT) && newlines > 0)
{
xfree (ret);
ret = 0;
if (lp)
*lp = 0;
if (lip)
*lip = 0;
if (niflp)
*niflp = 0;
if (vlp)
*vlp = 0;
}
/* end_clink_change */

return ret;
}

Expand All @@ -689,28 +643,6 @@ _rl_reset_prompt (void)
rl_visible_prompt_length = rl_expand_prompt (rl_prompt);
}

/* begin_clink_change */
/* Set up the right side prompt. Call this before calling readline ()
or rl_callback_handler_install (). The string should include
RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE around invisible
characters (escape codes). */
int
rl_set_rprompt (const char *rprompt)
{
FREE (rl_rprompt);

if (rprompt && *rprompt)
{
rl_rprompt = expand_prompt (rprompt, PMT_RPROMPT, (int *)NULL, (int *)NULL, (int *)NULL, &rl_visible_rprompt_length);
}
else
{
rl_rprompt = (char *)NULL;
rl_visible_rprompt_length = 0;
}

return 0;
}
/*
* Expand the prompt string into the various display components, if
* necessary.
Expand Down Expand Up @@ -3558,21 +3490,13 @@ _rl_erase_at_end_of_line (int l)
visible_line[--_rl_last_c_pos] = '\0';
rl_display_fixed++;
}
#endif /* OMIT_DEFAULT_DISPLAY_READLINE */

/* Clear to the end of the line. COUNT is the minimum
number of character spaces to clear, but we use a terminal escape
sequence if available. */
void
_rl_clear_to_eol (int count)
{
/* begin_clink_change */
/* Flag that the right side prompt is not shown, so it can be
redisplayed as appropriate. */
if (_rl_last_v_pos == 0)
_rl_rprompt_shown_len = 0;
/* end_clink_change */

#ifndef __MSDOS__
if (_rl_term_clreol)
tputs (_rl_term_clreol, 1, _rl_output_character_function);
Expand All @@ -3594,6 +3518,7 @@ space_to_eol (int count)

_rl_last_c_pos += count;
}
#endif /* OMIT_DEFAULT_DISPLAY_READLINE */

void
_rl_clear_screen (int clrscr)
Expand Down
6 changes: 0 additions & 6 deletions readline/readline/readline.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,6 @@ int _rl_echoing_p = 0;
char *rl_prompt = (char *)NULL;
int rl_visible_prompt_length = 0;

/* begin_clink_change */
/* Optional right-justified prompt string. */
char *rl_rprompt = (char *)NULL;
int rl_visible_rprompt_length = 0;
/* end_clink_change */

/* Set to non-zero by calling application if it has already printed rl_prompt
and does not want readline to do it the first time. */
int rl_already_prompted = 0;
Expand Down
8 changes: 0 additions & 8 deletions readline/readline/readline.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,6 @@ extern int rl_expand_prompt (char *);
extern const char *rl_get_local_prompt (void);
extern const char *rl_get_local_prompt_prefix (void);
extern const char *rl_get_message_buffer (void);
extern int rl_set_rprompt (const char *);
/* end_clink_change */

extern int rl_initialize (void);
Expand Down Expand Up @@ -615,13 +614,6 @@ extern char *rl_prompt;
applications can more easily supply their own redisplay functions. */
extern char *rl_display_prompt;

/* begin_clink_change */
/* The right-justified prompt string, if any. This is set by
rl_set_rprompt (), and should not be assigned to directly. */
extern char *rl_rprompt;
extern int rl_visible_rprompt_length;
/* end_clink_change */

/* The line buffer that is in use. */
extern char *rl_line_buffer;

Expand Down

0 comments on commit eb37b0e

Please sign in to comment.