1871 lines
54 KiB
C
1871 lines
54 KiB
C
/*
|
|
* gui-input.c - input functions (used by all GUI)
|
|
*
|
|
* Copyright (C) 2003-2020 Sébastien Helleu <flashcode@flashtux.org>
|
|
*
|
|
* This file is part of WeeChat, the extensible chat client.
|
|
*
|
|
* WeeChat is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* WeeChat is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with WeeChat. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "../core/weechat.h"
|
|
#include "../core/wee-config.h"
|
|
#include "../core/wee-hook.h"
|
|
#include "../core/wee-input.h"
|
|
#include "../core/wee-string.h"
|
|
#include "../core/wee-utf8.h"
|
|
#include "../plugins/plugin.h"
|
|
#include "gui-input.h"
|
|
#include "gui-buffer.h"
|
|
#include "gui-completion.h"
|
|
#include "gui-cursor.h"
|
|
#include "gui-history.h"
|
|
#include "gui-hotlist.h"
|
|
#include "gui-key.h"
|
|
#include "gui-line.h"
|
|
#include "gui-mouse.h"
|
|
#include "gui-window.h"
|
|
|
|
|
|
char *gui_input_clipboard = NULL; /* internal clipboard content */
|
|
|
|
|
|
/*
|
|
* Optimizes input buffer size by adding or deleting data block (predefined
|
|
* size).
|
|
*
|
|
* Returns:
|
|
* 1: input size optimized
|
|
* 0: error (input and its size are not changed)
|
|
*/
|
|
|
|
int
|
|
gui_input_optimize_size (struct t_gui_buffer *buffer,
|
|
int new_size, int new_length)
|
|
{
|
|
int optimal_size;
|
|
char *input_buffer2;
|
|
|
|
if (!buffer->input)
|
|
return 0;
|
|
|
|
optimal_size = ((new_size / GUI_BUFFER_INPUT_BLOCK_SIZE) *
|
|
GUI_BUFFER_INPUT_BLOCK_SIZE) + GUI_BUFFER_INPUT_BLOCK_SIZE;
|
|
if (buffer->input_buffer_alloc != optimal_size)
|
|
{
|
|
input_buffer2 = realloc (buffer->input_buffer, optimal_size);
|
|
if (!input_buffer2)
|
|
return 0;
|
|
buffer->input_buffer = input_buffer2;
|
|
buffer->input_buffer_alloc = optimal_size;
|
|
}
|
|
|
|
buffer->input_buffer_size = new_size;
|
|
buffer->input_buffer_length = new_length;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Replaces full input by another string, trying to keep cursor position if new
|
|
* string is long enough.
|
|
*/
|
|
|
|
void
|
|
gui_input_replace_input (struct t_gui_buffer *buffer, const char *new_input)
|
|
{
|
|
int size, length;
|
|
char *input_utf8;
|
|
|
|
input_utf8 = strdup (new_input);
|
|
if (input_utf8)
|
|
{
|
|
utf8_normalize (input_utf8, '?');
|
|
|
|
size = strlen (input_utf8);
|
|
length = utf8_strlen (input_utf8);
|
|
|
|
/* compute new buffer size */
|
|
if (gui_input_optimize_size (buffer, size, length))
|
|
{
|
|
/* copy new string to input */
|
|
strcpy (buffer->input_buffer, input_utf8);
|
|
|
|
/* move cursor to the end of new input if it is now after the end */
|
|
if (buffer->input_buffer_pos > buffer->input_buffer_length)
|
|
buffer->input_buffer_pos = buffer->input_buffer_length;
|
|
}
|
|
|
|
free (input_utf8);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Sends signal "input_paste_pending".
|
|
*/
|
|
|
|
void
|
|
gui_input_paste_pending_signal ()
|
|
{
|
|
if (CONFIG_BOOLEAN(config_look_bare_display_exit_on_input)
|
|
&& gui_window_bare_display)
|
|
{
|
|
gui_window_bare_display_toggle (NULL);
|
|
}
|
|
|
|
(void) hook_signal_send ("input_paste_pending",
|
|
WEECHAT_HOOK_SIGNAL_STRING, NULL);
|
|
}
|
|
|
|
/*
|
|
* Sends modifier and signal "input_text_changed".
|
|
*/
|
|
|
|
void
|
|
gui_input_text_changed_modifier_and_signal (struct t_gui_buffer *buffer,
|
|
int save_undo,
|
|
int stop_completion)
|
|
{
|
|
char str_buffer[128], *new_input;
|
|
|
|
if (CONFIG_BOOLEAN(config_look_bare_display_exit_on_input)
|
|
&& gui_window_bare_display)
|
|
{
|
|
gui_window_bare_display_toggle (NULL);
|
|
}
|
|
|
|
if (!gui_cursor_mode)
|
|
{
|
|
if (save_undo)
|
|
gui_buffer_undo_add (buffer);
|
|
|
|
/* send modifier, and change input if needed */
|
|
snprintf (str_buffer, sizeof (str_buffer),
|
|
"0x%lx", (unsigned long)buffer);
|
|
new_input = hook_modifier_exec (NULL,
|
|
"input_text_content",
|
|
str_buffer,
|
|
(buffer->input_buffer) ?
|
|
buffer->input_buffer : "");
|
|
if (new_input)
|
|
{
|
|
if (!buffer->input_buffer
|
|
|| strcmp (new_input, buffer->input_buffer) != 0)
|
|
{
|
|
/* input has been changed by modifier, use it */
|
|
gui_input_replace_input (buffer, new_input);
|
|
}
|
|
free (new_input);
|
|
}
|
|
}
|
|
|
|
if (stop_completion && !gui_completion_freeze)
|
|
gui_completion_stop (buffer->completion);
|
|
|
|
/* send signal */
|
|
(void) hook_signal_send ("input_text_changed",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
}
|
|
|
|
/*
|
|
* Sends signal "input_text_cursor_moved".
|
|
*/
|
|
|
|
void
|
|
gui_input_text_cursor_moved_signal (struct t_gui_buffer *buffer)
|
|
{
|
|
if (CONFIG_BOOLEAN(config_look_bare_display_exit_on_input)
|
|
&& gui_window_bare_display)
|
|
{
|
|
gui_window_bare_display_toggle (NULL);
|
|
}
|
|
|
|
(void) hook_signal_send ("input_text_cursor_moved",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
}
|
|
|
|
/*
|
|
* Sends signal "input_search".
|
|
*/
|
|
|
|
void
|
|
gui_input_search_signal (struct t_gui_buffer *buffer)
|
|
{
|
|
if (CONFIG_BOOLEAN(config_look_bare_display_exit_on_input)
|
|
&& gui_window_bare_display)
|
|
{
|
|
gui_window_bare_display_toggle (NULL);
|
|
}
|
|
|
|
(void) hook_signal_send ("input_search",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
}
|
|
|
|
/*
|
|
* Sets position in input line.
|
|
*/
|
|
|
|
void
|
|
gui_input_set_pos (struct t_gui_buffer *buffer, int pos)
|
|
{
|
|
if ((pos >= 0) && (buffer->input_buffer_pos != pos))
|
|
{
|
|
buffer->input_buffer_pos = pos;
|
|
if (buffer->input_buffer_pos > buffer->input_buffer_length)
|
|
buffer->input_buffer_pos = buffer->input_buffer_length;
|
|
gui_input_text_cursor_moved_signal (buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Inserts a string into the input buffer.
|
|
*
|
|
* If pos == -1, string is inserted at cursor position.
|
|
*/
|
|
|
|
void
|
|
gui_input_insert_string (struct t_gui_buffer *buffer, const char *string,
|
|
int pos)
|
|
{
|
|
int size, length;
|
|
char *string_utf8, *ptr_start;
|
|
|
|
if (buffer->input)
|
|
{
|
|
string_utf8 = strdup (string);
|
|
if (!string_utf8)
|
|
return;
|
|
|
|
if (pos == -1)
|
|
pos = buffer->input_buffer_pos;
|
|
|
|
utf8_normalize (string_utf8, '?');
|
|
|
|
size = strlen (string_utf8);
|
|
length = utf8_strlen (string_utf8);
|
|
|
|
if (gui_input_optimize_size (buffer,
|
|
buffer->input_buffer_size + size,
|
|
buffer->input_buffer_length + length))
|
|
{
|
|
buffer->input_buffer[buffer->input_buffer_size] = '\0';
|
|
|
|
/* move end of string to the right */
|
|
ptr_start = (char *)utf8_add_offset (buffer->input_buffer, pos);
|
|
memmove (ptr_start + size, ptr_start, strlen (ptr_start));
|
|
|
|
/* insert new string */
|
|
ptr_start = (char *)utf8_add_offset (buffer->input_buffer, pos);
|
|
memcpy (ptr_start, string_utf8, size);
|
|
|
|
buffer->input_buffer_pos += length;
|
|
}
|
|
|
|
free (string_utf8);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Moves input content and undo data from a buffer to another buffer.
|
|
*/
|
|
|
|
void
|
|
gui_input_move_to_buffer (struct t_gui_buffer *from_buffer,
|
|
struct t_gui_buffer *to_buffer)
|
|
{
|
|
int is_command;
|
|
|
|
/*
|
|
* move of input is allowed if:
|
|
* - 2 buffers are different
|
|
* - input_share is not set to "none"
|
|
* - input buffer in first buffer is not empty
|
|
*/
|
|
if (!from_buffer || !to_buffer || (from_buffer == to_buffer)
|
|
|| (CONFIG_INTEGER(config_look_input_share) == CONFIG_LOOK_INPUT_SHARE_NONE)
|
|
|| !from_buffer->input_buffer || !from_buffer->input_buffer[0])
|
|
return;
|
|
|
|
/*
|
|
* if input is command and that only text is allowed,
|
|
* or if input is text and that only command is allowed,
|
|
* then do nothing
|
|
*/
|
|
is_command = (string_input_for_buffer (from_buffer->input_buffer) == NULL) ? 1 : 0;
|
|
if ((is_command && (CONFIG_INTEGER(config_look_input_share) == CONFIG_LOOK_INPUT_SHARE_TEXT))
|
|
|| (!is_command && (CONFIG_INTEGER(config_look_input_share) == CONFIG_LOOK_INPUT_SHARE_COMMANDS)))
|
|
return;
|
|
|
|
/*
|
|
* if overwrite is off and that input of target buffer is not empty,
|
|
* then do nothing
|
|
*/
|
|
if ((!CONFIG_BOOLEAN(config_look_input_share_overwrite))
|
|
&& to_buffer->input_buffer && to_buffer->input_buffer[0])
|
|
return;
|
|
|
|
/* move input_buffer */
|
|
if (to_buffer->input_buffer)
|
|
free (to_buffer->input_buffer);
|
|
to_buffer->input_buffer = from_buffer->input_buffer;
|
|
to_buffer->input_buffer_alloc = from_buffer->input_buffer_alloc;
|
|
to_buffer->input_buffer_size = from_buffer->input_buffer_size;
|
|
to_buffer->input_buffer_length = from_buffer->input_buffer_length;
|
|
to_buffer->input_buffer_pos = from_buffer->input_buffer_pos;
|
|
to_buffer->input_buffer_1st_display = from_buffer->input_buffer_1st_display;
|
|
gui_buffer_input_buffer_init (from_buffer);
|
|
|
|
/* move undo data */
|
|
gui_buffer_undo_free_all (to_buffer);
|
|
(to_buffer->input_undo_snap)->data = (from_buffer->input_undo_snap)->data;
|
|
(to_buffer->input_undo_snap)->pos = (from_buffer->input_undo_snap)->pos;
|
|
to_buffer->input_undo = from_buffer->input_undo;
|
|
to_buffer->last_input_undo = from_buffer->last_input_undo;
|
|
to_buffer->ptr_input_undo = from_buffer->ptr_input_undo;
|
|
to_buffer->input_undo_count = from_buffer->input_undo_count;
|
|
(from_buffer->input_undo_snap)->data = NULL;
|
|
(from_buffer->input_undo_snap)->pos = 0;
|
|
from_buffer->input_undo = NULL;
|
|
from_buffer->last_input_undo = NULL;
|
|
from_buffer->ptr_input_undo = NULL;
|
|
from_buffer->input_undo_count = 0;
|
|
|
|
gui_completion_stop (from_buffer->completion);
|
|
}
|
|
|
|
/*
|
|
* Copies string into the internal clipboard.
|
|
*/
|
|
|
|
void
|
|
gui_input_clipboard_copy (const char *buffer, int size)
|
|
{
|
|
if (size <= 0)
|
|
return;
|
|
|
|
if (gui_input_clipboard != NULL)
|
|
free (gui_input_clipboard);
|
|
|
|
gui_input_clipboard = malloc ((size + 1) * sizeof (*gui_input_clipboard));
|
|
|
|
if (gui_input_clipboard)
|
|
{
|
|
memcpy (gui_input_clipboard, buffer, size);
|
|
gui_input_clipboard[size] = '\0';
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Pastes the internal clipboard at cursor pos in input line
|
|
* (default key: ctrl-Y).
|
|
*/
|
|
|
|
void
|
|
gui_input_clipboard_paste (struct t_gui_buffer *buffer)
|
|
{
|
|
if (buffer->input && gui_input_clipboard)
|
|
{
|
|
gui_buffer_undo_snap (buffer);
|
|
gui_input_insert_string (buffer,
|
|
gui_input_clipboard, -1);
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
1, /* save undo */
|
|
1); /* stop completion */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Terminates line:
|
|
* - saves text in history
|
|
* - stops completion
|
|
* - frees all undos
|
|
* - sends modifier and signal
|
|
* - sends data to buffer.
|
|
*/
|
|
|
|
void
|
|
gui_input_return (struct t_gui_buffer *buffer)
|
|
{
|
|
char *command;
|
|
|
|
if (CONFIG_BOOLEAN(config_look_bare_display_exit_on_input)
|
|
&& gui_window_bare_display)
|
|
{
|
|
gui_window_bare_display_toggle (NULL);
|
|
}
|
|
|
|
if (buffer->input
|
|
&& (buffer->input_get_empty || (buffer->input_buffer_size > 0)))
|
|
{
|
|
buffer->input_buffer[buffer->input_buffer_size] = '\0';
|
|
command = strdup (buffer->input_buffer);
|
|
if (command)
|
|
{
|
|
gui_history_add (buffer, buffer->input_buffer);
|
|
if (gui_input_optimize_size (buffer, 0, 0))
|
|
{
|
|
buffer->input_buffer[0] = '\0';
|
|
buffer->input_buffer_pos = 0;
|
|
buffer->input_buffer_1st_display = 0;
|
|
}
|
|
gui_buffer_undo_free_all (buffer);
|
|
buffer->ptr_history = NULL;
|
|
gui_history_ptr = NULL;
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
0, /* save undo */
|
|
1); /* stop completion */
|
|
(void) input_data (buffer, command, NULL);
|
|
free (command);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Completes a word in input buffer.
|
|
*/
|
|
|
|
void
|
|
gui_input_complete (struct t_gui_buffer *buffer)
|
|
{
|
|
int i;
|
|
|
|
if (!buffer->completion)
|
|
return;
|
|
|
|
if (buffer->completion->word_found)
|
|
{
|
|
/* replace word with new completed word into input buffer */
|
|
if (buffer->completion->diff_size > 0)
|
|
{
|
|
if (gui_input_optimize_size (
|
|
buffer,
|
|
buffer->input_buffer_size + buffer->completion->diff_size,
|
|
buffer->input_buffer_length + buffer->completion->diff_length))
|
|
{
|
|
buffer->input_buffer[buffer->input_buffer_size] = '\0';
|
|
for (i = buffer->input_buffer_size - 1;
|
|
i >= buffer->completion->position_replace +
|
|
(int)strlen (buffer->completion->word_found); i--)
|
|
{
|
|
buffer->input_buffer[i] =
|
|
buffer->input_buffer[i - buffer->completion->diff_size];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = buffer->completion->position_replace +
|
|
strlen (buffer->completion->word_found);
|
|
i < buffer->input_buffer_size; i++)
|
|
{
|
|
buffer->input_buffer[i] =
|
|
buffer->input_buffer[i - buffer->completion->diff_size];
|
|
}
|
|
if (gui_input_optimize_size (
|
|
buffer,
|
|
buffer->input_buffer_size + buffer->completion->diff_size,
|
|
buffer->input_buffer_length += buffer->completion->diff_length))
|
|
{
|
|
buffer->input_buffer[buffer->input_buffer_size] = '\0';
|
|
}
|
|
}
|
|
|
|
strncpy (buffer->input_buffer + buffer->completion->position_replace,
|
|
buffer->completion->word_found,
|
|
strlen (buffer->completion->word_found));
|
|
buffer->input_buffer_pos =
|
|
utf8_pos (buffer->input_buffer,
|
|
buffer->completion->position_replace) +
|
|
utf8_strlen (buffer->completion->word_found);
|
|
|
|
/*
|
|
* position is < 0 this means only one word was found to complete,
|
|
* so reinit to stop completion
|
|
*/
|
|
if (buffer->completion->position >= 0)
|
|
buffer->completion->position = utf8_real_pos (buffer->input_buffer,
|
|
buffer->input_buffer_pos);
|
|
|
|
/* add space if needed after completion */
|
|
if (buffer->completion->add_space)
|
|
{
|
|
if (buffer->input_buffer[utf8_real_pos (buffer->input_buffer,
|
|
buffer->input_buffer_pos)] != ' ')
|
|
{
|
|
gui_input_insert_string (buffer, " ",
|
|
buffer->input_buffer_pos);
|
|
}
|
|
else
|
|
buffer->input_buffer_pos++;
|
|
if (buffer->completion->position >= 0)
|
|
buffer->completion->position++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Completes with next word (default key: tab).
|
|
*/
|
|
|
|
void
|
|
gui_input_complete_next (struct t_gui_buffer *buffer)
|
|
{
|
|
if (buffer->input
|
|
&& (buffer->text_search == GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
gui_buffer_undo_snap (buffer);
|
|
gui_completion_search (buffer->completion,
|
|
1,
|
|
buffer->input_buffer,
|
|
buffer->input_buffer_size,
|
|
utf8_real_pos (buffer->input_buffer,
|
|
buffer->input_buffer_pos));
|
|
gui_input_complete (buffer);
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
1, /* save undo */
|
|
0); /* stop completion */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Completes with previous word (default key: shift-tab).
|
|
*/
|
|
|
|
void
|
|
gui_input_complete_previous (struct t_gui_buffer *buffer)
|
|
{
|
|
if (buffer->input
|
|
&& (buffer->text_search == GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
gui_buffer_undo_snap (buffer);
|
|
gui_completion_search (buffer->completion,
|
|
-1,
|
|
buffer->input_buffer,
|
|
buffer->input_buffer_size,
|
|
utf8_real_pos (buffer->input_buffer,
|
|
buffer->input_buffer_pos));
|
|
gui_input_complete (buffer);
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
1, /* save undo */
|
|
0); /* stop completion */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Searches for text in buffer at current position (default key: ctrl-R).
|
|
*/
|
|
|
|
void
|
|
gui_input_search_text_here (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window && (window->buffer->text_search == GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
gui_window_search_start (window, window->scroll->start_line);
|
|
gui_input_search_signal (buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Searches for text in buffer.
|
|
*/
|
|
|
|
void
|
|
gui_input_search_text (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window && (window->buffer->text_search == GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
gui_window_search_start (window, NULL);
|
|
gui_input_search_signal (buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Compiles regex used to search text in buffer.
|
|
*/
|
|
|
|
void
|
|
gui_input_search_compile_regex (struct t_gui_buffer *buffer)
|
|
{
|
|
int flags;
|
|
|
|
/* remove the compiled regex */
|
|
if (buffer->text_search_regex_compiled)
|
|
{
|
|
regfree (buffer->text_search_regex_compiled);
|
|
free (buffer->text_search_regex_compiled);
|
|
buffer->text_search_regex_compiled = NULL;
|
|
}
|
|
|
|
/* compile regex */
|
|
if (buffer->text_search_regex)
|
|
{
|
|
buffer->text_search_regex_compiled = malloc (sizeof (*buffer->text_search_regex_compiled));
|
|
if (buffer->text_search_regex_compiled)
|
|
{
|
|
flags = REG_EXTENDED;
|
|
if (!buffer->text_search_exact)
|
|
flags |= REG_ICASE;
|
|
if (string_regcomp (buffer->text_search_regex_compiled,
|
|
buffer->input_buffer, flags) != 0)
|
|
{
|
|
free (buffer->text_search_regex_compiled);
|
|
buffer->text_search_regex_compiled = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Switches case for search in buffer (default key: meta-c during search).
|
|
*/
|
|
|
|
void
|
|
gui_input_search_switch_case (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window && (window->buffer->text_search != GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
window->buffer->text_search_exact ^= 1;
|
|
gui_window_search_restart (window);
|
|
gui_input_search_signal (buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Switches string/regex for search in buffer (default key: ctrl-R during
|
|
* search).
|
|
*/
|
|
|
|
void
|
|
gui_input_search_switch_regex (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window && (window->buffer->text_search != GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
window->buffer->text_search_regex ^= 1;
|
|
gui_window_search_restart (window);
|
|
gui_input_search_signal (buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Switches search in messages/prefixes (default key: tab during search).
|
|
*/
|
|
|
|
void
|
|
gui_input_search_switch_where (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window && (window->buffer->text_search != GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
/* it's not possible to change that in a buffer with free content */
|
|
if (window->buffer->type == GUI_BUFFER_TYPE_FREE)
|
|
return;
|
|
|
|
if (window->buffer->text_search_where == GUI_TEXT_SEARCH_IN_MESSAGE)
|
|
window->buffer->text_search_where = GUI_TEXT_SEARCH_IN_PREFIX;
|
|
else if (window->buffer->text_search_where == GUI_TEXT_SEARCH_IN_PREFIX)
|
|
window->buffer->text_search_where = GUI_TEXT_SEARCH_IN_MESSAGE | GUI_TEXT_SEARCH_IN_PREFIX;
|
|
else
|
|
window->buffer->text_search_where = GUI_TEXT_SEARCH_IN_MESSAGE;
|
|
gui_window_search_restart (window);
|
|
gui_input_search_signal (buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Searches backward in buffer (default key: up during search).
|
|
*/
|
|
|
|
void
|
|
gui_input_search_previous (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window && (window->buffer->text_search != GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
window->buffer->text_search = GUI_TEXT_SEARCH_BACKWARD;
|
|
(void) gui_window_search_text (window);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Searches forward in buffer (default key: down during search).
|
|
*/
|
|
|
|
void
|
|
gui_input_search_next (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window && (window->buffer->text_search != GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
window->buffer->text_search = GUI_TEXT_SEARCH_FORWARD;
|
|
(void) gui_window_search_text (window);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Stops text search at current position (default key: return during search).
|
|
*/
|
|
|
|
void
|
|
gui_input_search_stop_here (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window && (window->buffer->text_search != GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
gui_window_search_stop_here (window);
|
|
gui_input_search_signal (buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Stops text search (default key: ctrl-Q during search).
|
|
*/
|
|
|
|
void
|
|
gui_input_search_stop (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window && (window->buffer->text_search != GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
gui_window_search_stop (window);
|
|
gui_input_search_signal (buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Deletes previous char (default key: backspace).
|
|
*/
|
|
|
|
void
|
|
gui_input_delete_previous_char (struct t_gui_buffer *buffer)
|
|
{
|
|
char *pos, *pos_last;
|
|
int char_size, size_to_move;
|
|
|
|
if (buffer->input && (buffer->input_buffer_pos > 0))
|
|
{
|
|
gui_buffer_undo_snap (buffer);
|
|
pos = (char *)utf8_add_offset (buffer->input_buffer,
|
|
buffer->input_buffer_pos);
|
|
pos_last = (char *)utf8_prev_char (buffer->input_buffer, pos);
|
|
char_size = pos - pos_last;
|
|
size_to_move = strlen (pos);
|
|
memmove (pos_last, pos, size_to_move);
|
|
if (gui_input_optimize_size (buffer,
|
|
buffer->input_buffer_size - char_size,
|
|
buffer->input_buffer_length - 1))
|
|
{
|
|
buffer->input_buffer_pos--;
|
|
buffer->input_buffer[buffer->input_buffer_size] = '\0';
|
|
}
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
1, /* save undo */
|
|
1); /* stop completion */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Deletes next char (default key: del).
|
|
*/
|
|
|
|
void
|
|
gui_input_delete_next_char (struct t_gui_buffer *buffer)
|
|
{
|
|
char *pos, *pos_next;
|
|
int char_size, size_to_move;
|
|
|
|
if (buffer->input
|
|
&& (buffer->input_buffer_pos < buffer->input_buffer_length))
|
|
{
|
|
gui_buffer_undo_snap (buffer);
|
|
pos = (char *)utf8_add_offset (buffer->input_buffer,
|
|
buffer->input_buffer_pos);
|
|
pos_next = (char *)utf8_next_char (pos);
|
|
char_size = pos_next - pos;
|
|
size_to_move = strlen (pos_next);
|
|
memmove (pos, pos_next, size_to_move);
|
|
if (gui_input_optimize_size (buffer,
|
|
buffer->input_buffer_size - char_size,
|
|
buffer->input_buffer_length - 1))
|
|
{
|
|
buffer->input_buffer[buffer->input_buffer_size] = '\0';
|
|
}
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
1, /* save undo */
|
|
1); /* stop completion */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Deletes previous word (default key: ctrl-W).
|
|
*/
|
|
|
|
void
|
|
gui_input_delete_previous_word (struct t_gui_buffer *buffer)
|
|
{
|
|
int length_deleted, size_deleted;
|
|
char *start, *string;
|
|
|
|
if (buffer->input && (buffer->input_buffer_pos > 0))
|
|
{
|
|
gui_buffer_undo_snap (buffer);
|
|
start = (char *)utf8_add_offset (buffer->input_buffer,
|
|
buffer->input_buffer_pos - 1);
|
|
string = start;
|
|
/* move to the left until we reach a word char */
|
|
while (string && !string_is_word_char_input (string))
|
|
{
|
|
string = (char *)utf8_prev_char (buffer->input_buffer, string);
|
|
}
|
|
/* move to the left to skip the whole word */
|
|
if (string)
|
|
{
|
|
while (string && string_is_word_char_input (string))
|
|
{
|
|
string = (char *)utf8_prev_char (buffer->input_buffer, string);
|
|
}
|
|
}
|
|
|
|
if (string)
|
|
string = (char *)utf8_next_char (string);
|
|
else
|
|
string = buffer->input_buffer;
|
|
|
|
size_deleted = utf8_next_char (start) - string;
|
|
length_deleted = utf8_strnlen (string, size_deleted);
|
|
|
|
gui_input_clipboard_copy (string, size_deleted);
|
|
|
|
memmove (string, string + size_deleted, strlen (string + size_deleted));
|
|
|
|
if (gui_input_optimize_size (
|
|
buffer,
|
|
buffer->input_buffer_size - size_deleted,
|
|
buffer->input_buffer_length - length_deleted))
|
|
{
|
|
buffer->input_buffer[buffer->input_buffer_size] = '\0';
|
|
buffer->input_buffer_pos -= length_deleted;
|
|
}
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
1, /* save undo */
|
|
1); /* stop completion */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Deletes next word (default key: meta-d).
|
|
*/
|
|
|
|
void
|
|
gui_input_delete_next_word (struct t_gui_buffer *buffer)
|
|
{
|
|
int size_deleted, length_deleted;
|
|
char *start, *string;
|
|
|
|
if (buffer->input)
|
|
{
|
|
gui_buffer_undo_snap (buffer);
|
|
start = (char *)utf8_add_offset (buffer->input_buffer,
|
|
buffer->input_buffer_pos);
|
|
string = start;
|
|
length_deleted = 0;
|
|
/* move to the right until we reach a word char */
|
|
while (string[0] && !string_is_word_char_input (string))
|
|
{
|
|
string = (char *)utf8_next_char (string);
|
|
length_deleted++;
|
|
}
|
|
/* move to the right to skip the whole word */
|
|
while (string[0] && string_is_word_char_input (string))
|
|
{
|
|
string = (char *)utf8_next_char (string);
|
|
length_deleted++;
|
|
}
|
|
size_deleted = string - start;
|
|
|
|
gui_input_clipboard_copy (start, size_deleted);
|
|
|
|
memmove (start, string, strlen (string));
|
|
|
|
if (gui_input_optimize_size (
|
|
buffer,
|
|
buffer->input_buffer_size - size_deleted,
|
|
buffer->input_buffer_length - length_deleted))
|
|
{
|
|
buffer->input_buffer[buffer->input_buffer_size] = '\0';
|
|
}
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
1, /* save undo */
|
|
1); /* stop completion */
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Deletes all from cursor pos to beginning of line (default key: ctrl-U).
|
|
*/
|
|
|
|
void
|
|
gui_input_delete_beginning_of_line (struct t_gui_buffer *buffer)
|
|
{
|
|
int length_deleted, size_deleted;
|
|
char *start;
|
|
|
|
if (buffer->input && (buffer->input_buffer_pos > 0))
|
|
{
|
|
gui_buffer_undo_snap (buffer);
|
|
start = (char *)utf8_add_offset (buffer->input_buffer,
|
|
buffer->input_buffer_pos);
|
|
size_deleted = start - buffer->input_buffer;
|
|
length_deleted = utf8_strnlen (buffer->input_buffer, size_deleted);
|
|
gui_input_clipboard_copy (buffer->input_buffer,
|
|
start - buffer->input_buffer);
|
|
|
|
memmove (buffer->input_buffer, start, strlen (start));
|
|
|
|
if (gui_input_optimize_size (
|
|
buffer,
|
|
buffer->input_buffer_size - size_deleted,
|
|
buffer->input_buffer_length - length_deleted))
|
|
{
|
|
buffer->input_buffer[buffer->input_buffer_size] = '\0';
|
|
buffer->input_buffer_pos = 0;
|
|
}
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
1, /* save undo */
|
|
1); /* stop completion */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Deletes all from cursor pos to end of line (default key: ctrl-K).
|
|
*/
|
|
|
|
void
|
|
gui_input_delete_end_of_line (struct t_gui_buffer *buffer)
|
|
{
|
|
char *start;
|
|
int size_deleted;
|
|
|
|
if (buffer->input)
|
|
{
|
|
gui_buffer_undo_snap (buffer);
|
|
start = (char *)utf8_add_offset (buffer->input_buffer,
|
|
buffer->input_buffer_pos);
|
|
size_deleted = strlen (start);
|
|
gui_input_clipboard_copy (start, size_deleted);
|
|
start[0] = '\0';
|
|
(void) gui_input_optimize_size (buffer,
|
|
strlen (buffer->input_buffer),
|
|
utf8_strlen (buffer->input_buffer));
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
1, /* save undo */
|
|
1); /* stop completion */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Deletes entire line (default key: meta-r).
|
|
*/
|
|
|
|
void
|
|
gui_input_delete_line (struct t_gui_buffer *buffer)
|
|
{
|
|
if (buffer->input)
|
|
{
|
|
gui_buffer_undo_snap (buffer);
|
|
if (gui_input_optimize_size (buffer, 0, 0))
|
|
{
|
|
buffer->input_buffer[0] = '\0';
|
|
buffer->input_buffer_pos = 0;
|
|
}
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
1, /* save undo */
|
|
1); /* stop completion */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Transposes chars at cursor pos (default key: ctrl-T).
|
|
*/
|
|
|
|
void
|
|
gui_input_transpose_chars (struct t_gui_buffer *buffer)
|
|
{
|
|
char *start, *prev_char, saved_char[5];
|
|
int size_prev_char, size_start_char;
|
|
|
|
if (buffer->input && (buffer->input_buffer_pos > 0)
|
|
&& (buffer->input_buffer_length > 1))
|
|
{
|
|
gui_buffer_undo_snap (buffer);
|
|
|
|
if (buffer->input_buffer_pos == buffer->input_buffer_length)
|
|
buffer->input_buffer_pos--;
|
|
|
|
start = (char *)utf8_add_offset (buffer->input_buffer,
|
|
buffer->input_buffer_pos);
|
|
prev_char = (char *)utf8_prev_char (buffer->input_buffer, start);
|
|
size_prev_char = start - prev_char;
|
|
size_start_char = utf8_char_size (start);
|
|
|
|
memcpy (saved_char, prev_char, size_prev_char);
|
|
memcpy (prev_char, start, size_start_char);
|
|
memcpy (prev_char + size_start_char, saved_char, size_prev_char);
|
|
|
|
buffer->input_buffer_pos++;
|
|
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
1, /* save undo */
|
|
1); /* stop completion */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Moves cursor to beginning of line (default key: home).
|
|
*/
|
|
|
|
void
|
|
gui_input_move_beginning_of_line (struct t_gui_buffer *buffer)
|
|
{
|
|
if (buffer->input && (buffer->input_buffer_pos > 0))
|
|
{
|
|
buffer->input_buffer_pos = 0;
|
|
gui_input_text_cursor_moved_signal (buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Moves cursor to end of line (default key: end).
|
|
*/
|
|
|
|
void
|
|
gui_input_move_end_of_line (struct t_gui_buffer *buffer)
|
|
{
|
|
if (buffer->input
|
|
&& (buffer->input_buffer_pos < buffer->input_buffer_length))
|
|
{
|
|
buffer->input_buffer_pos = buffer->input_buffer_length;
|
|
gui_input_text_cursor_moved_signal (buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Moves cursor to previous char (default key: left).
|
|
*/
|
|
|
|
void
|
|
gui_input_move_previous_char (struct t_gui_buffer *buffer)
|
|
{
|
|
if (buffer->input && (buffer->input_buffer_pos > 0))
|
|
{
|
|
buffer->input_buffer_pos--;
|
|
gui_input_text_cursor_moved_signal (buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Moves cursor to next char (default key: right).
|
|
*/
|
|
|
|
void
|
|
gui_input_move_next_char (struct t_gui_buffer *buffer)
|
|
{
|
|
if (buffer->input
|
|
&& (buffer->input_buffer_pos < buffer->input_buffer_length))
|
|
{
|
|
buffer->input_buffer_pos++;
|
|
gui_input_text_cursor_moved_signal (buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Moves cursor to beginning of previous word (default key: meta-b or
|
|
* ctrl-left).
|
|
*/
|
|
|
|
void
|
|
gui_input_move_previous_word (struct t_gui_buffer *buffer)
|
|
{
|
|
char *pos;
|
|
|
|
if (buffer->input
|
|
&& (buffer->input_buffer_pos > 0))
|
|
{
|
|
pos = (char *)utf8_add_offset (buffer->input_buffer,
|
|
buffer->input_buffer_pos - 1);
|
|
while (pos && !string_is_word_char_input (pos))
|
|
{
|
|
pos = (char *)utf8_prev_char (buffer->input_buffer, pos);
|
|
}
|
|
if (pos)
|
|
{
|
|
while (pos && string_is_word_char_input (pos))
|
|
{
|
|
pos = (char *)utf8_prev_char (buffer->input_buffer, pos);
|
|
}
|
|
if (pos)
|
|
pos = (char *)utf8_next_char (pos);
|
|
else
|
|
pos = buffer->input_buffer;
|
|
buffer->input_buffer_pos = utf8_pos (buffer->input_buffer,
|
|
pos - buffer->input_buffer);
|
|
}
|
|
else
|
|
buffer->input_buffer_pos = 0;
|
|
|
|
gui_input_text_cursor_moved_signal (buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Moves cursor to the beginning of next word (default key: meta-f or
|
|
* ctrl-right).
|
|
*/
|
|
|
|
void
|
|
gui_input_move_next_word (struct t_gui_buffer *buffer)
|
|
{
|
|
char *pos;
|
|
|
|
if (buffer->input
|
|
&& (buffer->input_buffer_pos < buffer->input_buffer_length))
|
|
{
|
|
pos = (char *)utf8_add_offset (buffer->input_buffer,
|
|
buffer->input_buffer_pos);
|
|
while (pos[0] && !string_is_word_char_input (pos))
|
|
{
|
|
pos = (char *)utf8_next_char (pos);
|
|
}
|
|
if (pos[0])
|
|
{
|
|
while (pos[0] && string_is_word_char_input (pos))
|
|
{
|
|
pos = (char *)utf8_next_char (pos);
|
|
}
|
|
if (pos[0])
|
|
{
|
|
buffer->input_buffer_pos =
|
|
utf8_pos (buffer->input_buffer,
|
|
pos - buffer->input_buffer);
|
|
}
|
|
else
|
|
buffer->input_buffer_pos = buffer->input_buffer_length;
|
|
}
|
|
else
|
|
{
|
|
buffer->input_buffer_pos =
|
|
utf8_pos (buffer->input_buffer,
|
|
utf8_prev_char (buffer->input_buffer, pos) - buffer->input_buffer);
|
|
}
|
|
|
|
gui_input_text_cursor_moved_signal (buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Recalls previous command from local or global history.
|
|
*/
|
|
|
|
void
|
|
gui_input_history_previous (struct t_gui_window *window,
|
|
struct t_gui_history *history,
|
|
struct t_gui_history **ptr_history)
|
|
{
|
|
if (!window->buffer->input)
|
|
return;
|
|
|
|
if (*ptr_history)
|
|
{
|
|
if (!(*ptr_history)->next_history)
|
|
return;
|
|
*ptr_history = (*ptr_history)->next_history;
|
|
}
|
|
if (!(*ptr_history))
|
|
*ptr_history = history;
|
|
|
|
if (!(*ptr_history))
|
|
return;
|
|
|
|
/* bash/readline like use of history */
|
|
if (window->buffer->input_buffer_size > 0)
|
|
{
|
|
if ((*ptr_history)->prev_history)
|
|
{
|
|
/* replace text in history with current input */
|
|
window->buffer->input_buffer[window->buffer->input_buffer_size] = '\0';
|
|
if ((*ptr_history)->prev_history->text)
|
|
free ((*ptr_history)->prev_history->text);
|
|
(*ptr_history)->prev_history->text =
|
|
strdup (window->buffer->input_buffer);
|
|
}
|
|
else
|
|
{
|
|
/* add current input in history */
|
|
window->buffer->input_buffer[window->buffer->input_buffer_size] = '\0';
|
|
gui_history_add (window->buffer,
|
|
window->buffer->input_buffer);
|
|
}
|
|
}
|
|
if (gui_input_optimize_size (window->buffer,
|
|
strlen ((*ptr_history)->text),
|
|
utf8_strlen ((*ptr_history)->text)))
|
|
{
|
|
window->buffer->input_buffer_pos = window->buffer->input_buffer_length;
|
|
window->buffer->input_buffer_1st_display = 0;
|
|
strcpy (window->buffer->input_buffer, (*ptr_history)->text);
|
|
}
|
|
gui_input_text_changed_modifier_and_signal (window->buffer,
|
|
0, /* save undo */
|
|
1); /* stop completion */
|
|
gui_buffer_undo_free_all (window->buffer);
|
|
}
|
|
|
|
/*
|
|
* Recalls next command from local or global history.
|
|
*/
|
|
|
|
void
|
|
gui_input_history_next (struct t_gui_window *window,
|
|
struct t_gui_history *history,
|
|
struct t_gui_history **ptr_history)
|
|
{
|
|
int input_changed, rc;
|
|
|
|
/* make C compiler happy */
|
|
(void) history;
|
|
|
|
input_changed = 0;
|
|
|
|
if (!window->buffer->input)
|
|
return;
|
|
|
|
if (*ptr_history)
|
|
{
|
|
/* replace text in history with current input */
|
|
window->buffer->input_buffer[window->buffer->input_buffer_size] = '\0';
|
|
if ((*ptr_history)->text)
|
|
free ((*ptr_history)->text);
|
|
(*ptr_history)->text = strdup (window->buffer->input_buffer);
|
|
|
|
*ptr_history = (*ptr_history)->prev_history;
|
|
if (*ptr_history)
|
|
{
|
|
rc = gui_input_optimize_size (window->buffer,
|
|
strlen ((*ptr_history)->text),
|
|
utf8_strlen ((*ptr_history)->text));
|
|
}
|
|
else
|
|
{
|
|
rc = gui_input_optimize_size (window->buffer, 0, 0);
|
|
if (rc)
|
|
window->buffer->input_buffer[0] = '\0';
|
|
}
|
|
if (rc)
|
|
{
|
|
window->buffer->input_buffer_pos =
|
|
window->buffer->input_buffer_length;
|
|
window->buffer->input_buffer_1st_display = 0;
|
|
if (*ptr_history)
|
|
{
|
|
strcpy (window->buffer->input_buffer, (*ptr_history)->text);
|
|
}
|
|
}
|
|
input_changed = 1;
|
|
}
|
|
else
|
|
{
|
|
/* add line to history then clear input */
|
|
if (window->buffer->input_buffer_size > 0)
|
|
{
|
|
window->buffer->input_buffer[window->buffer->input_buffer_size] = '\0';
|
|
gui_history_add (window->buffer,
|
|
window->buffer->input_buffer);
|
|
if (gui_input_optimize_size (window->buffer, 0, 0))
|
|
{
|
|
window->buffer->input_buffer[0] = '\0';
|
|
window->buffer->input_buffer_pos = 0;
|
|
window->buffer->input_buffer_1st_display = 0;
|
|
}
|
|
input_changed = 1;
|
|
}
|
|
}
|
|
if (input_changed)
|
|
{
|
|
gui_input_text_changed_modifier_and_signal (window->buffer,
|
|
0, /* save undo */
|
|
1); /* stop completion */
|
|
gui_buffer_undo_free_all (window->buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Recalls previous command from local history (default key: up).
|
|
*/
|
|
|
|
void
|
|
gui_input_history_local_previous (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window)
|
|
{
|
|
gui_input_history_previous (window,
|
|
window->buffer->history,
|
|
&(window->buffer->ptr_history));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Recalls next command from local history (default key: down).
|
|
*/
|
|
|
|
void
|
|
gui_input_history_local_next (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window)
|
|
{
|
|
gui_input_history_next (window,
|
|
window->buffer->history,
|
|
&(window->buffer->ptr_history));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Recalls previous command from global history (default key: ctrl-up).
|
|
*/
|
|
|
|
void
|
|
gui_input_history_global_previous (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window)
|
|
{
|
|
gui_input_history_previous (window,
|
|
gui_history,
|
|
&gui_history_ptr);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Recalls next command from global history (default key: ctrl-down).
|
|
*/
|
|
|
|
void
|
|
gui_input_history_global_next (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window)
|
|
{
|
|
gui_input_history_next (window,
|
|
gui_history,
|
|
&gui_history_ptr);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Jumps to buffer with activity (default key: alt-a).
|
|
*/
|
|
|
|
void
|
|
gui_input_jump_smart (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
int scroll_to_bottom;
|
|
|
|
scroll_to_bottom = 0;
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window
|
|
&& (window->buffer->text_search == GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
if (gui_hotlist)
|
|
{
|
|
if (!gui_hotlist_initial_buffer)
|
|
gui_hotlist_initial_buffer = window->buffer;
|
|
gui_window_switch_to_buffer (window, gui_hotlist->buffer, 1);
|
|
gui_hotlist_remove_buffer (window->buffer, 0);
|
|
scroll_to_bottom = 1;
|
|
}
|
|
else
|
|
{
|
|
if (gui_hotlist_initial_buffer)
|
|
{
|
|
if (CONFIG_BOOLEAN(config_look_jump_smart_back_to_buffer))
|
|
{
|
|
gui_window_switch_to_buffer (window,
|
|
gui_hotlist_initial_buffer, 1);
|
|
scroll_to_bottom = 1;
|
|
}
|
|
gui_hotlist_initial_buffer = NULL;
|
|
}
|
|
else
|
|
{
|
|
gui_hotlist_initial_buffer = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* scroll to bottom if window was scrolled (except if scrolled
|
|
* beyond the end)
|
|
*/
|
|
if (scroll_to_bottom
|
|
&& window->scroll
|
|
&& window->scroll->start_line
|
|
&& (window->scroll->start_line_pos >= 0))
|
|
{
|
|
gui_window_scroll_bottom (window);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Jumps to last buffer displayed (before last jump to a buffer) (default key:
|
|
* meta-/).
|
|
*/
|
|
|
|
void
|
|
gui_input_jump_last_buffer_displayed (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window
|
|
&& (window->buffer->text_search == GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
if (gui_buffer_last_displayed)
|
|
gui_buffer_switch_by_number (window,
|
|
gui_buffer_last_displayed->number);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Jumps to previously visited buffer (buffer displayed before current one)
|
|
* (default key: meta-<).
|
|
*/
|
|
|
|
void
|
|
gui_input_jump_previously_visited_buffer (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
int index;
|
|
struct t_gui_buffer_visited *ptr_buffer_visited;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window
|
|
&& (window->buffer->text_search == GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
index = gui_buffer_visited_get_index_previous ();
|
|
if (index >= 0)
|
|
{
|
|
gui_buffers_visited_index = index;
|
|
|
|
ptr_buffer_visited =
|
|
gui_buffer_visited_search_by_number (gui_buffers_visited_index);
|
|
if (ptr_buffer_visited)
|
|
{
|
|
gui_buffers_visited_frozen = 1;
|
|
gui_buffer_switch_by_number (window,
|
|
ptr_buffer_visited->buffer->number);
|
|
gui_buffers_visited_frozen = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Jumps to next visited buffer (buffer displayed after current one) (default
|
|
* key: meta->).
|
|
*/
|
|
|
|
void
|
|
gui_input_jump_next_visited_buffer (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *window;
|
|
int index;
|
|
struct t_gui_buffer_visited *ptr_buffer_visited;
|
|
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window
|
|
&& (window->buffer->text_search == GUI_TEXT_SEARCH_DISABLED))
|
|
{
|
|
index = gui_buffer_visited_get_index_next ();
|
|
if (index >= 0)
|
|
{
|
|
gui_buffers_visited_index = index;
|
|
|
|
ptr_buffer_visited = gui_buffer_visited_search_by_number (gui_buffers_visited_index);
|
|
if (ptr_buffer_visited)
|
|
{
|
|
gui_buffers_visited_frozen = 1;
|
|
gui_buffer_switch_by_number (window,
|
|
ptr_buffer_visited->buffer->number);
|
|
gui_buffers_visited_frozen = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Clears hotlist (default key: meta-h).
|
|
*/
|
|
|
|
void
|
|
gui_input_hotlist_clear (struct t_gui_buffer *buffer,
|
|
const char *str_level_mask)
|
|
{
|
|
long level_mask;
|
|
char *error;
|
|
struct t_gui_hotlist *ptr_hotlist;
|
|
int priority;
|
|
|
|
if (str_level_mask)
|
|
{
|
|
if (strcmp (str_level_mask, "lowest") == 0)
|
|
{
|
|
/* clear only lowest priority currently in hotlist */
|
|
priority = GUI_HOTLIST_MAX + 1;
|
|
for (ptr_hotlist = gui_hotlist; ptr_hotlist;
|
|
ptr_hotlist = ptr_hotlist->next_hotlist)
|
|
{
|
|
if ((int)ptr_hotlist->priority < priority)
|
|
priority = ptr_hotlist->priority;
|
|
}
|
|
if (priority <= GUI_HOTLIST_MAX)
|
|
{
|
|
gui_hotlist_clear (1 << priority);
|
|
gui_hotlist_initial_buffer = buffer;
|
|
}
|
|
}
|
|
else if (strcmp (str_level_mask, "highest") == 0)
|
|
{
|
|
/* clear only highest priority currently in hotlist */
|
|
priority = GUI_HOTLIST_MIN - 1;
|
|
for (ptr_hotlist = gui_hotlist; ptr_hotlist;
|
|
ptr_hotlist = ptr_hotlist->next_hotlist)
|
|
{
|
|
if ((int)ptr_hotlist->priority > priority)
|
|
priority = ptr_hotlist->priority;
|
|
}
|
|
if (priority >= GUI_HOTLIST_MIN)
|
|
{
|
|
gui_hotlist_clear (1 << priority);
|
|
gui_hotlist_initial_buffer = buffer;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* clear hotlist using a mask of levels */
|
|
error = NULL;
|
|
level_mask = strtol (str_level_mask, &error, 10);
|
|
if (error && !error[0] && (level_mask > 0))
|
|
{
|
|
gui_hotlist_clear ((int)level_mask);
|
|
gui_hotlist_initial_buffer = buffer;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gui_hotlist_clear (GUI_HOTLIST_MASK_MAX);
|
|
gui_hotlist_initial_buffer = buffer;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initializes "grab key mode" (next key will be inserted into input buffer)
|
|
* (default key: meta-k).
|
|
*/
|
|
|
|
void
|
|
gui_input_grab_key (struct t_gui_buffer *buffer, int command, const char *delay)
|
|
{
|
|
if (buffer->input)
|
|
gui_key_grab_init (command, delay);
|
|
}
|
|
|
|
/*
|
|
* Initializes "grab mouse mode" (next mouse event will be inserted into input
|
|
* buffer) (default key: button2 of mouse in input bar).
|
|
*/
|
|
|
|
void
|
|
gui_input_grab_mouse (struct t_gui_buffer *buffer, int area)
|
|
{
|
|
if (buffer->input)
|
|
gui_mouse_grab_init (area);
|
|
}
|
|
|
|
/*
|
|
* Sets unread marker for all buffers (default key: ctrl-S, ctrl-U).
|
|
*/
|
|
|
|
void
|
|
gui_input_set_unread ()
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
/* set read marker for all standard buffers */
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
gui_buffer_set_unread (ptr_buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Sets unread marker for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_input_set_unread_current (struct t_gui_buffer *buffer)
|
|
{
|
|
gui_buffer_set_unread (buffer);
|
|
}
|
|
|
|
/*
|
|
* Switches active buffer to next buffer (when many buffers are merged) (default
|
|
* key: ctrl-X).
|
|
*/
|
|
|
|
void
|
|
gui_input_switch_active_buffer (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
struct t_gui_window *window;
|
|
|
|
ptr_buffer = gui_buffer_get_next_active_buffer (buffer, 0);
|
|
if (ptr_buffer)
|
|
{
|
|
gui_buffer_set_active_buffer (ptr_buffer);
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window)
|
|
gui_window_switch_to_buffer (window, ptr_buffer, 1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Switches active buffer to previous buffer (when many buffers are merged).
|
|
*/
|
|
|
|
void
|
|
gui_input_switch_active_buffer_previous (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
struct t_gui_window *window;
|
|
|
|
ptr_buffer = gui_buffer_get_previous_active_buffer (buffer, 0);
|
|
if (ptr_buffer)
|
|
{
|
|
gui_buffer_set_active_buffer (ptr_buffer);
|
|
window = gui_window_search_with_buffer (buffer);
|
|
if (window)
|
|
gui_window_switch_to_buffer (window, ptr_buffer, 1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Zooms on current active merged buffer, or display all merged buffers if zoom
|
|
* was active (default key: alt-x).
|
|
*/
|
|
|
|
void
|
|
gui_input_zoom_merged_buffer (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *ptr_window;
|
|
struct t_gui_buffer *ptr_buffer;
|
|
int buffer_was_zoomed;
|
|
|
|
/* do nothing if current buffer is not merged with another buffer */
|
|
if (gui_buffer_count_merged_buffers (buffer->number) < 2)
|
|
return;
|
|
|
|
buffer_was_zoomed = (buffer->active == 2);
|
|
|
|
/* reset scroll in all windows displaying this buffer number */
|
|
for (ptr_window = gui_windows; ptr_window;
|
|
ptr_window = ptr_window->next_window)
|
|
{
|
|
if ((ptr_window->buffer->number == buffer->number)
|
|
&& ptr_window->scroll && ptr_window->scroll->start_line)
|
|
{
|
|
gui_window_scroll_bottom (ptr_window);
|
|
}
|
|
}
|
|
|
|
/* first make buffer active if it is not */
|
|
if (!buffer->active)
|
|
{
|
|
gui_buffer_set_active_buffer (buffer);
|
|
ptr_window = gui_window_search_with_buffer (buffer);
|
|
if (ptr_window)
|
|
gui_window_switch_to_buffer (ptr_window, buffer, 1);
|
|
}
|
|
|
|
/*
|
|
* toggle active flag between 1 and 2
|
|
* (1 = active with other merged buffers displayed, 2 = the only active)
|
|
*/
|
|
if (buffer->active == 1)
|
|
{
|
|
buffer->active = 2;
|
|
buffer->lines = buffer->own_lines;
|
|
}
|
|
else if (buffer->active == 2)
|
|
{
|
|
buffer->active = 1;
|
|
buffer->lines = buffer->mixed_lines;
|
|
}
|
|
|
|
/* set "zoomed" in merged buffers */
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if (ptr_buffer->number > buffer->number)
|
|
break;
|
|
if (ptr_buffer->number == buffer->number)
|
|
{
|
|
ptr_buffer->zoomed = (buffer->active == 2) ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
gui_buffer_compute_num_displayed ();
|
|
|
|
gui_buffer_ask_chat_refresh (buffer, 2);
|
|
|
|
(void) hook_signal_send ((buffer_was_zoomed) ?
|
|
"buffer_unzoomed" : "buffer_zoomed",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
}
|
|
|
|
/*
|
|
* Inserts a string in command line.
|
|
*/
|
|
|
|
void
|
|
gui_input_insert (struct t_gui_buffer *buffer, const char *args)
|
|
{
|
|
char *args2;
|
|
|
|
if (args)
|
|
{
|
|
gui_buffer_undo_snap (buffer);
|
|
args2 = string_convert_escaped_chars (args);
|
|
gui_input_insert_string (buffer, (args2) ? args2 : args, -1);
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
1, /* save undo */
|
|
1); /* stop completion */
|
|
if (args2)
|
|
free (args2);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Uses a undo: replace input with undo content.
|
|
*/
|
|
|
|
void
|
|
gui_input_undo_use (struct t_gui_buffer *buffer, struct t_gui_input_undo *undo)
|
|
{
|
|
if ((undo->data) && (strcmp (undo->data, buffer->input_buffer) != 0))
|
|
{
|
|
gui_input_replace_input (buffer, undo->data);
|
|
gui_input_set_pos (buffer, undo->pos);
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
0, /* save undo */
|
|
1); /* stop completion */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Undoes last action on input buffer (default key: ctrl-_).
|
|
*/
|
|
|
|
void
|
|
gui_input_undo (struct t_gui_buffer *buffer)
|
|
{
|
|
if (buffer->ptr_input_undo)
|
|
{
|
|
/*
|
|
* if we are doing undo and that undo pointer is to the end of list
|
|
* (for example first time undo is used), then save current input
|
|
* content in undo list
|
|
*/
|
|
if ((buffer->ptr_input_undo == buffer->last_input_undo)
|
|
&& (buffer->ptr_input_undo)->data
|
|
&& (strcmp (buffer->input_buffer, (buffer->ptr_input_undo)->data) != 0))
|
|
{
|
|
gui_buffer_undo_snap_free (buffer);
|
|
gui_buffer_undo_add (buffer);
|
|
}
|
|
|
|
if (buffer->ptr_input_undo
|
|
&& (buffer->ptr_input_undo)->prev_undo)
|
|
{
|
|
buffer->ptr_input_undo = (buffer->ptr_input_undo)->prev_undo;
|
|
gui_input_undo_use (buffer, buffer->ptr_input_undo);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Redoes last action on input buffer (default key: alt-_).
|
|
*/
|
|
|
|
void
|
|
gui_input_redo (struct t_gui_buffer *buffer)
|
|
{
|
|
if (buffer->ptr_input_undo
|
|
&& (buffer->ptr_input_undo)->next_undo)
|
|
{
|
|
buffer->ptr_input_undo = (buffer->ptr_input_undo)->next_undo;
|
|
gui_input_undo_use (buffer, buffer->ptr_input_undo);
|
|
}
|
|
}
|