API: Implement buffer_{get,set}_slice

This commit is contained in:
Thiago de Arruda 2014-05-10 18:32:33 -03:00
parent 417a61f54f
commit 4dc34bc0e0
2 changed files with 155 additions and 13 deletions

View File

@ -1,3 +1,5 @@
// Much of this code was adapted from 'if_py_both.h' from the original
// vim source
#include <stdint.h>
#include <stdlib.h>
@ -10,6 +12,7 @@
#include "memory.h"
#include "misc1.h"
#include "misc2.h"
#include "mark.h"
#include "move.h"
#include "../window.h"
#include "undo.h"
@ -136,20 +139,150 @@ void buffer_set_line(Buffer buffer, int64_t index, Object line, Error *err)
}
StringArray buffer_get_slice(Buffer buffer,
int64_t start,
int64_t end,
Error *err)
int64_t start,
int64_t end,
bool include_start,
bool include_end,
Error *err)
{
abort();
StringArray rv = {.size = 0};
buf_T *buf = find_buffer(buffer, err);
if (!buf) {
return rv;
}
start = normalize_index(buf, start) + (include_start ? 0 : 1);
end = normalize_index(buf, end) + (include_end ? 1 : 0);
if (start >= end) {
// Return 0-length array
return rv;
}
rv.size = end - start;
rv.items = xmalloc(sizeof(String) * rv.size);
for (uint32_t i = 0; i < rv.size; i++) {
rv.items[i].data = xstrdup((char *)ml_get_buf(buf, start + i, FALSE));
rv.items[i].size = strlen(rv.items[i].data);
}
return rv;
}
void buffer_set_slice(Buffer buffer,
int64_t start,
int64_t end,
StringArray lines,
Error *err)
int64_t start,
int64_t end,
bool include_start,
bool include_end,
StringArray replacement,
Error *err)
{
abort();
buf_T *buf = find_buffer(buffer, err);
if (!buf) {
return;
}
start = normalize_index(buf, start) + (include_start ? 0 : 1);
end = normalize_index(buf, end) + (include_end ? 1 : 0);
if (start > end) {
set_api_error("start > end", err);
return;
}
buf_T *save_curbuf = NULL;
win_T *save_curwin = NULL;
tabpage_T *save_curtab = NULL;
uint32_t new_len = replacement.size;
uint32_t old_len = end - start;
uint32_t i;
int32_t extra = 0; // lines added to text, can be negative
char **lines;
if (new_len == 0) {
// avoid allocating zero bytes
lines = NULL;
} else {
lines = xcalloc(sizeof(char *), new_len);
}
for (i = 0; i < new_len; i++) {
String l = replacement.items[i];
lines[i] = xstrndup(l.data, l.size);
}
try_start();
switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf);
if (u_save(start - 1, end) == FAIL) {
set_api_error("Cannot save undo information", err);
goto cleanup;
}
// If the size of the range is reducing (ie, new_len < old_len) we
// need to delete some old_len. We do this at the start, by
// repeatedly deleting line "start".
for (i = 0; new_len < old_len && i < old_len - new_len; i++) {
if (ml_delete(start, false) == FAIL) {
set_api_error("Cannot delete line", err);
goto cleanup;
}
}
extra -= i;
// For as long as possible, replace the existing old_len with the
// new old_len. This is a more efficient operation, as it requires
// less memory allocation and freeing.
for (i = 0; i < old_len && i < new_len; i++) {
if (ml_replace(start + i, (char_u *)lines[i], false) == FAIL) {
set_api_error("Cannot replace line", err);
goto cleanup;
}
// Mark lines that haven't been passed to the buffer as they need
// to be freed later
lines[i] = NULL;
}
// Now we may need to insert the remaining new old_len
while (i < new_len) {
if (ml_append(start + i - 1, (char_u *)lines[i], 0, false) == FAIL) {
set_api_error("Cannot insert line", err);
goto cleanup;
}
// Same as with replacing
lines[i] = NULL;
i++;
extra++;
}
// Adjust marks. Invalidate any which lie in the
// changed range, and move any in the remainder of the buffer.
// Only adjust marks if we managed to switch to a window that holds
// the buffer, otherwise line numbers will be invalid.
if (save_curbuf == NULL) {
mark_adjust(start, end - 1, MAXLNUM, extra);
}
changed_lines(start, 0, end, extra);
if (buf == curbuf) {
fix_cursor(start, end, extra);
}
cleanup:
for (uint32_t i = 0; i < new_len; i++) {
if (lines[i] != NULL) {
free(lines[i]);
}
}
free(lines);
restore_win_for_buf(save_curwin, save_curtab, save_curbuf);
try_end(err);
}
Object buffer_get_var(Buffer buffer, String name, Error *err)

View File

@ -34,25 +34,34 @@ void buffer_set_line(Buffer buffer, int64_t index, Object line, Error *err);
///
/// @param buffer The buffer handle
/// @param start The first line index
/// @param end The last line index(exclusive)
/// @param end The last line index
/// @param include_start True if the slice includes the `start` parameter
/// @param include_end True if the slice includes the `end` parameter
/// @param[out] err Details of an error that may have occurred
/// @return An array of lines
StringArray buffer_get_slice(Buffer buffer,
int64_t start,
int64_t end,
bool include_start,
bool include_end,
Error *err);
/// Replaces a line range on the buffer
///
/// @param buffer The buffer handle
/// @param start The first line index
/// @param end The last line index(exclusive)
/// @param lines An array of lines to use as replacement
/// @param end The last line index
/// @param include_start True if the slice includes the `start` parameter
/// @param include_end True if the slice includes the `end` parameter
/// @param lines An array of lines to use as replacement(A 0-length array
/// will simply delete the line range)
/// @param[out] err Details of an error that may have occurred
void buffer_set_slice(Buffer buffer,
int64_t start,
int64_t end,
StringArray lines,
bool include_start,
bool include_end,
StringArray replacement,
Error *err);
/// Gets a buffer variable