diff options
Diffstat (limited to 'src/nvim/api/buffer.c')
| -rw-r--r-- | src/nvim/api/buffer.c | 199 | 
1 files changed, 121 insertions, 78 deletions
| diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 26f9a6f592..6be981a18e 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1,3 +1,6 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +  // Much of this code was adapted from 'if_py_both.h' from the original  // vim source  #include <stdbool.h> @@ -32,7 +35,7 @@  /// @param[out] err Error details, if any  /// @return Line count  Integer nvim_buf_line_count(Buffer buffer, Error *err) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1)  {    buf_T *buf = find_buffer_by_handle(buffer, err); @@ -62,7 +65,7 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err)    index = convert_index(index);    Array slice = nvim_buf_get_lines(0, buffer, index, index+1, true, err); -  if (!err->set && slice.size) { +  if (!ERROR_SET(err) && slice.size) {      rv = slice.items[0].data.string;    } @@ -154,7 +157,7 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id,                                     Integer end,                                     Boolean strict_indexing,                                     Error *err) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1)  {    Array rv = ARRAY_DICT_INIT;    buf_T *buf = find_buffer_by_handle(buffer, err); @@ -168,7 +171,7 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id,    end = normalize_index(buf, end, &oob);    if (strict_indexing && oob) { -    api_set_error(err, Validation, _("Index out of bounds")); +    api_set_error(err, kErrorTypeValidation, "Index out of bounds");      return rv;    } @@ -183,16 +186,16 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id,    for (size_t i = 0; i < rv.size; i++) {      int64_t lnum = start + (int64_t)i; -    if (lnum > LONG_MAX) { -      api_set_error(err, Validation, _("Line index is too high")); +    if (lnum >= MAXLNUM) { +      api_set_error(err, kErrorTypeValidation, "Line index is too high");        goto end;      } -    const char *bufstr = (char *) ml_get_buf(buf, (linenr_T) lnum, false); +    const char *bufstr = (char *)ml_get_buf(buf, (linenr_T)lnum, false);      Object str = STRING_OBJ(cstr_to_string(bufstr));      // Vim represents NULs as NLs, but this may confuse clients. -    if (channel_id != INTERNAL_CALL) { +    if (channel_id != VIML_INTERNAL_CALL) {        strchrsub(str.data.string.data, '\n', '\0');      } @@ -200,7 +203,7 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id,    }  end: -  if (err->set) { +  if (ERROR_SET(err)) {      for (size_t i = 0; i < rv.size; i++) {        xfree(rv.items[i].data.string.data);      } @@ -267,7 +270,7 @@ void nvim_buf_set_lines(uint64_t channel_id,                          Boolean strict_indexing,                          ArrayOf(String) replacement,  // NOLINT                          Error *err) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1)  {    buf_T *buf = find_buffer_by_handle(buffer, err); @@ -280,18 +283,36 @@ void nvim_buf_set_lines(uint64_t channel_id,    end = normalize_index(buf, end, &oob);    if (strict_indexing && oob) { -    api_set_error(err, Validation, _("Index out of bounds")); +    api_set_error(err, kErrorTypeValidation, "Index out of bounds");      return;    }    if (start > end) {      api_set_error(err, -                  Validation, -                  _("Argument \"start\" is higher than \"end\"")); +                  kErrorTypeValidation, +                  "Argument \"start\" is higher than \"end\"");      return;    } +  for (size_t i = 0; i < replacement.size; i++) { +    if (replacement.items[i].type != kObjectTypeString) { +      api_set_error(err, +                    kErrorTypeValidation, +                    "All items in the replacement array must be strings"); +      return; +    } +    // Disallow newlines in the middle of the line. +    if (channel_id != VIML_INTERNAL_CALL) { +      const String l = replacement.items[i].data.string; +      if (memchr(l.data, NL, l.size)) { +        api_set_error(err, kErrorTypeValidation, +                      "String cannot contain newlines"); +        return; +      } +    } +  } +    win_T *save_curwin = NULL;    tabpage_T *save_curtab = NULL;    size_t new_len = replacement.size; @@ -300,34 +321,20 @@ void nvim_buf_set_lines(uint64_t channel_id,    char **lines = (new_len != 0) ? xcalloc(new_len, sizeof(char *)) : NULL;    for (size_t i = 0; i < new_len; i++) { -    if (replacement.items[i].type != kObjectTypeString) { -      api_set_error(err, -                    Validation, -                    _("All items in the replacement array must be strings")); -      goto end; -    } - -    String l = replacement.items[i].data.string; +    const String l = replacement.items[i].data.string; -    // Fill lines[i] with l's contents. Disallow newlines in the middle of a -    // line and convert NULs to newlines to avoid truncation. -    lines[i] = xmallocz(l.size); -    for (size_t j = 0; j < l.size; j++) { -      if (l.data[j] == '\n' && channel_id != INTERNAL_CALL) { -        api_set_error(err, Exception, _("string cannot contain newlines")); -        new_len = i + 1; -        goto end; -      } -      lines[i][j] = (char) (l.data[j] == '\0' ? '\n' : l.data[j]); -    } +    // Fill lines[i] with l's contents. Convert NULs to newlines as required by +    // NL-used-for-NUL. +    lines[i] = xmemdupz(l.data, l.size); +    memchrsub(lines[i], NUL, NL, l.size);    }    try_start(); -  bufref_T save_curbuf = { NULL, 0 }; +  bufref_T save_curbuf = { NULL, 0, 0 };    switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf);    if (u_save((linenr_T)(start - 1), (linenr_T)end) == FAIL) { -    api_set_error(err, Exception, _("Failed to save undo information")); +    api_set_error(err, kErrorTypeException, "Failed to save undo information");      goto end;    } @@ -337,7 +344,7 @@ void nvim_buf_set_lines(uint64_t channel_id,    size_t to_delete = (new_len < old_len) ? (size_t)(old_len - new_len) : 0;    for (size_t i = 0; i < to_delete; i++) {      if (ml_delete((linenr_T)start, false) == FAIL) { -      api_set_error(err, Exception, _("Failed to delete line")); +      api_set_error(err, kErrorTypeException, "Failed to delete line");        goto end;      }    } @@ -353,13 +360,13 @@ void nvim_buf_set_lines(uint64_t channel_id,    for (size_t i = 0; i < to_replace; i++) {      int64_t lnum = start + (int64_t)i; -    if (lnum > LONG_MAX) { -      api_set_error(err, Validation, _("Index value is too high")); +    if (lnum >= MAXLNUM) { +      api_set_error(err, kErrorTypeValidation, "Index value is too high");        goto end;      }      if (ml_replace((linenr_T)lnum, (char_u *)lines[i], false) == FAIL) { -      api_set_error(err, Exception, _("Failed to replace line")); +      api_set_error(err, kErrorTypeException, "Failed to replace line");        goto end;      }      // Mark lines that haven't been passed to the buffer as they need @@ -371,13 +378,13 @@ void nvim_buf_set_lines(uint64_t channel_id,    for (size_t i = to_replace; i < new_len; i++) {      int64_t lnum = start + (int64_t)i - 1; -    if (lnum > LONG_MAX) { -      api_set_error(err, Validation, _("Index value is too high")); +    if (lnum >= MAXLNUM) { +      api_set_error(err, kErrorTypeValidation, "Index value is too high");        goto end;      }      if (ml_append((linenr_T)lnum, (char_u *)lines[i], 0, false) == FAIL) { -      api_set_error(err, Exception, _("Failed to insert line")); +      api_set_error(err, kErrorTypeException, "Failed to insert line");        goto end;      } @@ -392,7 +399,11 @@ void nvim_buf_set_lines(uint64_t channel_id,    // Only adjust marks if we managed to switch to a window that holds    // the buffer, otherwise line numbers will be invalid.    if (save_curbuf.br_buf == NULL) { -    mark_adjust((linenr_T)start, (linenr_T)(end - 1), MAXLNUM, extra); +    mark_adjust((linenr_T)start, +                (linenr_T)(end - 1), +                MAXLNUM, +                (long)extra, +                false);    }    changed_lines((linenr_T)start, 0, (linenr_T)end, (long)extra); @@ -418,7 +429,7 @@ end:  /// @param[out] err   Error details, if any  /// @return Variable value  Object nvim_buf_get_var(Buffer buffer, String name, Error *err) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1)  {    buf_T *buf = find_buffer_by_handle(buffer, err); @@ -432,10 +443,11 @@ Object nvim_buf_get_var(Buffer buffer, String name, Error *err)  /// Gets a changed tick of a buffer  ///  /// @param[in]  buffer  Buffer handle. +/// @param[out] err     Error details, if any  ///  /// @return `b:changedtick` value.  Integer nvim_buf_get_changedtick(Buffer buffer, Error *err) -    FUNC_API_SINCE(2) +  FUNC_API_SINCE(2)  {    const buf_T *const buf = find_buffer_by_handle(buffer, err); @@ -446,6 +458,26 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err)    return buf->b_changedtick;  } +/// Gets a list of dictionaries describing buffer-local mappings. +/// The "buffer" key in the returned dictionary reflects the buffer +/// handle where the mapping is present. +/// +/// @param  mode       Mode short-name ("n", "i", "v", ...) +/// @param  buffer     Buffer handle +/// @param[out]  err   Error details, if any +/// @returns Array of maparg()-like dictionaries describing mappings +ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err) +    FUNC_API_SINCE(3) +{ +  buf_T *buf = find_buffer_by_handle(buffer, err); + +  if (!buf) { +    return (Array)ARRAY_DICT_INIT; +  } + +  return keymap_array(mode, buf); +} +  /// Sets a buffer-scoped (b:) variable  ///  /// @param buffer     Buffer handle @@ -453,7 +485,7 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err)  /// @param value      Variable value  /// @param[out] err   Error details, if any  void nvim_buf_set_var(Buffer buffer, String name, Object value, Error *err) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1)  {    buf_T *buf = find_buffer_by_handle(buffer, err); @@ -470,7 +502,7 @@ void nvim_buf_set_var(Buffer buffer, String name, Object value, Error *err)  /// @param name       Variable name  /// @param[out] err   Error details, if any  void nvim_buf_del_var(Buffer buffer, String name, Error *err) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1)  {    buf_T *buf = find_buffer_by_handle(buffer, err); @@ -531,7 +563,7 @@ Object buffer_del_var(Buffer buffer, String name, Error *err)  /// @param[out] err   Error details, if any  /// @return Option value  Object nvim_buf_get_option(Buffer buffer, String name, Error *err) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1)  {    buf_T *buf = find_buffer_by_handle(buffer, err); @@ -550,7 +582,7 @@ Object nvim_buf_get_option(Buffer buffer, String name, Error *err)  /// @param value      Option value  /// @param[out] err   Error details, if any  void nvim_buf_set_option(Buffer buffer, String name, Object value, Error *err) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1)  {    buf_T *buf = find_buffer_by_handle(buffer, err); @@ -563,11 +595,15 @@ void nvim_buf_set_option(Buffer buffer, String name, Object value, Error *err)  /// Gets the buffer number  /// +/// @deprecated The buffer number now is equal to the object id, +///             so there is no need to use this function. +///  /// @param buffer     Buffer handle  /// @param[out] err   Error details, if any  /// @return Buffer number  Integer nvim_buf_get_number(Buffer buffer, Error *err) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1) +  FUNC_API_DEPRECATED_SINCE(2)  {    Integer rv = 0;    buf_T *buf = find_buffer_by_handle(buffer, err); @@ -585,7 +621,7 @@ Integer nvim_buf_get_number(Buffer buffer, Error *err)  /// @param[out] err   Error details, if any  /// @return Buffer name  String nvim_buf_get_name(Buffer buffer, Error *err) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1)  {    String rv = STRING_INIT;    buf_T *buf = find_buffer_by_handle(buffer, err); @@ -603,7 +639,7 @@ String nvim_buf_get_name(Buffer buffer, Error *err)  /// @param name       Buffer name  /// @param[out] err   Error details, if any  void nvim_buf_set_name(Buffer buffer, String name, Error *err) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1)  {    buf_T *buf = find_buffer_by_handle(buffer, err); @@ -624,7 +660,7 @@ void nvim_buf_set_name(Buffer buffer, String name, Error *err)    }    if (ren_ret == FAIL) { -    api_set_error(err, Exception, _("Failed to rename buffer")); +    api_set_error(err, kErrorTypeException, "Failed to rename buffer");    }  } @@ -633,10 +669,12 @@ void nvim_buf_set_name(Buffer buffer, String name, Error *err)  /// @param buffer Buffer handle  /// @return true if the buffer is valid, false otherwise  Boolean nvim_buf_is_valid(Buffer buffer) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1)  {    Error stub = ERROR_INIT; -  return find_buffer_by_handle(buffer, &stub) != NULL; +  Boolean ret = find_buffer_by_handle(buffer, &stub) != NULL; +  api_clear_error(&stub); +  return ret;  }  /// Inserts a sequence of lines to a buffer at a certain index @@ -665,7 +703,7 @@ void buffer_insert(Buffer buffer,  /// @param[out] err   Error details, if any  /// @return (row, col) tuple  ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1)  {    Array rv = ARRAY_DICT_INIT;    buf_T *buf = find_buffer_by_handle(buffer, err); @@ -675,7 +713,8 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)    }    if (name.size != 1) { -    api_set_error(err, Validation, _("Mark name must be a single character")); +    api_set_error(err, kErrorTypeValidation, +                  "Mark name must be a single character");      return rv;    } @@ -693,7 +732,7 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)    }    if (posp == NULL) { -    api_set_error(err, Validation, _("Invalid mark name")); +    api_set_error(err, kErrorTypeValidation, "Invalid mark name");      return rv;    } @@ -705,31 +744,31 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)  /// 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 +/// Useful for plugins that 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 -/// nvim_buf_clear_highlight. If the highlight never will be manually deleted -/// pass in -1 for "src_id". +/// `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. +/// Successive calls can pass that `src_id` to associate new highlights with +/// the same source group. All highlights in the same group can be cleared +/// with `nvim_buf_clear_highlight`. If the highlight never will be manually +/// deleted, pass `src_id = -1`.  /// -/// If "hl_group" is the empty string no highlight is added, but a new 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. +/// request an unique `src_id` at initialization, and later asynchronously add +/// and clear highlights in response to buffer changes.  ///  /// @param buffer     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       Line to highlight -/// @param col_start  Start of range of columns to highlight -/// @param col_end    End of range of columns to highlight, +/// @param line       Line to highlight (zero-indexed) +/// @param col_start  Start of (byte-indexed) column range to highlight +/// @param col_end    End of (byte-indexed) column range to highlight,  ///                   or -1 to highlight to end of line  /// @param[out] err   Error details, if any  /// @return The src_id that was used @@ -740,7 +779,7 @@ Integer nvim_buf_add_highlight(Buffer buffer,                                 Integer col_start,                                 Integer col_end,                                 Error *err) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1)  {    buf_T *buf = find_buffer_by_handle(buffer, err);    if (!buf) { @@ -748,18 +787,22 @@ Integer nvim_buf_add_highlight(Buffer buffer,    }    if (line < 0 || line >= MAXLNUM) { -    api_set_error(err, Validation, _("Line number outside range")); +    api_set_error(err, kErrorTypeValidation, "Line number outside range");      return 0;    }    if (col_start < 0 || col_start > MAXCOL) { -    api_set_error(err, Validation, _("Column value outside range")); +    api_set_error(err, kErrorTypeValidation, "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 ? hl_group.data : "")); +  int hlg_id = 0; +  if (hl_group.size > 0) { +    hlg_id = syn_check_group((char_u *)hl_group.data, (int)hl_group.size); +  } +    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; @@ -767,7 +810,7 @@ Integer nvim_buf_add_highlight(Buffer buffer,  /// 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 +/// To clear a source group in the entire buffer, pass in 0 and -1 to  /// line_start and line_end respectively.  ///  /// @param buffer     Buffer handle @@ -781,7 +824,7 @@ void nvim_buf_clear_highlight(Buffer buffer,                                Integer line_start,                                Integer line_end,                                Error *err) -    FUNC_API_SINCE(1) +  FUNC_API_SINCE(1)  {    buf_T *buf = find_buffer_by_handle(buffer, err);    if (!buf) { @@ -789,7 +832,7 @@ void nvim_buf_clear_highlight(Buffer buffer,    }    if (line_start < 0 || line_start >= MAXLNUM) { -    api_set_error(err, Validation, _("Line number outside range")); +    api_set_error(err, kErrorTypeValidation, "Line number outside range");      return;    }    if (line_end < 0 || line_end > MAXLNUM) { | 
