mirror of
https://github.com/neovim/neovim.git
synced 2025-10-03 16:36:30 +00:00
vim-patch:8.2.0443: clipboard code is spread out #35949
Problem: Clipboard code is spread out.
Solution: Move clipboard code to its own file. (Yegappan Lakshmanan,
closes vim/vim#5827)
45fffdf10b
Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
285
src/nvim/clipboard.c
Normal file
285
src/nvim/clipboard.c
Normal file
@@ -0,0 +1,285 @@
|
||||
// clipboard.c: Functions to handle the clipboard
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "nvim/api/private/helpers.h"
|
||||
#include "nvim/ascii_defs.h"
|
||||
#include "nvim/clipboard.h"
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/option_vars.h"
|
||||
#include "nvim/register.h"
|
||||
|
||||
#include "clipboard.c.generated.h"
|
||||
|
||||
// for behavior between start_batch_changes() and end_batch_changes())
|
||||
static int batch_change_count = 0; // inside a script
|
||||
static bool clipboard_delay_update = false; // delay clipboard update
|
||||
static bool clipboard_needs_update = false; // clipboard was updated
|
||||
static bool clipboard_didwarn = false;
|
||||
|
||||
/// Determine if register `*name` should be used as a clipboard.
|
||||
/// In an unnamed operation, `*name` is `NUL` and will be adjusted to */+ if
|
||||
/// `clipboard=unnamed[plus]` is set.
|
||||
///
|
||||
/// @param name The name of register, or `NUL` if unnamed.
|
||||
/// @param quiet Suppress error messages
|
||||
/// @param writing if we're setting the contents of the clipboard
|
||||
///
|
||||
/// @returns the yankreg that should be written into, or `NULL`
|
||||
/// if the register isn't a clipboard or provider isn't available.
|
||||
yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing)
|
||||
{
|
||||
#define MSG_NO_CLIP "clipboard: No provider. " \
|
||||
"Try \":checkhealth\" or \":h clipboard\"."
|
||||
|
||||
yankreg_T *target = NULL;
|
||||
bool explicit_cb_reg = (*name == '*' || *name == '+');
|
||||
bool implicit_cb_reg = (*name == NUL) && (cb_flags & (kOptCbFlagUnnamed | kOptCbFlagUnnamedplus));
|
||||
if (!explicit_cb_reg && !implicit_cb_reg) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!eval_has_provider("clipboard", false)) {
|
||||
if (batch_change_count <= 1 && !quiet
|
||||
&& (!clipboard_didwarn || (explicit_cb_reg && !redirecting()))) {
|
||||
clipboard_didwarn = true;
|
||||
// Do NOT error (emsg()) here--if it interrupts :redir we get into
|
||||
// a weird state, stuck in "redirect mode".
|
||||
msg(MSG_NO_CLIP, 0);
|
||||
}
|
||||
// ... else, be silent (don't flood during :while, :redir, etc.).
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (explicit_cb_reg) {
|
||||
target = get_y_register(*name == '*' ? STAR_REGISTER : PLUS_REGISTER);
|
||||
if (writing && (cb_flags & (*name == '*' ? kOptCbFlagUnnamed : kOptCbFlagUnnamedplus))) {
|
||||
clipboard_needs_update = false;
|
||||
}
|
||||
goto end;
|
||||
} else { // unnamed register: "implicit" clipboard
|
||||
if (writing && clipboard_delay_update) {
|
||||
// For "set" (copy), defer the clipboard call.
|
||||
clipboard_needs_update = true;
|
||||
goto end;
|
||||
} else if (!writing && clipboard_needs_update) {
|
||||
// For "get" (paste), use the internal value.
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (cb_flags & kOptCbFlagUnnamedplus) {
|
||||
*name = (cb_flags & kOptCbFlagUnnamed && writing) ? '"' : '+';
|
||||
target = get_y_register(PLUS_REGISTER);
|
||||
} else {
|
||||
*name = '*';
|
||||
target = get_y_register(STAR_REGISTER);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
return target;
|
||||
}
|
||||
|
||||
bool get_clipboard(int name, yankreg_T **target, bool quiet)
|
||||
{
|
||||
// show message on error
|
||||
bool errmsg = true;
|
||||
|
||||
yankreg_T *reg = adjust_clipboard_name(&name, quiet, false);
|
||||
if (reg == NULL) {
|
||||
return false;
|
||||
}
|
||||
free_register(reg);
|
||||
|
||||
list_T *const args = tv_list_alloc(1);
|
||||
const char regname = (char)name;
|
||||
tv_list_append_string(args, ®name, 1);
|
||||
|
||||
typval_T result = eval_call_provider("clipboard", "get", args, false);
|
||||
|
||||
if (result.v_type != VAR_LIST) {
|
||||
if (result.v_type == VAR_NUMBER && result.vval.v_number == 0) {
|
||||
// failure has already been indicated by provider
|
||||
errmsg = false;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_T *res = result.vval.v_list;
|
||||
list_T *lines = NULL;
|
||||
if (tv_list_len(res) == 2
|
||||
&& TV_LIST_ITEM_TV(tv_list_first(res))->v_type == VAR_LIST) {
|
||||
lines = TV_LIST_ITEM_TV(tv_list_first(res))->vval.v_list;
|
||||
if (TV_LIST_ITEM_TV(tv_list_last(res))->v_type != VAR_STRING) {
|
||||
goto err;
|
||||
}
|
||||
char *regtype = TV_LIST_ITEM_TV(tv_list_last(res))->vval.v_string;
|
||||
if (regtype == NULL || strlen(regtype) > 1) {
|
||||
goto err;
|
||||
}
|
||||
switch (regtype[0]) {
|
||||
case 0:
|
||||
reg->y_type = kMTUnknown;
|
||||
break;
|
||||
case 'v':
|
||||
case 'c':
|
||||
reg->y_type = kMTCharWise;
|
||||
break;
|
||||
case 'V':
|
||||
case 'l':
|
||||
reg->y_type = kMTLineWise;
|
||||
break;
|
||||
case 'b':
|
||||
case Ctrl_V:
|
||||
reg->y_type = kMTBlockWise;
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
lines = res;
|
||||
// provider did not specify regtype, calculate it below
|
||||
reg->y_type = kMTUnknown;
|
||||
}
|
||||
|
||||
reg->y_array = xcalloc((size_t)tv_list_len(lines), sizeof(String));
|
||||
reg->y_size = (size_t)tv_list_len(lines);
|
||||
reg->additional_data = NULL;
|
||||
reg->timestamp = 0;
|
||||
// Timestamp is not saved for clipboard registers because clipboard registers
|
||||
// are not saved in the ShaDa file.
|
||||
|
||||
size_t tv_idx = 0;
|
||||
TV_LIST_ITER_CONST(lines, li, {
|
||||
if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) {
|
||||
goto err;
|
||||
}
|
||||
const char *s = TV_LIST_ITEM_TV(li)->vval.v_string;
|
||||
reg->y_array[tv_idx++] = cstr_to_string(s != NULL ? s : "");
|
||||
});
|
||||
|
||||
if (reg->y_size > 0 && reg->y_array[reg->y_size - 1].size == 0) {
|
||||
// a known-to-be charwise yank might have a final linebreak
|
||||
// but otherwise there is no line after the final newline
|
||||
if (reg->y_type != kMTCharWise) {
|
||||
xfree(reg->y_array[reg->y_size - 1].data);
|
||||
reg->y_size--;
|
||||
if (reg->y_type == kMTUnknown) {
|
||||
reg->y_type = kMTLineWise;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (reg->y_type == kMTUnknown) {
|
||||
reg->y_type = kMTCharWise;
|
||||
}
|
||||
}
|
||||
|
||||
update_yankreg_width(reg);
|
||||
|
||||
*target = reg;
|
||||
return true;
|
||||
|
||||
err:
|
||||
if (reg->y_array) {
|
||||
for (size_t i = 0; i < reg->y_size; i++) {
|
||||
xfree(reg->y_array[i].data);
|
||||
}
|
||||
xfree(reg->y_array);
|
||||
}
|
||||
reg->y_array = NULL;
|
||||
reg->y_size = 0;
|
||||
reg->additional_data = NULL;
|
||||
reg->timestamp = 0;
|
||||
if (errmsg) {
|
||||
emsg("clipboard: provider returned invalid data");
|
||||
}
|
||||
*target = reg;
|
||||
return false;
|
||||
}
|
||||
|
||||
void set_clipboard(int name, yankreg_T *reg)
|
||||
{
|
||||
if (!adjust_clipboard_name(&name, false, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
list_T *const lines = tv_list_alloc((ptrdiff_t)reg->y_size + (reg->y_type != kMTCharWise));
|
||||
|
||||
for (size_t i = 0; i < reg->y_size; i++) {
|
||||
tv_list_append_string(lines, reg->y_array[i].data, -1);
|
||||
}
|
||||
|
||||
char regtype;
|
||||
switch (reg->y_type) {
|
||||
case kMTLineWise:
|
||||
regtype = 'V';
|
||||
tv_list_append_string(lines, NULL, 0);
|
||||
break;
|
||||
case kMTCharWise:
|
||||
regtype = 'v';
|
||||
break;
|
||||
case kMTBlockWise:
|
||||
regtype = 'b';
|
||||
tv_list_append_string(lines, NULL, 0);
|
||||
break;
|
||||
case kMTUnknown:
|
||||
abort();
|
||||
}
|
||||
|
||||
list_T *args = tv_list_alloc(3);
|
||||
tv_list_append_list(args, lines);
|
||||
tv_list_append_string(args, ®type, 1);
|
||||
tv_list_append_string(args, ((char[]) { (char)name }), 1);
|
||||
|
||||
eval_call_provider("clipboard", "set", args, true);
|
||||
}
|
||||
|
||||
/// Avoid slow things (clipboard) during batch operations (while/for-loops).
|
||||
void start_batch_changes(void)
|
||||
{
|
||||
if (++batch_change_count > 1) {
|
||||
return;
|
||||
}
|
||||
clipboard_delay_update = true;
|
||||
}
|
||||
|
||||
/// Counterpart to start_batch_changes().
|
||||
void end_batch_changes(void)
|
||||
{
|
||||
if (--batch_change_count > 0) {
|
||||
// recursive
|
||||
return;
|
||||
}
|
||||
clipboard_delay_update = false;
|
||||
if (clipboard_needs_update) {
|
||||
// must be before, as set_clipboard will invoke
|
||||
// start/end_batch_changes recursively
|
||||
clipboard_needs_update = false;
|
||||
// unnamed ("implicit" clipboard)
|
||||
set_clipboard(NUL, get_y_previous());
|
||||
}
|
||||
}
|
||||
|
||||
int save_batch_count(void)
|
||||
{
|
||||
int save_count = batch_change_count;
|
||||
batch_change_count = 0;
|
||||
clipboard_delay_update = false;
|
||||
if (clipboard_needs_update) {
|
||||
clipboard_needs_update = false;
|
||||
// unnamed ("implicit" clipboard)
|
||||
set_clipboard(NUL, get_y_previous());
|
||||
}
|
||||
return save_count;
|
||||
}
|
||||
|
||||
void restore_batch_count(int save_count)
|
||||
{
|
||||
assert(batch_change_count == 0);
|
||||
batch_change_count = save_count;
|
||||
if (batch_change_count > 0) {
|
||||
clipboard_delay_update = true;
|
||||
}
|
||||
}
|
7
src/nvim/clipboard.h
Normal file
7
src/nvim/clipboard.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "nvim/register_defs.h"
|
||||
|
||||
#include "clipboard.h.generated.h"
|
@@ -25,6 +25,7 @@
|
||||
#include "nvim/change.h"
|
||||
#include "nvim/channel.h"
|
||||
#include "nvim/charset.h"
|
||||
#include "nvim/clipboard.h"
|
||||
#include "nvim/cmdexpand.h"
|
||||
#include "nvim/cmdexpand_defs.h"
|
||||
#include "nvim/cursor.h"
|
||||
@@ -89,7 +90,6 @@
|
||||
#include "nvim/quickfix.h"
|
||||
#include "nvim/regexp.h"
|
||||
#include "nvim/regexp_defs.h"
|
||||
#include "nvim/register.h"
|
||||
#include "nvim/runtime.h"
|
||||
#include "nvim/runtime_defs.h"
|
||||
#include "nvim/search.h"
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include "nvim/buffer.h"
|
||||
#include "nvim/buffer_defs.h"
|
||||
#include "nvim/charset.h"
|
||||
#include "nvim/clipboard.h"
|
||||
#include "nvim/cmdexpand.h"
|
||||
#include "nvim/cmdexpand_defs.h"
|
||||
#include "nvim/cmdhist.h"
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include "nvim/buffer_updates.h"
|
||||
#include "nvim/change.h"
|
||||
#include "nvim/charset.h"
|
||||
#include "nvim/clipboard.h"
|
||||
#include "nvim/cursor.h"
|
||||
#include "nvim/drawscreen.h"
|
||||
#include "nvim/edit.h"
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include "nvim/buffer_updates.h"
|
||||
#include "nvim/change.h"
|
||||
#include "nvim/charset.h"
|
||||
#include "nvim/clipboard.h"
|
||||
#include "nvim/cursor.h"
|
||||
#include "nvim/drawscreen.h"
|
||||
#include "nvim/edit.h"
|
||||
@@ -54,12 +55,6 @@ static yankreg_T y_regs[NUM_REGISTERS] = { 0 };
|
||||
|
||||
static yankreg_T *y_previous = NULL; // ptr to last written yankreg
|
||||
|
||||
// for behavior between start_batch_changes() and end_batch_changes())
|
||||
static int batch_change_count = 0; // inside a script
|
||||
static bool clipboard_delay_update = false; // delay clipboard update
|
||||
static bool clipboard_needs_update = false; // clipboard was updated
|
||||
static bool clipboard_didwarn = false;
|
||||
|
||||
static const char e_search_pattern_and_expression_register_may_not_contain_two_or_more_lines[]
|
||||
= N_("E883: Search pattern and expression register may not contain two or more lines");
|
||||
|
||||
@@ -74,6 +69,12 @@ yankreg_T *get_y_register(int reg)
|
||||
return &y_regs[reg];
|
||||
}
|
||||
|
||||
yankreg_T *get_y_previous(void)
|
||||
FUNC_ATTR_PURE
|
||||
{
|
||||
return y_previous;
|
||||
}
|
||||
|
||||
/// Get an expression for the "\"=expr1" or "CTRL-R =expr1"
|
||||
///
|
||||
/// @return '=' when OK, NUL otherwise.
|
||||
@@ -170,91 +171,6 @@ int get_default_register_name(void)
|
||||
return name;
|
||||
}
|
||||
|
||||
void set_clipboard(int name, yankreg_T *reg)
|
||||
{
|
||||
if (!adjust_clipboard_name(&name, false, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
list_T *const lines = tv_list_alloc((ptrdiff_t)reg->y_size + (reg->y_type != kMTCharWise));
|
||||
|
||||
for (size_t i = 0; i < reg->y_size; i++) {
|
||||
tv_list_append_string(lines, reg->y_array[i].data, -1);
|
||||
}
|
||||
|
||||
char regtype;
|
||||
switch (reg->y_type) {
|
||||
case kMTLineWise:
|
||||
regtype = 'V';
|
||||
tv_list_append_string(lines, NULL, 0);
|
||||
break;
|
||||
case kMTCharWise:
|
||||
regtype = 'v';
|
||||
break;
|
||||
case kMTBlockWise:
|
||||
regtype = 'b';
|
||||
tv_list_append_string(lines, NULL, 0);
|
||||
break;
|
||||
case kMTUnknown:
|
||||
abort();
|
||||
}
|
||||
|
||||
list_T *args = tv_list_alloc(3);
|
||||
tv_list_append_list(args, lines);
|
||||
tv_list_append_string(args, ®type, 1);
|
||||
tv_list_append_string(args, ((char[]) { (char)name }), 1);
|
||||
|
||||
eval_call_provider("clipboard", "set", args, true);
|
||||
}
|
||||
|
||||
/// Avoid slow things (clipboard) during batch operations (while/for-loops).
|
||||
void start_batch_changes(void)
|
||||
{
|
||||
if (++batch_change_count > 1) {
|
||||
return;
|
||||
}
|
||||
clipboard_delay_update = true;
|
||||
}
|
||||
|
||||
/// Counterpart to start_batch_changes().
|
||||
void end_batch_changes(void)
|
||||
{
|
||||
if (--batch_change_count > 0) {
|
||||
// recursive
|
||||
return;
|
||||
}
|
||||
clipboard_delay_update = false;
|
||||
if (clipboard_needs_update) {
|
||||
// must be before, as set_clipboard will invoke
|
||||
// start/end_batch_changes recursively
|
||||
clipboard_needs_update = false;
|
||||
// unnamed ("implicit" clipboard)
|
||||
set_clipboard(NUL, y_previous);
|
||||
}
|
||||
}
|
||||
|
||||
int save_batch_count(void)
|
||||
{
|
||||
int save_count = batch_change_count;
|
||||
batch_change_count = 0;
|
||||
clipboard_delay_update = false;
|
||||
if (clipboard_needs_update) {
|
||||
clipboard_needs_update = false;
|
||||
// unnamed ("implicit" clipboard)
|
||||
set_clipboard(NUL, y_previous);
|
||||
}
|
||||
return save_count;
|
||||
}
|
||||
|
||||
void restore_batch_count(int save_count)
|
||||
{
|
||||
assert(batch_change_count == 0);
|
||||
batch_change_count = save_count;
|
||||
if (batch_change_count > 0) {
|
||||
clipboard_delay_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate over registers `regs`.
|
||||
///
|
||||
/// @param[in] iter Iterator. Pass NULL to start iteration.
|
||||
@@ -365,73 +281,9 @@ bool op_reg_set_previous(const char name)
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Determine if register `*name` should be used as a clipboard.
|
||||
/// In an unnamed operation, `*name` is `NUL` and will be adjusted to */+ if
|
||||
/// `clipboard=unnamed[plus]` is set.
|
||||
///
|
||||
/// @param name The name of register, or `NUL` if unnamed.
|
||||
/// @param quiet Suppress error messages
|
||||
/// @param writing if we're setting the contents of the clipboard
|
||||
///
|
||||
/// @returns the yankreg that should be written into, or `NULL`
|
||||
/// if the register isn't a clipboard or provider isn't available.
|
||||
static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing)
|
||||
{
|
||||
#define MSG_NO_CLIP "clipboard: No provider. " \
|
||||
"Try \":checkhealth\" or \":h clipboard\"."
|
||||
|
||||
yankreg_T *target = NULL;
|
||||
bool explicit_cb_reg = (*name == '*' || *name == '+');
|
||||
bool implicit_cb_reg = (*name == NUL) && (cb_flags & (kOptCbFlagUnnamed | kOptCbFlagUnnamedplus));
|
||||
if (!explicit_cb_reg && !implicit_cb_reg) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!eval_has_provider("clipboard", false)) {
|
||||
if (batch_change_count <= 1 && !quiet
|
||||
&& (!clipboard_didwarn || (explicit_cb_reg && !redirecting()))) {
|
||||
clipboard_didwarn = true;
|
||||
// Do NOT error (emsg()) here--if it interrupts :redir we get into
|
||||
// a weird state, stuck in "redirect mode".
|
||||
msg(MSG_NO_CLIP, 0);
|
||||
}
|
||||
// ... else, be silent (don't flood during :while, :redir, etc.).
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (explicit_cb_reg) {
|
||||
target = &y_regs[*name == '*' ? STAR_REGISTER : PLUS_REGISTER];
|
||||
if (writing && (cb_flags & (*name == '*' ? kOptCbFlagUnnamed : kOptCbFlagUnnamedplus))) {
|
||||
clipboard_needs_update = false;
|
||||
}
|
||||
goto end;
|
||||
} else { // unnamed register: "implicit" clipboard
|
||||
if (writing && clipboard_delay_update) {
|
||||
// For "set" (copy), defer the clipboard call.
|
||||
clipboard_needs_update = true;
|
||||
goto end;
|
||||
} else if (!writing && clipboard_needs_update) {
|
||||
// For "get" (paste), use the internal value.
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (cb_flags & kOptCbFlagUnnamedplus) {
|
||||
*name = (cb_flags & kOptCbFlagUnnamed && writing) ? '"' : '+';
|
||||
target = &y_regs[PLUS_REGISTER];
|
||||
} else {
|
||||
*name = '*';
|
||||
target = &y_regs[STAR_REGISTER];
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
return target;
|
||||
}
|
||||
|
||||
/// Updates the "y_width" of a blockwise register based on its contents.
|
||||
/// Do nothing on a non-blockwise register.
|
||||
static void update_yankreg_width(yankreg_T *reg)
|
||||
void update_yankreg_width(yankreg_T *reg)
|
||||
{
|
||||
if (reg->y_type == kMTBlockWise) {
|
||||
size_t maxlen = 0;
|
||||
@@ -444,123 +296,6 @@ static void update_yankreg_width(yankreg_T *reg)
|
||||
}
|
||||
}
|
||||
|
||||
static bool get_clipboard(int name, yankreg_T **target, bool quiet)
|
||||
{
|
||||
// show message on error
|
||||
bool errmsg = true;
|
||||
|
||||
yankreg_T *reg = adjust_clipboard_name(&name, quiet, false);
|
||||
if (reg == NULL) {
|
||||
return false;
|
||||
}
|
||||
free_register(reg);
|
||||
|
||||
list_T *const args = tv_list_alloc(1);
|
||||
const char regname = (char)name;
|
||||
tv_list_append_string(args, ®name, 1);
|
||||
|
||||
typval_T result = eval_call_provider("clipboard", "get", args, false);
|
||||
|
||||
if (result.v_type != VAR_LIST) {
|
||||
if (result.v_type == VAR_NUMBER && result.vval.v_number == 0) {
|
||||
// failure has already been indicated by provider
|
||||
errmsg = false;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_T *res = result.vval.v_list;
|
||||
list_T *lines = NULL;
|
||||
if (tv_list_len(res) == 2
|
||||
&& TV_LIST_ITEM_TV(tv_list_first(res))->v_type == VAR_LIST) {
|
||||
lines = TV_LIST_ITEM_TV(tv_list_first(res))->vval.v_list;
|
||||
if (TV_LIST_ITEM_TV(tv_list_last(res))->v_type != VAR_STRING) {
|
||||
goto err;
|
||||
}
|
||||
char *regtype = TV_LIST_ITEM_TV(tv_list_last(res))->vval.v_string;
|
||||
if (regtype == NULL || strlen(regtype) > 1) {
|
||||
goto err;
|
||||
}
|
||||
switch (regtype[0]) {
|
||||
case 0:
|
||||
reg->y_type = kMTUnknown;
|
||||
break;
|
||||
case 'v':
|
||||
case 'c':
|
||||
reg->y_type = kMTCharWise;
|
||||
break;
|
||||
case 'V':
|
||||
case 'l':
|
||||
reg->y_type = kMTLineWise;
|
||||
break;
|
||||
case 'b':
|
||||
case Ctrl_V:
|
||||
reg->y_type = kMTBlockWise;
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
lines = res;
|
||||
// provider did not specify regtype, calculate it below
|
||||
reg->y_type = kMTUnknown;
|
||||
}
|
||||
|
||||
reg->y_array = xcalloc((size_t)tv_list_len(lines), sizeof(String));
|
||||
reg->y_size = (size_t)tv_list_len(lines);
|
||||
reg->additional_data = NULL;
|
||||
reg->timestamp = 0;
|
||||
// Timestamp is not saved for clipboard registers because clipboard registers
|
||||
// are not saved in the ShaDa file.
|
||||
|
||||
size_t tv_idx = 0;
|
||||
TV_LIST_ITER_CONST(lines, li, {
|
||||
if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) {
|
||||
goto err;
|
||||
}
|
||||
const char *s = TV_LIST_ITEM_TV(li)->vval.v_string;
|
||||
reg->y_array[tv_idx++] = cstr_to_string(s != NULL ? s : "");
|
||||
});
|
||||
|
||||
if (reg->y_size > 0 && reg->y_array[reg->y_size - 1].size == 0) {
|
||||
// a known-to-be charwise yank might have a final linebreak
|
||||
// but otherwise there is no line after the final newline
|
||||
if (reg->y_type != kMTCharWise) {
|
||||
xfree(reg->y_array[reg->y_size - 1].data);
|
||||
reg->y_size--;
|
||||
if (reg->y_type == kMTUnknown) {
|
||||
reg->y_type = kMTLineWise;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (reg->y_type == kMTUnknown) {
|
||||
reg->y_type = kMTCharWise;
|
||||
}
|
||||
}
|
||||
|
||||
update_yankreg_width(reg);
|
||||
|
||||
*target = reg;
|
||||
return true;
|
||||
|
||||
err:
|
||||
if (reg->y_array) {
|
||||
for (size_t i = 0; i < reg->y_size; i++) {
|
||||
xfree(reg->y_array[i].data);
|
||||
}
|
||||
xfree(reg->y_array);
|
||||
}
|
||||
reg->y_array = NULL;
|
||||
reg->y_size = 0;
|
||||
reg->additional_data = NULL;
|
||||
reg->timestamp = 0;
|
||||
if (errmsg) {
|
||||
emsg("clipboard: provider returned invalid data");
|
||||
}
|
||||
*target = reg;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @return yankreg_T to use, according to the value of `regname`.
|
||||
/// Cannot handle the '_' (black hole) register.
|
||||
/// Must only be called with a valid register name!
|
||||
|
Reference in New Issue
Block a user