mirror of
https://github.com/weechat/weechat.git
synced 2026-06-25 12:26:40 +02:00
db0bdc2ac6
The default value is 0 (legacy behavior). When it is set to 1, an empty input (just by pressing Return with nothing in input) is sent to the input callback, which receives an empty string.
1871 lines
54 KiB
C
1871 lines
54 KiB
C
/*
|
|
* gui-input.c - input functions (used by all GUI)
|
|
*
|
|
* Copyright (C) 2003-2017 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 <http://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", (long unsigned int)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);
|
|
strncpy (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);
|
|
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;
|
|
while (string && !string_is_word_char_input (string))
|
|
{
|
|
string = (char *)utf8_prev_char (buffer->input_buffer, string);
|
|
}
|
|
if (string)
|
|
{
|
|
while (string && string_is_word_char_input (string))
|
|
{
|
|
string = (char *)utf8_prev_char (buffer->input_buffer, string);
|
|
}
|
|
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 (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;
|
|
while (string[0])
|
|
{
|
|
if (!string_is_word_char_input (string) && (string > start))
|
|
break;
|
|
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);
|
|
}
|
|
}
|