diff options
Diffstat (limited to 'src/nvim/api/buffer.c')
| -rw-r--r-- | src/nvim/api/buffer.c | 274 | 
1 files changed, 247 insertions, 27 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index a8446265d0..55b535c78c 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1,6 +1,5 @@  // Much of this code was adapted from 'if_py_both.h' from the original  // vim source -#include <errno.h>  #include <stdbool.h>  #include <stdint.h>  #include <stdlib.h> @@ -20,6 +19,7 @@  #include "nvim/mark.h"  #include "nvim/fileio.h"  #include "nvim/move.h" +#include "nvim/syntax.h"  #include "nvim/window.h"  #include "nvim/undo.h" @@ -45,14 +45,22 @@ Integer buffer_line_count(Buffer buffer, Error *err)  /// Gets a buffer line  /// +/// @deprecated use buffer_get_lines instead. +///             for positive indices (including 0) use +///                 "buffer_get_lines(buffer, index, index+1, true)" +///             for negative indices use +///                 "buffer_get_lines(buffer, index-1, index, true)" +///  /// @param buffer The buffer handle  /// @param index The line index  /// @param[out] err Details of an error that may have occurred  /// @return The line string  String buffer_get_line(Buffer buffer, Integer index, Error *err)  { -  String rv = {.size = 0}; -  Array slice = buffer_get_line_slice(buffer, index, index, true, true, err); +  String rv = { .size = 0 }; + +  index = convert_index(index); +  Array slice = buffer_get_lines(buffer, index, index+1, true, err);    if (!err->set && slice.size) {      rv = slice.items[0].data.string; @@ -65,6 +73,12 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err)  /// Sets a buffer line  /// +/// @deprecated use buffer_set_lines instead. +///             for positive indices use +///                 "buffer_set_lines(buffer, index, index+1, true, [line])" +///             for negative indices use +///                 "buffer_set_lines(buffer, index-1, index, true, [line])" +///  /// @param buffer The buffer handle  /// @param index The line index  /// @param line The new line. @@ -72,23 +86,34 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err)  void buffer_set_line(Buffer buffer, Integer index, String line, Error *err)  {    Object l = STRING_OBJ(line); -  Array array = {.items = &l, .size = 1}; -  buffer_set_line_slice(buffer, index, index, true, true, array, err); +  Array array = { .items = &l, .size = 1 }; +  index = convert_index(index); +  buffer_set_lines(buffer, index, index+1, true,  array, err);  }  /// Deletes a buffer line  /// +/// @deprecated use buffer_set_lines instead. +///             for positive indices use +///                 "buffer_set_lines(buffer, index, index+1, true, [])" +///             for negative indices use +///                 "buffer_set_lines(buffer, index-1, index, true, [])"  /// @param buffer The buffer handle  /// @param index The line index  /// @param[out] err Details of an error that may have occurred  void buffer_del_line(Buffer buffer, Integer index, Error *err)  {    Array array = ARRAY_DICT_INIT; -  buffer_set_line_slice(buffer, index, index, true, true, array, err); +  index = convert_index(index); +  buffer_set_lines(buffer, index, index+1, true, array, err);  }  /// Retrieves a line range from the buffer  /// +/// @deprecated use buffer_get_lines(buffer, newstart, newend, false) +///             where newstart = start + int(not include_start) - int(start < 0) +///                   newend = end + int(include_end) - int(end < 0) +///                   int(bool) = 1 if bool is true else 0  /// @param buffer The buffer handle  /// @param start The first line index  /// @param end The last line index @@ -103,16 +128,48 @@ ArrayOf(String) buffer_get_line_slice(Buffer buffer,                                   Boolean include_end,                                   Error *err)  { +  start = convert_index(start) + !include_start; +  end = convert_index(end) + include_end; +  return buffer_get_lines(buffer, start , end, false, err); +} + + +/// Retrieves a line range from the buffer +/// +/// Indexing is zero-based, end-exclusive. Negative indices are interpreted +/// as length+1+index, i e -1 refers to the index past the end. So to get the +/// last element set start=-2 and end=-1. +/// +/// Out-of-bounds indices are clamped to the nearest valid value, unless +/// `strict_indexing` is set. +/// +/// @param buffer The buffer handle +/// @param start The first line index +/// @param end The last line index (exclusive) +/// @param strict_indexing whether out-of-bounds should be an error. +/// @param[out] err Details of an error that may have occurred +/// @return An array of lines +ArrayOf(String) buffer_get_lines(Buffer buffer, +                                 Integer start, +                                 Integer end, +                                 Boolean strict_indexing, +                                 Error *err) +{    Array rv = ARRAY_DICT_INIT;    buf_T *buf = find_buffer_by_handle(buffer, err); -  if (!buf || !inbounds(buf, start)) { +  if (!buf) {      return rv;    } -  start = normalize_index(buf, start) + (include_start ? 0 : 1); -  include_end = include_end || (end >= buf->b_ml.ml_line_count); -  end = normalize_index(buf, end) + (include_end ? 1 : 0); +  bool oob = false; +  start = normalize_index(buf, start, &oob); +  end = normalize_index(buf, end, &oob); + +  if (strict_indexing && oob) { +    api_set_error(err, Validation, _("Index out of bounds")); +    return rv; +  }    if (start >= end) {      // Return 0-length array @@ -152,8 +209,14 @@ end:    return rv;  } +  /// Replaces a line range on the buffer  /// +/// @deprecated use buffer_set_lines(buffer, newstart, newend, false, lines) +///             where newstart = start + int(not include_start) + int(start < 0) +///                   newend = end + int(include_end) + int(end < 0) +///                   int(bool) = 1 if bool is true else 0 +///  /// @param buffer The buffer handle  /// @param start The first line index  /// @param end The last line index @@ -170,20 +233,52 @@ void buffer_set_line_slice(Buffer buffer,                        ArrayOf(String) replacement,                        Error *err)  { +  start = convert_index(start) + !include_start; +  end = convert_index(end) + include_end; +  buffer_set_lines(buffer, start, end, false, replacement, err); +} + + +/// Replaces line range on the buffer +/// +/// Indexing is zero-based, end-exclusive. Negative indices are interpreted +/// as length+1+index, i e -1 refers to the index past the end. So to change +/// or delete the last element set start=-2 and end=-1. +/// +/// To insert lines at a given index, set both start and end to the same index. +/// To delete a range of lines, set replacement to an empty array. +/// +/// Out-of-bounds indices are clamped to the nearest valid value, unless +/// `strict_indexing` is set. +/// +/// @param buffer The buffer handle +/// @param start The first line index +/// @param end The last line index (exclusive) +/// @param strict_indexing whether out-of-bounds should be an error. +/// @param replacement An array of lines to use as replacement +/// @param[out] err Details of an error that may have occurred +void buffer_set_lines(Buffer buffer, +                      Integer start, +                      Integer end, +                      Boolean strict_indexing, +                      ArrayOf(String) replacement, +                      Error *err) +{    buf_T *buf = find_buffer_by_handle(buffer, err);    if (!buf) {      return;    } -  if (!inbounds(buf, start)) { +  bool oob = false; +  start = normalize_index(buf, start, &oob); +  end = normalize_index(buf, end, &oob); + +  if (strict_indexing && oob) {      api_set_error(err, Validation, _("Index out of bounds"));      return;    } -  start = normalize_index(buf, start) + (include_start ? 0 : 1); -  include_end = include_end || (end >= buf->b_ml.ml_line_count); -  end = normalize_index(buf, end) + (include_end ? 1 : 0);    if (start > end) {      api_set_error(err, @@ -328,13 +423,16 @@ Object buffer_get_var(Buffer buffer, String name, Error *err)    return dict_get_value(buf->b_vars, name, err);  } -/// Sets a buffer-scoped (b:) variable. 'nil' value deletes the variable. +/// Sets a buffer-scoped (b:) variable  ///  /// @param buffer The buffer handle  /// @param name The variable name  /// @param value The variable value  /// @param[out] err Details of an error that may have occurred -/// @return The old value +/// @return The old value or nil if there was no previous value. +/// +///         @warning It may return nil if there was no previous value +///                  or if previous value was `v:null`.  Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)  {    buf_T *buf = find_buffer_by_handle(buffer, err); @@ -343,7 +441,27 @@ Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)      return (Object) OBJECT_INIT;    } -  return dict_set_value(buf->b_vars, name, value, err); +  return dict_set_value(buf->b_vars, name, value, false, err); +} + +/// Removes a buffer-scoped (b:) variable +/// +/// @param buffer The buffer handle +/// @param name The variable name +/// @param[out] err Details of an error that may have occurred +/// @return The old value or nil if there was no previous value. +/// +///         @warning It may return nil if there was no previous value +///                  or if previous value was `v:null`. +Object buffer_del_var(Buffer buffer, String name, Error *err) +{ +  buf_T *buf = find_buffer_by_handle(buffer, err); + +  if (!buf) { +    return (Object) OBJECT_INIT; +  } + +  return dict_set_value(buf->b_vars, name, NIL, true, err);  }  /// Gets a buffer option value @@ -457,6 +575,8 @@ Boolean buffer_is_valid(Buffer buffer)  /// Inserts a sequence of lines to a buffer at a certain index  /// +/// @deprecated use buffer_set_lines(buffer, lnum, lnum, true, lines) +///  /// @param buffer The buffer handle  /// @param lnum Insert the lines after `lnum`. If negative, it will append  ///        to the end of the buffer. @@ -467,8 +587,9 @@ void buffer_insert(Buffer buffer,                     ArrayOf(String) lines,                     Error *err)  { -  bool end_start = lnum < 0; -  buffer_set_line_slice(buffer, lnum, lnum, !end_start, end_start, lines, err); +  // "lnum" will be the index of the line after inserting, +  // no matter if it is negative or not +  buffer_set_lines(buffer, lnum, lnum, true, lines, err);  }  /// Return a tuple (row,col) representing the position of the named mark @@ -515,6 +636,99 @@ ArrayOf(Integer, 2) buffer_get_mark(Buffer buffer, String name, Error *err)    return rv;  } +/// Adds a highlight to buffer. +/// +/// This can be used for plugins which dynamically generate highlights to a +/// buffer (like a semantic highlighter or linter). The function adds a single +/// highlight to a buffer. Unlike matchaddpos() highlights follow changes to +/// line numbering (as lines are inserted/removed above the highlighted line), +/// like signs and marks do. +/// +/// "src_id" is useful for batch deletion/updating of a set of highlights. When +/// called with src_id = 0, an unique source id is generated and returned. +/// Succesive calls can pass in it as "src_id" to add new highlights to the same +/// source group. All highlights in the same group can then be cleared with +/// buffer_clear_highlight. If the highlight never will be manually deleted +/// pass in -1 for "src_id". +/// +/// If "hl_group" is the empty string no highlight is added, but a new src_id +/// is still returned. This is useful for an external plugin to synchrounously +/// request an unique src_id at initialization, and later asynchronously add and +/// clear highlights in response to buffer changes. +/// +/// @param buffer The buffer handle +/// @param src_id Source group to use or 0 to use a new group, +///               or -1 for ungrouped highlight +/// @param hl_group Name of the highlight group to use +/// @param line The line to highlight +/// @param col_start Start of range of columns to highlight +/// @param col_end End of range of columns to highlight, +///                or -1 to highlight to end of line +/// @param[out] err Details of an error that may have occurred +/// @return The src_id that was used +Integer buffer_add_highlight(Buffer buffer, +                             Integer src_id, +                             String hl_group, +                             Integer line, +                             Integer col_start, +                             Integer col_end, +                             Error *err) +{ +  buf_T *buf = find_buffer_by_handle(buffer, err); +  if (!buf) { +    return 0; +  } + +  if (line < 0 || line >= MAXLNUM) { +    api_set_error(err, Validation, _("Line number outside range")); +    return 0; +  } +  if (col_start < 0 || col_start > MAXCOL) { +    api_set_error(err, Validation, _("Column value outside range")); +    return 0; +  } +  if (col_end < 0 || col_end > MAXCOL) { +    col_end = MAXCOL; +  } + +  int hlg_id = syn_name2id((char_u*)hl_group.data); +  src_id = bufhl_add_hl(buf, (int)src_id, hlg_id, (linenr_T)line+1, +                        (colnr_T)col_start+1, (colnr_T)col_end); +  return src_id; +} + +/// Clears highlights from a given source group and a range of lines +/// +/// To clear a source group in the entire buffer, pass in 1 and -1 to +/// line_start and line_end respectively. +/// +/// @param buffer The buffer handle +/// @param src_id Highlight source group to clear, or -1 to clear all groups. +/// @param line_start Start of range of lines to clear +/// @param line_end End of range of lines to clear (exclusive) +///                 or -1 to clear to end of file. +/// @param[out] err Details of an error that may have occurred +void buffer_clear_highlight(Buffer buffer, +                            Integer src_id, +                            Integer line_start, +                            Integer line_end, +                            Error *err) +{ +  buf_T *buf = find_buffer_by_handle(buffer, err); +  if (!buf) { +    return; +  } + +  if (line_start < 0 || line_start >= MAXLNUM) { +    api_set_error(err, Validation, _("Line number outside range")); +    return; +  } +  if (line_end < 0 || line_end > MAXLNUM) { +    line_end = MAXLNUM; +  } + +  bufhl_clear_line_range(buf, (int)src_id, (int)line_start+1, (int)line_end); +}  // Check if deleting lines made the cursor position invalid.  // Changed the lines from "lo" to "hi" and added "extra" lines (negative if @@ -539,20 +753,26 @@ static void fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra)  }  // Normalizes 0-based indexes to buffer line numbers -static int64_t normalize_index(buf_T *buf, int64_t index) +static int64_t normalize_index(buf_T *buf, int64_t index, bool *oob)  { +  int64_t line_count = buf->b_ml.ml_line_count;    // Fix if < 0 -  index = index < 0 ?  buf->b_ml.ml_line_count + index : index; +  index = index < 0 ? line_count + index +1 : index; + +  // Check for oob +  if (index > line_count) { +    *oob = true; +    index = line_count; +  } else if (index < 0) { +    *oob = true; +    index = 0; +  }    // Convert the index to a vim line number    index++; -  // Fix if > line_count -  index = index > buf->b_ml.ml_line_count ? buf->b_ml.ml_line_count : index;    return index;  } -// Returns true if the 0-indexed `index` is within the 1-indexed buffer bounds. -static bool inbounds(buf_T *buf, int64_t index) +static int64_t convert_index(int64_t index)  { -  linenr_T nlines = buf->b_ml.ml_line_count; -  return index >= -nlines && index < nlines; +  return index < 0 ? index - 1 : index;  }  | 
