mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-25 20:33:08 +00:00
Add experimental support for selection and visual mode
This commit is contained in:
parent
fc21bb6eda
commit
c8d5131a42
10 changed files with 172 additions and 24 deletions
|
@ -211,6 +211,7 @@ static int builtin_commandline(parser_t &parser, wchar_t **argv)
|
|||
int append_mode=0;
|
||||
|
||||
int function_mode = 0;
|
||||
int selection_mode = 0;
|
||||
|
||||
int tokenize = 0;
|
||||
|
||||
|
@ -315,6 +316,10 @@ static int builtin_commandline(parser_t &parser, wchar_t **argv)
|
|||
L"search-mode", no_argument, 0, 'S'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"selection", no_argument, 0, 's'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
|
@ -402,6 +407,10 @@ static int builtin_commandline(parser_t &parser, wchar_t **argv)
|
|||
search_mode = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
selection_mode = 1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help(parser, argv[0], stdout_buffer);
|
||||
return 0;
|
||||
|
@ -465,6 +474,26 @@ static int builtin_commandline(parser_t &parser, wchar_t **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (selection_mode)
|
||||
{
|
||||
size_t sel_start, sel_stop;
|
||||
const wchar_t *buffer = reader_get_buffer();
|
||||
if(reader_get_selection_pos(sel_start, sel_stop))
|
||||
{
|
||||
size_t len = std::min(sel_stop - sel_start + 1, wcslen(buffer));
|
||||
wchar_t *selection = new wchar_t[len];
|
||||
selection = wcsncpy(selection, current_buffer + sel_start, len);
|
||||
|
||||
append_format(stdout_buffer, selection);
|
||||
delete selection;
|
||||
}
|
||||
else
|
||||
{
|
||||
append_format(stdout_buffer, L"");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Check for invalid switch combinations
|
||||
*/
|
||||
|
|
|
@ -70,6 +70,11 @@
|
|||
*/
|
||||
#define HIGHLIGHT_AUTOSUGGESTION 0x2000
|
||||
|
||||
/**
|
||||
Internal value representing highlighting an active selection
|
||||
*/
|
||||
#define HIGHLIGHT_SELECTION 0x80
|
||||
|
||||
class history_item_t;
|
||||
struct file_detection_context_t;
|
||||
|
||||
|
|
10
input.cpp
10
input.cpp
|
@ -137,7 +137,9 @@ static const wchar_t * const name_arr[] =
|
|||
L"up-line",
|
||||
L"down-line",
|
||||
L"suppress-autosuggestion",
|
||||
L"accept-autosuggestion"
|
||||
L"accept-autosuggestion",
|
||||
L"begin-selection",
|
||||
L"end-selection",
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -227,7 +229,9 @@ static const wchar_t code_arr[] =
|
|||
R_UP_LINE,
|
||||
R_DOWN_LINE,
|
||||
R_SUPPRESS_AUTOSUGGESTION,
|
||||
R_ACCEPT_AUTOSUGGESTION
|
||||
R_ACCEPT_AUTOSUGGESTION,
|
||||
R_BEGIN_SELECTION,
|
||||
R_END_SELECTION
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -265,7 +269,7 @@ const wchar_t *input_get_bind_mode()
|
|||
const env_var_t bind_mode_var = env_get_string(FISH_BIND_MODE_VAR);
|
||||
if(!bind_mode_var.missing())
|
||||
{
|
||||
bind_mode = bind_mode_var.c_str();
|
||||
bind_mode = bind_mode_var.c_str();
|
||||
}
|
||||
return bind_mode;
|
||||
}
|
||||
|
|
4
input.h
4
input.h
|
@ -61,11 +61,13 @@ enum
|
|||
R_DOWN_LINE,
|
||||
R_SUPPRESS_AUTOSUGGESTION,
|
||||
R_ACCEPT_AUTOSUGGESTION,
|
||||
R_BEGIN_SELECTION,
|
||||
R_END_SELECTION
|
||||
}
|
||||
;
|
||||
|
||||
#define R_MIN R_NULL
|
||||
#define R_MAX R_ACCEPT_AUTOSUGGESTION
|
||||
#define R_MAX R_END_SELECTION
|
||||
|
||||
/**
|
||||
Initialize the terminal by calling setupterm, and set up arrays
|
||||
|
|
111
reader.cpp
111
reader.cpp
|
@ -172,6 +172,13 @@ commence.
|
|||
History search mode. This value means we are searching forwards.
|
||||
*/
|
||||
#define SEARCH_FORWARD 1
|
||||
/**
|
||||
The color used to display an active selection
|
||||
*/
|
||||
#define FISH_SELECTION_COLOR_VAR L"fish-selection-color"
|
||||
|
||||
/** The color used if the variable above is not set */
|
||||
#define DEFAULT_SELECTION_COLOR L"gray"
|
||||
|
||||
/* Any time the contents of a buffer changes, we update the generation count. This allows for our background highlighting thread to notice it and skip doing work that it would otherwise have to do. This variable should really be of some kind of interlocked or atomic type that guarantees we're not reading stale cache values. With C++11 we should use atomics, but until then volatile should work as well, at least on x86.*/
|
||||
static volatile unsigned int s_generation_count;
|
||||
|
@ -258,6 +265,9 @@ public:
|
|||
/** Indicates whether a selection is currently active */
|
||||
bool sel_active;
|
||||
|
||||
/** The position of the cursor, when selection was initiated. */
|
||||
size_t sel_begin_pos;
|
||||
|
||||
/** The start position of the current selection, if one. */
|
||||
size_t sel_start_pos;
|
||||
|
||||
|
@ -349,6 +359,7 @@ public:
|
|||
search_pos(0),
|
||||
buff_pos(0),
|
||||
sel_active(0),
|
||||
sel_begin_pos(0),
|
||||
sel_start_pos(0),
|
||||
sel_stop_pos(0),
|
||||
complete_func(0),
|
||||
|
@ -448,9 +459,22 @@ static void term_donate()
|
|||
/**
|
||||
Update the cursor position
|
||||
*/
|
||||
static void update_buff_pos(int buff_pos)
|
||||
static void update_buff_pos(size_t buff_pos)
|
||||
{
|
||||
data->buff_pos = buff_pos;
|
||||
if(data->sel_active)
|
||||
{
|
||||
if(data->sel_begin_pos <= buff_pos)
|
||||
{
|
||||
data->sel_start_pos = data->sel_begin_pos;
|
||||
data->sel_stop_pos = buff_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
data->sel_start_pos = buff_pos;
|
||||
data->sel_stop_pos = data->sel_begin_pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -536,7 +560,6 @@ wcstring combine_command_and_autosuggestion(const wcstring &cmdline, const wcstr
|
|||
commandline, write the prompt, perform syntax highlighting, write
|
||||
the commandline and move the cursor.
|
||||
*/
|
||||
|
||||
static void reader_repaint()
|
||||
{
|
||||
// Update the indentation
|
||||
|
@ -552,6 +575,15 @@ static void reader_repaint()
|
|||
std::vector<color_t> colors = data->colors;
|
||||
colors.resize(len, HIGHLIGHT_AUTOSUGGESTION);
|
||||
|
||||
if(data->sel_active)
|
||||
{
|
||||
int selection_color = HIGHLIGHT_SELECTION << 16;
|
||||
for(int i = data->sel_start_pos; i <= std::min(len - 1, data->sel_stop_pos); i++)
|
||||
{
|
||||
colors[i] = selection_color;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> indents = data->indents;
|
||||
indents.resize(len);
|
||||
|
||||
|
@ -562,11 +594,14 @@ static void reader_repaint()
|
|||
data->command_length(),
|
||||
&colors[0],
|
||||
&indents[0],
|
||||
data->buff_pos);
|
||||
data->buff_pos,
|
||||
data->sel_start_pos,
|
||||
data->sel_stop_pos);
|
||||
|
||||
data->repaint_needed = false;
|
||||
}
|
||||
|
||||
|
||||
static void reader_repaint_without_autosuggestion()
|
||||
{
|
||||
// Swap in an empty autosuggestion, repaint, then swap it out
|
||||
|
@ -606,7 +641,7 @@ static void reader_kill(size_t begin_idx, size_t length, int mode, int newv)
|
|||
{
|
||||
/* Move the buff position back by the number of characters we deleted, but don't go past buff_pos */
|
||||
size_t backtrack = mini(data->buff_pos - begin_idx, length);
|
||||
data->buff_pos -= backtrack;
|
||||
update_buff_pos(data->buff_pos - backtrack);
|
||||
}
|
||||
|
||||
data->command_line.erase(begin_idx, length);
|
||||
|
@ -1101,7 +1136,7 @@ static void remove_backward()
|
|||
int width;
|
||||
do
|
||||
{
|
||||
data->buff_pos -= 1;
|
||||
update_buff_pos(data->buff_pos - 1);
|
||||
width = fish_wcwidth(data->command_line.at(data->buff_pos));
|
||||
data->command_line.erase(data->buff_pos, 1);
|
||||
}
|
||||
|
@ -1129,7 +1164,7 @@ static bool insert_string(const wcstring &str, bool should_expand_abbreviations
|
|||
return false;
|
||||
|
||||
data->command_line.insert(data->buff_pos, str);
|
||||
data->buff_pos += len;
|
||||
update_buff_pos(data->buff_pos + len);
|
||||
data->command_line_changed();
|
||||
data->suppress_autosuggestion = false;
|
||||
|
||||
|
@ -2475,6 +2510,26 @@ size_t reader_get_cursor_pos()
|
|||
return data->buff_pos;
|
||||
}
|
||||
|
||||
bool reader_get_selection_pos(size_t &start, size_t &stop)
|
||||
{
|
||||
if (!data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!data->sel_active)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
start = data->sel_start_pos;
|
||||
stop = data->sel_stop_pos;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define ENV_CMD_DURATION L"CMD_DURATION"
|
||||
|
||||
void set_env_cmd_duration(struct timeval *after, struct timeval *before)
|
||||
|
@ -2572,6 +2627,8 @@ int reader_shell_test(const wchar_t *b)
|
|||
0,
|
||||
tmp,
|
||||
tmp2,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
|
||||
|
||||
|
@ -2945,7 +3002,7 @@ static int read_i(void)
|
|||
else if (tmp)
|
||||
{
|
||||
wcstring command = tmp;
|
||||
data->buff_pos=0;
|
||||
update_buff_pos(0);
|
||||
data->command_line.clear();
|
||||
data->command_line_changed();
|
||||
reader_run_command(parser, command);
|
||||
|
@ -3136,7 +3193,7 @@ const wchar_t *reader_readline(void)
|
|||
while ((data->buff_pos>0) &&
|
||||
(buff[data->buff_pos-1] != L'\n'))
|
||||
{
|
||||
data->buff_pos--;
|
||||
update_buff_pos(data->buff_pos - 1);
|
||||
}
|
||||
|
||||
reader_repaint();
|
||||
|
@ -3150,7 +3207,7 @@ const wchar_t *reader_readline(void)
|
|||
while (buff[data->buff_pos] &&
|
||||
buff[data->buff_pos] != L'\n')
|
||||
{
|
||||
data->buff_pos++;
|
||||
update_buff_pos(data->buff_pos + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -3174,8 +3231,6 @@ const wchar_t *reader_readline(void)
|
|||
/* go to EOL*/
|
||||
case R_END_OF_BUFFER:
|
||||
{
|
||||
data->buff_pos = data->command_length();
|
||||
|
||||
update_buff_pos(data->command_length());
|
||||
|
||||
reader_repaint();
|
||||
|
@ -3442,7 +3497,7 @@ const wchar_t *reader_readline(void)
|
|||
*/
|
||||
if (data->buff_pos < data->command_length())
|
||||
{
|
||||
data->buff_pos++;
|
||||
update_buff_pos(data->buff_pos + 1);
|
||||
remove_backward();
|
||||
}
|
||||
break;
|
||||
|
@ -3496,7 +3551,7 @@ const wchar_t *reader_readline(void)
|
|||
}
|
||||
}
|
||||
finished=1;
|
||||
data->buff_pos=data->command_length();
|
||||
update_buff_pos(data->command_length());
|
||||
reader_repaint();
|
||||
break;
|
||||
}
|
||||
|
@ -3617,7 +3672,7 @@ const wchar_t *reader_readline(void)
|
|||
{
|
||||
if (data->buff_pos > 0)
|
||||
{
|
||||
data->buff_pos--;
|
||||
update_buff_pos(data->buff_pos - 1);
|
||||
reader_repaint();
|
||||
}
|
||||
break;
|
||||
|
@ -3628,7 +3683,7 @@ const wchar_t *reader_readline(void)
|
|||
{
|
||||
if (data->buff_pos < data->command_length())
|
||||
{
|
||||
data->buff_pos++;
|
||||
update_buff_pos(data->buff_pos + 1);
|
||||
reader_repaint();
|
||||
}
|
||||
else
|
||||
|
@ -3760,7 +3815,7 @@ const wchar_t *reader_readline(void)
|
|||
/* If the cursor is at the end, transpose the last two characters of the line */
|
||||
if (data->buff_pos == data->command_length())
|
||||
{
|
||||
data->buff_pos--;
|
||||
update_buff_pos(data->buff_pos - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3783,8 +3838,11 @@ const wchar_t *reader_readline(void)
|
|||
const wchar_t *tok_begin, *tok_end, *prev_begin, *prev_end;
|
||||
|
||||
/* If we are not in a token, look for one ahead */
|
||||
while (data->buff_pos != len && !iswalnum(buff[data->buff_pos]))
|
||||
data->buff_pos++;
|
||||
size_t buff_pos = data->buff_pos;
|
||||
while (buff_pos != len && !iswalnum(buff[buff_pos]))
|
||||
buff_pos++;
|
||||
|
||||
update_buff_pos(buff_pos);
|
||||
|
||||
parse_util_token_extent(buff, data->buff_pos, &tok_begin, &tok_end, &prev_begin, &prev_end);
|
||||
|
||||
|
@ -3852,6 +3910,23 @@ const wchar_t *reader_readline(void)
|
|||
break;
|
||||
}
|
||||
|
||||
case R_BEGIN_SELECTION:
|
||||
{
|
||||
data->sel_active = true;
|
||||
data->sel_begin_pos = data->buff_pos;
|
||||
data->sel_start_pos = data->buff_pos;
|
||||
data->sel_stop_pos = data->buff_pos;
|
||||
break;
|
||||
}
|
||||
|
||||
case R_END_SELECTION:
|
||||
{
|
||||
data->sel_active = false;
|
||||
data->sel_start_pos = data->buff_pos;
|
||||
data->sel_stop_pos = data->buff_pos;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Other, if a normal character, we add it to the command */
|
||||
default:
|
||||
{
|
||||
|
|
7
reader.h
7
reader.h
|
@ -114,6 +114,13 @@ void reader_set_buffer(const wcstring &b, size_t p);
|
|||
*/
|
||||
size_t reader_get_cursor_pos();
|
||||
|
||||
|
||||
/**
|
||||
Get the current selection range in the command line.
|
||||
Returns false if there is no active selection, true otherwise.
|
||||
*/
|
||||
bool reader_get_selection_pos(size_t &start, size_t &stop);
|
||||
|
||||
/**
|
||||
Return the value of the interrupted flag, which is set by the sigint
|
||||
handler, and clear it if it was set.
|
||||
|
|
|
@ -1234,7 +1234,9 @@ void s_write(screen_t *s,
|
|||
size_t explicit_len,
|
||||
const int *colors,
|
||||
const int *indent,
|
||||
size_t cursor_pos)
|
||||
size_t cursor_pos,
|
||||
size_t sel_start_pos,
|
||||
size_t sel_stop_pos)
|
||||
{
|
||||
screen_data_t::cursor_t cursor_arr;
|
||||
|
||||
|
|
6
screen.h
6
screen.h
|
@ -181,6 +181,8 @@ public:
|
|||
\param colors the colors to use for the comand line
|
||||
\param indent the indent to use for the command line
|
||||
\param cursor_pos where the cursor is
|
||||
\param sel_start_pos where the selections starts (inclusive)
|
||||
\param sel_stop_pos where the selections ends (inclusive)
|
||||
*/
|
||||
void s_write(screen_t *s,
|
||||
const wcstring &left_prompt,
|
||||
|
@ -189,7 +191,9 @@ void s_write(screen_t *s,
|
|||
size_t explicit_len,
|
||||
const int *colors,
|
||||
const int *indent,
|
||||
size_t cursor_pos);
|
||||
size_t cursor_pos,
|
||||
size_t sel_start_pos,
|
||||
size_t sel_stop_pos);
|
||||
|
||||
/**
|
||||
This function resets the screen buffers internal knowledge about
|
||||
|
|
|
@ -28,6 +28,7 @@ function fish_vi_key_bindings -d "vi-like key bindings for fish"
|
|||
bind -m insert I beginning-of-line force-repaint
|
||||
bind -m insert a forward-char force-repaint
|
||||
bind -m insert A end-of-line force-repaint
|
||||
bind -m visual v begin-selection force-repaint
|
||||
|
||||
bind -m insert o "commandline -a \n" down-line force-repaint
|
||||
#bind -m insert O beginning-of-line "commandline -i \n" up-line force-repaint # doesn't work
|
||||
|
@ -148,4 +149,20 @@ function fish_vi_key_bindings -d "vi-like key bindings for fish"
|
|||
bind -M insert \cd exit
|
||||
|
||||
bind -M insert \ef forward-word
|
||||
|
||||
|
||||
|
||||
#
|
||||
# visual mode
|
||||
#
|
||||
|
||||
bind -M visual \e\[C forward-char
|
||||
bind -M visual \e\[D backward-char
|
||||
bind -M visual -k right forward-char
|
||||
bind -M visual -k left backward-char
|
||||
bind -M visual h backward-char
|
||||
bind -M visual l forward-char
|
||||
|
||||
bind -M visual -m default \cc end-selection force-repaint
|
||||
bind -M visual -m default \e end-selection force-repaint
|
||||
end
|
||||
|
|
|
@ -7,6 +7,9 @@ function fish_vi_prompt_cm --description "Displays the current mode"
|
|||
case insert
|
||||
set_color --bold --background red white
|
||||
echo "[I]"
|
||||
case visual
|
||||
set_color --bold --background magenta white
|
||||
echo "[V]"
|
||||
end
|
||||
set_color normal
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue