mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-14 05:53:59 +00:00
Remove some unnecessary fish_pager.cpp specific code from the new pager
This commit is contained in:
parent
0a1960865e
commit
5849cd3a2e
2 changed files with 24 additions and 354 deletions
376
pager.cpp
376
pager.cpp
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
#include "highlight.h"
|
#include "highlight.h"
|
||||||
|
#include "input_common.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -58,6 +62,7 @@
|
||||||
#include "env_universal.h"
|
#include "env_universal.h"
|
||||||
#include "print_help.h"
|
#include "print_help.h"
|
||||||
#include "highlight.h"
|
#include "highlight.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define PAGER_SELECTION_NONE ((size_t)(-1))
|
#define PAGER_SELECTION_NONE ((size_t)(-1))
|
||||||
|
|
||||||
|
@ -75,55 +80,12 @@ enum
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
enum
|
/** The minimum width (in characters) the terminal may have for fish_pager to not refuse showing the completions */
|
||||||
{
|
|
||||||
/*
|
|
||||||
Returnd by the pager if no more displaying is needed
|
|
||||||
*/
|
|
||||||
PAGER_DONE,
|
|
||||||
/*
|
|
||||||
Returned by the pager if the completions would not fit in the specified number of columns
|
|
||||||
*/
|
|
||||||
PAGER_RETRY,
|
|
||||||
/*
|
|
||||||
Returned by the pager if the terminal changes size
|
|
||||||
*/
|
|
||||||
PAGER_RESIZE
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
/**
|
|
||||||
The minimum width (in characters) the terminal may have for fish_pager to not refuse showing the completions
|
|
||||||
*/
|
|
||||||
#define PAGER_MIN_WIDTH 16
|
#define PAGER_MIN_WIDTH 16
|
||||||
|
|
||||||
/**
|
/** The maximum number of columns of completion to attempt to fit onto the screen */
|
||||||
The maximum number of columns of completion to attempt to fit onto the screen
|
|
||||||
*/
|
|
||||||
#define PAGER_MAX_COLS 6
|
#define PAGER_MAX_COLS 6
|
||||||
|
|
||||||
/**
|
|
||||||
The string describing the single-character options accepted by fish_pager
|
|
||||||
*/
|
|
||||||
#define GETOPT_STRING "c:hr:qvp:"
|
|
||||||
|
|
||||||
/**
|
|
||||||
Error to use when given an invalid file descriptor for reading completions or writing output
|
|
||||||
*/
|
|
||||||
#define ERR_NOT_FD _( L"%ls: Argument '%s' is not a valid file descriptor\n" )
|
|
||||||
|
|
||||||
/**
|
|
||||||
This buffer is used to buffer the output of the pager to improve
|
|
||||||
screen redraw performance bu cutting down the number of write()
|
|
||||||
calls to only one.
|
|
||||||
*/
|
|
||||||
static std::vector<char> pager_buffer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
This string contains the text that should be sent back to the calling program
|
|
||||||
*/
|
|
||||||
static wcstring out_buff;
|
|
||||||
|
|
||||||
/* Returns numer / denom, rounding up */
|
/* Returns numer / denom, rounding up */
|
||||||
static size_t divide_round_up(size_t numer, size_t denom)
|
static size_t divide_round_up(size_t numer, size_t denom)
|
||||||
{
|
{
|
||||||
|
@ -148,100 +110,6 @@ void pager_t::recalc_min_widths(comp_info_list_t * lst) const
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
Test if the specified character sequence has been entered on the
|
|
||||||
keyboard
|
|
||||||
*/
|
|
||||||
static int try_sequence(const char *seq)
|
|
||||||
{
|
|
||||||
int j, k;
|
|
||||||
wint_t c=0;
|
|
||||||
|
|
||||||
for (j=0;
|
|
||||||
seq[j] != '\0' && seq[j] == (c=input_common_readch(j>0));
|
|
||||||
j++)
|
|
||||||
;
|
|
||||||
|
|
||||||
if (seq[j] == '\0')
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
input_common_unreadch(c);
|
|
||||||
for (k=j-1; k>=0; k--)
|
|
||||||
input_common_unreadch(seq[k]);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Read a character from keyboard
|
|
||||||
*/
|
|
||||||
static wint_t readch()
|
|
||||||
{
|
|
||||||
struct mapping
|
|
||||||
{
|
|
||||||
const char *seq;
|
|
||||||
wint_t bnd;
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
struct mapping m[]=
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"\x1b[A", LINE_UP
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
key_up, LINE_UP
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
"\x1b[B", LINE_DOWN
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
key_down, LINE_DOWN
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
key_ppage, PAGE_UP
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
key_npage, PAGE_DOWN
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
" ", PAGE_DOWN
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
"\t", PAGE_DOWN
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
0, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i=0; m[i].bnd; i++)
|
|
||||||
{
|
|
||||||
if (!m[i].seq)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (try_sequence(m[i].seq))
|
|
||||||
return m[i].bnd;
|
|
||||||
}
|
|
||||||
return input_common_readch(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Print the specified string, but use at most the specified amount of
|
Print the specified string, but use at most the specified amount of
|
||||||
space. If the whole string can't be fitted, ellipsize it.
|
space. If the whole string can't be fitted, ellipsize it.
|
||||||
|
@ -536,62 +404,6 @@ void pager_t::measure_completion_infos(comp_info_list_t *infos, const wcstring &
|
||||||
recalc_min_widths(infos);
|
recalc_min_widths(infos);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
page_rendering_t render_completions(const completion_list_t &raw_completions, const wcstring &prefix)
|
|
||||||
{
|
|
||||||
// Save old output function so we can restore it
|
|
||||||
int (* const saved_writer_func)(char) = output_get_writer();
|
|
||||||
output_set_writer(&pager_buffered_writer);
|
|
||||||
|
|
||||||
// Get completion infos out of it
|
|
||||||
comp_info_list_t completion_infos = process_completions_into_infos(raw_completions, prefix.c_str());
|
|
||||||
|
|
||||||
// Maybe join them
|
|
||||||
if (prefix == L"-")
|
|
||||||
join_completions(&completion_infos);
|
|
||||||
|
|
||||||
// Compute their various widths
|
|
||||||
measure_completion_infos(&completion_infos, prefix);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Try to print the completions. Start by trying to print the
|
|
||||||
list in PAGER_MAX_COLS columns, if the completions won't
|
|
||||||
fit, reduce the number of columns by one. Printing a single
|
|
||||||
column never fails.
|
|
||||||
*/
|
|
||||||
for (int i = PAGER_MAX_COLS; i>0; i--)
|
|
||||||
{
|
|
||||||
switch (completion_try_print(i, prefix, completion_infos))
|
|
||||||
{
|
|
||||||
|
|
||||||
case PAGER_RETRY:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PAGER_DONE:
|
|
||||||
i=0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PAGER_RESIZE:
|
|
||||||
/*
|
|
||||||
This means we got a resize event, so we start
|
|
||||||
over from the beginning. Since it the screen got
|
|
||||||
bigger, we might be able to fit all completions
|
|
||||||
on-screen.
|
|
||||||
*/
|
|
||||||
i=PAGER_MAX_COLS+1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fwprintf(out_file, L"%ls", out_buff.c_str());
|
|
||||||
|
|
||||||
// Restore saved writer function
|
|
||||||
pager_buffer.clear();
|
|
||||||
output_set_writer(saved_writer_func);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void pager_t::set_completions(const completion_list_t &raw_completions)
|
void pager_t::set_completions(const completion_list_t &raw_completions)
|
||||||
{
|
{
|
||||||
// Get completion infos out of it
|
// Get completion infos out of it
|
||||||
|
@ -620,22 +432,12 @@ void pager_t::set_term_size(int w, int h)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Try to print the list of completions l with the prefix prefix using
|
Try to print the list of completions l with the prefix prefix using
|
||||||
cols as the number of columns. Return 1 if the completion list was
|
cols as the number of columns. Return true if the completion list was
|
||||||
printed, 0 if the terminal is to narrow for the specified number of
|
printed, false if the terminal is to narrow for the specified number of
|
||||||
columns. Always succeeds if cols is 1.
|
columns. Always succeeds if cols is 1.
|
||||||
|
|
||||||
If all the elements do not fit on the screen at once, make the list
|
|
||||||
scrollable using the up, down and space keys to move. The list will
|
|
||||||
exit when any other key is pressed.
|
|
||||||
|
|
||||||
\param cols the number of columns to try to fit onto the screen
|
|
||||||
\param prefix the character string to prefix each completion with
|
|
||||||
\param l the list of completions
|
|
||||||
|
|
||||||
\return one of PAGER_RETRY, PAGER_DONE and PAGER_RESIZE
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int pager_t::completion_try_print(size_t cols, const wcstring &prefix, const comp_info_list_t &lst, page_rendering_t *rendering, size_t suggested_start_row) const
|
bool pager_t::completion_try_print(size_t cols, const wcstring &prefix, const comp_info_list_t &lst, page_rendering_t *rendering, size_t suggested_start_row) const
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
The calculated preferred width of each column
|
The calculated preferred width of each column
|
||||||
|
@ -649,10 +451,9 @@ int pager_t::completion_try_print(size_t cols, const wcstring &prefix, const com
|
||||||
If the list can be printed with this width, width will contain the width of each column
|
If the list can be printed with this width, width will contain the width of each column
|
||||||
*/
|
*/
|
||||||
int *width=pref_width;
|
int *width=pref_width;
|
||||||
/*
|
|
||||||
Set to one if the list should be printed at this width
|
/* Set to one if the list should be printed at this width */
|
||||||
*/
|
bool print = false;
|
||||||
int print=0;
|
|
||||||
|
|
||||||
/* Compute the effective term width and term height, accounting for disclosure */
|
/* Compute the effective term width and term height, accounting for disclosure */
|
||||||
int term_width = this->available_term_width;
|
int term_width = this->available_term_width;
|
||||||
|
@ -674,11 +475,10 @@ int pager_t::completion_try_print(size_t cols, const wcstring &prefix, const com
|
||||||
|
|
||||||
int pref_tot_width=0;
|
int pref_tot_width=0;
|
||||||
int min_tot_width = 0;
|
int min_tot_width = 0;
|
||||||
int res=PAGER_RETRY;
|
|
||||||
|
|
||||||
/* Skip completions on tiny terminals */
|
/* Skip completions on tiny terminals */
|
||||||
if (term_width < PAGER_MIN_WIDTH)
|
if (term_width < PAGER_MIN_WIDTH)
|
||||||
return PAGER_DONE;
|
return true;
|
||||||
|
|
||||||
/* Calculate how wide the list would be */
|
/* Calculate how wide the list would be */
|
||||||
for (long col = 0; col < cols; col++)
|
for (long col = 0; col < cols; col++)
|
||||||
|
@ -717,13 +517,13 @@ int pager_t::completion_try_print(size_t cols, const wcstring &prefix, const com
|
||||||
pref_width[0] = term_width;
|
pref_width[0] = term_width;
|
||||||
}
|
}
|
||||||
width = pref_width;
|
width = pref_width;
|
||||||
print=1;
|
print = true;
|
||||||
}
|
}
|
||||||
else if (pref_tot_width <= term_width)
|
else if (pref_tot_width <= term_width)
|
||||||
{
|
{
|
||||||
/* Terminal is wide enough. Print the list! */
|
/* Terminal is wide enough. Print the list! */
|
||||||
width = pref_width;
|
width = pref_width;
|
||||||
print=1;
|
print = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -770,7 +570,7 @@ int pager_t::completion_try_print(size_t cols, const wcstring &prefix, const com
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print=1;
|
print = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -820,118 +620,8 @@ int pager_t::completion_try_print(size_t cols, const wcstring &prefix, const com
|
||||||
}
|
}
|
||||||
line_t &line = rendering->screen_data.add_line();
|
line_t &line = rendering->screen_data.add_line();
|
||||||
print_max(progress_text.c_str(), highlight_spec_pager_progress | highlight_make_background(highlight_spec_pager_progress), term_width, true /* has_more */, &line);
|
print_max(progress_text.c_str(), highlight_spec_pager_progress | highlight_make_background(highlight_spec_pager_progress), term_width, true /* has_more */, &line);
|
||||||
|
|
||||||
return PAGER_DONE;
|
|
||||||
|
|
||||||
res=PAGER_DONE;
|
|
||||||
if (row_count < term_height)
|
|
||||||
{
|
|
||||||
completion_print(cols, width, 0, row_count, prefix, lst, rendering);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
completion_print(cols, width, 0, term_height - 1, prefix, lst, rendering);
|
|
||||||
|
|
||||||
assert(0);
|
|
||||||
int npos, pos = 0;
|
|
||||||
int do_loop = 1;
|
|
||||||
|
|
||||||
completion_print(cols, width, 0, term_height-1, prefix, lst, rendering);
|
|
||||||
|
|
||||||
/* List does not fit on screen. Print one screenful and leave a scrollable interface */
|
|
||||||
while (do_loop)
|
|
||||||
{
|
|
||||||
set_color(rgb_color_t::black(), highlight_get_color(highlight_spec_pager_progress, true));
|
|
||||||
wcstring msg = format_string(_(L" %d to %d of %d"), pos, pos+term_height-1, row_count);
|
|
||||||
msg.append(L" \r");
|
|
||||||
|
|
||||||
writestr(msg.c_str());
|
|
||||||
set_color(rgb_color_t::normal(), rgb_color_t::normal());
|
|
||||||
int c = readch();
|
|
||||||
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case LINE_UP:
|
|
||||||
{
|
|
||||||
if (pos > 0)
|
|
||||||
{
|
|
||||||
pos--;
|
|
||||||
writembs(tparm(cursor_address, 0, 0));
|
|
||||||
writembs(scroll_reverse);
|
|
||||||
completion_print(cols, width, pos, pos+1, prefix, lst, rendering);
|
|
||||||
writembs(tparm(cursor_address, term_height-1, 0));
|
|
||||||
writembs(clr_eol);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case LINE_DOWN:
|
|
||||||
{
|
|
||||||
if (pos <= (row_count - term_height))
|
|
||||||
{
|
|
||||||
pos++;
|
|
||||||
completion_print(cols, width, pos+term_height-2, pos+term_height-1, prefix, lst, rendering);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PAGE_DOWN:
|
|
||||||
{
|
|
||||||
|
|
||||||
npos = mini((int)(row_count - term_height+1), (int)(pos + term_height-1));
|
|
||||||
if (npos != pos)
|
|
||||||
{
|
|
||||||
pos = npos;
|
|
||||||
completion_print(cols, width, pos, pos+term_height-1, prefix, lst, rendering);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (flash_screen)
|
|
||||||
writembs(flash_screen);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PAGE_UP:
|
|
||||||
{
|
|
||||||
npos = maxi(0, pos - term_height+1);
|
|
||||||
|
|
||||||
if (npos != pos)
|
|
||||||
{
|
|
||||||
pos = npos;
|
|
||||||
completion_print(cols, width, pos, pos+term_height-1, prefix, lst, rendering);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (flash_screen)
|
|
||||||
writembs(flash_screen);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case R_NULL:
|
|
||||||
{
|
|
||||||
do_loop=0;
|
|
||||||
res=PAGER_RESIZE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
out_buff.push_back(c);
|
|
||||||
do_loop = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
writembs(clr_eol);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return res;
|
return print;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -950,8 +640,7 @@ page_rendering_t pager_t::render() const
|
||||||
|
|
||||||
if (! this->empty())
|
if (! this->empty())
|
||||||
{
|
{
|
||||||
int cols;
|
for (int cols = PAGER_MAX_COLS; cols > 0; cols--)
|
||||||
for (cols = PAGER_MAX_COLS; cols > 0; cols--)
|
|
||||||
{
|
{
|
||||||
/* Initially empty rendering */
|
/* Initially empty rendering */
|
||||||
rendering.screen_data.resize(0);
|
rendering.screen_data.resize(0);
|
||||||
|
@ -971,30 +660,11 @@ page_rendering_t pager_t::render() const
|
||||||
rendering.rows = min_rows_required_for_cols;
|
rendering.rows = min_rows_required_for_cols;
|
||||||
rendering.selected_completion_idx = this->visual_selected_completion_index(rendering.rows, rendering.cols);
|
rendering.selected_completion_idx = this->visual_selected_completion_index(rendering.rows, rendering.cols);
|
||||||
|
|
||||||
bool done = false;
|
if (completion_try_print(cols, prefix, completion_infos, &rendering, suggested_row_start))
|
||||||
switch (completion_try_print(cols, prefix, completion_infos, &rendering, suggested_row_start))
|
|
||||||
{
|
{
|
||||||
case PAGER_RETRY:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PAGER_DONE:
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PAGER_RESIZE:
|
|
||||||
/*
|
|
||||||
This means we got a resize event, so we start
|
|
||||||
over from the beginning. Since it the screen got
|
|
||||||
bigger, we might be able to fit all completions
|
|
||||||
on-screen.
|
|
||||||
*/
|
|
||||||
cols=PAGER_MAX_COLS+1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (done)
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
assert(cols >= 0);
|
|
||||||
}
|
}
|
||||||
return rendering;
|
return rendering;
|
||||||
}
|
}
|
||||||
|
@ -1240,8 +910,7 @@ const completion_t *pager_t::selected_completion(const page_rendering_t &renderi
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Completions are rendered column first, i.e. we go south before we go west. So if we have N rows, and our selected index is N + 2, then our row is 2 (mod by N) and our column is 1 (divide by N) */
|
/* Get the selected row and column. Completions are rendered column first, i.e. we go south before we go west. So if we have N rows, and our selected index is N + 2, then our row is 2 (mod by N) and our column is 1 (divide by N) */
|
||||||
|
|
||||||
size_t pager_t::get_selected_row(const page_rendering_t &rendering) const
|
size_t pager_t::get_selected_row(const page_rendering_t &rendering) const
|
||||||
{
|
{
|
||||||
return selected_completion_idx == PAGER_SELECTION_NONE ? PAGER_SELECTION_NONE : selected_completion_idx % rendering.rows;
|
return selected_completion_idx == PAGER_SELECTION_NONE ? PAGER_SELECTION_NONE : selected_completion_idx % rendering.rows;
|
||||||
|
@ -1260,6 +929,7 @@ void pager_t::clear()
|
||||||
fully_disclosed = false;
|
fully_disclosed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Constructor */
|
||||||
page_rendering_t::page_rendering_t() : term_width(-1), term_height(-1), rows(0), cols(0), row_start(0), row_end(0), selected_completion_idx(-1), remaining_to_disclose(0)
|
page_rendering_t::page_rendering_t() : term_width(-1), term_height(-1), rows(0), cols(0), row_start(0), row_end(0), selected_completion_idx(-1), remaining_to_disclose(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
2
pager.h
2
pager.h
|
@ -84,7 +84,7 @@ class pager_t
|
||||||
|
|
||||||
wcstring prefix;
|
wcstring prefix;
|
||||||
|
|
||||||
int completion_try_print(size_t cols, const wcstring &prefix, const comp_info_list_t &lst, page_rendering_t *rendering, size_t suggested_start_row) const;
|
bool completion_try_print(size_t cols, const wcstring &prefix, const comp_info_list_t &lst, page_rendering_t *rendering, size_t suggested_start_row) const;
|
||||||
|
|
||||||
void recalc_min_widths(comp_info_list_t * lst) const;
|
void recalc_min_widths(comp_info_list_t * lst) const;
|
||||||
void measure_completion_infos(std::vector<comp_t> *infos, const wcstring &prefix) const;
|
void measure_completion_infos(std::vector<comp_t> *infos, const wcstring &prefix) const;
|
||||||
|
|
Loading…
Reference in a new issue