mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
commit
122426966e
@ -438,6 +438,42 @@ Example: create a float with scratch buffer: >
|
|||||||
call nvim_win_set_option(win, 'winhl', 'Normal:MyHighlight')
|
call nvim_win_set_option(win, 'winhl', 'Normal:MyHighlight')
|
||||||
>
|
>
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
Extended marks *api-extended-marks*
|
||||||
|
|
||||||
|
An extended mark (extmark) represents a buffer annotation that follows
|
||||||
|
movements as the buffer changes. They could be used to represent cursors,
|
||||||
|
folds, misspelled words, and anything else that needs to track a logical
|
||||||
|
location in the buffer over time.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
We will set an extmark at the first row and third column. As the API is zero-
|
||||||
|
indexed, use row and column counts 0 and 2:
|
||||||
|
|
||||||
|
`let g:mark_ns = nvim_create_namespace('myplugin')`
|
||||||
|
`let g:mark_id = nvim_buf_set_extmark(0, g:mark_ns, 0, 0, 2)`
|
||||||
|
|
||||||
|
Passing in id=0 creates a new mark and returns the id. we can look-up a mark
|
||||||
|
by its id:
|
||||||
|
|
||||||
|
`echo nvim_buf_get_extmark_by_id(0, g:mark_ns, g:mark_id)`
|
||||||
|
=> [0, 2]
|
||||||
|
|
||||||
|
Or we can look-up all marks in a buffer for our namespace (or by a range):
|
||||||
|
`echo nvim_buf_get_extmarks(0, g:mark_ns, 0, -1, -1)`
|
||||||
|
=> [[1, 0, 2]]
|
||||||
|
|
||||||
|
Deleting the text all around an extended mark does not remove it. If you want
|
||||||
|
to remove an extended mark, use the |nvim_buf_del_extmark()| function.
|
||||||
|
|
||||||
|
The namespace ensures your plugin doesn't have to deal with extmarks created
|
||||||
|
by another plugin.
|
||||||
|
|
||||||
|
Mark positions changed by an edit will be restored on undo/redo. Creating and
|
||||||
|
deleting marks doesn't count as a buffer change on itself, i e new undo
|
||||||
|
states will not be created only for marks.
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
Global Functions *api-global*
|
Global Functions *api-global*
|
||||||
|
|
||||||
@ -1747,6 +1783,86 @@ nvim_buf_get_mark({buffer}, {name}) *nvim_buf_get_mark()*
|
|||||||
Return: ~
|
Return: ~
|
||||||
(row, col) tuple
|
(row, col) tuple
|
||||||
|
|
||||||
|
*nvim_buf_get_extmark_by_id()*
|
||||||
|
nvim_buf_get_extmark_by_id({buffer}, {ns_id}, {id})
|
||||||
|
Returns position for a given extmark id
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
{buffer} The buffer handle
|
||||||
|
{namespace} a identifier returned previously with
|
||||||
|
nvim_create_namespace
|
||||||
|
{id} the extmark id
|
||||||
|
|
||||||
|
Return: ~
|
||||||
|
(row, col) tuple or empty list () if extmark id was absent
|
||||||
|
|
||||||
|
*nvim_buf_get_extmarks()*
|
||||||
|
nvim_buf_get_extmarks({buffer}, {ns_id}, {start}, {end}, {opts})
|
||||||
|
List extmarks in a range (inclusive)
|
||||||
|
|
||||||
|
range ends can be specified as (row, col) tuples, as well as
|
||||||
|
extmark ids in the same namespace. In addition, 0 and -1 works
|
||||||
|
as shorthands for (0,0) and (-1,-1) respectively, so that all
|
||||||
|
marks in the buffer can be quieried as:
|
||||||
|
|
||||||
|
all_marks = nvim_buf_get_extmarks(0, my_ns, 0, -1, -1)
|
||||||
|
|
||||||
|
If end is a lower position than start, then the range will be
|
||||||
|
traversed backwards. This is mostly used with limited amount,
|
||||||
|
to be able to get the first marks prior to a given position.
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
{buffer} The buffer handle
|
||||||
|
{ns_id} An id returned previously from
|
||||||
|
nvim_create_namespace
|
||||||
|
{lower} One of: extmark id, (row, col) or 0, -1 for
|
||||||
|
buffer ends
|
||||||
|
{upper} One of: extmark id, (row, col) or 0, -1 for
|
||||||
|
buffer ends
|
||||||
|
{opts} additional options. Supports the keys:
|
||||||
|
• amount: Maximum number of marks to return •
|
||||||
|
|
||||||
|
Return: ~
|
||||||
|
[[nsmark_id, row, col], ...]
|
||||||
|
|
||||||
|
*nvim_buf_set_extmark()*
|
||||||
|
nvim_buf_set_extmark({buffer}, {ns_id}, {id}, {line}, {col}, {opts})
|
||||||
|
Create or update an extmark at a position
|
||||||
|
|
||||||
|
If an invalid namespace is given, an error will be raised.
|
||||||
|
|
||||||
|
To create a new extmark, pass in id=0. The new extmark id will
|
||||||
|
be returned. To move an existing mark, pass in its id.
|
||||||
|
|
||||||
|
It is also allowed to create a new mark by passing in a
|
||||||
|
previously unused id, but the caller must then keep track of
|
||||||
|
existing and unused ids itself. This is mainly useful over
|
||||||
|
RPC, to avoid needing to wait for the return value.
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
{buffer} The buffer handle
|
||||||
|
{ns_id} a identifier returned previously with
|
||||||
|
nvim_create_namespace
|
||||||
|
{id} The extmark's id or 0 to create a new mark.
|
||||||
|
{row} The row to set the extmark to.
|
||||||
|
{col} The column to set the extmark to.
|
||||||
|
{opts} Optional parameters. Currently not used.
|
||||||
|
|
||||||
|
Return: ~
|
||||||
|
the id of the extmark.
|
||||||
|
|
||||||
|
nvim_buf_del_extmark({buffer}, {ns_id}, {id}) *nvim_buf_del_extmark()*
|
||||||
|
Remove an extmark
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
{buffer} The buffer handle
|
||||||
|
{ns_id} a identifier returned previously with
|
||||||
|
nvim_create_namespace
|
||||||
|
{id} The extmarks's id
|
||||||
|
|
||||||
|
Return: ~
|
||||||
|
true on success, false if the extmark was not found.
|
||||||
|
|
||||||
*nvim_buf_add_highlight()*
|
*nvim_buf_add_highlight()*
|
||||||
nvim_buf_add_highlight({buffer}, {ns_id}, {hl_group}, {line},
|
nvim_buf_add_highlight({buffer}, {ns_id}, {hl_group}, {line},
|
||||||
{col_start}, {col_end})
|
{col_start}, {col_end})
|
||||||
|
@ -23,7 +23,10 @@
|
|||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/misc1.h"
|
#include "nvim/misc1.h"
|
||||||
#include "nvim/ex_cmds.h"
|
#include "nvim/ex_cmds.h"
|
||||||
|
#include "nvim/map_defs.h"
|
||||||
|
#include "nvim/map.h"
|
||||||
#include "nvim/mark.h"
|
#include "nvim/mark.h"
|
||||||
|
#include "nvim/mark_extended.h"
|
||||||
#include "nvim/fileio.h"
|
#include "nvim/fileio.h"
|
||||||
#include "nvim/move.h"
|
#include "nvim/move.h"
|
||||||
#include "nvim/syntax.h"
|
#include "nvim/syntax.h"
|
||||||
@ -544,7 +547,8 @@ void nvim_buf_set_lines(uint64_t channel_id,
|
|||||||
(linenr_T)(end - 1),
|
(linenr_T)(end - 1),
|
||||||
MAXLNUM,
|
MAXLNUM,
|
||||||
(long)extra,
|
(long)extra,
|
||||||
false);
|
false,
|
||||||
|
kExtmarkUndo);
|
||||||
|
|
||||||
changed_lines((linenr_T)start, 0, (linenr_T)end, (long)extra, true);
|
changed_lines((linenr_T)start, 0, (linenr_T)end, (long)extra, true);
|
||||||
fix_cursor((linenr_T)start, (linenr_T)end, (linenr_T)extra);
|
fix_cursor((linenr_T)start, (linenr_T)end, (linenr_T)extra);
|
||||||
@ -999,6 +1003,240 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns position for a given extmark id
|
||||||
|
///
|
||||||
|
/// @param buffer The buffer handle
|
||||||
|
/// @param namespace a identifier returned previously with nvim_create_namespace
|
||||||
|
/// @param id the extmark id
|
||||||
|
/// @param[out] err Details of an error that may have occurred
|
||||||
|
/// @return (row, col) tuple or empty list () if extmark id was absent
|
||||||
|
ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
|
||||||
|
Integer id, Error *err)
|
||||||
|
FUNC_API_SINCE(7)
|
||||||
|
{
|
||||||
|
Array rv = ARRAY_DICT_INIT;
|
||||||
|
|
||||||
|
buf_T *buf = find_buffer_by_handle(buffer, err);
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ns_initialized((uint64_t)ns_id)) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, _("Invalid ns_id"));
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtendedMark *extmark = extmark_from_id(buf,
|
||||||
|
(uint64_t)ns_id,
|
||||||
|
(uint64_t)id);
|
||||||
|
if (!extmark) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
ADD(rv, INTEGER_OBJ((Integer)extmark->line->lnum-1));
|
||||||
|
ADD(rv, INTEGER_OBJ((Integer)extmark->col-1));
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List extmarks in a range (inclusive)
|
||||||
|
///
|
||||||
|
/// range ends can be specified as (row, col) tuples, as well as extmark
|
||||||
|
/// ids in the same namespace. In addition, 0 and -1 works as shorthands
|
||||||
|
/// for (0,0) and (-1,-1) respectively, so that all marks in the buffer can be
|
||||||
|
/// quieried as:
|
||||||
|
///
|
||||||
|
/// all_marks = nvim_buf_get_extmarks(0, my_ns, 0, -1, -1)
|
||||||
|
///
|
||||||
|
/// If end is a lower position than start, then the range will be traversed
|
||||||
|
/// backwards. This is mostly used with limited amount, to be able to get the
|
||||||
|
/// first marks prior to a given position.
|
||||||
|
///
|
||||||
|
/// @param buffer The buffer handle
|
||||||
|
/// @param ns_id An id returned previously from nvim_create_namespace
|
||||||
|
/// @param lower One of: extmark id, (row, col) or 0, -1 for buffer ends
|
||||||
|
/// @param upper One of: extmark id, (row, col) or 0, -1 for buffer ends
|
||||||
|
/// @param opts additional options. Supports the keys:
|
||||||
|
/// - amount: Maximum number of marks to return
|
||||||
|
/// @param[out] err Details of an error that may have occurred
|
||||||
|
/// @return [[nsmark_id, row, col], ...]
|
||||||
|
Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
|
||||||
|
Object start, Object end, Dictionary opts,
|
||||||
|
Error *err)
|
||||||
|
FUNC_API_SINCE(7)
|
||||||
|
{
|
||||||
|
Array rv = ARRAY_DICT_INIT;
|
||||||
|
|
||||||
|
buf_T *buf = find_buffer_by_handle(buffer, err);
|
||||||
|
if (!buf) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ns_initialized((uint64_t)ns_id)) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, _("Invalid ns_id"));
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
Integer amount = -1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < opts.size; i++) {
|
||||||
|
String k = opts.items[i].key;
|
||||||
|
Object *v = &opts.items[i].value;
|
||||||
|
if (strequal("amount", k.data)) {
|
||||||
|
if (v->type != kObjectTypeInteger) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "amount is not an integer");
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
amount = v->data.integer;
|
||||||
|
v->data.integer = LUA_NOREF;
|
||||||
|
} else {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amount == 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool reverse = false;
|
||||||
|
|
||||||
|
linenr_T l_lnum;
|
||||||
|
colnr_T l_col;
|
||||||
|
if (!set_extmark_index_from_obj(buf, ns_id, start, &l_lnum, &l_col, err)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
linenr_T u_lnum;
|
||||||
|
colnr_T u_col;
|
||||||
|
if (!set_extmark_index_from_obj(buf, ns_id, end, &u_lnum, &u_col, err)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l_lnum > u_lnum || (l_lnum == u_lnum && l_col > u_col)) {
|
||||||
|
reverse = true;
|
||||||
|
linenr_T tmp_lnum = l_lnum;
|
||||||
|
l_lnum = u_lnum;
|
||||||
|
u_lnum = tmp_lnum;
|
||||||
|
colnr_T tmp_col = l_col;
|
||||||
|
l_col = u_col;
|
||||||
|
u_col = tmp_col;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ExtmarkArray marks = extmark_get(buf, (uint64_t)ns_id, l_lnum, l_col,
|
||||||
|
u_lnum, u_col, (int64_t)amount,
|
||||||
|
reverse);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < kv_size(marks); i++) {
|
||||||
|
Array mark = ARRAY_DICT_INIT;
|
||||||
|
ExtendedMark *extmark = kv_A(marks, i);
|
||||||
|
ADD(mark, INTEGER_OBJ((Integer)extmark->mark_id));
|
||||||
|
ADD(mark, INTEGER_OBJ(extmark->line->lnum-1));
|
||||||
|
ADD(mark, INTEGER_OBJ(extmark->col-1));
|
||||||
|
ADD(rv, ARRAY_OBJ(mark));
|
||||||
|
}
|
||||||
|
|
||||||
|
kv_destroy(marks);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create or update an extmark at a position
|
||||||
|
///
|
||||||
|
/// If an invalid namespace is given, an error will be raised.
|
||||||
|
///
|
||||||
|
/// To create a new extmark, pass in id=0. The new extmark id will be
|
||||||
|
/// returned. To move an existing mark, pass in its id.
|
||||||
|
///
|
||||||
|
/// It is also allowed to create a new mark by passing in a previously unused
|
||||||
|
/// id, but the caller must then keep track of existing and unused ids itself.
|
||||||
|
/// This is mainly useful over RPC, to avoid needing to wait for the return
|
||||||
|
/// value.
|
||||||
|
///
|
||||||
|
/// @param buffer The buffer handle
|
||||||
|
/// @param ns_id a identifier returned previously with nvim_create_namespace
|
||||||
|
/// @param id The extmark's id or 0 to create a new mark.
|
||||||
|
/// @param row The row to set the extmark to.
|
||||||
|
/// @param col The column to set the extmark to.
|
||||||
|
/// @param opts Optional parameters. Currently not used.
|
||||||
|
/// @param[out] err Details of an error that may have occurred
|
||||||
|
/// @return the id of the extmark.
|
||||||
|
Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer id,
|
||||||
|
Integer line, Integer col,
|
||||||
|
Dictionary opts, Error *err)
|
||||||
|
FUNC_API_SINCE(7)
|
||||||
|
{
|
||||||
|
buf_T *buf = find_buffer_by_handle(buffer, err);
|
||||||
|
if (!buf) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ns_initialized((uint64_t)ns_id)) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, _("Invalid ns_id"));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.size > 0) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "opts dict isn't empty");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = 0;
|
||||||
|
if (line < 0 || line > buf->b_ml.ml_line_count) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "line value outside range");
|
||||||
|
return 0;
|
||||||
|
} else if (line < buf->b_ml.ml_line_count) {
|
||||||
|
len = STRLEN(ml_get_buf(curbuf, (linenr_T)line+1, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (col == -1) {
|
||||||
|
col = (Integer)len;
|
||||||
|
} else if (col < -1 || col > (Integer)len) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "col value outside range");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t id_num;
|
||||||
|
if (id == 0) {
|
||||||
|
id_num = extmark_free_id_get(buf, (uint64_t)ns_id);
|
||||||
|
} else if (id > 0) {
|
||||||
|
id_num = (uint64_t)id;
|
||||||
|
} else {
|
||||||
|
api_set_error(err, kErrorTypeValidation, _("Invalid mark id"));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extmark_set(buf, (uint64_t)ns_id, id_num,
|
||||||
|
(linenr_T)line+1, (colnr_T)col+1, kExtmarkUndo);
|
||||||
|
|
||||||
|
return (Integer)id_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove an extmark
|
||||||
|
///
|
||||||
|
/// @param buffer The buffer handle
|
||||||
|
/// @param ns_id a identifier returned previously with nvim_create_namespace
|
||||||
|
/// @param id The extmarks's id
|
||||||
|
/// @param[out] err Details of an error that may have occurred
|
||||||
|
/// @return true on success, false if the extmark was not found.
|
||||||
|
Boolean nvim_buf_del_extmark(Buffer buffer,
|
||||||
|
Integer ns_id,
|
||||||
|
Integer id,
|
||||||
|
Error *err)
|
||||||
|
FUNC_API_SINCE(7)
|
||||||
|
{
|
||||||
|
buf_T *buf = find_buffer_by_handle(buffer, err);
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!ns_initialized((uint64_t)ns_id)) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, _("Invalid ns_id"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return extmark_del(buf, (uint64_t)ns_id, (uint64_t)id, kExtmarkUndo);
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds a highlight to buffer.
|
/// Adds a highlight to buffer.
|
||||||
///
|
///
|
||||||
/// Useful for plugins that dynamically generate highlights to a buffer
|
/// Useful for plugins that dynamically generate highlights to a buffer
|
||||||
@ -1097,6 +1335,10 @@ void nvim_buf_clear_namespace(Buffer buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bufhl_clear_line_range(buf, (int)ns_id, (int)line_start+1, (int)line_end);
|
bufhl_clear_line_range(buf, (int)ns_id, (int)line_start+1, (int)line_end);
|
||||||
|
extmark_clear(buf, ns_id == -1 ? 0 : (uint64_t)ns_id,
|
||||||
|
(linenr_T)line_start+1,
|
||||||
|
(linenr_T)line_end,
|
||||||
|
kExtmarkUndo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clears highlights and virtual text from namespace and range of lines
|
/// Clears highlights and virtual text from namespace and range of lines
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "nvim/api/private/helpers.h"
|
#include "nvim/api/private/helpers.h"
|
||||||
#include "nvim/api/private/defs.h"
|
#include "nvim/api/private/defs.h"
|
||||||
#include "nvim/api/private/handle.h"
|
#include "nvim/api/private/handle.h"
|
||||||
|
#include "nvim/api/vim.h"
|
||||||
#include "nvim/msgpack_rpc/helpers.h"
|
#include "nvim/msgpack_rpc/helpers.h"
|
||||||
#include "nvim/lua/executor.h"
|
#include "nvim/lua/executor.h"
|
||||||
#include "nvim/ascii.h"
|
#include "nvim/ascii.h"
|
||||||
@ -23,6 +24,7 @@
|
|||||||
#include "nvim/eval/typval.h"
|
#include "nvim/eval/typval.h"
|
||||||
#include "nvim/map_defs.h"
|
#include "nvim/map_defs.h"
|
||||||
#include "nvim/map.h"
|
#include "nvim/map.h"
|
||||||
|
#include "nvim/mark_extended.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
#include "nvim/option_defs.h"
|
#include "nvim/option_defs.h"
|
||||||
#include "nvim/version.h"
|
#include "nvim/version.h"
|
||||||
@ -1505,3 +1507,131 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf)
|
|||||||
|
|
||||||
return mappings;
|
return mappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns an extmark given an id or a positional index
|
||||||
|
// If throw == true then an error will be raised if nothing
|
||||||
|
// was found
|
||||||
|
// Returns NULL if something went wrong
|
||||||
|
ExtendedMark *extmark_from_id_or_pos(Buffer buffer,
|
||||||
|
Integer namespace,
|
||||||
|
Object id,
|
||||||
|
Error *err,
|
||||||
|
bool throw)
|
||||||
|
{
|
||||||
|
buf_T *buf = find_buffer_by_handle(buffer, err);
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtendedMark *extmark = NULL;
|
||||||
|
if (id.type == kObjectTypeArray) {
|
||||||
|
if (id.data.array.size != 2) {
|
||||||
|
api_set_error(err, kErrorTypeValidation,
|
||||||
|
_("Position must have 2 elements"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
linenr_T row = (linenr_T)id.data.array.items[0].data.integer;
|
||||||
|
colnr_T col = (colnr_T)id.data.array.items[1].data.integer;
|
||||||
|
if (row < 1 || col < 1) {
|
||||||
|
if (throw) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, _("Row and column MUST be > 0"));
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
extmark = extmark_from_pos(buf, (uint64_t)namespace, row, col);
|
||||||
|
} else if (id.type != kObjectTypeInteger) {
|
||||||
|
if (throw) {
|
||||||
|
api_set_error(err, kErrorTypeValidation,
|
||||||
|
_("Mark id must be an int or [row, col]"));
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
} else if (id.data.integer < 0) {
|
||||||
|
if (throw) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, _("Mark id must be positive"));
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
extmark = extmark_from_id(buf,
|
||||||
|
(uint64_t)namespace,
|
||||||
|
(uint64_t)id.data.integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!extmark) {
|
||||||
|
if (throw) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, _("Mark doesn't exist"));
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return extmark;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the Namespace in use?
|
||||||
|
bool ns_initialized(uint64_t ns)
|
||||||
|
{
|
||||||
|
if (ns < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ns < (uint64_t)next_namespace_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get line and column from extmark object
|
||||||
|
///
|
||||||
|
/// Extmarks may be queried from position or name or even special names
|
||||||
|
/// in the future such as "cursor". This function sets the line and col
|
||||||
|
/// to make the extmark functions recognize what's required
|
||||||
|
///
|
||||||
|
/// @param[out] lnum lnum to be set
|
||||||
|
/// @param[out] colnr col to be set
|
||||||
|
bool set_extmark_index_from_obj(buf_T *buf, Integer namespace,
|
||||||
|
Object obj, linenr_T *lnum, colnr_T *colnr,
|
||||||
|
Error *err)
|
||||||
|
{
|
||||||
|
// Check if it is mark id
|
||||||
|
if (obj.type == kObjectTypeInteger) {
|
||||||
|
Integer id = obj.data.integer;
|
||||||
|
if (id == 0) {
|
||||||
|
*lnum = 1;
|
||||||
|
*colnr = 1;
|
||||||
|
return true;
|
||||||
|
} else if (id == -1) {
|
||||||
|
*lnum = MAXLNUM;
|
||||||
|
*colnr = MAXCOL;
|
||||||
|
return true;
|
||||||
|
} else if (id < 0) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, _("Mark id must be positive"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtendedMark *extmark = extmark_from_id(buf, (uint64_t)namespace,
|
||||||
|
(uint64_t)id);
|
||||||
|
if (extmark) {
|
||||||
|
*lnum = extmark->line->lnum;
|
||||||
|
*colnr = extmark->col;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
api_set_error(err, kErrorTypeValidation, _("No mark with requested id"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it is a position
|
||||||
|
} else if (obj.type == kObjectTypeArray) {
|
||||||
|
Array pos = obj.data.array;
|
||||||
|
if (pos.size != 2
|
||||||
|
|| pos.items[0].type != kObjectTypeInteger
|
||||||
|
|| pos.items[1].type != kObjectTypeInteger) {
|
||||||
|
api_set_error(err, kErrorTypeValidation,
|
||||||
|
_("Position must have 2 integer elements"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Integer line = pos.items[0].data.integer;
|
||||||
|
Integer col = pos.items[1].data.integer;
|
||||||
|
*lnum = (linenr_T)(line >= 0 ? line + 1 : MAXLNUM);
|
||||||
|
*colnr = (colnr_T)(col >= 0 ? col + 1 : MAXCOL);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
api_set_error(err, kErrorTypeValidation,
|
||||||
|
_("Position must be a mark id Integer or position Array"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "nvim/ops.h"
|
#include "nvim/ops.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
#include "nvim/state.h"
|
#include "nvim/state.h"
|
||||||
|
#include "nvim/mark_extended.h"
|
||||||
#include "nvim/syntax.h"
|
#include "nvim/syntax.h"
|
||||||
#include "nvim/getchar.h"
|
#include "nvim/getchar.h"
|
||||||
#include "nvim/os/input.h"
|
#include "nvim/os/input.h"
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#include "nvim/indent_c.h"
|
#include "nvim/indent_c.h"
|
||||||
#include "nvim/main.h"
|
#include "nvim/main.h"
|
||||||
#include "nvim/mark.h"
|
#include "nvim/mark.h"
|
||||||
|
#include "nvim/mark_extended.h"
|
||||||
#include "nvim/mbyte.h"
|
#include "nvim/mbyte.h"
|
||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
@ -816,6 +817,7 @@ static void free_buffer_stuff(buf_T *buf, int free_flags)
|
|||||||
}
|
}
|
||||||
uc_clear(&buf->b_ucmds); // clear local user commands
|
uc_clear(&buf->b_ucmds); // clear local user commands
|
||||||
buf_delete_signs(buf, (char_u *)"*"); // delete any signs
|
buf_delete_signs(buf, (char_u *)"*"); // delete any signs
|
||||||
|
extmark_free_all(buf); // delete any extmarks
|
||||||
bufhl_clear_all(buf); // delete any highligts
|
bufhl_clear_all(buf); // delete any highligts
|
||||||
map_clear_int(buf, MAP_ALL_MODES, true, false); // clear local mappings
|
map_clear_int(buf, MAP_ALL_MODES, true, false); // clear local mappings
|
||||||
map_clear_int(buf, MAP_ALL_MODES, true, true); // clear local abbrevs
|
map_clear_int(buf, MAP_ALL_MODES, true, true); // clear local abbrevs
|
||||||
@ -5496,6 +5498,7 @@ void bufhl_clear_line_range(buf_T *buf,
|
|||||||
linenr_T line_start,
|
linenr_T line_start,
|
||||||
linenr_T line_end)
|
linenr_T line_end)
|
||||||
{
|
{
|
||||||
|
// TODO(bfredl): implement kb_itr_interval to jump directly to the first line
|
||||||
kbitr_t(bufhl) itr;
|
kbitr_t(bufhl) itr;
|
||||||
BufhlLine *l, t = BUFHLLINE_INIT(line_start);
|
BufhlLine *l, t = BUFHLLINE_INIT(line_start);
|
||||||
if (!kb_itr_get(bufhl, &buf->b_bufhl_info, &t, &itr)) {
|
if (!kb_itr_get(bufhl, &buf->b_bufhl_info, &t, &itr)) {
|
||||||
|
@ -115,6 +115,9 @@ typedef uint16_t disptick_T; // display tick type
|
|||||||
#include "nvim/os/fs_defs.h" // for FileID
|
#include "nvim/os/fs_defs.h" // for FileID
|
||||||
#include "nvim/terminal.h" // for Terminal
|
#include "nvim/terminal.h" // for Terminal
|
||||||
|
|
||||||
|
#include "nvim/lib/kbtree.h"
|
||||||
|
#include "nvim/mark_extended.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The taggy struct is used to store the information about a :tag command.
|
* The taggy struct is used to store the information about a :tag command.
|
||||||
*/
|
*/
|
||||||
@ -805,6 +808,10 @@ struct file_buffer {
|
|||||||
|
|
||||||
kvec_t(BufhlLine *) b_bufhl_move_space; // temporary space for highlights
|
kvec_t(BufhlLine *) b_bufhl_move_space; // temporary space for highlights
|
||||||
|
|
||||||
|
PMap(uint64_t) *b_extmark_ns; // extmark namespaces
|
||||||
|
kbtree_t(extmarklines) b_extlines; // extmarks
|
||||||
|
kvec_t(ExtMarkLine *) b_extmark_move_space; // temp space for extmarks
|
||||||
|
|
||||||
// array of channel_id:s which have asked to receive updates for this
|
// array of channel_id:s which have asked to receive updates for this
|
||||||
// buffer.
|
// buffer.
|
||||||
kvec_t(uint64_t) update_channels;
|
kvec_t(uint64_t) update_channels;
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "nvim/indent.h"
|
#include "nvim/indent.h"
|
||||||
#include "nvim/indent_c.h"
|
#include "nvim/indent_c.h"
|
||||||
#include "nvim/mark.h"
|
#include "nvim/mark.h"
|
||||||
|
#include "nvim/mark_extended.h"
|
||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/misc1.h"
|
#include "nvim/misc1.h"
|
||||||
#include "nvim/move.h"
|
#include "nvim/move.h"
|
||||||
@ -372,7 +373,7 @@ void appended_lines_mark(linenr_T lnum, long count)
|
|||||||
// Skip mark_adjust when adding a line after the last one, there can't
|
// Skip mark_adjust when adding a line after the last one, there can't
|
||||||
// be marks there. But it's still needed in diff mode.
|
// be marks there. But it's still needed in diff mode.
|
||||||
if (lnum + count < curbuf->b_ml.ml_line_count || curwin->w_p_diff) {
|
if (lnum + count < curbuf->b_ml.ml_line_count || curwin->w_p_diff) {
|
||||||
mark_adjust(lnum + 1, (linenr_T)MAXLNUM, count, 0L, false);
|
mark_adjust(lnum + 1, (linenr_T)MAXLNUM, count, 0L, false, kExtmarkUndo);
|
||||||
}
|
}
|
||||||
changed_lines(lnum + 1, 0, lnum + 1, count, true);
|
changed_lines(lnum + 1, 0, lnum + 1, count, true);
|
||||||
}
|
}
|
||||||
@ -390,7 +391,8 @@ void deleted_lines(linenr_T lnum, long count)
|
|||||||
/// be triggered to display the cursor.
|
/// be triggered to display the cursor.
|
||||||
void deleted_lines_mark(linenr_T lnum, long count)
|
void deleted_lines_mark(linenr_T lnum, long count)
|
||||||
{
|
{
|
||||||
mark_adjust(lnum, (linenr_T)(lnum + count - 1), (long)MAXLNUM, -count, false);
|
mark_adjust(lnum, (linenr_T)(lnum + count - 1), (long)MAXLNUM, -count, false,
|
||||||
|
kExtmarkUndo);
|
||||||
changed_lines(lnum, 0, lnum + count, -count, true);
|
changed_lines(lnum, 0, lnum + count, -count, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -951,6 +953,9 @@ int open_line(
|
|||||||
bool did_append; // appended a new line
|
bool did_append; // appended a new line
|
||||||
int saved_pi = curbuf->b_p_pi; // copy of preserveindent setting
|
int saved_pi = curbuf->b_p_pi; // copy of preserveindent setting
|
||||||
|
|
||||||
|
linenr_T lnum = curwin->w_cursor.lnum;
|
||||||
|
colnr_T mincol = curwin->w_cursor.col + 1;
|
||||||
|
|
||||||
// make a copy of the current line so we can mess with it
|
// make a copy of the current line so we can mess with it
|
||||||
char_u *saved_line = vim_strsave(get_cursor_line_ptr());
|
char_u *saved_line = vim_strsave(get_cursor_line_ptr());
|
||||||
|
|
||||||
@ -1574,7 +1579,8 @@ int open_line(
|
|||||||
// be marks there. But still needed in diff mode.
|
// be marks there. But still needed in diff mode.
|
||||||
if (curwin->w_cursor.lnum + 1 < curbuf->b_ml.ml_line_count
|
if (curwin->w_cursor.lnum + 1 < curbuf->b_ml.ml_line_count
|
||||||
|| curwin->w_p_diff) {
|
|| curwin->w_p_diff) {
|
||||||
mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L, false);
|
mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L, false,
|
||||||
|
kExtmarkUndo);
|
||||||
}
|
}
|
||||||
did_append = true;
|
did_append = true;
|
||||||
} else {
|
} else {
|
||||||
@ -1663,8 +1669,12 @@ int open_line(
|
|||||||
if (flags & OPENLINE_MARKFIX) {
|
if (flags & OPENLINE_MARKFIX) {
|
||||||
mark_col_adjust(curwin->w_cursor.lnum,
|
mark_col_adjust(curwin->w_cursor.lnum,
|
||||||
curwin->w_cursor.col + less_cols_off,
|
curwin->w_cursor.col + less_cols_off,
|
||||||
1L, (long)-less_cols, 0);
|
1L, (long)-less_cols, 0, kExtmarkNOOP);
|
||||||
}
|
}
|
||||||
|
// Always move extmarks - Here we move only the line where the
|
||||||
|
// cursor is, the previous mark_adjust takes care of the lines after
|
||||||
|
extmark_col_adjust(curbuf, lnum, mincol, 1L, (long)-less_cols,
|
||||||
|
kExtmarkUndo);
|
||||||
} else {
|
} else {
|
||||||
changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
|
changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
|
||||||
}
|
}
|
||||||
|
@ -2690,7 +2690,8 @@ void ex_diffgetput(exarg_T *eap)
|
|||||||
|
|
||||||
// Adjust marks. This will change the following entries!
|
// Adjust marks. This will change the following entries!
|
||||||
if (added != 0) {
|
if (added != 0) {
|
||||||
mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, (long)added, false);
|
mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, (long)added, false,
|
||||||
|
kExtmarkUndo);
|
||||||
if (curwin->w_cursor.lnum >= lnum) {
|
if (curwin->w_cursor.lnum >= lnum) {
|
||||||
// Adjust the cursor position if it's in/after the changed
|
// Adjust the cursor position if it's in/after the changed
|
||||||
// lines.
|
// lines.
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "nvim/indent.h"
|
#include "nvim/indent.h"
|
||||||
#include "nvim/indent_c.h"
|
#include "nvim/indent_c.h"
|
||||||
#include "nvim/main.h"
|
#include "nvim/main.h"
|
||||||
|
#include "nvim/mark_extended.h"
|
||||||
#include "nvim/mbyte.h"
|
#include "nvim/mbyte.h"
|
||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
@ -1837,6 +1838,13 @@ change_indent (
|
|||||||
|
|
||||||
xfree(new_line);
|
xfree(new_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// change_indent seems to bec called twice, this combination only triggers
|
||||||
|
// once for both calls
|
||||||
|
if (new_cursor_col - vcol != 0) {
|
||||||
|
extmark_col_adjust(curbuf, curwin->w_cursor.lnum, 0, 0, amount,
|
||||||
|
kExtmarkUndo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -5587,6 +5595,9 @@ insertchar (
|
|||||||
do_digraph(buf[i-1]); /* may be the start of a digraph */
|
do_digraph(buf[i-1]); /* may be the start of a digraph */
|
||||||
buf[i] = NUL;
|
buf[i] = NUL;
|
||||||
ins_str(buf);
|
ins_str(buf);
|
||||||
|
extmark_col_adjust(curbuf, curwin->w_cursor.lnum,
|
||||||
|
(colnr_T)(curwin->w_cursor.col + 1), 0,
|
||||||
|
(long)STRLEN(buf), kExtmarkUndo);
|
||||||
if (flags & INSCHAR_CTRLV) {
|
if (flags & INSCHAR_CTRLV) {
|
||||||
redo_literal(*buf);
|
redo_literal(*buf);
|
||||||
i = 1;
|
i = 1;
|
||||||
@ -5597,6 +5608,9 @@ insertchar (
|
|||||||
} else {
|
} else {
|
||||||
int cc;
|
int cc;
|
||||||
|
|
||||||
|
extmark_col_adjust(curbuf, curwin->w_cursor.lnum,
|
||||||
|
(colnr_T)(curwin->w_cursor.col + 1), 0,
|
||||||
|
1, kExtmarkUndo);
|
||||||
if ((cc = utf_char2len(c)) > 1) {
|
if ((cc = utf_char2len(c)) > 1) {
|
||||||
char_u buf[MB_MAXBYTES + 1];
|
char_u buf[MB_MAXBYTES + 1];
|
||||||
|
|
||||||
@ -5606,10 +5620,11 @@ insertchar (
|
|||||||
AppendCharToRedobuff(c);
|
AppendCharToRedobuff(c);
|
||||||
} else {
|
} else {
|
||||||
ins_char(c);
|
ins_char(c);
|
||||||
if (flags & INSCHAR_CTRLV)
|
if (flags & INSCHAR_CTRLV) {
|
||||||
redo_literal(c);
|
redo_literal(c);
|
||||||
else
|
} else {
|
||||||
AppendCharToRedobuff(c);
|
AppendCharToRedobuff(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6891,8 +6906,9 @@ static void mb_replace_pop_ins(int cc)
|
|||||||
for (i = 1; i < n; ++i)
|
for (i = 1; i < n; ++i)
|
||||||
buf[i] = replace_pop();
|
buf[i] = replace_pop();
|
||||||
ins_bytes_len(buf, n);
|
ins_bytes_len(buf, n);
|
||||||
} else
|
} else {
|
||||||
ins_char(cc);
|
ins_char(cc);
|
||||||
|
}
|
||||||
|
|
||||||
if (enc_utf8)
|
if (enc_utf8)
|
||||||
/* Handle composing chars. */
|
/* Handle composing chars. */
|
||||||
@ -8002,9 +8018,9 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
|
|||||||
Insstart_orig.col = curwin->w_cursor.col;
|
Insstart_orig.col = curwin->w_cursor.col;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (State & VREPLACE_FLAG)
|
if (State & VREPLACE_FLAG) {
|
||||||
ins_char(' ');
|
ins_char(' ');
|
||||||
else {
|
} else {
|
||||||
ins_str((char_u *)" ");
|
ins_str((char_u *)" ");
|
||||||
if ((State & REPLACE_FLAG))
|
if ((State & REPLACE_FLAG))
|
||||||
replace_push(NUL);
|
replace_push(NUL);
|
||||||
@ -8482,8 +8498,17 @@ static bool ins_tab(void)
|
|||||||
} else { // otherwise use "tabstop"
|
} else { // otherwise use "tabstop"
|
||||||
temp = (int)curbuf->b_p_ts;
|
temp = (int)curbuf->b_p_ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
temp -= get_nolist_virtcol() % temp;
|
temp -= get_nolist_virtcol() % temp;
|
||||||
|
|
||||||
|
// Move extmarks
|
||||||
|
extmark_col_adjust(curbuf,
|
||||||
|
curwin->w_cursor.lnum,
|
||||||
|
curwin->w_cursor.col,
|
||||||
|
0,
|
||||||
|
temp,
|
||||||
|
kExtmarkUndo);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Insert the first space with ins_char(). It will delete one char in
|
* Insert the first space with ins_char(). It will delete one char in
|
||||||
* replace mode. Insert the rest with ins_str(); it will not delete any
|
* replace mode. Insert the rest with ins_str(); it will not delete any
|
||||||
@ -8491,12 +8516,13 @@ static bool ins_tab(void)
|
|||||||
*/
|
*/
|
||||||
ins_char(' ');
|
ins_char(' ');
|
||||||
while (--temp > 0) {
|
while (--temp > 0) {
|
||||||
if (State & VREPLACE_FLAG)
|
if (State & VREPLACE_FLAG) {
|
||||||
ins_char(' ');
|
ins_char(' ');
|
||||||
else {
|
} else {
|
||||||
ins_str((char_u *)" ");
|
ins_str((char_u *)" ");
|
||||||
if (State & REPLACE_FLAG) /* no char replaced */
|
if (State & REPLACE_FLAG) { // no char replaced
|
||||||
replace_push(NUL);
|
replace_push(NUL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "nvim/buffer_updates.h"
|
#include "nvim/buffer_updates.h"
|
||||||
#include "nvim/main.h"
|
#include "nvim/main.h"
|
||||||
#include "nvim/mark.h"
|
#include "nvim/mark.h"
|
||||||
|
#include "nvim/mark_extended.h"
|
||||||
#include "nvim/mbyte.h"
|
#include "nvim/mbyte.h"
|
||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/message.h"
|
#include "nvim/message.h"
|
||||||
@ -658,10 +659,10 @@ void ex_sort(exarg_T *eap)
|
|||||||
deleted = (long)(count - (lnum - eap->line2));
|
deleted = (long)(count - (lnum - eap->line2));
|
||||||
if (deleted > 0) {
|
if (deleted > 0) {
|
||||||
mark_adjust(eap->line2 - deleted, eap->line2, (long)MAXLNUM, -deleted,
|
mark_adjust(eap->line2 - deleted, eap->line2, (long)MAXLNUM, -deleted,
|
||||||
false);
|
false, kExtmarkUndo);
|
||||||
msgmore(-deleted);
|
msgmore(-deleted);
|
||||||
} else if (deleted < 0) {
|
} else if (deleted < 0) {
|
||||||
mark_adjust(eap->line2, MAXLNUM, -deleted, 0L, false);
|
mark_adjust(eap->line2, MAXLNUM, -deleted, 0L, false, kExtmarkUndo);
|
||||||
}
|
}
|
||||||
if (change_occurred || deleted != 0) {
|
if (change_occurred || deleted != 0) {
|
||||||
changed_lines(eap->line1, 0, eap->line2 + 1, -deleted, true);
|
changed_lines(eap->line1, 0, eap->line2 + 1, -deleted, true);
|
||||||
@ -874,10 +875,12 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
|
|||||||
* their final destination at the new text position -- webb
|
* their final destination at the new text position -- webb
|
||||||
*/
|
*/
|
||||||
last_line = curbuf->b_ml.ml_line_count;
|
last_line = curbuf->b_ml.ml_line_count;
|
||||||
mark_adjust_nofold(line1, line2, last_line - line2, 0L, true);
|
mark_adjust_nofold(line1, line2, last_line - line2, 0L, true, kExtmarkNoUndo);
|
||||||
|
extmark_adjust(curbuf, line1, line2, last_line - line2, 0L, kExtmarkNoUndo,
|
||||||
|
true);
|
||||||
changed_lines(last_line - num_lines + 1, 0, last_line + 1, num_lines, false);
|
changed_lines(last_line - num_lines + 1, 0, last_line + 1, num_lines, false);
|
||||||
if (dest >= line2) {
|
if (dest >= line2) {
|
||||||
mark_adjust_nofold(line2 + 1, dest, -num_lines, 0L, false);
|
mark_adjust_nofold(line2 + 1, dest, -num_lines, 0L, false, kExtmarkNoUndo);
|
||||||
FOR_ALL_TAB_WINDOWS(tab, win) {
|
FOR_ALL_TAB_WINDOWS(tab, win) {
|
||||||
if (win->w_buffer == curbuf) {
|
if (win->w_buffer == curbuf) {
|
||||||
foldMoveRange(&win->w_folds, line1, line2, dest);
|
foldMoveRange(&win->w_folds, line1, line2, dest);
|
||||||
@ -886,7 +889,8 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
|
|||||||
curbuf->b_op_start.lnum = dest - num_lines + 1;
|
curbuf->b_op_start.lnum = dest - num_lines + 1;
|
||||||
curbuf->b_op_end.lnum = dest;
|
curbuf->b_op_end.lnum = dest;
|
||||||
} else {
|
} else {
|
||||||
mark_adjust_nofold(dest + 1, line1 - 1, num_lines, 0L, false);
|
mark_adjust_nofold(dest + 1, line1 - 1, num_lines, 0L, false,
|
||||||
|
kExtmarkNoUndo);
|
||||||
FOR_ALL_TAB_WINDOWS(tab, win) {
|
FOR_ALL_TAB_WINDOWS(tab, win) {
|
||||||
if (win->w_buffer == curbuf) {
|
if (win->w_buffer == curbuf) {
|
||||||
foldMoveRange(&win->w_folds, dest + 1, line1 - 1, line2);
|
foldMoveRange(&win->w_folds, dest + 1, line1 - 1, line2);
|
||||||
@ -897,7 +901,9 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
|
|||||||
}
|
}
|
||||||
curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
|
curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
|
||||||
mark_adjust_nofold(last_line - num_lines + 1, last_line,
|
mark_adjust_nofold(last_line - num_lines + 1, last_line,
|
||||||
-(last_line - dest - extra), 0L, true);
|
-(last_line - dest - extra), 0L, true, kExtmarkNoUndo);
|
||||||
|
|
||||||
|
u_extmark_move(curbuf, line1, line2, last_line, dest, num_lines, extra);
|
||||||
changed_lines(last_line - num_lines + 1, 0, last_line + 1, -extra, false);
|
changed_lines(last_line - num_lines + 1, 0, last_line + 1, -extra, false);
|
||||||
|
|
||||||
// send update regarding the new lines that were added
|
// send update regarding the new lines that were added
|
||||||
@ -1281,12 +1287,14 @@ static void do_filter(
|
|||||||
if (cmdmod.keepmarks || vim_strchr(p_cpo, CPO_REMMARK) == NULL) {
|
if (cmdmod.keepmarks || vim_strchr(p_cpo, CPO_REMMARK) == NULL) {
|
||||||
if (read_linecount >= linecount) {
|
if (read_linecount >= linecount) {
|
||||||
// move all marks from old lines to new lines
|
// move all marks from old lines to new lines
|
||||||
mark_adjust(line1, line2, linecount, 0L, false);
|
mark_adjust(line1, line2, linecount, 0L, false, kExtmarkUndo);
|
||||||
} else {
|
} else {
|
||||||
// move marks from old lines to new lines, delete marks
|
// move marks from old lines to new lines, delete marks
|
||||||
// that are in deleted lines
|
// that are in deleted lines
|
||||||
mark_adjust(line1, line1 + read_linecount - 1, linecount, 0L, false);
|
mark_adjust(line1, line1 + read_linecount - 1, linecount, 0L, false,
|
||||||
mark_adjust(line1 + read_linecount, line2, MAXLNUM, 0L, false);
|
kExtmarkUndo);
|
||||||
|
mark_adjust(line1 + read_linecount, line2, MAXLNUM, 0L, false,
|
||||||
|
kExtmarkUndo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3214,6 +3222,189 @@ static char_u *sub_parse_flags(char_u *cmd, subflags_T *subflags,
|
|||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void extmark_move_regmatch_single(lpos_T startpos,
|
||||||
|
lpos_T endpos,
|
||||||
|
linenr_T lnum,
|
||||||
|
int sublen)
|
||||||
|
{
|
||||||
|
colnr_T mincol;
|
||||||
|
colnr_T endcol;
|
||||||
|
colnr_T col_amount;
|
||||||
|
|
||||||
|
mincol = startpos.col + 1;
|
||||||
|
endcol = endpos.col + 1;
|
||||||
|
|
||||||
|
// There are cases such as :s/^/x/ where this happens
|
||||||
|
// a delete is simply not required.
|
||||||
|
if (mincol + 1 <= endcol) {
|
||||||
|
extmark_col_adjust_delete(curbuf,
|
||||||
|
lnum, mincol + 1, endcol, kExtmarkUndo, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert, sublen seems to be the value we need but + 1...
|
||||||
|
col_amount = sublen - 1;
|
||||||
|
extmark_col_adjust(curbuf, lnum, mincol, 0, col_amount, kExtmarkUndo);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void extmark_move_regmatch_multi(ExtmarkSubMulti s, long i)
|
||||||
|
{
|
||||||
|
colnr_T mincol;
|
||||||
|
linenr_T u_lnum;
|
||||||
|
mincol = s.startpos.col + 1;
|
||||||
|
|
||||||
|
linenr_T n_u_lnum = s.lnum + s.endpos.lnum - s.startpos.lnum;
|
||||||
|
colnr_T n_after_newline_in_pat = s.endpos.col;
|
||||||
|
colnr_T n_before_newline_in_pat = mincol - s.cm_start.col;
|
||||||
|
long n_after_newline_in_sub;
|
||||||
|
if (!s.newline_in_sub) {
|
||||||
|
n_after_newline_in_sub = s.cm_end.col - s.cm_start.col;
|
||||||
|
} else {
|
||||||
|
n_after_newline_in_sub = s.cm_end.col;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.newline_in_pat && !s.newline_in_sub) {
|
||||||
|
// -- Delete Pattern --
|
||||||
|
// 1. Move marks in the pattern
|
||||||
|
mincol = s.startpos.col + 1;
|
||||||
|
u_lnum = n_u_lnum;
|
||||||
|
assert(n_u_lnum == u_lnum);
|
||||||
|
extmark_copy_and_place(curbuf,
|
||||||
|
s.lnum, mincol,
|
||||||
|
u_lnum, n_after_newline_in_pat,
|
||||||
|
s.lnum, mincol,
|
||||||
|
kExtmarkUndo, true, NULL);
|
||||||
|
// 2. Move marks on last newline
|
||||||
|
mincol = mincol - n_before_newline_in_pat;
|
||||||
|
extmark_col_adjust(curbuf,
|
||||||
|
u_lnum,
|
||||||
|
n_after_newline_in_pat + 1,
|
||||||
|
-s.newline_in_pat,
|
||||||
|
mincol - n_after_newline_in_pat,
|
||||||
|
kExtmarkUndo);
|
||||||
|
// Take care of the lines after
|
||||||
|
extmark_adjust(curbuf,
|
||||||
|
u_lnum,
|
||||||
|
u_lnum,
|
||||||
|
MAXLNUM,
|
||||||
|
-s.newline_in_pat,
|
||||||
|
kExtmarkUndo,
|
||||||
|
false);
|
||||||
|
// 1. first insert the text in the substitutaion
|
||||||
|
extmark_col_adjust(curbuf,
|
||||||
|
s.lnum,
|
||||||
|
mincol + 1,
|
||||||
|
s.newline_in_sub,
|
||||||
|
n_after_newline_in_sub,
|
||||||
|
kExtmarkUndo);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// The data in sub_obj is as if the substituons above had already taken
|
||||||
|
// place. For our extmarks they haven't as we work from the bottom of the
|
||||||
|
// buffer up. Readjust the data.
|
||||||
|
n_u_lnum = s.lnum + s.endpos.lnum - s.startpos.lnum;
|
||||||
|
n_u_lnum = n_u_lnum - s.lnum_added;
|
||||||
|
|
||||||
|
// adjusted = L - (i-1)N
|
||||||
|
// where L = lnum value, N= lnum_added and i = iteration
|
||||||
|
linenr_T a_l_lnum = s.cm_start.lnum - ((i -1) * s.lnum_added);
|
||||||
|
linenr_T a_u_lnum = a_l_lnum + s.endpos.lnum;
|
||||||
|
assert(s.startpos.lnum == 0);
|
||||||
|
|
||||||
|
mincol = s.startpos.col + 1;
|
||||||
|
u_lnum = n_u_lnum;
|
||||||
|
|
||||||
|
if (!s.newline_in_pat && s.newline_in_sub) {
|
||||||
|
// -- Delete Pattern --
|
||||||
|
// 1. Move marks in the pattern
|
||||||
|
extmark_col_adjust_delete(curbuf,
|
||||||
|
a_l_lnum,
|
||||||
|
mincol + 1,
|
||||||
|
s.endpos.col + 1,
|
||||||
|
kExtmarkUndo,
|
||||||
|
s.eol);
|
||||||
|
|
||||||
|
extmark_adjust(curbuf,
|
||||||
|
a_u_lnum + 1,
|
||||||
|
MAXLNUM,
|
||||||
|
(long)s.newline_in_sub,
|
||||||
|
0,
|
||||||
|
kExtmarkUndo,
|
||||||
|
false);
|
||||||
|
// 3. Insert
|
||||||
|
extmark_col_adjust(curbuf,
|
||||||
|
a_l_lnum,
|
||||||
|
mincol,
|
||||||
|
s.newline_in_sub,
|
||||||
|
(long)-mincol + 1 + n_after_newline_in_sub,
|
||||||
|
kExtmarkUndo);
|
||||||
|
} else if (s.newline_in_pat && s.newline_in_sub) {
|
||||||
|
if (s.lnum_added >= 0) {
|
||||||
|
linenr_T u_col = n_after_newline_in_pat == 0
|
||||||
|
? 1 : n_after_newline_in_pat;
|
||||||
|
extmark_copy_and_place(curbuf,
|
||||||
|
a_l_lnum, mincol,
|
||||||
|
a_u_lnum, u_col,
|
||||||
|
a_l_lnum, mincol,
|
||||||
|
kExtmarkUndo, true, NULL);
|
||||||
|
// 2. Move marks on last newline
|
||||||
|
mincol = mincol - (colnr_T)n_before_newline_in_pat;
|
||||||
|
extmark_col_adjust(curbuf,
|
||||||
|
a_u_lnum,
|
||||||
|
(colnr_T)(n_after_newline_in_pat + 1),
|
||||||
|
-s.newline_in_pat,
|
||||||
|
mincol - n_after_newline_in_pat,
|
||||||
|
kExtmarkUndo);
|
||||||
|
// TODO(timeyyy): nothing to do here if lnum_added = 0
|
||||||
|
extmark_adjust(curbuf,
|
||||||
|
a_u_lnum + 1,
|
||||||
|
MAXLNUM,
|
||||||
|
(long)s.lnum_added,
|
||||||
|
0,
|
||||||
|
kExtmarkUndo,
|
||||||
|
false);
|
||||||
|
|
||||||
|
extmark_col_adjust(curbuf,
|
||||||
|
a_l_lnum,
|
||||||
|
mincol + 1,
|
||||||
|
s.newline_in_sub,
|
||||||
|
(long)-mincol + n_after_newline_in_sub,
|
||||||
|
kExtmarkUndo);
|
||||||
|
} else {
|
||||||
|
mincol = s.startpos.col + 1;
|
||||||
|
a_l_lnum = s.startpos.lnum + 1;
|
||||||
|
a_u_lnum = s.endpos.lnum + 1;
|
||||||
|
extmark_copy_and_place(curbuf,
|
||||||
|
a_l_lnum, mincol,
|
||||||
|
a_u_lnum, n_after_newline_in_pat,
|
||||||
|
a_l_lnum, mincol,
|
||||||
|
kExtmarkUndo, true, NULL);
|
||||||
|
// 2. Move marks on last newline
|
||||||
|
mincol = mincol - (colnr_T)n_before_newline_in_pat;
|
||||||
|
extmark_col_adjust(curbuf,
|
||||||
|
a_u_lnum,
|
||||||
|
(colnr_T)(n_after_newline_in_pat + 1),
|
||||||
|
-s.newline_in_pat,
|
||||||
|
mincol - n_after_newline_in_pat,
|
||||||
|
kExtmarkUndo);
|
||||||
|
extmark_adjust(curbuf,
|
||||||
|
a_u_lnum,
|
||||||
|
a_u_lnum,
|
||||||
|
MAXLNUM,
|
||||||
|
s.lnum_added,
|
||||||
|
kExtmarkUndo,
|
||||||
|
false);
|
||||||
|
// 3. Insert
|
||||||
|
extmark_col_adjust(curbuf,
|
||||||
|
a_l_lnum,
|
||||||
|
mincol + 1,
|
||||||
|
s.newline_in_sub,
|
||||||
|
(long)-mincol + n_after_newline_in_sub,
|
||||||
|
kExtmarkUndo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Perform a substitution from line eap->line1 to line eap->line2 using the
|
/// Perform a substitution from line eap->line1 to line eap->line2 using the
|
||||||
/// command pointed to by eap->arg which should be of the form:
|
/// command pointed to by eap->arg which should be of the form:
|
||||||
///
|
///
|
||||||
@ -3260,6 +3451,17 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
|
|||||||
int save_ma = 0;
|
int save_ma = 0;
|
||||||
int save_b_changed = curbuf->b_changed;
|
int save_b_changed = curbuf->b_changed;
|
||||||
bool preview = (State & CMDPREVIEW);
|
bool preview = (State & CMDPREVIEW);
|
||||||
|
extmark_sub_multi_vec_t extmark_sub_multi = KV_INITIAL_VALUE;
|
||||||
|
extmark_sub_single_vec_t extmark_sub_single = KV_INITIAL_VALUE;
|
||||||
|
linenr_T no_of_lines_changed = 0;
|
||||||
|
linenr_T newline_in_pat = 0;
|
||||||
|
linenr_T newline_in_sub = 0;
|
||||||
|
|
||||||
|
// inccomand tests fail without this check
|
||||||
|
if (!preview) {
|
||||||
|
// Requried for Undo to work for nsmarks,
|
||||||
|
u_save_cursor();
|
||||||
|
}
|
||||||
|
|
||||||
if (!global_busy) {
|
if (!global_busy) {
|
||||||
sub_nsubs = 0;
|
sub_nsubs = 0;
|
||||||
@ -3418,6 +3620,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
|
|||||||
// Check for a match on each line.
|
// Check for a match on each line.
|
||||||
// If preview: limit to max('cmdwinheight', viewport).
|
// If preview: limit to max('cmdwinheight', viewport).
|
||||||
linenr_T line2 = eap->line2;
|
linenr_T line2 = eap->line2;
|
||||||
|
|
||||||
for (linenr_T lnum = eap->line1;
|
for (linenr_T lnum = eap->line1;
|
||||||
lnum <= line2 && !got_quit && !aborting()
|
lnum <= line2 && !got_quit && !aborting()
|
||||||
&& (!preview || preview_lines.lines_needed <= (linenr_T)p_cwh
|
&& (!preview || preview_lines.lines_needed <= (linenr_T)p_cwh
|
||||||
@ -3876,6 +4079,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
|
|||||||
|
|
||||||
ADJUST_SUB_FIRSTLNUM();
|
ADJUST_SUB_FIRSTLNUM();
|
||||||
|
|
||||||
|
|
||||||
// Now the trick is to replace CTRL-M chars with a real line
|
// Now the trick is to replace CTRL-M chars with a real line
|
||||||
// break. This would make it impossible to insert a CTRL-M in
|
// break. This would make it impossible to insert a CTRL-M in
|
||||||
// the text. The line break can be avoided by preceding the
|
// the text. The line break can be avoided by preceding the
|
||||||
@ -3890,7 +4094,9 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
|
|||||||
*p1 = NUL; // truncate up to the CR
|
*p1 = NUL; // truncate up to the CR
|
||||||
ml_append(lnum - 1, new_start,
|
ml_append(lnum - 1, new_start,
|
||||||
(colnr_T)(p1 - new_start + 1), false);
|
(colnr_T)(p1 - new_start + 1), false);
|
||||||
mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L, false);
|
mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L, false,
|
||||||
|
kExtmarkNOOP);
|
||||||
|
|
||||||
if (subflags.do_ask) {
|
if (subflags.do_ask) {
|
||||||
appended_lines(lnum - 1, 1L);
|
appended_lines(lnum - 1, 1L);
|
||||||
} else {
|
} else {
|
||||||
@ -3917,6 +4123,44 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
|
|||||||
current_match.end.lnum = lnum;
|
current_match.end.lnum = lnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adjust extmarks, by delete and then insert
|
||||||
|
if (!preview) {
|
||||||
|
newline_in_pat = (regmatch.endpos[0].lnum
|
||||||
|
- regmatch.startpos[0].lnum);
|
||||||
|
newline_in_sub = current_match.end.lnum - current_match.start.lnum;
|
||||||
|
if (newline_in_pat || newline_in_sub) {
|
||||||
|
ExtmarkSubMulti sub_multi;
|
||||||
|
no_of_lines_changed = newline_in_sub - newline_in_pat;
|
||||||
|
|
||||||
|
sub_multi.newline_in_pat = newline_in_pat;
|
||||||
|
sub_multi.newline_in_sub = newline_in_sub;
|
||||||
|
sub_multi.lnum = lnum;
|
||||||
|
sub_multi.lnum_added = no_of_lines_changed;
|
||||||
|
sub_multi.cm_start = current_match.start;
|
||||||
|
sub_multi.cm_end = current_match.end;
|
||||||
|
|
||||||
|
sub_multi.startpos = regmatch.startpos[0];
|
||||||
|
sub_multi.endpos = regmatch.endpos[0];
|
||||||
|
sub_multi.eol = extmark_eol_col(curbuf, lnum);
|
||||||
|
|
||||||
|
kv_push(extmark_sub_multi, sub_multi);
|
||||||
|
// Collect information required for moving extmarks WITHOUT \n, \r
|
||||||
|
} else {
|
||||||
|
no_of_lines_changed = 0;
|
||||||
|
|
||||||
|
if (regmatch.startpos[0].col != -1) {
|
||||||
|
ExtmarkSubSingle sub_single;
|
||||||
|
sub_single.sublen = sublen;
|
||||||
|
sub_single.lnum = lnum;
|
||||||
|
sub_single.startpos = regmatch.startpos[0];
|
||||||
|
sub_single.endpos = regmatch.endpos[0];
|
||||||
|
|
||||||
|
kv_push(extmark_sub_single, sub_single);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 4. If subflags.do_all is set, find next match.
|
// 4. If subflags.do_all is set, find next match.
|
||||||
// Prevent endless loop with patterns that match empty
|
// Prevent endless loop with patterns that match empty
|
||||||
// strings, e.g. :s/$/pat/g or :s/[a-z]* /(&)/g.
|
// strings, e.g. :s/$/pat/g or :s/[a-z]* /(&)/g.
|
||||||
@ -3983,7 +4227,7 @@ skip:
|
|||||||
ml_delete(lnum, false);
|
ml_delete(lnum, false);
|
||||||
}
|
}
|
||||||
mark_adjust(lnum, lnum + nmatch_tl - 1,
|
mark_adjust(lnum, lnum + nmatch_tl - 1,
|
||||||
(long)MAXLNUM, -nmatch_tl, false);
|
(long)MAXLNUM, -nmatch_tl, false, kExtmarkNOOP);
|
||||||
if (subflags.do_ask) {
|
if (subflags.do_ask) {
|
||||||
deleted_lines(lnum, nmatch_tl);
|
deleted_lines(lnum, nmatch_tl);
|
||||||
}
|
}
|
||||||
@ -4159,6 +4403,35 @@ skip:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (newline_in_pat || newline_in_sub) {
|
||||||
|
long n = (long)kv_size(extmark_sub_multi);
|
||||||
|
ExtmarkSubMulti sub_multi;
|
||||||
|
if (no_of_lines_changed < 0) {
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
sub_multi = kv_A(extmark_sub_multi, i);
|
||||||
|
extmark_move_regmatch_multi(sub_multi, i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Move extmarks in reverse order to avoid moving marks we just moved...
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
sub_multi = kv_Z(extmark_sub_multi, i);
|
||||||
|
extmark_move_regmatch_multi(sub_multi, n - i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kv_destroy(extmark_sub_multi);
|
||||||
|
} else {
|
||||||
|
long n = (long)kv_size(extmark_sub_single);
|
||||||
|
ExtmarkSubSingle sub_single;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
sub_single = kv_Z(extmark_sub_single, i);
|
||||||
|
extmark_move_regmatch_single(sub_single.startpos,
|
||||||
|
sub_single.endpos,
|
||||||
|
sub_single.lnum,
|
||||||
|
sub_single.sublen);
|
||||||
|
}
|
||||||
|
|
||||||
|
kv_destroy(extmark_sub_single);
|
||||||
|
}
|
||||||
|
|
||||||
kv_destroy(preview_lines.subresults);
|
kv_destroy(preview_lines.subresults);
|
||||||
|
|
||||||
|
@ -25,6 +25,12 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Gotchas
|
||||||
|
// -------
|
||||||
|
//
|
||||||
|
// if you delete from a kbtree while iterating over it you must use
|
||||||
|
// kb_del_itr and not kb_del otherwise the iterator might point to freed memory.
|
||||||
|
|
||||||
#ifndef NVIM_LIB_KBTREE_H
|
#ifndef NVIM_LIB_KBTREE_H
|
||||||
#define NVIM_LIB_KBTREE_H
|
#define NVIM_LIB_KBTREE_H
|
||||||
|
|
||||||
|
@ -905,9 +905,10 @@ void mark_adjust(linenr_T line1,
|
|||||||
linenr_T line2,
|
linenr_T line2,
|
||||||
long amount,
|
long amount,
|
||||||
long amount_after,
|
long amount_after,
|
||||||
bool end_temp)
|
bool end_temp,
|
||||||
|
ExtmarkOp op)
|
||||||
{
|
{
|
||||||
mark_adjust_internal(line1, line2, amount, amount_after, true, end_temp);
|
mark_adjust_internal(line1, line2, amount, amount_after, true, end_temp, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark_adjust_nofold() does the same as mark_adjust() but without adjusting
|
// mark_adjust_nofold() does the same as mark_adjust() but without adjusting
|
||||||
@ -916,14 +917,16 @@ void mark_adjust(linenr_T line1,
|
|||||||
// calling foldMarkAdjust() with arguments line1, line2, amount, amount_after,
|
// calling foldMarkAdjust() with arguments line1, line2, amount, amount_after,
|
||||||
// for an example of why this may be necessary, see do_move().
|
// for an example of why this may be necessary, see do_move().
|
||||||
void mark_adjust_nofold(linenr_T line1, linenr_T line2, long amount,
|
void mark_adjust_nofold(linenr_T line1, linenr_T line2, long amount,
|
||||||
long amount_after, bool end_temp)
|
long amount_after, bool end_temp,
|
||||||
|
ExtmarkOp op)
|
||||||
{
|
{
|
||||||
mark_adjust_internal(line1, line2, amount, amount_after, false, end_temp);
|
mark_adjust_internal(line1, line2, amount, amount_after, false, end_temp, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mark_adjust_internal(linenr_T line1, linenr_T line2,
|
static void mark_adjust_internal(linenr_T line1, linenr_T line2,
|
||||||
long amount, long amount_after,
|
long amount, long amount_after,
|
||||||
bool adjust_folds, bool end_temp)
|
bool adjust_folds, bool end_temp,
|
||||||
|
ExtmarkOp op)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int fnum = curbuf->b_fnum;
|
int fnum = curbuf->b_fnum;
|
||||||
@ -979,6 +982,9 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2,
|
|||||||
|
|
||||||
sign_mark_adjust(line1, line2, amount, amount_after);
|
sign_mark_adjust(line1, line2, amount, amount_after);
|
||||||
bufhl_mark_adjust(curbuf, line1, line2, amount, amount_after, end_temp);
|
bufhl_mark_adjust(curbuf, line1, line2, amount, amount_after, end_temp);
|
||||||
|
if (op != kExtmarkNOOP) {
|
||||||
|
extmark_adjust(curbuf, line1, line2, amount, amount_after, op, end_temp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* previous context mark */
|
/* previous context mark */
|
||||||
@ -1090,7 +1096,7 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2,
|
|||||||
// cursor is inside them.
|
// cursor is inside them.
|
||||||
void mark_col_adjust(
|
void mark_col_adjust(
|
||||||
linenr_T lnum, colnr_T mincol, long lnum_amount, long col_amount,
|
linenr_T lnum, colnr_T mincol, long lnum_amount, long col_amount,
|
||||||
int spaces_removed)
|
int spaces_removed, ExtmarkOp op)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int fnum = curbuf->b_fnum;
|
int fnum = curbuf->b_fnum;
|
||||||
@ -1110,6 +1116,13 @@ void mark_col_adjust(
|
|||||||
col_adjust(&(namedfm[i].fmark.mark));
|
col_adjust(&(namedfm[i].fmark.mark));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extmarks
|
||||||
|
if (op != kExtmarkNOOP) {
|
||||||
|
// TODO(timeyyy): consider spaces_removed? (behave like a delete)
|
||||||
|
extmark_col_adjust(curbuf, lnum, mincol, lnum_amount, col_amount,
|
||||||
|
kExtmarkUndo);
|
||||||
|
}
|
||||||
|
|
||||||
/* last Insert position */
|
/* last Insert position */
|
||||||
col_adjust(&(curbuf->b_last_insert.mark));
|
col_adjust(&(curbuf->b_last_insert.mark));
|
||||||
|
|
||||||
|
1136
src/nvim/mark_extended.c
Normal file
1136
src/nvim/mark_extended.c
Normal file
File diff suppressed because it is too large
Load Diff
282
src/nvim/mark_extended.h
Normal file
282
src/nvim/mark_extended.h
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
#ifndef NVIM_MARK_EXTENDED_H
|
||||||
|
#define NVIM_MARK_EXTENDED_H
|
||||||
|
|
||||||
|
#include "nvim/mark_extended_defs.h"
|
||||||
|
#include "nvim/buffer_defs.h" // for buf_T
|
||||||
|
|
||||||
|
|
||||||
|
// Macro Documentation: FOR_ALL_?
|
||||||
|
// Search exclusively using the range values given.
|
||||||
|
// Use MAXCOL/MAXLNUM for the start and end of the line/col.
|
||||||
|
// The ns parameter: Unless otherwise stated, this is only a starting point
|
||||||
|
// for the btree to searched in, the results being itterated over will
|
||||||
|
// still contain extmarks from other namespaces.
|
||||||
|
|
||||||
|
// see FOR_ALL_? for documentation
|
||||||
|
#define FOR_ALL_EXTMARKLINES(buf, l_lnum, u_lnum, code)\
|
||||||
|
kbitr_t(extmarklines) itr;\
|
||||||
|
ExtMarkLine t;\
|
||||||
|
t.lnum = l_lnum;\
|
||||||
|
if (!kb_itr_get(extmarklines, &buf->b_extlines, &t, &itr)) { \
|
||||||
|
kb_itr_next(extmarklines, &buf->b_extlines, &itr);\
|
||||||
|
}\
|
||||||
|
ExtMarkLine *extmarkline;\
|
||||||
|
for (; kb_itr_valid(&itr); kb_itr_next(extmarklines, \
|
||||||
|
&buf->b_extlines, &itr)) { \
|
||||||
|
extmarkline = kb_itr_key(&itr);\
|
||||||
|
if (extmarkline->lnum > u_lnum) { \
|
||||||
|
break;\
|
||||||
|
}\
|
||||||
|
code;\
|
||||||
|
}
|
||||||
|
|
||||||
|
// see FOR_ALL_? for documentation
|
||||||
|
#define FOR_ALL_EXTMARKLINES_PREV(buf, l_lnum, u_lnum, code)\
|
||||||
|
kbitr_t(extmarklines) itr;\
|
||||||
|
ExtMarkLine t;\
|
||||||
|
t.lnum = u_lnum;\
|
||||||
|
if (!kb_itr_get(extmarklines, &buf->b_extlines, &t, &itr)) { \
|
||||||
|
kb_itr_prev(extmarklines, &buf->b_extlines, &itr);\
|
||||||
|
}\
|
||||||
|
ExtMarkLine *extmarkline;\
|
||||||
|
for (; kb_itr_valid(&itr); kb_itr_prev(extmarklines, \
|
||||||
|
&buf->b_extlines, &itr)) { \
|
||||||
|
extmarkline = kb_itr_key(&itr);\
|
||||||
|
if (extmarkline->lnum < l_lnum) { \
|
||||||
|
break;\
|
||||||
|
}\
|
||||||
|
code;\
|
||||||
|
}
|
||||||
|
|
||||||
|
// see FOR_ALL_? for documentation
|
||||||
|
#define FOR_ALL_EXTMARKS(buf, ns, l_lnum, l_col, u_lnum, u_col, code)\
|
||||||
|
kbitr_t(markitems) mitr;\
|
||||||
|
ExtendedMark mt;\
|
||||||
|
mt.ns_id = ns;\
|
||||||
|
mt.mark_id = 0;\
|
||||||
|
mt.line = NULL;\
|
||||||
|
FOR_ALL_EXTMARKLINES(buf, l_lnum, u_lnum, { \
|
||||||
|
mt.col = (extmarkline->lnum != l_lnum) ? MINCOL : l_col;\
|
||||||
|
if (!kb_itr_get(markitems, &extmarkline->items, mt, &mitr)) { \
|
||||||
|
kb_itr_next(markitems, &extmarkline->items, &mitr);\
|
||||||
|
} \
|
||||||
|
ExtendedMark *extmark;\
|
||||||
|
for (; \
|
||||||
|
kb_itr_valid(&mitr); \
|
||||||
|
kb_itr_next(markitems, &extmarkline->items, &mitr)) { \
|
||||||
|
extmark = &kb_itr_key(&mitr);\
|
||||||
|
if (extmark->line->lnum == u_lnum \
|
||||||
|
&& extmark->col > u_col) { \
|
||||||
|
break;\
|
||||||
|
}\
|
||||||
|
code;\
|
||||||
|
}\
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// see FOR_ALL_? for documentation
|
||||||
|
#define FOR_ALL_EXTMARKS_PREV(buf, ns, l_lnum, l_col, u_lnum, u_col, code)\
|
||||||
|
kbitr_t(markitems) mitr;\
|
||||||
|
ExtendedMark mt;\
|
||||||
|
mt.mark_id = sizeof(uint64_t);\
|
||||||
|
mt.ns_id = ns;\
|
||||||
|
FOR_ALL_EXTMARKLINES_PREV(buf, l_lnum, u_lnum, { \
|
||||||
|
mt.col = (extmarkline->lnum != u_lnum) ? MAXCOL : u_col;\
|
||||||
|
if (!kb_itr_get(markitems, &extmarkline->items, mt, &mitr)) { \
|
||||||
|
kb_itr_prev(markitems, &extmarkline->items, &mitr);\
|
||||||
|
} \
|
||||||
|
ExtendedMark *extmark;\
|
||||||
|
for (; \
|
||||||
|
kb_itr_valid(&mitr); \
|
||||||
|
kb_itr_prev(markitems, &extmarkline->items, &mitr)) { \
|
||||||
|
extmark = &kb_itr_key(&mitr);\
|
||||||
|
if (extmark->line->lnum == l_lnum \
|
||||||
|
&& extmark->col < l_col) { \
|
||||||
|
break;\
|
||||||
|
}\
|
||||||
|
code;\
|
||||||
|
}\
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
#define FOR_ALL_EXTMARKS_IN_LINE(items, l_col, u_col, code)\
|
||||||
|
kbitr_t(markitems) mitr;\
|
||||||
|
ExtendedMark mt;\
|
||||||
|
mt.ns_id = 0;\
|
||||||
|
mt.mark_id = 0;\
|
||||||
|
mt.line = NULL;\
|
||||||
|
mt.col = l_col;\
|
||||||
|
colnr_T extmarkline_u_col = u_col;\
|
||||||
|
if (!kb_itr_get(markitems, &items, mt, &mitr)) { \
|
||||||
|
kb_itr_next(markitems, &items, &mitr);\
|
||||||
|
} \
|
||||||
|
ExtendedMark *extmark;\
|
||||||
|
for (; kb_itr_valid(&mitr); kb_itr_next(markitems, &items, &mitr)) { \
|
||||||
|
extmark = &kb_itr_key(&mitr);\
|
||||||
|
if (extmark->col > extmarkline_u_col) { \
|
||||||
|
break;\
|
||||||
|
}\
|
||||||
|
code;\
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ExtmarkNs { // For namespacing extmarks
|
||||||
|
PMap(uint64_t) *map; // For fast lookup
|
||||||
|
uint64_t free_id; // For automatically assigning id's
|
||||||
|
} ExtmarkNs;
|
||||||
|
|
||||||
|
|
||||||
|
typedef kvec_t(ExtendedMark *) ExtmarkArray;
|
||||||
|
|
||||||
|
|
||||||
|
// Undo/redo extmarks
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kExtmarkNOOP, // Extmarks shouldn't be moved
|
||||||
|
kExtmarkUndo, // Operation should be reversable/undoable
|
||||||
|
kExtmarkNoUndo, // Operation should not be reversable
|
||||||
|
kExtmarkUndoNoRedo, // Operation should be undoable, but not redoable
|
||||||
|
} ExtmarkOp;
|
||||||
|
|
||||||
|
|
||||||
|
// adjust line numbers only, corresponding to mark_adjust call
|
||||||
|
typedef struct {
|
||||||
|
linenr_T line1;
|
||||||
|
linenr_T line2;
|
||||||
|
long amount;
|
||||||
|
long amount_after;
|
||||||
|
} Adjust;
|
||||||
|
|
||||||
|
// adjust columns after split/join line, like mark_col_adjust
|
||||||
|
typedef struct {
|
||||||
|
linenr_T lnum;
|
||||||
|
colnr_T mincol;
|
||||||
|
long col_amount;
|
||||||
|
long lnum_amount;
|
||||||
|
} ColAdjust;
|
||||||
|
|
||||||
|
// delete the columns between mincol and endcol
|
||||||
|
typedef struct {
|
||||||
|
linenr_T lnum;
|
||||||
|
colnr_T mincol;
|
||||||
|
colnr_T endcol;
|
||||||
|
int eol;
|
||||||
|
} ColAdjustDelete;
|
||||||
|
|
||||||
|
// adjust linenumbers after :move operation
|
||||||
|
typedef struct {
|
||||||
|
linenr_T line1;
|
||||||
|
linenr_T line2;
|
||||||
|
linenr_T last_line;
|
||||||
|
linenr_T dest;
|
||||||
|
linenr_T num_lines;
|
||||||
|
linenr_T extra;
|
||||||
|
} AdjustMove;
|
||||||
|
|
||||||
|
// TODO(bfredl): reconsider if we really should track mark creation/updating
|
||||||
|
// itself, these are not really "edit" operation.
|
||||||
|
// extmark was created
|
||||||
|
typedef struct {
|
||||||
|
uint64_t ns_id;
|
||||||
|
uint64_t mark_id;
|
||||||
|
linenr_T lnum;
|
||||||
|
colnr_T col;
|
||||||
|
} ExtmarkSet;
|
||||||
|
|
||||||
|
// extmark was updated
|
||||||
|
typedef struct {
|
||||||
|
uint64_t ns_id;
|
||||||
|
uint64_t mark_id;
|
||||||
|
linenr_T old_lnum;
|
||||||
|
colnr_T old_col;
|
||||||
|
linenr_T lnum;
|
||||||
|
colnr_T col;
|
||||||
|
} ExtmarkUpdate;
|
||||||
|
|
||||||
|
// copied mark before deletion (as operation is destructive)
|
||||||
|
typedef struct {
|
||||||
|
uint64_t ns_id;
|
||||||
|
uint64_t mark_id;
|
||||||
|
linenr_T lnum;
|
||||||
|
colnr_T col;
|
||||||
|
} ExtmarkCopy;
|
||||||
|
|
||||||
|
// also used as part of :move operation? probably can be simplified to one
|
||||||
|
// event.
|
||||||
|
typedef struct {
|
||||||
|
linenr_T l_lnum;
|
||||||
|
colnr_T l_col;
|
||||||
|
linenr_T u_lnum;
|
||||||
|
colnr_T u_col;
|
||||||
|
linenr_T p_lnum;
|
||||||
|
colnr_T p_col;
|
||||||
|
} ExtmarkCopyPlace;
|
||||||
|
|
||||||
|
// extmark was cleared.
|
||||||
|
// TODO(bfredl): same reconsideration as for ExtmarkSet/ExtmarkUpdate
|
||||||
|
typedef struct {
|
||||||
|
uint64_t ns_id;
|
||||||
|
linenr_T l_lnum;
|
||||||
|
linenr_T u_lnum;
|
||||||
|
} ExtmarkClear;
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kLineAdjust,
|
||||||
|
kColAdjust,
|
||||||
|
kColAdjustDelete,
|
||||||
|
kAdjustMove,
|
||||||
|
kExtmarkSet,
|
||||||
|
kExtmarkDel,
|
||||||
|
kExtmarkUpdate,
|
||||||
|
kExtmarkCopy,
|
||||||
|
kExtmarkCopyPlace,
|
||||||
|
kExtmarkClear,
|
||||||
|
} UndoObjectType;
|
||||||
|
|
||||||
|
// TODO(bfredl): reduce the number of undo action types
|
||||||
|
struct undo_object {
|
||||||
|
UndoObjectType type;
|
||||||
|
union {
|
||||||
|
Adjust adjust;
|
||||||
|
ColAdjust col_adjust;
|
||||||
|
ColAdjustDelete col_adjust_delete;
|
||||||
|
AdjustMove move;
|
||||||
|
ExtmarkSet set;
|
||||||
|
ExtmarkUpdate update;
|
||||||
|
ExtmarkCopy copy;
|
||||||
|
ExtmarkCopyPlace copy_place;
|
||||||
|
ExtmarkClear clear;
|
||||||
|
} data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// For doing move of extmarks in substitutions
|
||||||
|
typedef struct {
|
||||||
|
lpos_T startpos;
|
||||||
|
lpos_T endpos;
|
||||||
|
linenr_T lnum;
|
||||||
|
int sublen;
|
||||||
|
} ExtmarkSubSingle;
|
||||||
|
|
||||||
|
// For doing move of extmarks in substitutions
|
||||||
|
typedef struct {
|
||||||
|
lpos_T startpos;
|
||||||
|
lpos_T endpos;
|
||||||
|
linenr_T lnum;
|
||||||
|
linenr_T newline_in_pat;
|
||||||
|
linenr_T newline_in_sub;
|
||||||
|
linenr_T lnum_added;
|
||||||
|
lpos_T cm_start; // start of the match
|
||||||
|
lpos_T cm_end; // end of the match
|
||||||
|
int eol; // end of the match
|
||||||
|
} ExtmarkSubMulti;
|
||||||
|
|
||||||
|
typedef kvec_t(ExtmarkSubSingle) extmark_sub_single_vec_t;
|
||||||
|
typedef kvec_t(ExtmarkSubMulti) extmark_sub_multi_vec_t;
|
||||||
|
|
||||||
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
|
# include "mark_extended.h.generated.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // NVIM_MARK_EXTENDED_H
|
54
src/nvim/mark_extended_defs.h
Normal file
54
src/nvim/mark_extended_defs.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef NVIM_MARK_EXTENDED_DEFS_H
|
||||||
|
#define NVIM_MARK_EXTENDED_DEFS_H
|
||||||
|
|
||||||
|
#include "nvim/pos.h" // for colnr_T
|
||||||
|
#include "nvim/map.h" // for uint64_t
|
||||||
|
#include "nvim/lib/kbtree.h"
|
||||||
|
#include "nvim/lib/kvec.h"
|
||||||
|
|
||||||
|
struct ExtMarkLine;
|
||||||
|
|
||||||
|
typedef struct ExtendedMark
|
||||||
|
{
|
||||||
|
uint64_t ns_id;
|
||||||
|
uint64_t mark_id;
|
||||||
|
struct ExtMarkLine *line;
|
||||||
|
colnr_T col;
|
||||||
|
} ExtendedMark;
|
||||||
|
|
||||||
|
|
||||||
|
// We only need to compare columns as rows are stored in a different tree.
|
||||||
|
// Marks are ordered by: position, namespace, mark_id
|
||||||
|
// This improves moving marks but slows down all other use cases (searches)
|
||||||
|
static inline int extmark_cmp(ExtendedMark a, ExtendedMark b)
|
||||||
|
{
|
||||||
|
int cmp = kb_generic_cmp(a.col, b.col);
|
||||||
|
if (cmp != 0) {
|
||||||
|
return cmp;
|
||||||
|
}
|
||||||
|
cmp = kb_generic_cmp(a.ns_id, b.ns_id);
|
||||||
|
if (cmp != 0) {
|
||||||
|
return cmp;
|
||||||
|
}
|
||||||
|
return kb_generic_cmp(a.mark_id, b.mark_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define markitems_cmp(a, b) (extmark_cmp((a), (b)))
|
||||||
|
KBTREE_INIT(markitems, ExtendedMark, markitems_cmp, 10)
|
||||||
|
|
||||||
|
typedef struct ExtMarkLine
|
||||||
|
{
|
||||||
|
linenr_T lnum;
|
||||||
|
kbtree_t(markitems) items;
|
||||||
|
} ExtMarkLine;
|
||||||
|
|
||||||
|
#define EXTMARKLINE_CMP(a, b) (kb_generic_cmp((a)->lnum, (b)->lnum))
|
||||||
|
KBTREE_INIT(extmarklines, ExtMarkLine *, EXTMARKLINE_CMP, 10)
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct undo_object ExtmarkUndoObject;
|
||||||
|
typedef kvec_t(ExtmarkUndoObject) extmark_undo_vec_t;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NVIM_MARK_EXTENDED_DEFS_H
|
@ -30,7 +30,6 @@
|
|||||||
#include "nvim/indent_c.h"
|
#include "nvim/indent_c.h"
|
||||||
#include "nvim/buffer_updates.h"
|
#include "nvim/buffer_updates.h"
|
||||||
#include "nvim/main.h"
|
#include "nvim/main.h"
|
||||||
#include "nvim/mark.h"
|
|
||||||
#include "nvim/mbyte.h"
|
#include "nvim/mbyte.h"
|
||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
|
138
src/nvim/ops.c
138
src/nvim/ops.c
@ -49,6 +49,7 @@
|
|||||||
#include "nvim/undo.h"
|
#include "nvim/undo.h"
|
||||||
#include "nvim/macros.h"
|
#include "nvim/macros.h"
|
||||||
#include "nvim/window.h"
|
#include "nvim/window.h"
|
||||||
|
#include "nvim/lib/kvec.h"
|
||||||
#include "nvim/os/input.h"
|
#include "nvim/os/input.h"
|
||||||
#include "nvim/os/time.h"
|
#include "nvim/os/time.h"
|
||||||
|
|
||||||
@ -306,6 +307,15 @@ void shift_line(
|
|||||||
change_indent(INDENT_SET, count, false, NUL, call_changed_bytes);
|
change_indent(INDENT_SET, count, false, NUL, call_changed_bytes);
|
||||||
} else {
|
} else {
|
||||||
(void)set_indent(count, call_changed_bytes ? SIN_CHANGED : 0);
|
(void)set_indent(count, call_changed_bytes ? SIN_CHANGED : 0);
|
||||||
|
|
||||||
|
colnr_T mincol = (curwin->w_cursor.col + 1) -p_sw;
|
||||||
|
colnr_T col_amount = left ? -p_sw : p_sw;
|
||||||
|
extmark_col_adjust(curbuf,
|
||||||
|
curwin->w_cursor.lnum,
|
||||||
|
mincol,
|
||||||
|
0,
|
||||||
|
col_amount,
|
||||||
|
kExtmarkUndo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,6 +489,10 @@ static void shift_block(oparg_T *oap, int amount)
|
|||||||
State = oldstate;
|
State = oldstate;
|
||||||
curwin->w_cursor.col = oldcol;
|
curwin->w_cursor.col = oldcol;
|
||||||
p_ri = old_p_ri;
|
p_ri = old_p_ri;
|
||||||
|
|
||||||
|
colnr_T col_amount = left ? -p_sw : p_sw;
|
||||||
|
extmark_col_adjust(curbuf, curwin->w_cursor.lnum,
|
||||||
|
curwin->w_cursor.col, 0, col_amount, kExtmarkUndo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -623,10 +637,19 @@ void op_reindent(oparg_T *oap, Indenter how)
|
|||||||
amount = how(); /* get the indent for this line */
|
amount = how(); /* get the indent for this line */
|
||||||
|
|
||||||
if (amount >= 0 && set_indent(amount, SIN_UNDO)) {
|
if (amount >= 0 && set_indent(amount, SIN_UNDO)) {
|
||||||
/* did change the indent, call changed_lines() later */
|
// did change the indent, call changed_lines() later
|
||||||
if (first_changed == 0)
|
if (first_changed == 0) {
|
||||||
first_changed = curwin->w_cursor.lnum;
|
first_changed = curwin->w_cursor.lnum;
|
||||||
|
}
|
||||||
last_changed = curwin->w_cursor.lnum;
|
last_changed = curwin->w_cursor.lnum;
|
||||||
|
|
||||||
|
// Adjust extmarks
|
||||||
|
extmark_col_adjust(curbuf,
|
||||||
|
curwin->w_cursor.lnum,
|
||||||
|
0, // mincol
|
||||||
|
0, // lnum_amount
|
||||||
|
amount, // col_amount
|
||||||
|
kExtmarkUndo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++curwin->w_cursor.lnum;
|
++curwin->w_cursor.lnum;
|
||||||
@ -1621,6 +1644,8 @@ int op_delete(oparg_T *oap)
|
|||||||
curwin->w_cursor.col = 0;
|
curwin->w_cursor.col = 0;
|
||||||
(void)del_bytes((colnr_T)n, !virtual_op,
|
(void)del_bytes((colnr_T)n, !virtual_op,
|
||||||
oap->op_type == OP_DELETE && !oap->is_VIsual);
|
oap->op_type == OP_DELETE && !oap->is_VIsual);
|
||||||
|
extmark_col_adjust(curbuf, curwin->w_cursor.lnum,
|
||||||
|
(colnr_T)0, 0L, (long)-n, kExtmarkUndo);
|
||||||
curwin->w_cursor = curpos; // restore curwin->w_cursor
|
curwin->w_cursor = curpos; // restore curwin->w_cursor
|
||||||
(void)do_join(2, false, false, false, false);
|
(void)do_join(2, false, false, false, false);
|
||||||
}
|
}
|
||||||
@ -1632,10 +1657,36 @@ setmarks:
|
|||||||
if (oap->motion_type == kMTBlockWise) {
|
if (oap->motion_type == kMTBlockWise) {
|
||||||
curbuf->b_op_end.lnum = oap->end.lnum;
|
curbuf->b_op_end.lnum = oap->end.lnum;
|
||||||
curbuf->b_op_end.col = oap->start.col;
|
curbuf->b_op_end.col = oap->start.col;
|
||||||
} else
|
} else {
|
||||||
curbuf->b_op_end = oap->start;
|
curbuf->b_op_end = oap->start;
|
||||||
|
}
|
||||||
curbuf->b_op_start = oap->start;
|
curbuf->b_op_start = oap->start;
|
||||||
|
|
||||||
|
// TODO(timeyyy): refactor: Move extended marks
|
||||||
|
// + 1 to change to buf mode,
|
||||||
|
// and + 1 because we only move marks after the deleted col
|
||||||
|
colnr_T mincol = oap->start.col + 1 + 1;
|
||||||
|
colnr_T endcol;
|
||||||
|
if (oap->motion_type == kMTBlockWise) {
|
||||||
|
// TODO(timeyyy): refactor extmark_col_adjust to take lnumstart, lnum_end ?
|
||||||
|
endcol = bd.end_vcol + 1;
|
||||||
|
for (lnum = curwin->w_cursor.lnum; lnum <= oap->end.lnum; lnum++) {
|
||||||
|
extmark_col_adjust_delete(curbuf, lnum, mincol, endcol,
|
||||||
|
kExtmarkUndo, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete characters within one line,
|
||||||
|
// The case with multiple lines is handled by do_join
|
||||||
|
} else if (oap->motion_type == kMTCharWise && oap->line_count == 1) {
|
||||||
|
// + 1 to change to buf mode, then plus 1 to fit function requirements
|
||||||
|
endcol = oap->end.col + 1 + 1;
|
||||||
|
|
||||||
|
lnum = curwin->w_cursor.lnum;
|
||||||
|
if (oap->is_VIsual == false) {
|
||||||
|
endcol = MAX(endcol - 1, mincol);
|
||||||
|
}
|
||||||
|
extmark_col_adjust_delete(curbuf, lnum, mincol, endcol, kExtmarkUndo, 0);
|
||||||
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2031,8 +2082,8 @@ bool swapchar(int op_type, pos_T *pos)
|
|||||||
pos_T sp = curwin->w_cursor;
|
pos_T sp = curwin->w_cursor;
|
||||||
|
|
||||||
curwin->w_cursor = *pos;
|
curwin->w_cursor = *pos;
|
||||||
/* don't use del_char(), it also removes composing chars */
|
// don't use del_char(), it also removes composing chars
|
||||||
del_bytes(utf_ptr2len(get_cursor_pos_ptr()), FALSE, FALSE);
|
del_bytes(utf_ptr2len(get_cursor_pos_ptr()), false, false);
|
||||||
ins_char(nc);
|
ins_char(nc);
|
||||||
curwin->w_cursor = sp;
|
curwin->w_cursor = sp;
|
||||||
} else {
|
} else {
|
||||||
@ -2105,8 +2156,9 @@ void op_insert(oparg_T *oap, long count1)
|
|||||||
* values in "bd". */
|
* values in "bd". */
|
||||||
if (u_save_cursor() == FAIL)
|
if (u_save_cursor() == FAIL)
|
||||||
return;
|
return;
|
||||||
for (i = 0; i < bd.endspaces; i++)
|
for (i = 0; i < bd.endspaces; i++) {
|
||||||
ins_char(' ');
|
ins_char(' ');
|
||||||
|
}
|
||||||
bd.textlen += bd.endspaces;
|
bd.textlen += bd.endspaces;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2224,6 +2276,10 @@ void op_insert(oparg_T *oap, long count1)
|
|||||||
xfree(ins_text);
|
xfree(ins_text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
colnr_T col = oap->start.col;
|
||||||
|
for (linenr_T lnum = oap->start.lnum; lnum <= oap->end.lnum; lnum++) {
|
||||||
|
extmark_col_adjust(curbuf, lnum, col, 0, 1, kExtmarkUndo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2694,6 +2750,27 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void extmarks_do_put(int dir,
|
||||||
|
size_t totlen,
|
||||||
|
MotionType y_type,
|
||||||
|
linenr_T lnum,
|
||||||
|
colnr_T col)
|
||||||
|
{
|
||||||
|
// adjust extmarks
|
||||||
|
colnr_T col_amount = (colnr_T)(dir == FORWARD ? totlen-1 : totlen);
|
||||||
|
// Move extmark with char put
|
||||||
|
if (y_type == kMTCharWise) {
|
||||||
|
extmark_col_adjust(curbuf, lnum, col, 0, col_amount, kExtmarkUndo);
|
||||||
|
// Move extmark with blockwise put
|
||||||
|
} else if (y_type == kMTBlockWise) {
|
||||||
|
for (lnum = curbuf->b_op_start.lnum;
|
||||||
|
lnum <= curbuf->b_op_end.lnum;
|
||||||
|
lnum++) {
|
||||||
|
extmark_col_adjust(curbuf, lnum, col, 0, col_amount, kExtmarkUndo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Put contents of register "regname" into the text.
|
* Put contents of register "regname" into the text.
|
||||||
* Caller must check "regname" to be valid!
|
* Caller must check "regname" to be valid!
|
||||||
@ -2708,8 +2785,8 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
|
|||||||
char_u *oldp;
|
char_u *oldp;
|
||||||
int yanklen;
|
int yanklen;
|
||||||
size_t totlen = 0; // init for gcc
|
size_t totlen = 0; // init for gcc
|
||||||
linenr_T lnum;
|
linenr_T lnum = 0;
|
||||||
colnr_T col;
|
colnr_T col = 0;
|
||||||
size_t i; // index in y_array[]
|
size_t i; // index in y_array[]
|
||||||
MotionType y_type;
|
MotionType y_type;
|
||||||
size_t y_size;
|
size_t y_size;
|
||||||
@ -3286,11 +3363,11 @@ error:
|
|||||||
curbuf->b_op_start.lnum++;
|
curbuf->b_op_start.lnum++;
|
||||||
}
|
}
|
||||||
// Skip mark_adjust when adding lines after the last one, there
|
// Skip mark_adjust when adding lines after the last one, there
|
||||||
// can't be marks there. But still needed in diff mode.
|
// can't be marks there.
|
||||||
if (curbuf->b_op_start.lnum + (y_type == kMTCharWise) - 1 + nr_lines
|
if (curbuf->b_op_start.lnum + (y_type == kMTCharWise) - 1 + nr_lines
|
||||||
< curbuf->b_ml.ml_line_count || curwin->w_p_diff) {
|
< curbuf->b_ml.ml_line_count) {
|
||||||
mark_adjust(curbuf->b_op_start.lnum + (y_type == kMTCharWise),
|
mark_adjust(curbuf->b_op_start.lnum + (y_type == kMTCharWise),
|
||||||
(linenr_T)MAXLNUM, nr_lines, 0L, false);
|
(linenr_T)MAXLNUM, nr_lines, 0L, false, kExtmarkUndo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// note changed text for displaying and folding
|
// note changed text for displaying and folding
|
||||||
@ -3352,6 +3429,8 @@ end:
|
|||||||
|
|
||||||
/* If the cursor is past the end of the line put it at the end. */
|
/* If the cursor is past the end of the line put it at the end. */
|
||||||
adjust_cursor_eol();
|
adjust_cursor_eol();
|
||||||
|
|
||||||
|
extmarks_do_put(dir, totlen, y_type, lnum, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3745,6 +3824,7 @@ int do_join(size_t count,
|
|||||||
* column. This is not Vi compatible, but Vi deletes the marks, thus that
|
* column. This is not Vi compatible, but Vi deletes the marks, thus that
|
||||||
* should not really be a problem.
|
* should not really be a problem.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (t = (linenr_T)count - 1;; t--) {
|
for (t = (linenr_T)count - 1;; t--) {
|
||||||
cend -= currsize;
|
cend -= currsize;
|
||||||
memmove(cend, curr, (size_t)currsize);
|
memmove(cend, curr, (size_t)currsize);
|
||||||
@ -3756,12 +3836,18 @@ int do_join(size_t count,
|
|||||||
// If deleting more spaces than adding, the cursor moves no more than
|
// If deleting more spaces than adding, the cursor moves no more than
|
||||||
// what is added if it is inside these spaces.
|
// what is added if it is inside these spaces.
|
||||||
const int spaces_removed = (int)((curr - curr_start) - spaces[t]);
|
const int spaces_removed = (int)((curr - curr_start) - spaces[t]);
|
||||||
|
linenr_T lnum = curwin->w_cursor.lnum + t;
|
||||||
|
colnr_T mincol = (colnr_T)0;
|
||||||
|
long lnum_amount = (linenr_T)-t;
|
||||||
|
long col_amount = (long)(cend - newp - spaces_removed);
|
||||||
|
|
||||||
|
mark_col_adjust(lnum, mincol, lnum_amount, col_amount, spaces_removed,
|
||||||
|
kExtmarkUndo);
|
||||||
|
|
||||||
mark_col_adjust(curwin->w_cursor.lnum + t, (colnr_T)0, (linenr_T)-t,
|
|
||||||
(long)(cend - newp - spaces_removed), spaces_removed);
|
|
||||||
if (t == 0) {
|
if (t == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t - 1));
|
curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t - 1));
|
||||||
if (remove_comments)
|
if (remove_comments)
|
||||||
curr += comments[t - 1];
|
curr += comments[t - 1];
|
||||||
@ -3769,6 +3855,7 @@ int do_join(size_t count,
|
|||||||
curr = skipwhite(curr);
|
curr = skipwhite(curr);
|
||||||
currsize = (int)STRLEN(curr);
|
currsize = (int)STRLEN(curr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ml_replace(curwin->w_cursor.lnum, newp, false);
|
ml_replace(curwin->w_cursor.lnum, newp, false);
|
||||||
|
|
||||||
if (setmark) {
|
if (setmark) {
|
||||||
@ -4189,14 +4276,14 @@ format_lines(
|
|||||||
if (next_leader_len > 0) {
|
if (next_leader_len > 0) {
|
||||||
(void)del_bytes(next_leader_len, false, false);
|
(void)del_bytes(next_leader_len, false, false);
|
||||||
mark_col_adjust(curwin->w_cursor.lnum, (colnr_T)0, 0L,
|
mark_col_adjust(curwin->w_cursor.lnum, (colnr_T)0, 0L,
|
||||||
(long)-next_leader_len, 0);
|
(long)-next_leader_len, 0, kExtmarkUndo);
|
||||||
} else if (second_indent > 0) { // the "leader" for FO_Q_SECOND
|
} else if (second_indent > 0) { // the "leader" for FO_Q_SECOND
|
||||||
int indent = (int)getwhitecols_curline();
|
int indent = (int)getwhitecols_curline();
|
||||||
|
|
||||||
if (indent > 0) {
|
if (indent > 0) {
|
||||||
(void)del_bytes(indent, FALSE, FALSE);
|
(void)del_bytes(indent, FALSE, FALSE);
|
||||||
mark_col_adjust(curwin->w_cursor.lnum,
|
mark_col_adjust(curwin->w_cursor.lnum,
|
||||||
(colnr_T)0, 0L, (long)-indent, 0);
|
(colnr_T)0, 0L, (long)-indent, 0, kExtmarkUndo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
curwin->w_cursor.lnum--;
|
curwin->w_cursor.lnum--;
|
||||||
@ -4539,7 +4626,7 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd)
|
|||||||
int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
|
int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
|
||||||
{
|
{
|
||||||
int col;
|
int col;
|
||||||
char_u *buf1;
|
char_u *buf1 = NULL;
|
||||||
char_u buf2[NUMBUFLEN];
|
char_u buf2[NUMBUFLEN];
|
||||||
int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin
|
int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin
|
||||||
static bool hexupper = false; // 0xABC
|
static bool hexupper = false; // 0xABC
|
||||||
@ -4848,7 +4935,6 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
|
|||||||
*ptr = NUL;
|
*ptr = NUL;
|
||||||
STRCAT(buf1, buf2);
|
STRCAT(buf1, buf2);
|
||||||
ins_str(buf1); // insert the new number
|
ins_str(buf1); // insert the new number
|
||||||
xfree(buf1);
|
|
||||||
endpos = curwin->w_cursor;
|
endpos = curwin->w_cursor;
|
||||||
if (curwin->w_cursor.col) {
|
if (curwin->w_cursor.col) {
|
||||||
curwin->w_cursor.col--;
|
curwin->w_cursor.col--;
|
||||||
@ -4862,7 +4948,25 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
|
|||||||
curbuf->b_op_end.col--;
|
curbuf->b_op_end.col--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if buf1 wasn't allocated, only a singe ASCII char was changed in-place.
|
||||||
|
if (did_change && buf1 != NULL) {
|
||||||
|
extmark_col_adjust_delete(curbuf,
|
||||||
|
pos->lnum,
|
||||||
|
startpos.col + 2,
|
||||||
|
endpos.col + 1 + length,
|
||||||
|
kExtmarkUndo,
|
||||||
|
0);
|
||||||
|
long col_amount = (long)STRLEN(buf1);
|
||||||
|
extmark_col_adjust(curbuf,
|
||||||
|
pos->lnum,
|
||||||
|
startpos.col + 1,
|
||||||
|
0,
|
||||||
|
col_amount,
|
||||||
|
kExtmarkUndo);
|
||||||
|
}
|
||||||
|
|
||||||
theend:
|
theend:
|
||||||
|
xfree(buf1);
|
||||||
if (visual) {
|
if (visual) {
|
||||||
curwin->w_cursor = save_cursor;
|
curwin->w_cursor = save_cursor;
|
||||||
} else if (did_change) {
|
} else if (did_change) {
|
||||||
|
@ -14,6 +14,10 @@ typedef int colnr_T;
|
|||||||
enum { MAXLNUM = 0x7fffffff };
|
enum { MAXLNUM = 0x7fffffff };
|
||||||
/// Maximal column number, 31 bits
|
/// Maximal column number, 31 bits
|
||||||
enum { MAXCOL = 0x7fffffff };
|
enum { MAXCOL = 0x7fffffff };
|
||||||
|
// Minimum line number
|
||||||
|
enum { MINLNUM = 1 };
|
||||||
|
// minimum column number
|
||||||
|
enum { MINCOL = 1 };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* position in file or buffer
|
* position in file or buffer
|
||||||
|
@ -91,7 +91,9 @@
|
|||||||
#include "nvim/fileio.h"
|
#include "nvim/fileio.h"
|
||||||
#include "nvim/fold.h"
|
#include "nvim/fold.h"
|
||||||
#include "nvim/buffer_updates.h"
|
#include "nvim/buffer_updates.h"
|
||||||
|
#include "nvim/pos.h" // MAXLNUM
|
||||||
#include "nvim/mark.h"
|
#include "nvim/mark.h"
|
||||||
|
#include "nvim/mark_extended.h"
|
||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/message.h"
|
#include "nvim/message.h"
|
||||||
#include "nvim/misc1.h"
|
#include "nvim/misc1.h"
|
||||||
@ -106,6 +108,7 @@
|
|||||||
#include "nvim/types.h"
|
#include "nvim/types.h"
|
||||||
#include "nvim/os/os.h"
|
#include "nvim/os/os.h"
|
||||||
#include "nvim/os/time.h"
|
#include "nvim/os/time.h"
|
||||||
|
#include "nvim/lib/kvec.h"
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "undo.c.generated.h"
|
# include "undo.c.generated.h"
|
||||||
@ -384,6 +387,7 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
|
|||||||
* up the undo info when out of memory.
|
* up the undo info when out of memory.
|
||||||
*/
|
*/
|
||||||
uhp = xmalloc(sizeof(u_header_T));
|
uhp = xmalloc(sizeof(u_header_T));
|
||||||
|
kv_init(uhp->uh_extmark);
|
||||||
#ifdef U_DEBUG
|
#ifdef U_DEBUG
|
||||||
uhp->uh_magic = UH_MAGIC;
|
uhp->uh_magic = UH_MAGIC;
|
||||||
#endif
|
#endif
|
||||||
@ -2249,10 +2253,10 @@ static void u_undoredo(int undo, bool do_buf_event)
|
|||||||
xfree((char_u *)uep->ue_array);
|
xfree((char_u *)uep->ue_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* adjust marks */
|
// Adjust marks
|
||||||
if (oldsize != newsize) {
|
if (oldsize != newsize) {
|
||||||
mark_adjust(top + 1, top + oldsize, (long)MAXLNUM,
|
mark_adjust(top + 1, top + oldsize, (long)MAXLNUM,
|
||||||
(long)newsize - (long)oldsize, false);
|
(long)newsize - (long)oldsize, false, kExtmarkNOOP);
|
||||||
if (curbuf->b_op_start.lnum > top + oldsize) {
|
if (curbuf->b_op_start.lnum > top + oldsize) {
|
||||||
curbuf->b_op_start.lnum += newsize - oldsize;
|
curbuf->b_op_start.lnum += newsize - oldsize;
|
||||||
}
|
}
|
||||||
@ -2285,6 +2289,23 @@ static void u_undoredo(int undo, bool do_buf_event)
|
|||||||
newlist = uep;
|
newlist = uep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adjust Extmarks
|
||||||
|
ExtmarkUndoObject undo_info;
|
||||||
|
if (undo) {
|
||||||
|
for (i = (int)kv_size(curhead->uh_extmark) - 1; i > -1; i--) {
|
||||||
|
undo_info = kv_A(curhead->uh_extmark, i);
|
||||||
|
extmark_apply_undo(undo_info, undo);
|
||||||
|
}
|
||||||
|
// redo
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < (int)kv_size(curhead->uh_extmark); i++) {
|
||||||
|
undo_info = kv_A(curhead->uh_extmark, i);
|
||||||
|
extmark_apply_undo(undo_info, undo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// finish Adjusting extmarks
|
||||||
|
|
||||||
|
|
||||||
curhead->uh_entry = newlist;
|
curhead->uh_entry = newlist;
|
||||||
curhead->uh_flags = new_flags;
|
curhead->uh_flags = new_flags;
|
||||||
if ((old_flags & UH_EMPTYBUF) && BUFEMPTY()) {
|
if ((old_flags & UH_EMPTYBUF) && BUFEMPTY()) {
|
||||||
@ -2828,6 +2849,8 @@ u_freeentries(
|
|||||||
u_freeentry(uep, uep->ue_size);
|
u_freeentry(uep, uep->ue_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kv_destroy(uhp->uh_extmark);
|
||||||
|
|
||||||
#ifdef U_DEBUG
|
#ifdef U_DEBUG
|
||||||
uhp->uh_magic = 0;
|
uhp->uh_magic = 0;
|
||||||
#endif
|
#endif
|
||||||
@ -3022,3 +3045,28 @@ list_T *u_eval_tree(const u_header_T *const first_uhp)
|
|||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Given the buffer, Return the undo header. If none is set, set one first.
|
||||||
|
// NULL will be returned if e.g undolevels = -1 (undo disabled)
|
||||||
|
u_header_T *u_force_get_undo_header(buf_T *buf)
|
||||||
|
{
|
||||||
|
u_header_T *uhp = NULL;
|
||||||
|
if (buf->b_u_curhead != NULL) {
|
||||||
|
uhp = buf->b_u_curhead;
|
||||||
|
} else if (buf->b_u_newhead) {
|
||||||
|
uhp = buf->b_u_newhead;
|
||||||
|
}
|
||||||
|
// Create the first undo header for the buffer
|
||||||
|
if (!uhp) {
|
||||||
|
// TODO(timeyyy): there would be a better way to do this!
|
||||||
|
u_save_cursor();
|
||||||
|
uhp = buf->b_u_curhead;
|
||||||
|
if (!uhp) {
|
||||||
|
uhp = buf->b_u_newhead;
|
||||||
|
if (get_undolevel() > 0 && !uhp) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uhp;
|
||||||
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <time.h> // for time_t
|
#include <time.h> // for time_t
|
||||||
|
|
||||||
#include "nvim/pos.h"
|
#include "nvim/pos.h"
|
||||||
|
#include "nvim/mark_extended_defs.h"
|
||||||
#include "nvim/mark_defs.h"
|
#include "nvim/mark_defs.h"
|
||||||
|
|
||||||
typedef struct u_header u_header_T;
|
typedef struct u_header u_header_T;
|
||||||
@ -56,14 +57,15 @@ struct u_header {
|
|||||||
u_entry_T *uh_getbot_entry; /* pointer to where ue_bot must be set */
|
u_entry_T *uh_getbot_entry; /* pointer to where ue_bot must be set */
|
||||||
pos_T uh_cursor; /* cursor position before saving */
|
pos_T uh_cursor; /* cursor position before saving */
|
||||||
long uh_cursor_vcol;
|
long uh_cursor_vcol;
|
||||||
int uh_flags; /* see below */
|
int uh_flags; // see below
|
||||||
fmark_T uh_namedm[NMARKS]; /* marks before undo/after redo */
|
fmark_T uh_namedm[NMARKS]; // marks before undo/after redo
|
||||||
visualinfo_T uh_visual; /* Visual areas before undo/after redo */
|
extmark_undo_vec_t uh_extmark; // info to move extmarks
|
||||||
time_t uh_time; /* timestamp when the change was made */
|
visualinfo_T uh_visual; // Visual areas before undo/after redo
|
||||||
long uh_save_nr; /* set when the file was saved after the
|
time_t uh_time; // timestamp when the change was made
|
||||||
changes in this block */
|
long uh_save_nr; // set when the file was saved after the
|
||||||
|
// changes in this block
|
||||||
#ifdef U_DEBUG
|
#ifdef U_DEBUG
|
||||||
int uh_magic; /* magic number to check allocation */
|
int uh_magic; // magic number to check allocation
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
1369
test/functional/api/mark_extended_spec.lua
Normal file
1369
test/functional/api/mark_extended_spec.lua
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user