Introduce nvim namespace: Move files.

Move files from src/ to src/nvim/.
- src/nvim/ becomes the new root dir for nvim executable sources.
- src/libnvim/ is planned to become root dir of the neovim library.
This commit is contained in:
Eliseo Martínez
2014-05-12 02:25:17 +02:00
parent ffe61e5ba1
commit da51dc9cf2
463 changed files with 0 additions and 0 deletions

114
src/nvim/CMakeLists.txt Normal file
View File

@@ -0,0 +1,114 @@
include(CheckLibraryExists)
set(GENERATED_DIR ${PROJECT_BINARY_DIR}/src/auto)
set(DISPATCH_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/msgpack-gen.lua)
file(GLOB API_HEADERS api/*.h)
set(MSGPACK_RPC_HEADER ${PROJECT_SOURCE_DIR}/src/os/msgpack_rpc.h)
set(MSGPACK_DISPATCH ${GENERATED_DIR}/msgpack_dispatch.c)
# Remove helpers.h from API_HEADERS since it doesn't contain public API
# functions
foreach(sfile ${API_HEADERS})
get_filename_component(f ${sfile} NAME)
if(${f} MATCHES "^(helpers.h)$")
list(APPEND to_remove ${sfile})
endif()
endforeach()
list(REMOVE_ITEM API_HEADERS ${to_remove})
set(to_remove)
file(MAKE_DIRECTORY ${GENERATED_DIR})
add_custom_command(OUTPUT ${MSGPACK_DISPATCH}
COMMAND ${LUA_PRG} ${DISPATCH_GENERATOR} ${API_HEADERS} ${MSGPACK_DISPATCH}
DEPENDS
${API_HEADERS}
${MSGPACK_RPC_HEADER}
${DISPATCH_GENERATOR}
)
file( GLOB NEOVIM_SOURCES *.c )
foreach(sfile ${NEOVIM_SOURCES})
get_filename_component(f ${sfile} NAME)
if(${f} MATCHES "^(regexp_nfa.c)$")
list(APPEND to_remove ${sfile})
endif()
endforeach()
list(REMOVE_ITEM NEOVIM_SOURCES ${to_remove})
list(APPEND NEOVIM_SOURCES "${PROJECT_BINARY_DIR}/config/auto/pathdef.c")
list(APPEND NEOVIM_SOURCES "${MSGPACK_DISPATCH}")
file( GLOB OS_SOURCES os/*.c )
file( GLOB API_SOURCES api/*.c )
set(CONV_SRCS
api.c
arabic.c
garray.c
memory.c
os/env.c
os/event.c
os/job.c
os/mem.c
os/rstream.c
os/signal.c
os/users.c
os/wstream.c
)
set_source_files_properties(
${CONV_SRCS} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wconversion")
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
if(DEFINED ENV{SANITIZE})
message(STATUS "Enabling the sanitizers")
add_definitions(-DEXITFREE) # is this necessary for LeakSanitizer?
add_definitions(-fno-sanitize-recover -fno-omit-frame-pointer
-fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined)
set(CMAKE_EXE_LINKER_FLAGS
"-fsanitize=address -fsanitize=undefined ${CMAKE_EXE_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS
"-fsanitize=address -fsanitize=undefined ${CMAKE_SHARED_LINKER_FLAGS}")
endif()
endif()
# Our dependencies come first.
if (LibIntl_FOUND)
list(APPEND NVIM_LINK_LIBRARIES ${LibIntl_LIBRARY})
endif()
check_library_exists(curses tgetent "" HAVE_LIBCURSES)
if (HAVE_LIBCURSES)
list(APPEND NVIM_LINK_LIBRARIES curses)
else()
check_library_exists(tinfo tgetent "" HAVE_LIBTINFO)
if (HAVE_LIBTINFO)
list(APPEND NVIM_LINK_LIBRARIES tinfo)
else()
find_package(Curses REQUIRED)
list(APPEND NVIM_LINK_LIBRARIES ${CURSES_LIBRARIES})
endif()
endif()
# Put these last on the link line, since multiple things may depend on them.
list(APPEND NVIM_LINK_LIBRARIES
${LIBUV_LIBRARIES}
${MSGPACK_LIBRARIES}
${LUAJIT_LIBRARIES}
m
${CMAKE_THREAD_LIBS_INIT})
if(NOT DEFINED ENV{SKIP_EXEC})
add_executable(nvim ${NEOVIM_SOURCES} ${OS_SOURCES} ${API_SOURCES})
target_link_libraries(nvim ${NVIM_LINK_LIBRARIES})
install(TARGETS nvim RUNTIME DESTINATION bin)
endif()
if(NOT DEFINED ENV{SKIP_UNITTEST})
add_library(nvim-test MODULE EXCLUDE_FROM_ALL ${NEOVIM_SOURCES}
${OS_SOURCES} ${API_SOURCES})
target_link_libraries(nvim-test ${NVIM_LINK_LIBRARIES})
endif()

413
src/nvim/api/buffer.c Normal file
View File

@@ -0,0 +1,413 @@
// Much of this code was adapted from 'if_py_both.h' from the original
// vim source
#include <stdint.h>
#include <stdlib.h>
#include "api/buffer.h"
#include "api/helpers.h"
#include "api/defs.h"
#include "../vim.h"
#include "../buffer.h"
#include "memline.h"
#include "memory.h"
#include "misc1.h"
#include "misc2.h"
#include "ex_cmds.h"
#include "mark.h"
#include "fileio.h"
#include "move.h"
#include "../window.h"
#include "undo.h"
// Find a window that contains "buf" and switch to it.
// If there is no such window, use the current window and change "curbuf".
// Caller must initialize save_curbuf to NULL.
// restore_win_for_buf() MUST be called later!
static void switch_to_win_for_buf(buf_T *buf,
win_T **save_curwinp,
tabpage_T **save_curtabp,
buf_T **save_curbufp);
static void restore_win_for_buf(win_T *save_curwin,
tabpage_T *save_curtab,
buf_T *save_curbuf);
// Check if deleting lines made the cursor position invalid.
// Changed the lines from "lo" to "hi" and added "extra" lines (negative if
// deleted).
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);
int64_t buffer_get_length(Buffer buffer, Error *err)
{
buf_T *buf = find_buffer(buffer, err);
if (!buf) {
return 0;
}
return buf->b_ml.ml_line_count;
}
String buffer_get_line(Buffer buffer, int64_t index, Error *err)
{
String rv = {.size = 0};
StringArray slice = buffer_get_slice(buffer, index, index, true, true, err);
if (slice.size) {
rv = slice.items[0];
}
return rv;
}
void buffer_set_line(Buffer buffer, int64_t index, String line, Error *err)
{
StringArray array = {.items = &line, .size = 1};
buffer_set_slice(buffer, index, index, true, true, array, err);
}
void buffer_del_line(Buffer buffer, int64_t index, Error *err)
{
StringArray array = {.size = 0};
buffer_set_slice(buffer, index, index, true, true, array, err);
}
StringArray buffer_get_slice(Buffer buffer,
int64_t start,
int64_t end,
bool include_start,
bool include_end,
Error *err)
{
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,
bool include_start,
bool include_end,
StringArray replacement,
Error *err)
{
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)
{
Object rv;
buf_T *buf = find_buffer(buffer, err);
if (!buf) {
return rv;
}
return dict_get_value(buf->b_vars, name, err);
}
Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)
{
Object rv;
buf_T *buf = find_buffer(buffer, err);
if (!buf) {
return rv;
}
return dict_set_value(buf->b_vars, name, value, err);
}
Object buffer_get_option(Buffer buffer, String name, Error *err)
{
Object rv;
buf_T *buf = find_buffer(buffer, err);
if (!buf) {
return rv;
}
return get_option_from(buf, SREQ_BUF, name, err);
}
void buffer_set_option(Buffer buffer, String name, Object value, Error *err)
{
buf_T *buf = find_buffer(buffer, err);
if (!buf) {
return;
}
set_option_to(buf, SREQ_BUF, name, value, err);
}
String buffer_get_name(Buffer buffer, Error *err)
{
String rv = {.size = 0, .data = ""};
buf_T *buf = find_buffer(buffer, err);
if (!buf || buf->b_ffname == NULL) {
return rv;
}
rv.data = xstrdup((char *)buf->b_ffname);
rv.size = strlen(rv.data);
return rv;
}
void buffer_set_name(Buffer buffer, String name, Error *err)
{
buf_T *buf = find_buffer(buffer, err);
if (!buf) {
return;
}
aco_save_T aco;
int ren_ret;
char *val = xstrndup(name.data, name.size);
try_start();
// Using aucmd_*: autocommands will be executed by rename_buffer
aucmd_prepbuf(&aco, buf);
ren_ret = rename_buffer((char_u *)val);
aucmd_restbuf(&aco);
if (try_end(err)) {
return;
}
if (ren_ret == FAIL) {
set_api_error("failed to rename buffer", err);
}
}
bool buffer_is_valid(Buffer buffer)
{
Error stub = {.set = false};
return find_buffer(buffer, &stub) != NULL;
}
void buffer_insert(Buffer buffer, int64_t index, StringArray lines, Error *err)
{
buffer_set_slice(buffer, index, index, false, true, lines, err);
}
Position buffer_get_mark(Buffer buffer, String name, Error *err)
{
Position rv;
buf_T *buf = find_buffer(buffer, err);
if (!buf) {
return rv;
}
if (name.size != 0) {
set_api_error("mark name must be a single character", err);
return rv;
}
pos_T *posp;
buf_T *savebuf;
char mark = *name.data;
try_start();
switch_buffer(&savebuf, buf);
posp = getmark(mark, false);
restore_buffer(savebuf);
if (try_end(err)) {
return rv;
}
if (posp == NULL) {
set_api_error("invalid mark name", err);
return rv;
}
rv.row = posp->lnum;
rv.col = posp->col;
return rv;
}
static void switch_to_win_for_buf(buf_T *buf,
win_T **save_curwinp,
tabpage_T **save_curtabp,
buf_T **save_curbufp)
{
win_T *wp;
tabpage_T *tp;
if (find_win_for_buf(buf, &wp, &tp) == FAIL
|| switch_win(save_curwinp, save_curtabp, wp, tp, true) == FAIL)
switch_buffer(save_curbufp, buf);
}
static void restore_win_for_buf(win_T *save_curwin,
tabpage_T *save_curtab,
buf_T *save_curbuf)
{
if (save_curbuf == NULL) {
restore_win(save_curwin, save_curtab, true);
} else {
restore_buffer(save_curbuf);
}
}
static void fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra)
{
if (curwin->w_cursor.lnum >= lo) {
// Adjust the cursor position if it's in/after the changed
// lines.
if (curwin->w_cursor.lnum >= hi) {
curwin->w_cursor.lnum += extra;
check_cursor_col();
} else if (extra < 0) {
curwin->w_cursor.lnum = lo;
check_cursor();
} else {
check_cursor_col();
}
changed_cline_bef_curs();
}
invalidate_botline();
}
static int64_t normalize_index(buf_T *buf, int64_t index)
{
// Fix if < 0
index = index < 0 ? buf->b_ml.ml_line_count + index : index;
// 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;
}

145
src/nvim/api/buffer.h Normal file
View File

@@ -0,0 +1,145 @@
#ifndef NEOVIM_API_BUFFER_H
#define NEOVIM_API_BUFFER_H
#include <stdint.h>
#include <stdbool.h>
#include "api/defs.h"
/// Gets the buffer line count
///
/// @param buffer The buffer handle
/// @param[out] err Details of an error that may have occurred
/// @return The line count
int64_t buffer_get_length(Buffer buffer, Error *err);
/// Gets a buffer line
///
/// @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, int64_t index, Error *err);
/// Sets a buffer line
///
/// @param buffer The buffer handle
/// @param index The line index
/// @param line The new line.
/// @param[out] err Details of an error that may have occurred
void buffer_set_line(Buffer buffer, int64_t index, String line, Error *err);
/// Deletes a buffer line
///
/// @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, int64_t index, Error *err);
/// Retrieves a line range from the buffer
///
/// @param buffer The buffer handle
/// @param start The first line index
/// @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
/// @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,
bool include_start,
bool include_end,
StringArray replacement,
Error *err);
/// Gets a buffer variable
///
/// @param buffer The buffer handle
/// @param name The variable name
/// @param[out] err Details of an error that may have occurred
/// @return The variable value
Object buffer_get_var(Buffer buffer, String name, Error *err);
/// Sets a buffer variable. Passing 'nil' as value deletes the 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
Object buffer_set_var(Buffer buffer, String name, Object value, Error *err);
/// Gets a buffer option value
///
/// @param buffer The buffer handle
/// @param name The option name
/// @param[out] err Details of an error that may have occurred
/// @return The option value
Object buffer_get_option(Buffer buffer, String name, Error *err);
/// Sets a buffer option value. Passing 'nil' as value deletes the option(only
/// works if there's a global fallback)
///
/// @param buffer The buffer handle
/// @param name The option name
/// @param value The option value
/// @param[out] err Details of an error that may have occurred
void buffer_set_option(Buffer buffer, String name, Object value, Error *err);
/// Gets the full file name for the buffer
///
/// @param buffer The buffer handle
/// @param[out] err Details of an error that may have occurred
/// @return The buffer name
String buffer_get_name(Buffer buffer, Error *err);
/// Sets the full file name for a buffer
///
/// @param buffer The buffer handle
/// @param name The buffer name
/// @param[out] err Details of an error that may have occurred
void buffer_set_name(Buffer buffer, String name, Error *err);
/// Checks if a buffer is valid
///
/// @param buffer The buffer handle
/// @return true if the buffer is valid, false otherwise
bool buffer_is_valid(Buffer buffer);
/// Inserts a sequence of lines to a buffer at a certain index
///
/// @param buffer The buffer handle
/// @param lnum Insert the lines before `lnum`. If negative, it will append
/// to the end of the buffer.
/// @param lines An array of lines
/// @param[out] err Details of an error that may have occurred
void buffer_insert(Buffer buffer, int64_t index, StringArray lines, Error *err);
/// Return a tuple (row,col) representing the position of the named mark
///
/// @param buffer The buffer handle
/// @param name The mark's name
/// @param[out] err Details of an error that may have occurred
/// @return The (row, col) tuple
Position buffer_get_mark(Buffer buffer, String name, Error *err);
#endif // NEOVIM_API_BUFFER_H

74
src/nvim/api/defs.h Normal file
View File

@@ -0,0 +1,74 @@
#ifndef NEOVIM_API_DEFS_H
#define NEOVIM_API_DEFS_H
#include <stdint.h>
#include <string.h>
// Basic types
typedef struct {
char msg[256];
bool set;
} Error;
typedef struct {
char *data;
size_t size;
} String;
typedef uint16_t Buffer;
typedef uint16_t Window;
typedef uint16_t Tabpage;
typedef struct object Object;
typedef struct {
String *items;
size_t size;
} StringArray;
typedef struct {
uint16_t row, col;
} Position;
typedef struct {
Object *items;
size_t size;
} Array;
typedef struct key_value_pair KeyValuePair;
typedef struct {
KeyValuePair *items;
size_t size;
} Dictionary;
typedef enum {
kObjectTypeNil,
kObjectTypeBool,
kObjectTypeInt,
kObjectTypeFloat,
kObjectTypeString,
kObjectTypeArray,
kObjectTypeDictionary
} ObjectType;
struct object {
ObjectType type;
union {
bool boolean;
int64_t integer;
double floating_point;
String string;
Array array;
Dictionary dictionary;
} data;
};
struct key_value_pair {
String key;
Object value;
};
#endif // NEOVIM_API_DEFS_H

578
src/nvim/api/helpers.c Normal file
View File

@@ -0,0 +1,578 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "api/helpers.h"
#include "api/defs.h"
#include "../vim.h"
#include "../buffer.h"
#include "../window.h"
#include "memory.h"
#include "eval.h"
#include "option.h"
#include "option_defs.h"
#include "lib/khash.h"
#if defined(ARCH_64)
typedef uint64_t ptr_int_t;
KHASH_SET_INIT_INT64(Lookup)
#elif defined(ARCH_32)
typedef uint32_t ptr_int_t;
KHASH_SET_INIT_INT(Lookup)
#endif
/// Recursion helper for the `vim_to_object`. This uses a pointer table
/// to avoid infinite recursion due to cyclic references
///
/// @param obj The source object
/// @param lookup Lookup table containing pointers to all processed objects
/// @return The converted value
static Object vim_to_object_rec(typval_T *obj, khash_t(Lookup) *lookup);
static bool object_to_vim(Object obj, typval_T *tv, Error *err);
static void set_option_value_for(char *key,
int numval,
char *stringval,
int opt_flags,
int opt_type,
void *from,
Error *err);
static void set_option_value_err(char *key,
int numval,
char *stringval,
int opt_flags,
Error *err);
void try_start()
{
++trylevel;
}
bool try_end(Error *err)
{
--trylevel;
// Without this it stops processing all subsequent VimL commands and
// generates strange error messages if I e.g. try calling Test() in a
// cycle
did_emsg = false;
if (got_int) {
if (did_throw) {
// If we got an interrupt, discard the current exception
discard_current_exception();
}
set_api_error("Keyboard interrupt", err);
got_int = false;
} else if (msg_list != NULL && *msg_list != NULL) {
int should_free;
char *msg = (char *)get_exception_string(*msg_list,
ET_ERROR,
NULL,
&should_free);
strncpy(err->msg, msg, sizeof(err->msg));
err->set = true;
free_global_msglist();
if (should_free) {
free(msg);
}
} else if (did_throw) {
set_api_error((char *)current_exception->value, err);
}
return err->set;
}
Object dict_get_value(dict_T *dict, String key, Error *err)
{
Object rv;
hashitem_T *hi;
dictitem_T *di;
char *k = xstrndup(key.data, key.size);
hi = hash_find(&dict->dv_hashtab, (uint8_t *)k);
free(k);
if (HASHITEM_EMPTY(hi)) {
set_api_error("Key not found", err);
return rv;
}
di = dict_lookup(hi);
rv = vim_to_object(&di->di_tv);
return rv;
}
Object dict_set_value(dict_T *dict, String key, Object value, Error *err)
{
Object rv = {.type = kObjectTypeNil};
if (dict->dv_lock) {
set_api_error("Dictionary is locked", err);
return rv;
}
if (key.size == 0) {
set_api_error("Empty dictionary keys aren't allowed", err);
return rv;
}
dictitem_T *di = dict_find(dict, (uint8_t *)key.data, key.size);
if (value.type == kObjectTypeNil) {
// Delete the key
if (di == NULL) {
// Doesn't exist, fail
set_api_error("Key doesn't exist", err);
} else {
// Return the old value
rv = vim_to_object(&di->di_tv);
// Delete the entry
hashitem_T *hi = hash_find(&dict->dv_hashtab, di->di_key);
hash_remove(&dict->dv_hashtab, hi);
dictitem_free(di);
}
} else {
// Update the key
typval_T tv;
// Convert the object to a vimscript type in the temporary variable
if (!object_to_vim(value, &tv, err)) {
return rv;
}
if (di == NULL) {
// Need to create an entry
char *k = xstrndup(key.data, key.size);
di = dictitem_alloc((uint8_t *)k);
free(k);
dict_add(dict, di);
} else {
// Return the old value
clear_tv(&di->di_tv);
}
// Update the value
copy_tv(&tv, &di->di_tv);
// Clear the temporary variable
clear_tv(&tv);
}
return rv;
}
Object get_option_from(void *from, int type, String name, Error *err)
{
Object rv = {.type = kObjectTypeNil};
if (name.size == 0) {
set_api_error("Empty option name", err);
return rv;
}
// Return values
int64_t numval;
char *stringval = NULL;
// copy the option name into 0-delimited string
char *key = xstrndup(name.data, name.size);
int flags = get_option_value_strict(key, &numval, &stringval, type, from);
free(key);
if (!flags) {
set_api_error("invalid option name", err);
return rv;
}
if (flags & SOPT_BOOL) {
rv.type = kObjectTypeBool;
rv.data.boolean = numval ? true : false;
} else if (flags & SOPT_NUM) {
rv.type = kObjectTypeInt;
rv.data.integer = numval;
} else if (flags & SOPT_STRING) {
if (stringval) {
rv.type = kObjectTypeString;
rv.data.string.data = stringval;
rv.data.string.size = strlen(stringval);
} else {
set_api_error(N_("Unable to get option value"), err);
}
} else {
set_api_error(N_("internal error: unknown option type"), err);
}
return rv;
}
void set_option_to(void *to, int type, String name, Object value, Error *err)
{
if (name.size == 0) {
set_api_error("Empty option name", err);
return;
}
char *key = xstrndup(name.data, name.size);
int flags = get_option_value_strict(key, NULL, NULL, type, to);
if (flags == 0) {
set_api_error("invalid option name", err);
goto cleanup;
}
if (value.type == kObjectTypeNil) {
if (type == SREQ_GLOBAL) {
set_api_error("unable to unset option", err);
goto cleanup;
} else if (!(flags & SOPT_GLOBAL)) {
set_api_error("cannot unset option that doesn't have a global value",
err);
goto cleanup;
} else {
unset_global_local_option(key, to);
goto cleanup;
}
}
int opt_flags = (type ? OPT_LOCAL : OPT_GLOBAL);
if (flags & SOPT_BOOL) {
if (value.type != kObjectTypeBool) {
set_api_error("option requires a boolean value", err);
goto cleanup;
}
bool val = value.data.boolean;
set_option_value_for(key, val, NULL, opt_flags, type, to, err);
} else if (flags & SOPT_NUM) {
if (value.type != kObjectTypeInt) {
set_api_error("option requires an integer value", err);
goto cleanup;
}
int val = value.data.integer;
set_option_value_for(key, val, NULL, opt_flags, type, to, err);
} else {
if (value.type != kObjectTypeString) {
set_api_error("option requires a string value", err);
goto cleanup;
}
char *val = xstrndup(value.data.string.data, value.data.string.size);
set_option_value_for(key, 0, val, opt_flags, type, to, err);
}
cleanup:
free(key);
}
Object vim_to_object(typval_T *obj)
{
Object rv;
// We use a lookup table to break out of cyclic references
khash_t(Lookup) *lookup = kh_init(Lookup);
rv = vim_to_object_rec(obj, lookup);
// Free the table
kh_destroy(Lookup, lookup);
return rv;
}
buf_T *find_buffer(Buffer buffer, Error *err)
{
buf_T *buf = buflist_findnr(buffer);
if (buf == NULL) {
set_api_error("Invalid buffer id", err);
}
return buf;
}
win_T * find_window(Window window, Error *err)
{
tabpage_T *tp;
win_T *wp;
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (!--window) {
return wp;
}
}
set_api_error("Invalid window id", err);
return NULL;
}
tabpage_T * find_tab(Tabpage tabpage, Error *err)
{
tabpage_T *rv = find_tabpage(tabpage);
if (!rv) {
set_api_error("Invalid tabpage id", err);
}
return rv;
}
static bool object_to_vim(Object obj, typval_T *tv, Error *err)
{
tv->v_type = VAR_UNKNOWN;
tv->v_lock = 0;
switch (obj.type) {
case kObjectTypeNil:
tv->v_type = VAR_NUMBER;
tv->vval.v_number = 0;
break;
case kObjectTypeBool:
tv->v_type = VAR_NUMBER;
tv->vval.v_number = obj.data.boolean;
break;
case kObjectTypeInt:
tv->v_type = VAR_NUMBER;
tv->vval.v_number = obj.data.integer;
break;
case kObjectTypeFloat:
tv->v_type = VAR_FLOAT;
tv->vval.v_float = obj.data.floating_point;
break;
case kObjectTypeString:
tv->v_type = VAR_STRING;
tv->vval.v_string = (uint8_t *)xstrndup(obj.data.string.data,
obj.data.string.size);
break;
case kObjectTypeArray:
tv->v_type = VAR_LIST;
tv->vval.v_list = list_alloc();
for (uint32_t i = 0; i < obj.data.array.size; i++) {
Object item = obj.data.array.items[i];
listitem_T *li = listitem_alloc();
if (!object_to_vim(item, &li->li_tv, err)) {
// cleanup
listitem_free(li);
list_free(tv->vval.v_list, true);
return false;
}
list_append(tv->vval.v_list, li);
}
tv->vval.v_list->lv_refcount++;
break;
case kObjectTypeDictionary:
tv->v_type = VAR_DICT;
tv->vval.v_dict = dict_alloc();
for (uint32_t i = 0; i < obj.data.dictionary.size; i++) {
KeyValuePair item = obj.data.dictionary.items[i];
String key = item.key;
if (key.size == 0) {
set_api_error("Empty dictionary keys aren't allowed", err);
// cleanup
dict_free(tv->vval.v_dict, true);
return false;
}
char *k = xstrndup(key.data, key.size);
dictitem_T *di = dictitem_alloc((uint8_t *)k);
free(k);
if (!object_to_vim(item.value, &di->di_tv, err)) {
// cleanup
dictitem_free(di);
dict_free(tv->vval.v_dict, true);
return false;
}
dict_add(tv->vval.v_dict, di);
}
tv->vval.v_dict->dv_refcount++;
break;
}
return true;
}
static Object vim_to_object_rec(typval_T *obj, khash_t(Lookup) *lookup)
{
Object rv = {.type = kObjectTypeNil};
if (obj->v_type == VAR_LIST || obj->v_type == VAR_DICT) {
int ret;
// Container object, add it to the lookup table
kh_put(Lookup, lookup, (ptr_int_t)obj, &ret);
if (!ret) {
// It's already present, meaning we alredy processed it so just return
// nil instead.
return rv;
}
}
switch (obj->v_type) {
case VAR_STRING:
if (obj->vval.v_string != NULL) {
rv.type = kObjectTypeString;
rv.data.string.data = xstrdup((char *)obj->vval.v_string);
rv.data.string.size = strlen(rv.data.string.data);
}
break;
case VAR_NUMBER:
rv.type = kObjectTypeInt;
rv.data.integer = obj->vval.v_number;
break;
case VAR_FLOAT:
rv.type = kObjectTypeFloat;
rv.data.floating_point = obj->vval.v_float;
break;
case VAR_LIST:
{
list_T *list = obj->vval.v_list;
listitem_T *item;
if (list != NULL) {
rv.type = kObjectTypeArray;
rv.data.array.size = list->lv_len;
rv.data.array.items = xmalloc(list->lv_len * sizeof(Object));
uint32_t i = 0;
for (item = list->lv_first; item != NULL; item = item->li_next) {
rv.data.array.items[i] = vim_to_object_rec(&item->li_tv, lookup);
i++;
}
}
}
break;
case VAR_DICT:
{
dict_T *dict = obj->vval.v_dict;
hashtab_T *ht;
uint64_t todo;
hashitem_T *hi;
dictitem_T *di;
if (dict != NULL) {
ht = &obj->vval.v_dict->dv_hashtab;
todo = ht->ht_used;
rv.type = kObjectTypeDictionary;
// Count items
rv.data.dictionary.size = 0;
for (hi = ht->ht_array; todo > 0; ++hi) {
if (!HASHITEM_EMPTY(hi)) {
todo--;
rv.data.dictionary.size++;
}
}
rv.data.dictionary.items =
xmalloc(rv.data.dictionary.size * sizeof(KeyValuePair));
todo = ht->ht_used;
uint32_t i = 0;
// Convert all
for (hi = ht->ht_array; todo > 0; ++hi) {
if (!HASHITEM_EMPTY(hi)) {
di = dict_lookup(hi);
// Convert key
rv.data.dictionary.items[i].key.data =
xstrdup((char *)hi->hi_key);
rv.data.dictionary.items[i].key.size =
strlen((char *)hi->hi_key);
// Convert value
rv.data.dictionary.items[i].value =
vim_to_object_rec(&di->di_tv, lookup);
todo--;
i++;
}
}
}
}
break;
}
return rv;
}
static void set_option_value_for(char *key,
int numval,
char *stringval,
int opt_flags,
int opt_type,
void *from,
Error *err)
{
win_T *save_curwin = NULL;
tabpage_T *save_curtab = NULL;
buf_T *save_curbuf = NULL;
try_start();
switch (opt_type)
{
case SREQ_WIN:
if (switch_win(&save_curwin, &save_curtab, (win_T *)from,
win_find_tabpage((win_T *)from), false) == FAIL)
{
if (try_end(err)) {
return;
}
set_api_error("problem while switching windows", err);
return;
}
set_option_value_err(key, numval, stringval, opt_flags, err);
restore_win(save_curwin, save_curtab, true);
break;
case SREQ_BUF:
switch_buffer(&save_curbuf, (buf_T *)from);
set_option_value_err(key, numval, stringval, opt_flags, err);
restore_buffer(save_curbuf);
break;
case SREQ_GLOBAL:
set_option_value_err(key, numval, stringval, opt_flags, err);
break;
}
if (err->set) {
return;
}
try_end(err);
}
static void set_option_value_err(char *key,
int numval,
char *stringval,
int opt_flags,
Error *err)
{
char *errmsg;
if ((errmsg = (char *)set_option_value((uint8_t *)key,
numval,
(uint8_t *)stringval,
opt_flags)))
{
if (try_end(err)) {
return;
}
set_api_error(errmsg, err);
}
}

90
src/nvim/api/helpers.h Normal file
View File

@@ -0,0 +1,90 @@
#ifndef NEOVIM_API_HELPERS_H
#define NEOVIM_API_HELPERS_H
#include <stdbool.h>
#include "api/defs.h"
#include "../vim.h"
#define set_api_error(message, err) \
do { \
strncpy(err->msg, message, sizeof(err->msg)); \
err->set = true; \
} while (0)
/// Start block that may cause vimscript exceptions
void try_start(void);
/// End try block, set the error message if any and return true if an error
/// occurred.
///
/// @param err Pointer to the stack-allocated error object
/// @return true if an error occurred
bool try_end(Error *err);
/// Recursively expands a vimscript value in a dict
///
/// @param dict The vimscript dict
/// @param key The key
/// @param[out] err Details of an error that may have occurred
Object dict_get_value(dict_T *dict, String key, Error *err);
/// Set a value in a dict. Objects are recursively expanded into their
/// vimscript equivalents. Passing 'nil' as value deletes the key.
///
/// @param dict The vimscript dict
/// @param key The key
/// @param value The new value
/// @param[out] err Details of an error that may have occurred
/// @return the old value, if any
Object dict_set_value(dict_T *dict, String key, Object value, Error *err);
/// Gets the value of a global or local(buffer, window) option.
///
/// @param from If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer
/// to the window or buffer.
/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF`
/// @param name The option name
/// @param[out] err Details of an error that may have occurred
/// @return the option value
Object get_option_from(void *from, int type, String name, Error *err);
/// Sets the value of a global or local(buffer, window) option.
///
/// @param to If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer
/// to the window or buffer.
/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF`
/// @param name The option name
/// @param[out] err Details of an error that may have occurred
void set_option_to(void *to, int type, String name, Object value, Error *err);
/// Convert a vim object to an `Object` instance, recursively expanding
/// Arrays/Dictionaries.
///
/// @param obj The source object
/// @return The converted value
Object vim_to_object(typval_T *obj);
/// Finds the pointer for a window number
///
/// @param window the window number
/// @param[out] err Details of an error that may have occurred
/// @return the window pointer
buf_T *find_buffer(Buffer buffer, Error *err);
/// Finds the pointer for a window number
///
/// @param window the window number
/// @param[out] err Details of an error that may have occurred
/// @return the window pointer
win_T * find_window(Window window, Error *err);
/// Finds the pointer for a tabpage number
///
/// @param tabpage the tabpage number
/// @param[out] err Details of an error that may have occurred
/// @return the tabpage pointer
tabpage_T * find_tab(Tabpage tabpage, Error *err);
#endif // NEOVIM_API_HELPERS_H

88
src/nvim/api/tabpage.c Normal file
View File

@@ -0,0 +1,88 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "api/tabpage.h"
#include "api/vim.h"
#include "api/defs.h"
#include "api/helpers.h"
int64_t tabpage_get_window_count(Tabpage tabpage, Error *err)
{
uint64_t rv = 0;
tabpage_T *tab = find_tab(tabpage, err);
if (!tab) {
return rv;
}
tabpage_T *tp;
win_T *wp;
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (tp != tab) {
break;
}
rv++;
}
return rv;
}
Object tabpage_get_var(Tabpage tabpage, String name, Error *err)
{
Object rv;
tabpage_T *tab = find_tab(tabpage, err);
if (!tab) {
return rv;
}
return dict_get_value(tab->tp_vars, name, err);
}
Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
{
Object rv;
tabpage_T *tab = find_tab(tabpage, err);
if (!tab) {
return rv;
}
return dict_set_value(tab->tp_vars, name, value, err);
}
Window tabpage_get_window(Tabpage tabpage, Error *err)
{
Window rv = 0;
tabpage_T *tab = find_tab(tabpage, err);
if (!tab) {
return rv;
}
if (tab == curtab) {
return vim_get_current_window();
} else {
tabpage_T *tp;
win_T *wp;
rv = 1;
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (tp == tab && wp == tab->tp_curwin) {
return rv;
}
rv++;
}
// There should always be a current window for a tabpage
abort();
}
}
bool tabpage_is_valid(Tabpage tabpage)
{
Error stub = {.set = false};
return find_tab(tabpage, &stub) != NULL;
}

47
src/nvim/api/tabpage.h Normal file
View File

@@ -0,0 +1,47 @@
#ifndef NEOVIM_API_TABPAGE_H
#define NEOVIM_API_TABPAGE_H
#include <stdint.h>
#include <stdbool.h>
#include "api/defs.h"
/// Gets the number of windows in a tabpage
///
/// @param tabpage The tabpage
/// @param[out] err Details of an error that may have occurred
/// @return The number of windows in `tabpage`
int64_t tabpage_get_window_count(Tabpage tabpage, Error *err);
/// Gets a tabpage variable
///
/// @param tabpage The tab page handle
/// @param name The variable name
/// @param[out] err Details of an error that may have occurred
/// @return The variable value
Object tabpage_get_var(Tabpage tabpage, String name, Error *err);
/// Sets a tabpage variable. Passing 'nil' as value deletes the variable.
///
/// @param tabpage handle
/// @param name The variable name
/// @param value The variable value
/// @param[out] err Details of an error that may have occurred
/// @return The tab page handle
Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err);
/// Gets the current window in a tab page
///
/// @param tabpage The tab page handle
/// @param[out] err Details of an error that may have occurred
/// @return The Window handle
Window tabpage_get_window(Tabpage tabpage, Error *err);
/// Checks if a tab page is valid
///
/// @param tabpage The tab page handle
/// @return true if the tab page is valid, false otherwise
bool tabpage_is_valid(Tabpage tabpage);
#endif // NEOVIM_API_TABPAGE_H

321
src/nvim/api/vim.c Normal file
View File

@@ -0,0 +1,321 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "api/vim.h"
#include "api/helpers.h"
#include "api/defs.h"
#include "api/buffer.h"
#include "../vim.h"
#include "../buffer.h"
#include "../window.h"
#include "types.h"
#include "ascii.h"
#include "ex_docmd.h"
#include "screen.h"
#include "memory.h"
#include "message.h"
#include "eval.h"
#include "misc2.h"
#define LINE_BUFFER_SIZE 4096
/// Writes a message to vim output or error buffer. The string is split
/// and flushed after each newline. Incomplete lines are kept for writing
/// later.
///
/// @param message The message to write
/// @param to_err True if it should be treated as an error message(use
/// `emsg` instead of `msg` to print each line)
static void write_msg(String message, bool to_err);
void vim_push_keys(String str)
{
abort();
}
void vim_command(String str, Error *err)
{
// We still use 0-terminated strings, so we must convert.
char *cmd_str = xstrndup(str.data, str.size);
// Run the command
try_start();
do_cmdline_cmd((char_u *)cmd_str);
free(cmd_str);
update_screen(VALID);
try_end(err);
}
Object vim_eval(String str, Error *err)
{
Object rv;
char *expr_str = xstrndup(str.data, str.size);
// Evaluate the expression
try_start();
typval_T *expr_result = eval_expr((char_u *)expr_str, NULL);
free(expr_str);
if (!try_end(err)) {
// No errors, convert the result
rv = vim_to_object(expr_result);
}
// Free the vim object
free_tv(expr_result);
return rv;
}
int64_t vim_strwidth(String str)
{
return mb_string2cells((char_u *)str.data, str.size);
}
StringArray vim_list_runtime_paths(void)
{
StringArray rv = {.size = 0};
uint8_t *rtp = p_rtp;
if (*rtp == NUL) {
// No paths
return rv;
}
// Count the number of paths in rtp
while (*rtp != NUL) {
if (*rtp == ',') {
rv.size++;
}
rtp++;
}
// index
uint32_t i = 0;
// Allocate memory for the copies
rv.items = xmalloc(sizeof(String) * rv.size);
// reset the position
rtp = p_rtp;
// Start copying
while (*rtp != NUL) {
rv.items[i].data = xmalloc(MAXPATHL);
// Copy the path from 'runtimepath' to rv.items[i]
rv.items[i].size = copy_option_part(&rtp,
(char_u *)rv.items[i].data,
MAXPATHL,
",");
i++;
}
return rv;
}
void vim_change_directory(String dir, Error *err)
{
char string[MAXPATHL];
strncpy(string, dir.data, dir.size);
try_start();
if (vim_chdir((char_u *)string)) {
if (!try_end(err)) {
set_api_error("failed to change directory", err);
}
return;
}
post_chdir(false);
try_end(err);
}
String vim_get_current_line(Error *err)
{
return buffer_get_line(curbuf->b_fnum, curwin->w_cursor.lnum - 1, err);
}
void vim_set_current_line(String line, Error *err)
{
buffer_set_line(curbuf->b_fnum, curwin->w_cursor.lnum - 1, line, err);
}
void vim_del_current_line(Error *err)
{
buffer_del_line(curbuf->b_fnum, curwin->w_cursor.lnum - 1, err);
}
Object vim_get_var(String name, Error *err)
{
return dict_get_value(&globvardict, name, err);
}
Object vim_set_var(String name, Object value, Error *err)
{
return dict_set_value(&globvardict, name, value, err);
}
Object vim_get_vvar(String name, Error *err)
{
return dict_get_value(&vimvardict, name, err);
}
Object vim_get_option(String name, Error *err)
{
return get_option_from(NULL, SREQ_GLOBAL, name, err);
}
void vim_set_option(String name, Object value, Error *err)
{
set_option_to(NULL, SREQ_GLOBAL, name, value, err);
}
void vim_out_write(String str)
{
write_msg(str, false);
}
void vim_err_write(String str)
{
write_msg(str, true);
}
int64_t vim_get_buffer_count(void)
{
buf_T *b = firstbuf;
uint64_t n = 0;
while (b) {
n++;
b = b->b_next;
}
return n;
}
Buffer vim_get_current_buffer(void)
{
return curbuf->b_fnum;
}
void vim_set_current_buffer(Buffer buffer, Error *err)
{
try_start();
if (do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, buffer, 0) == FAIL) {
if (try_end(err)) {
return;
}
char msg[256];
snprintf(msg, sizeof(msg), "failed to switch to buffer %d", (int)buffer);
set_api_error(msg, err);
return;
}
try_end(err);
}
int64_t vim_get_window_count(void)
{
tabpage_T *tp;
win_T *wp;
uint64_t rv = 0;
FOR_ALL_TAB_WINDOWS(tp, wp) {
rv++;
}
return rv;
}
Window vim_get_current_window(void)
{
tabpage_T *tp;
win_T *wp;
Window rv = 1;
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp == curwin) {
return rv;
}
rv++;
}
// There should always be a current window
abort();
}
void vim_set_current_window(Window window, Error *err)
{
win_T *win = find_window(window, err);
if (!win) {
return;
}
try_start();
win_goto(win);
if (win != curwin) {
if (try_end(err)) {
return;
}
set_api_error("did not switch to the specified window", err);
return;
}
try_end(err);
}
int64_t vim_get_tabpage_count(void)
{
tabpage_T *tp = first_tabpage;
uint64_t rv = 0;
while (tp != NULL) {
tp = tp->tp_next;
rv++;
}
return rv;
}
Tabpage vim_get_current_tabpage(void)
{
Tabpage rv = 1;
tabpage_T *t;
for (t = first_tabpage; t != NULL && t != curtab; t = t->tp_next) {
rv++;
}
return rv;
}
void vim_set_current_tabpage(Tabpage tabpage, Error *err)
{
try_start();
goto_tabpage(tabpage);
try_end(err);
}
static void write_msg(String message, bool to_err)
{
static int pos = 0;
static char line_buf[LINE_BUFFER_SIZE];
for (uint32_t i = 0; i < message.size; i++) {
if (message.data[i] == NL || pos == LINE_BUFFER_SIZE - 1) {
// Flush line
line_buf[pos] = NUL;
if (to_err) {
emsg((uint8_t *)line_buf);
} else {
msg((uint8_t *)line_buf);
}
pos = 0;
continue;
}
line_buf[pos++] = message.data[i];
}
}

158
src/nvim/api/vim.h Normal file
View File

@@ -0,0 +1,158 @@
#ifndef NEOVIM_API_VIM_H
#define NEOVIM_API_VIM_H
#include <stdint.h>
#include <stdbool.h>
#include "api/defs.h"
/// Send keys to vim input buffer, simulating user input.
///
/// @param str The keys to send
void vim_push_keys(String str);
/// Executes an ex-mode command str
///
/// @param str The command str
/// @param[out] err Details of an error that may have occurred
void vim_command(String str, Error *err);
/// Evaluates the expression str using the vim internal expression
/// evaluator (see |expression|).
/// Dictionaries and lists are recursively expanded.
///
/// @param str The expression str
/// @param[out] err Details of an error that may have occurred
/// @return The expanded object
Object vim_eval(String str, Error *err);
/// Calculates the number of display cells `str` occupies, tab is counted as
/// one cell.
///
/// @param str Some text
/// @return The number of cells
int64_t vim_strwidth(String str);
/// Returns a list of paths contained in 'runtimepath'
///
/// @return The list of paths
StringArray vim_list_runtime_paths(void);
/// Changes vim working directory
///
/// @param dir The new working directory
/// @param[out] err Details of an error that may have occurred
void vim_change_directory(String dir, Error *err);
/// Return the current line
///
/// @param[out] err Details of an error that may have occurred
/// @return The current line string
String vim_get_current_line(Error *err);
/// Delete the current line
///
/// @param[out] err Details of an error that may have occurred
void vim_del_current_line(Error *err);
/// Sets the current line
///
/// @param line The line contents
/// @param[out] err Details of an error that may have occurred
void vim_set_current_line(String line, Error *err);
/// Gets a global variable
///
/// @param name The variable name
/// @param[out] err Details of an error that may have occurred
/// @return The variable value
Object vim_get_var(String name, Error *err);
/// Sets a global variable. Passing 'nil' as value deletes the variable.
///
/// @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 if any
Object vim_set_var(String name, Object value, Error *err);
/// Gets a vim variable
///
/// @param name The variable name
/// @param[out] err Details of an error that may have occurred
/// @return The variable value
Object vim_get_vvar(String name, Error *err);
/// Get an option value string
///
/// @param name The option name
/// @param[out] err Details of an error that may have occurred
/// @return The option value
Object vim_get_option(String name, Error *err);
/// Sets an option value
///
/// @param name The option name
/// @param value The new option value
/// @param[out] err Details of an error that may have occurred
void vim_set_option(String name, Object value, Error *err);
/// Write a message to vim output buffer
///
/// @param str The message
void vim_out_write(String str);
/// Write a message to vim error buffer
///
/// @param str The message
void vim_err_write(String str);
/// Gets the number of buffers
///
/// @return The number of buffers
int64_t vim_get_buffer_count(void);
/// Return the current buffer
///
/// @reqturn The buffer handle
Buffer vim_get_current_buffer(void);
/// Sets the current buffer
///
/// @param id The buffer handle
/// @param[out] err Details of an error that may have occurred
void vim_set_current_buffer(Buffer buffer, Error *err);
/// Gets the number of windows
///
/// @return The number of windows
int64_t vim_get_window_count(void);
/// Return the current window
///
/// @return The window handle
Window vim_get_current_window(void);
/// Sets the current window
///
/// @param handle The window handle
void vim_set_current_window(Window window, Error *err);
/// Gets the number of tab pages
///
/// @return The number of tab pages
int64_t vim_get_tabpage_count(void);
/// Return the current tab page
///
/// @return The tab page handle
Tabpage vim_get_current_tabpage(void);
/// Sets the current tab page
///
/// @param handle The tab page handle
/// @param[out] err Details of an error that may have occurred
void vim_set_current_tabpage(Tabpage tabpage, Error *err);
#endif // NEOVIM_API_VIM_H

184
src/nvim/api/window.c Normal file
View File

@@ -0,0 +1,184 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "api/window.h"
#include "api/defs.h"
#include "api/helpers.h"
#include "../vim.h"
#include "../window.h"
#include "screen.h"
#include "misc2.h"
Buffer window_get_buffer(Window window, Error *err)
{
win_T *win = find_window(window, err);
if (!win) {
return 0;
}
return win->w_buffer->b_fnum;
}
Position window_get_cursor(Window window, Error *err)
{
Position rv = {.row = 0, .col = 0};
win_T *win = find_window(window, err);
if (win) {
rv.row = win->w_cursor.lnum;
rv.col = win->w_cursor.col;
}
return rv;
}
void window_set_cursor(Window window, Position pos, Error *err)
{
win_T *win = find_window(window, err);
if (!win) {
return;
}
if (pos.row <= 0 || pos.row > win->w_buffer->b_ml.ml_line_count) {
set_api_error("cursor position outside buffer", err);
return;
}
win->w_cursor.lnum = pos.row;
win->w_cursor.col = pos.col;
win->w_cursor.coladd = 0;
// When column is out of range silently correct it.
check_cursor_col_win(win);
update_screen(VALID);
}
int64_t window_get_height(Window window, Error *err)
{
win_T *win = find_window(window, err);
if (!win) {
return 0;
}
return win->w_height;
}
void window_set_height(Window window, int64_t height, Error *err)
{
win_T *win = find_window(window, err);
if (!win) {
return;
}
win_T *savewin = curwin;
curwin = win;
try_start();
win_setheight(height);
curwin = savewin;
try_end(err);
}
int64_t window_get_width(Window window, Error *err)
{
win_T *win = find_window(window, err);
if (!win) {
return 0;
}
return win->w_width;
}
void window_set_width(Window window, int64_t width, Error *err)
{
win_T *win = find_window(window, err);
if (!win) {
return;
}
win_T *savewin = curwin;
curwin = win;
try_start();
win_setwidth(width);
curwin = savewin;
try_end(err);
}
Object window_get_var(Window window, String name, Error *err)
{
Object rv;
win_T *win = find_window(window, err);
if (!win) {
return rv;
}
return dict_get_value(win->w_vars, name, err);
}
Object window_set_var(Window window, String name, Object value, Error *err)
{
Object rv;
win_T *win = find_window(window, err);
if (!win) {
return rv;
}
return dict_set_value(win->w_vars, name, value, err);
}
Object window_get_option(Window window, String name, Error *err)
{
Object rv;
win_T *win = find_window(window, err);
if (!win) {
return rv;
}
return get_option_from(win, SREQ_WIN, name, err);
}
void window_set_option(Window window, String name, Object value, Error *err)
{
win_T *win = find_window(window, err);
if (!win) {
return;
}
set_option_to(win, SREQ_WIN, name, value, err);
}
Position window_get_position(Window window, Error *err)
{
Position rv;
win_T *win = find_window(window, err);
if (win) {
rv.col = win->w_wincol;
rv.row = win->w_winrow;
}
return rv;
}
Tabpage window_get_tabpage(Window window, Error *err)
{
set_api_error("Not implemented", err);
return 0;
}
bool window_is_valid(Window window)
{
Error stub = {.set = false};
return find_window(window, &stub) != NULL;
}

115
src/nvim/api/window.h Normal file
View File

@@ -0,0 +1,115 @@
#ifndef NEOVIM_API_WINDOW_H
#define NEOVIM_API_WINDOW_H
#include <stdint.h>
#include <stdbool.h>
#include "api/defs.h"
/// Gets the current buffer in a window
///
/// @param window The window handle
/// @param[out] err Details of an error that may have occurred
/// @return The buffer handle
Buffer window_get_buffer(Window window, Error *err);
/// Gets the cursor position in the window
///
/// @param window The window handle
/// @param[out] err Details of an error that may have occurred
/// @return the (row, col) tuple
Position window_get_cursor(Window window, Error *err);
/// Sets the cursor position in the window
///
/// @param window The window handle
/// @param pos the (row, col) tuple representing the new position
/// @param[out] err Details of an error that may have occurred
void window_set_cursor(Window window, Position pos, Error *err);
/// Gets the window height
///
/// @param window The window handle
/// @param[out] err Details of an error that may have occurred
/// @return the height in rows
int64_t window_get_height(Window window, Error *err);
/// Sets the window height. This will only succeed if the screen is split
/// horizontally.
///
/// @param window The window handle
/// @param height the new height in rows
/// @param[out] err Details of an error that may have occurred
void window_set_height(Window window, int64_t height, Error *err);
/// Gets the window width
///
/// @param window The window handle
/// @param[out] err Details of an error that may have occurred
/// @return the width in columns
int64_t window_get_width(Window window, Error *err);
/// Sets the window width. This will only succeed if the screen is split
/// vertically.
///
/// @param window The window handle
/// @param width the new width in columns
/// @param[out] err Details of an error that may have occurred
void window_set_width(Window window, int64_t width, Error *err);
/// Gets a window variable
///
/// @param window The window handle
/// @param name The variable name
/// @param[out] err Details of an error that may have occurred
/// @return The variable value
Object window_get_var(Window window, String name, Error *err);
/// Sets a window variable. Passing 'nil' as value deletes the variable.
///
/// @param window The window 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
Object window_set_var(Window window, String name, Object value, Error *err);
/// Gets a window option value
///
/// @param window The window handle
/// @param name The option name
/// @param[out] err Details of an error that may have occurred
/// @return The option value
Object window_get_option(Window window, String name, Error *err);
/// Sets a window option value. Passing 'nil' as value deletes the option(only
/// works if there's a global fallback)
///
/// @param window The window handle
/// @param name The option name
/// @param value The option value
/// @param[out] err Details of an error that may have occurred
void window_set_option(Window window, String name, Object value, Error *err);
/// Gets the window position in display cells. First position is zero.
///
/// @param window The window handle
/// @param[out] err Details of an error that may have occurred
/// @return The (row, col) tuple with the window position
Position window_get_position(Window window, Error *err);
/// Gets the window tab page
///
/// @param window The window handle
/// @param[out] err Details of an error that may have occurred
/// @return The tab page that contains the window
Tabpage window_get_tabpage(Window window, Error *err);
/// Checks if a window is valid
///
/// @param window The window handle
/// @return true if the window is valid, false otherwise
bool window_is_valid(Window window);
#endif // NEOVIM_API_WINDOW_H

1532
src/nvim/arabic.c Normal file

File diff suppressed because it is too large Load Diff

16
src/nvim/arabic.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef NEOVIM_ARABIC_H
#define NEOVIM_ARABIC_H
/// Whether c belongs to the range of Arabic characters that might be shaped.
static inline int arabic_char(int c)
{
// return c >= a_HAMZA && c <= a_MINI_ALEF;
return c >= 0x0621 && c <= 0x0670;
}
int arabic_shape(int c, int *ccp, int *c1p, int prev_c, int prev_c1,
int next_c);
int arabic_combine(int one, int two);
int arabic_maycombine(int two);
#endif // NEOVIM_ARABIC_H

97
src/nvim/ascii.h Normal file
View File

@@ -0,0 +1,97 @@
/*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
*/
#ifndef NEOVIM_ASCII_H
#define NEOVIM_ASCII_H
/*
* Definitions of various common control characters.
* For EBCDIC we have to use different values.
*/
/* IF_EB(ASCII_constant, EBCDIC_constant) */
#define IF_EB(a, b) a
#define CharOrd(x) ((x) < 'a' ? (x) - 'A' : (x) - 'a')
#define CharOrdLow(x) ((x) - 'a')
#define CharOrdUp(x) ((x) - 'A')
#define ROT13(c, a) (((((c) - (a)) + 13) % 26) + (a))
#define NUL '\000'
#define BELL '\007'
#define BS '\010'
#define TAB '\011'
#define NL '\012'
#define NL_STR (char_u *)"\012"
#define FF '\014'
#define CAR '\015' /* CR is used by Mac OS X */
#define ESC '\033'
#define ESC_STR (char_u *)"\033"
#define ESC_STR_nc "\033"
#define DEL 0x7f
#define DEL_STR (char_u *)"\177"
#define CSI 0x9b /* Control Sequence Introducer */
#define CSI_STR "\233"
#define DCS 0x90 /* Device Control String */
#define STERM 0x9c /* String Terminator */
#define POUND 0xA3
#define Ctrl_chr(x) (TOUPPER_ASC(x) ^ 0x40) /* '?' -> DEL, '@' -> ^@, etc. */
#define Meta(x) ((x) | 0x80)
#define CTRL_F_STR "\006"
#define CTRL_H_STR "\010"
#define CTRL_V_STR "\026"
#define Ctrl_AT 0 /* @ */
#define Ctrl_A 1
#define Ctrl_B 2
#define Ctrl_C 3
#define Ctrl_D 4
#define Ctrl_E 5
#define Ctrl_F 6
#define Ctrl_G 7
#define Ctrl_H 8
#define Ctrl_I 9
#define Ctrl_J 10
#define Ctrl_K 11
#define Ctrl_L 12
#define Ctrl_M 13
#define Ctrl_N 14
#define Ctrl_O 15
#define Ctrl_P 16
#define Ctrl_Q 17
#define Ctrl_R 18
#define Ctrl_S 19
#define Ctrl_T 20
#define Ctrl_U 21
#define Ctrl_V 22
#define Ctrl_W 23
#define Ctrl_X 24
#define Ctrl_Y 25
#define Ctrl_Z 26
/* CTRL- [ Left Square Bracket == ESC*/
#define Ctrl_BSL 28 /* \ BackSLash */
#define Ctrl_RSB 29 /* ] Right Square Bracket */
#define Ctrl_HAT 30 /* ^ */
#define Ctrl__ 31
/*
* Character that separates dir names in a path.
*/
#ifdef BACKSLASH_IN_FILENAME
# define PATHSEP psepc
# define PATHSEPSTR pseps
#else
# define PATHSEP '/'
# define PATHSEPSTR "/"
#endif
#endif /* NEOVIM_ASCII_H */

622
src/nvim/blowfish.c Normal file
View File

@@ -0,0 +1,622 @@
/*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
* See README.txt for an overview of the Vim source code.
*
* Blowfish encryption for Vim; in Blowfish cipher feedback mode.
* Contributed by Mohsin Ahmed, http://www.cs.albany.edu/~mosh
* Based on http://www.schneier.com/blowfish.html by Bruce Schneier.
*/
#include <string.h>
#include "vim.h"
#include "blowfish.h"
#include "message.h"
#include "sha256.h"
#define ARRAY_LENGTH(A) (sizeof(A) / sizeof(A[0]))
#define BF_BLOCK 8
#define BF_BLOCK_MASK 7
#define BF_CFB_LEN (8 * (BF_BLOCK))
typedef union {
uint32_t ul[2];
char_u uc[8];
} block8;
static void bf_e_block(uint32_t *p_xl, uint32_t *p_xr);
static void bf_e_cblock(char_u *block);
static int bf_check_tables(uint32_t a_ipa[18], uint32_t a_sbi[4][256],
uint32_t val);
static int bf_self_test(void);
/* Blowfish code */
static uint32_t pax[18];
static uint32_t ipa[18] = {
0x243f6a88u, 0x85a308d3u, 0x13198a2eu,
0x03707344u, 0xa4093822u, 0x299f31d0u,
0x082efa98u, 0xec4e6c89u, 0x452821e6u,
0x38d01377u, 0xbe5466cfu, 0x34e90c6cu,
0xc0ac29b7u, 0xc97c50ddu, 0x3f84d5b5u,
0xb5470917u, 0x9216d5d9u, 0x8979fb1bu
};
static uint32_t sbx[4][256];
static uint32_t sbi[4][256] = {
{0xd1310ba6u, 0x98dfb5acu, 0x2ffd72dbu, 0xd01adfb7u,
0xb8e1afedu, 0x6a267e96u, 0xba7c9045u, 0xf12c7f99u,
0x24a19947u, 0xb3916cf7u, 0x0801f2e2u, 0x858efc16u,
0x636920d8u, 0x71574e69u, 0xa458fea3u, 0xf4933d7eu,
0x0d95748fu, 0x728eb658u, 0x718bcd58u, 0x82154aeeu,
0x7b54a41du, 0xc25a59b5u, 0x9c30d539u, 0x2af26013u,
0xc5d1b023u, 0x286085f0u, 0xca417918u, 0xb8db38efu,
0x8e79dcb0u, 0x603a180eu, 0x6c9e0e8bu, 0xb01e8a3eu,
0xd71577c1u, 0xbd314b27u, 0x78af2fdau, 0x55605c60u,
0xe65525f3u, 0xaa55ab94u, 0x57489862u, 0x63e81440u,
0x55ca396au, 0x2aab10b6u, 0xb4cc5c34u, 0x1141e8ceu,
0xa15486afu, 0x7c72e993u, 0xb3ee1411u, 0x636fbc2au,
0x2ba9c55du, 0x741831f6u, 0xce5c3e16u, 0x9b87931eu,
0xafd6ba33u, 0x6c24cf5cu, 0x7a325381u, 0x28958677u,
0x3b8f4898u, 0x6b4bb9afu, 0xc4bfe81bu, 0x66282193u,
0x61d809ccu, 0xfb21a991u, 0x487cac60u, 0x5dec8032u,
0xef845d5du, 0xe98575b1u, 0xdc262302u, 0xeb651b88u,
0x23893e81u, 0xd396acc5u, 0x0f6d6ff3u, 0x83f44239u,
0x2e0b4482u, 0xa4842004u, 0x69c8f04au, 0x9e1f9b5eu,
0x21c66842u, 0xf6e96c9au, 0x670c9c61u, 0xabd388f0u,
0x6a51a0d2u, 0xd8542f68u, 0x960fa728u, 0xab5133a3u,
0x6eef0b6cu, 0x137a3be4u, 0xba3bf050u, 0x7efb2a98u,
0xa1f1651du, 0x39af0176u, 0x66ca593eu, 0x82430e88u,
0x8cee8619u, 0x456f9fb4u, 0x7d84a5c3u, 0x3b8b5ebeu,
0xe06f75d8u, 0x85c12073u, 0x401a449fu, 0x56c16aa6u,
0x4ed3aa62u, 0x363f7706u, 0x1bfedf72u, 0x429b023du,
0x37d0d724u, 0xd00a1248u, 0xdb0fead3u, 0x49f1c09bu,
0x075372c9u, 0x80991b7bu, 0x25d479d8u, 0xf6e8def7u,
0xe3fe501au, 0xb6794c3bu, 0x976ce0bdu, 0x04c006bau,
0xc1a94fb6u, 0x409f60c4u, 0x5e5c9ec2u, 0x196a2463u,
0x68fb6fafu, 0x3e6c53b5u, 0x1339b2ebu, 0x3b52ec6fu,
0x6dfc511fu, 0x9b30952cu, 0xcc814544u, 0xaf5ebd09u,
0xbee3d004u, 0xde334afdu, 0x660f2807u, 0x192e4bb3u,
0xc0cba857u, 0x45c8740fu, 0xd20b5f39u, 0xb9d3fbdbu,
0x5579c0bdu, 0x1a60320au, 0xd6a100c6u, 0x402c7279u,
0x679f25feu, 0xfb1fa3ccu, 0x8ea5e9f8u, 0xdb3222f8u,
0x3c7516dfu, 0xfd616b15u, 0x2f501ec8u, 0xad0552abu,
0x323db5fau, 0xfd238760u, 0x53317b48u, 0x3e00df82u,
0x9e5c57bbu, 0xca6f8ca0u, 0x1a87562eu, 0xdf1769dbu,
0xd542a8f6u, 0x287effc3u, 0xac6732c6u, 0x8c4f5573u,
0x695b27b0u, 0xbbca58c8u, 0xe1ffa35du, 0xb8f011a0u,
0x10fa3d98u, 0xfd2183b8u, 0x4afcb56cu, 0x2dd1d35bu,
0x9a53e479u, 0xb6f84565u, 0xd28e49bcu, 0x4bfb9790u,
0xe1ddf2dau, 0xa4cb7e33u, 0x62fb1341u, 0xcee4c6e8u,
0xef20cadau, 0x36774c01u, 0xd07e9efeu, 0x2bf11fb4u,
0x95dbda4du, 0xae909198u, 0xeaad8e71u, 0x6b93d5a0u,
0xd08ed1d0u, 0xafc725e0u, 0x8e3c5b2fu, 0x8e7594b7u,
0x8ff6e2fbu, 0xf2122b64u, 0x8888b812u, 0x900df01cu,
0x4fad5ea0u, 0x688fc31cu, 0xd1cff191u, 0xb3a8c1adu,
0x2f2f2218u, 0xbe0e1777u, 0xea752dfeu, 0x8b021fa1u,
0xe5a0cc0fu, 0xb56f74e8u, 0x18acf3d6u, 0xce89e299u,
0xb4a84fe0u, 0xfd13e0b7u, 0x7cc43b81u, 0xd2ada8d9u,
0x165fa266u, 0x80957705u, 0x93cc7314u, 0x211a1477u,
0xe6ad2065u, 0x77b5fa86u, 0xc75442f5u, 0xfb9d35cfu,
0xebcdaf0cu, 0x7b3e89a0u, 0xd6411bd3u, 0xae1e7e49u,
0x00250e2du, 0x2071b35eu, 0x226800bbu, 0x57b8e0afu,
0x2464369bu, 0xf009b91eu, 0x5563911du, 0x59dfa6aau,
0x78c14389u, 0xd95a537fu, 0x207d5ba2u, 0x02e5b9c5u,
0x83260376u, 0x6295cfa9u, 0x11c81968u, 0x4e734a41u,
0xb3472dcau, 0x7b14a94au, 0x1b510052u, 0x9a532915u,
0xd60f573fu, 0xbc9bc6e4u, 0x2b60a476u, 0x81e67400u,
0x08ba6fb5u, 0x571be91fu, 0xf296ec6bu, 0x2a0dd915u,
0xb6636521u, 0xe7b9f9b6u, 0xff34052eu, 0xc5855664u,
0x53b02d5du, 0xa99f8fa1u, 0x08ba4799u, 0x6e85076au},
{0x4b7a70e9u, 0xb5b32944u, 0xdb75092eu, 0xc4192623u,
0xad6ea6b0u, 0x49a7df7du, 0x9cee60b8u, 0x8fedb266u,
0xecaa8c71u, 0x699a17ffu, 0x5664526cu, 0xc2b19ee1u,
0x193602a5u, 0x75094c29u, 0xa0591340u, 0xe4183a3eu,
0x3f54989au, 0x5b429d65u, 0x6b8fe4d6u, 0x99f73fd6u,
0xa1d29c07u, 0xefe830f5u, 0x4d2d38e6u, 0xf0255dc1u,
0x4cdd2086u, 0x8470eb26u, 0x6382e9c6u, 0x021ecc5eu,
0x09686b3fu, 0x3ebaefc9u, 0x3c971814u, 0x6b6a70a1u,
0x687f3584u, 0x52a0e286u, 0xb79c5305u, 0xaa500737u,
0x3e07841cu, 0x7fdeae5cu, 0x8e7d44ecu, 0x5716f2b8u,
0xb03ada37u, 0xf0500c0du, 0xf01c1f04u, 0x0200b3ffu,
0xae0cf51au, 0x3cb574b2u, 0x25837a58u, 0xdc0921bdu,
0xd19113f9u, 0x7ca92ff6u, 0x94324773u, 0x22f54701u,
0x3ae5e581u, 0x37c2dadcu, 0xc8b57634u, 0x9af3dda7u,
0xa9446146u, 0x0fd0030eu, 0xecc8c73eu, 0xa4751e41u,
0xe238cd99u, 0x3bea0e2fu, 0x3280bba1u, 0x183eb331u,
0x4e548b38u, 0x4f6db908u, 0x6f420d03u, 0xf60a04bfu,
0x2cb81290u, 0x24977c79u, 0x5679b072u, 0xbcaf89afu,
0xde9a771fu, 0xd9930810u, 0xb38bae12u, 0xdccf3f2eu,
0x5512721fu, 0x2e6b7124u, 0x501adde6u, 0x9f84cd87u,
0x7a584718u, 0x7408da17u, 0xbc9f9abcu, 0xe94b7d8cu,
0xec7aec3au, 0xdb851dfau, 0x63094366u, 0xc464c3d2u,
0xef1c1847u, 0x3215d908u, 0xdd433b37u, 0x24c2ba16u,
0x12a14d43u, 0x2a65c451u, 0x50940002u, 0x133ae4ddu,
0x71dff89eu, 0x10314e55u, 0x81ac77d6u, 0x5f11199bu,
0x043556f1u, 0xd7a3c76bu, 0x3c11183bu, 0x5924a509u,
0xf28fe6edu, 0x97f1fbfau, 0x9ebabf2cu, 0x1e153c6eu,
0x86e34570u, 0xeae96fb1u, 0x860e5e0au, 0x5a3e2ab3u,
0x771fe71cu, 0x4e3d06fau, 0x2965dcb9u, 0x99e71d0fu,
0x803e89d6u, 0x5266c825u, 0x2e4cc978u, 0x9c10b36au,
0xc6150ebau, 0x94e2ea78u, 0xa5fc3c53u, 0x1e0a2df4u,
0xf2f74ea7u, 0x361d2b3du, 0x1939260fu, 0x19c27960u,
0x5223a708u, 0xf71312b6u, 0xebadfe6eu, 0xeac31f66u,
0xe3bc4595u, 0xa67bc883u, 0xb17f37d1u, 0x018cff28u,
0xc332ddefu, 0xbe6c5aa5u, 0x65582185u, 0x68ab9802u,
0xeecea50fu, 0xdb2f953bu, 0x2aef7dadu, 0x5b6e2f84u,
0x1521b628u, 0x29076170u, 0xecdd4775u, 0x619f1510u,
0x13cca830u, 0xeb61bd96u, 0x0334fe1eu, 0xaa0363cfu,
0xb5735c90u, 0x4c70a239u, 0xd59e9e0bu, 0xcbaade14u,
0xeecc86bcu, 0x60622ca7u, 0x9cab5cabu, 0xb2f3846eu,
0x648b1eafu, 0x19bdf0cau, 0xa02369b9u, 0x655abb50u,
0x40685a32u, 0x3c2ab4b3u, 0x319ee9d5u, 0xc021b8f7u,
0x9b540b19u, 0x875fa099u, 0x95f7997eu, 0x623d7da8u,
0xf837889au, 0x97e32d77u, 0x11ed935fu, 0x16681281u,
0x0e358829u, 0xc7e61fd6u, 0x96dedfa1u, 0x7858ba99u,
0x57f584a5u, 0x1b227263u, 0x9b83c3ffu, 0x1ac24696u,
0xcdb30aebu, 0x532e3054u, 0x8fd948e4u, 0x6dbc3128u,
0x58ebf2efu, 0x34c6ffeau, 0xfe28ed61u, 0xee7c3c73u,
0x5d4a14d9u, 0xe864b7e3u, 0x42105d14u, 0x203e13e0u,
0x45eee2b6u, 0xa3aaabeau, 0xdb6c4f15u, 0xfacb4fd0u,
0xc742f442u, 0xef6abbb5u, 0x654f3b1du, 0x41cd2105u,
0xd81e799eu, 0x86854dc7u, 0xe44b476au, 0x3d816250u,
0xcf62a1f2u, 0x5b8d2646u, 0xfc8883a0u, 0xc1c7b6a3u,
0x7f1524c3u, 0x69cb7492u, 0x47848a0bu, 0x5692b285u,
0x095bbf00u, 0xad19489du, 0x1462b174u, 0x23820e00u,
0x58428d2au, 0x0c55f5eau, 0x1dadf43eu, 0x233f7061u,
0x3372f092u, 0x8d937e41u, 0xd65fecf1u, 0x6c223bdbu,
0x7cde3759u, 0xcbee7460u, 0x4085f2a7u, 0xce77326eu,
0xa6078084u, 0x19f8509eu, 0xe8efd855u, 0x61d99735u,
0xa969a7aau, 0xc50c06c2u, 0x5a04abfcu, 0x800bcadcu,
0x9e447a2eu, 0xc3453484u, 0xfdd56705u, 0x0e1e9ec9u,
0xdb73dbd3u, 0x105588cdu, 0x675fda79u, 0xe3674340u,
0xc5c43465u, 0x713e38d8u, 0x3d28f89eu, 0xf16dff20u,
0x153e21e7u, 0x8fb03d4au, 0xe6e39f2bu, 0xdb83adf7u},
{0xe93d5a68u, 0x948140f7u, 0xf64c261cu, 0x94692934u,
0x411520f7u, 0x7602d4f7u, 0xbcf46b2eu, 0xd4a20068u,
0xd4082471u, 0x3320f46au, 0x43b7d4b7u, 0x500061afu,
0x1e39f62eu, 0x97244546u, 0x14214f74u, 0xbf8b8840u,
0x4d95fc1du, 0x96b591afu, 0x70f4ddd3u, 0x66a02f45u,
0xbfbc09ecu, 0x03bd9785u, 0x7fac6dd0u, 0x31cb8504u,
0x96eb27b3u, 0x55fd3941u, 0xda2547e6u, 0xabca0a9au,
0x28507825u, 0x530429f4u, 0x0a2c86dau, 0xe9b66dfbu,
0x68dc1462u, 0xd7486900u, 0x680ec0a4u, 0x27a18deeu,
0x4f3ffea2u, 0xe887ad8cu, 0xb58ce006u, 0x7af4d6b6u,
0xaace1e7cu, 0xd3375fecu, 0xce78a399u, 0x406b2a42u,
0x20fe9e35u, 0xd9f385b9u, 0xee39d7abu, 0x3b124e8bu,
0x1dc9faf7u, 0x4b6d1856u, 0x26a36631u, 0xeae397b2u,
0x3a6efa74u, 0xdd5b4332u, 0x6841e7f7u, 0xca7820fbu,
0xfb0af54eu, 0xd8feb397u, 0x454056acu, 0xba489527u,
0x55533a3au, 0x20838d87u, 0xfe6ba9b7u, 0xd096954bu,
0x55a867bcu, 0xa1159a58u, 0xcca92963u, 0x99e1db33u,
0xa62a4a56u, 0x3f3125f9u, 0x5ef47e1cu, 0x9029317cu,
0xfdf8e802u, 0x04272f70u, 0x80bb155cu, 0x05282ce3u,
0x95c11548u, 0xe4c66d22u, 0x48c1133fu, 0xc70f86dcu,
0x07f9c9eeu, 0x41041f0fu, 0x404779a4u, 0x5d886e17u,
0x325f51ebu, 0xd59bc0d1u, 0xf2bcc18fu, 0x41113564u,
0x257b7834u, 0x602a9c60u, 0xdff8e8a3u, 0x1f636c1bu,
0x0e12b4c2u, 0x02e1329eu, 0xaf664fd1u, 0xcad18115u,
0x6b2395e0u, 0x333e92e1u, 0x3b240b62u, 0xeebeb922u,
0x85b2a20eu, 0xe6ba0d99u, 0xde720c8cu, 0x2da2f728u,
0xd0127845u, 0x95b794fdu, 0x647d0862u, 0xe7ccf5f0u,
0x5449a36fu, 0x877d48fau, 0xc39dfd27u, 0xf33e8d1eu,
0x0a476341u, 0x992eff74u, 0x3a6f6eabu, 0xf4f8fd37u,
0xa812dc60u, 0xa1ebddf8u, 0x991be14cu, 0xdb6e6b0du,
0xc67b5510u, 0x6d672c37u, 0x2765d43bu, 0xdcd0e804u,
0xf1290dc7u, 0xcc00ffa3u, 0xb5390f92u, 0x690fed0bu,
0x667b9ffbu, 0xcedb7d9cu, 0xa091cf0bu, 0xd9155ea3u,
0xbb132f88u, 0x515bad24u, 0x7b9479bfu, 0x763bd6ebu,
0x37392eb3u, 0xcc115979u, 0x8026e297u, 0xf42e312du,
0x6842ada7u, 0xc66a2b3bu, 0x12754cccu, 0x782ef11cu,
0x6a124237u, 0xb79251e7u, 0x06a1bbe6u, 0x4bfb6350u,
0x1a6b1018u, 0x11caedfau, 0x3d25bdd8u, 0xe2e1c3c9u,
0x44421659u, 0x0a121386u, 0xd90cec6eu, 0xd5abea2au,
0x64af674eu, 0xda86a85fu, 0xbebfe988u, 0x64e4c3feu,
0x9dbc8057u, 0xf0f7c086u, 0x60787bf8u, 0x6003604du,
0xd1fd8346u, 0xf6381fb0u, 0x7745ae04u, 0xd736fcccu,
0x83426b33u, 0xf01eab71u, 0xb0804187u, 0x3c005e5fu,
0x77a057beu, 0xbde8ae24u, 0x55464299u, 0xbf582e61u,
0x4e58f48fu, 0xf2ddfda2u, 0xf474ef38u, 0x8789bdc2u,
0x5366f9c3u, 0xc8b38e74u, 0xb475f255u, 0x46fcd9b9u,
0x7aeb2661u, 0x8b1ddf84u, 0x846a0e79u, 0x915f95e2u,
0x466e598eu, 0x20b45770u, 0x8cd55591u, 0xc902de4cu,
0xb90bace1u, 0xbb8205d0u, 0x11a86248u, 0x7574a99eu,
0xb77f19b6u, 0xe0a9dc09u, 0x662d09a1u, 0xc4324633u,
0xe85a1f02u, 0x09f0be8cu, 0x4a99a025u, 0x1d6efe10u,
0x1ab93d1du, 0x0ba5a4dfu, 0xa186f20fu, 0x2868f169u,
0xdcb7da83u, 0x573906feu, 0xa1e2ce9bu, 0x4fcd7f52u,
0x50115e01u, 0xa70683fau, 0xa002b5c4u, 0x0de6d027u,
0x9af88c27u, 0x773f8641u, 0xc3604c06u, 0x61a806b5u,
0xf0177a28u, 0xc0f586e0u, 0x006058aau, 0x30dc7d62u,
0x11e69ed7u, 0x2338ea63u, 0x53c2dd94u, 0xc2c21634u,
0xbbcbee56u, 0x90bcb6deu, 0xebfc7da1u, 0xce591d76u,
0x6f05e409u, 0x4b7c0188u, 0x39720a3du, 0x7c927c24u,
0x86e3725fu, 0x724d9db9u, 0x1ac15bb4u, 0xd39eb8fcu,
0xed545578u, 0x08fca5b5u, 0xd83d7cd3u, 0x4dad0fc4u,
0x1e50ef5eu, 0xb161e6f8u, 0xa28514d9u, 0x6c51133cu,
0x6fd5c7e7u, 0x56e14ec4u, 0x362abfceu, 0xddc6c837u,
0xd79a3234u, 0x92638212u, 0x670efa8eu, 0x406000e0u},
{0x3a39ce37u, 0xd3faf5cfu, 0xabc27737u, 0x5ac52d1bu,
0x5cb0679eu, 0x4fa33742u, 0xd3822740u, 0x99bc9bbeu,
0xd5118e9du, 0xbf0f7315u, 0xd62d1c7eu, 0xc700c47bu,
0xb78c1b6bu, 0x21a19045u, 0xb26eb1beu, 0x6a366eb4u,
0x5748ab2fu, 0xbc946e79u, 0xc6a376d2u, 0x6549c2c8u,
0x530ff8eeu, 0x468dde7du, 0xd5730a1du, 0x4cd04dc6u,
0x2939bbdbu, 0xa9ba4650u, 0xac9526e8u, 0xbe5ee304u,
0xa1fad5f0u, 0x6a2d519au, 0x63ef8ce2u, 0x9a86ee22u,
0xc089c2b8u, 0x43242ef6u, 0xa51e03aau, 0x9cf2d0a4u,
0x83c061bau, 0x9be96a4du, 0x8fe51550u, 0xba645bd6u,
0x2826a2f9u, 0xa73a3ae1u, 0x4ba99586u, 0xef5562e9u,
0xc72fefd3u, 0xf752f7dau, 0x3f046f69u, 0x77fa0a59u,
0x80e4a915u, 0x87b08601u, 0x9b09e6adu, 0x3b3ee593u,
0xe990fd5au, 0x9e34d797u, 0x2cf0b7d9u, 0x022b8b51u,
0x96d5ac3au, 0x017da67du, 0xd1cf3ed6u, 0x7c7d2d28u,
0x1f9f25cfu, 0xadf2b89bu, 0x5ad6b472u, 0x5a88f54cu,
0xe029ac71u, 0xe019a5e6u, 0x47b0acfdu, 0xed93fa9bu,
0xe8d3c48du, 0x283b57ccu, 0xf8d56629u, 0x79132e28u,
0x785f0191u, 0xed756055u, 0xf7960e44u, 0xe3d35e8cu,
0x15056dd4u, 0x88f46dbau, 0x03a16125u, 0x0564f0bdu,
0xc3eb9e15u, 0x3c9057a2u, 0x97271aecu, 0xa93a072au,
0x1b3f6d9bu, 0x1e6321f5u, 0xf59c66fbu, 0x26dcf319u,
0x7533d928u, 0xb155fdf5u, 0x03563482u, 0x8aba3cbbu,
0x28517711u, 0xc20ad9f8u, 0xabcc5167u, 0xccad925fu,
0x4de81751u, 0x3830dc8eu, 0x379d5862u, 0x9320f991u,
0xea7a90c2u, 0xfb3e7bceu, 0x5121ce64u, 0x774fbe32u,
0xa8b6e37eu, 0xc3293d46u, 0x48de5369u, 0x6413e680u,
0xa2ae0810u, 0xdd6db224u, 0x69852dfdu, 0x09072166u,
0xb39a460au, 0x6445c0ddu, 0x586cdecfu, 0x1c20c8aeu,
0x5bbef7ddu, 0x1b588d40u, 0xccd2017fu, 0x6bb4e3bbu,
0xdda26a7eu, 0x3a59ff45u, 0x3e350a44u, 0xbcb4cdd5u,
0x72eacea8u, 0xfa6484bbu, 0x8d6612aeu, 0xbf3c6f47u,
0xd29be463u, 0x542f5d9eu, 0xaec2771bu, 0xf64e6370u,
0x740e0d8du, 0xe75b1357u, 0xf8721671u, 0xaf537d5du,
0x4040cb08u, 0x4eb4e2ccu, 0x34d2466au, 0x0115af84u,
0xe1b00428u, 0x95983a1du, 0x06b89fb4u, 0xce6ea048u,
0x6f3f3b82u, 0x3520ab82u, 0x011a1d4bu, 0x277227f8u,
0x611560b1u, 0xe7933fdcu, 0xbb3a792bu, 0x344525bdu,
0xa08839e1u, 0x51ce794bu, 0x2f32c9b7u, 0xa01fbac9u,
0xe01cc87eu, 0xbcc7d1f6u, 0xcf0111c3u, 0xa1e8aac7u,
0x1a908749u, 0xd44fbd9au, 0xd0dadecbu, 0xd50ada38u,
0x0339c32au, 0xc6913667u, 0x8df9317cu, 0xe0b12b4fu,
0xf79e59b7u, 0x43f5bb3au, 0xf2d519ffu, 0x27d9459cu,
0xbf97222cu, 0x15e6fc2au, 0x0f91fc71u, 0x9b941525u,
0xfae59361u, 0xceb69cebu, 0xc2a86459u, 0x12baa8d1u,
0xb6c1075eu, 0xe3056a0cu, 0x10d25065u, 0xcb03a442u,
0xe0ec6e0eu, 0x1698db3bu, 0x4c98a0beu, 0x3278e964u,
0x9f1f9532u, 0xe0d392dfu, 0xd3a0342bu, 0x8971f21eu,
0x1b0a7441u, 0x4ba3348cu, 0xc5be7120u, 0xc37632d8u,
0xdf359f8du, 0x9b992f2eu, 0xe60b6f47u, 0x0fe3f11du,
0xe54cda54u, 0x1edad891u, 0xce6279cfu, 0xcd3e7e6fu,
0x1618b166u, 0xfd2c1d05u, 0x848fd2c5u, 0xf6fb2299u,
0xf523f357u, 0xa6327623u, 0x93a83531u, 0x56cccd02u,
0xacf08162u, 0x5a75ebb5u, 0x6e163697u, 0x88d273ccu,
0xde966292u, 0x81b949d0u, 0x4c50901bu, 0x71c65614u,
0xe6c6c7bdu, 0x327a140au, 0x45e1d006u, 0xc3f27b9au,
0xc9aa53fdu, 0x62a80f00u, 0xbb25bfe2u, 0x35bdd2f6u,
0x71126905u, 0xb2040222u, 0xb6cbcf7cu, 0xcd769c2bu,
0x53113ec0u, 0x1640e3d3u, 0x38abbd60u, 0x2547adf0u,
0xba38209cu, 0xf746ce76u, 0x77afa1c5u, 0x20756060u,
0x85cbfe4eu, 0x8ae88dd8u, 0x7aaaf9b0u, 0x4cf9aa7eu,
0x1948c25cu, 0x02fb8a8cu, 0x01c36ae4u, 0xd6ebe1f9u,
0x90d4f869u, 0xa65cdea0u, 0x3f09252du, 0xc208e69fu,
0xb74e6132u, 0xce77e25bu, 0x578fdfe3u, 0x3ac372e6u}
};
#define F1(i) \
xl ^= pax[i]; \
xr ^= ((sbx[0][xl >> 24] + \
sbx[1][(xl & 0xFF0000) >> 16]) ^ \
sbx[2][(xl & 0xFF00) >> 8]) + \
sbx[3][xl & 0xFF];
#define F2(i) \
xr ^= pax[i]; \
xl ^= ((sbx[0][xr >> 24] + \
sbx[1][(xr & 0xFF0000) >> 16]) ^ \
sbx[2][(xr & 0xFF00) >> 8]) + \
sbx[3][xr & 0xFF];
static void bf_e_block(uint32_t *p_xl, uint32_t *p_xr)
{
uint32_t temp;
uint32_t xl = *p_xl;
uint32_t xr = *p_xr;
F1(0) F2(1) F1(2) F2(3) F1(4) F2(5) F1(6) F2(7)
F1(8) F2(9) F1(10) F2(11) F1(12) F2(13) F1(14) F2(15)
xl ^= pax[16];
xr ^= pax[17];
temp = xl;
xl = xr;
xr = temp;
*p_xl = xl;
*p_xr = xr;
}
#ifdef WORDS_BIGENDIAN
# define htonl2(x) \
x = ((((x) & 0xffL) << 24) | (((x) & 0xff00L) << 8) | \
(((x) & 0xff0000L) >> 8) | (((x) & 0xff000000L) >> 24))
#else // ifdef WORDS_BIGENDIAN
# define htonl2(x)
#endif // ifdef WORDS_BIGENDIAN
static void bf_e_cblock(char_u *block)
{
block8 bk;
memcpy(bk.uc, block, 8);
htonl2(bk.ul[0]);
htonl2(bk.ul[1]);
bf_e_block(&bk.ul[0], &bk.ul[1]);
htonl2(bk.ul[0]);
htonl2(bk.ul[1]);
memcpy(block, bk.uc, 8);
}
// Initialize the crypt method using "password" as the encryption key and
// "salt[salt_len]" as the salt.
void bf_key_init(char_u *password, char_u *salt, int salt_len)
{
// Process the key 1000 times.
// See http://en.wikipedia.org/wiki/Key_strengthening.
char_u *key = sha256_key(password, salt, salt_len);
int i;
for (i = 0; i < 1000; i++) {
key = sha256_key(key, salt, salt_len);
}
// Convert the key from 64 hex chars to 32 binary chars.
int keylen = (int)STRLEN(key) / 2;
if (keylen == 0) {
EMSG(_("E831: bf_key_init() called with empty password"));
return;
}
unsigned u;
for (i = 0; i < keylen; i++) {
sscanf((char *)&key[i * 2], "%2x", &u);
key[i] = u;
}
memmove(sbx, sbi, 4 * 4 * 256);
int keypos = 0;
for (i = 0; i < 18; i++) {
uint32_t val = 0;
int j;
for (j = 0; j < 4; j++) {
val = (val << 8) | key[keypos++ % keylen];
}
pax[i] = ipa[i] ^ val;
}
uint32_t data_l = 0;
uint32_t data_r = 0;
for (i = 0; i < 18; i += 2) {
bf_e_block(&data_l, &data_r);
pax[i + 0] = data_l;
pax[i + 1] = data_r;
}
for (i = 0; i < 4; i++) {
int j;
for (j = 0; j < 256; j += 2) {
bf_e_block(&data_l, &data_r);
sbx[i][j + 0] = data_l;
sbx[i][j + 1] = data_r;
}
}
}
/// BF Self test for corrupted tables or instructions
static int bf_check_tables(uint32_t a_ipa[18], uint32_t a_sbi[4][256],
uint32_t val)
{
uint32_t c = 0;
int i;
for (i = 0; i < 18; i++) {
c ^= a_ipa[i];
}
for (i = 0; i < 4; i++) {
int j;
for (j = 0; j < 256; j++) {
c ^= a_sbi[i][j];
}
}
return c == val;
}
typedef struct {
char_u password[64];
char_u salt[9];
char_u plaintxt[9];
char_u cryptxt[9];
char_u badcryptxt[9]; // cryptxt when big/little endian is wrong.
uint32_t keysum;
} struct_bf_test_data;
// Assert bf(password, plaintxt) is cryptxt.
// Assert csum(pax sbx(password)) is keysum.
static struct_bf_test_data bf_test_data[] = {
{
"password",
"salt",
"plaintxt",
"\xad\x3d\xfa\x7f\xe8\xea\x40\xf6", // cryptxt
"\x72\x50\x3b\x38\x10\x60\x22\xa7", // badcryptxt
0x56701b5du // keysum
},
};
// Return FAIL when there is something wrong with blowfish encryption.
static int bf_self_test(void)
{
int err = 0;
if (!bf_check_tables(ipa, sbi, 0x6ffa520a)) {
err++;
}
int bn = ARRAY_LENGTH(bf_test_data);
int i;
for (i = 0; i < bn; i++) {
bf_key_init((char_u *)(bf_test_data[i].password), bf_test_data[i].salt,
(int)STRLEN(bf_test_data[i].salt));
if (!bf_check_tables(pax, sbx, bf_test_data[i].keysum)) {
err++;
}
// Don't modify bf_test_data[i].plaintxt, self test is idempotent.
block8 bk;
memcpy(bk.uc, bf_test_data[i].plaintxt, 8);
bf_e_cblock(bk.uc);
if (memcmp(bk.uc, bf_test_data[i].cryptxt, 8) != 0) {
if ((err == 0) && (memcmp(bk.uc, bf_test_data[i].badcryptxt, 8) == 0)) {
EMSG(_("E817: Blowfish big/little endian use wrong"));
}
err++;
}
}
return err > 0 ? FAIL : OK;
}
// Cipher feedback mode.
static int randbyte_offset = 0;
static int update_offset = 0;
static char_u cfb_buffer[BF_CFB_LEN]; // 64 bytes
// Initialize with seed "iv[iv_len]".
void bf_cfb_init(char_u *iv, int iv_len)
{
randbyte_offset = update_offset = 0;
memset(cfb_buffer, 0, BF_CFB_LEN);
if (iv_len > 0) {
int mi = iv_len > BF_CFB_LEN ? iv_len : BF_CFB_LEN;
int i;
for (i = 0; i < mi; i++) {
cfb_buffer[i % BF_CFB_LEN] ^= iv[i % iv_len];
}
}
}
#define BF_CFB_UPDATE(c) \
{ \
cfb_buffer[update_offset] ^= (char_u)c; \
if (++update_offset == BF_CFB_LEN) { \
update_offset = 0; \
} \
}
#define BF_RANBYTE(t) \
{ \
if ((randbyte_offset & BF_BLOCK_MASK) == 0) { \
bf_e_cblock(&cfb_buffer[randbyte_offset]); \
} \
t = cfb_buffer[randbyte_offset]; \
if (++randbyte_offset == BF_CFB_LEN) { \
randbyte_offset = 0; \
} \
}
// Encrypt "from[len]" into "to[len]".
// "from" and "to" can be equal to encrypt in place.
void bf_crypt_encode(char_u *from, size_t len, char_u *to)
{
size_t i;
for (i = 0; i < len; i++) {
int ztemp = from[i];
int t;
BF_RANBYTE(t);
BF_CFB_UPDATE(ztemp);
to[i] = t ^ ztemp;
}
}
/*
* Decrypt "ptr[len]" in place.
*/
void bf_crypt_decode(char_u *ptr, long len)
{
char_u *p;
for (p = ptr; p < ptr + len; p++) {
int t;
BF_RANBYTE(t);
*p ^= t;
BF_CFB_UPDATE(*p);
}
}
/*
* Initialize the encryption keys and the random header according to
* the given password.
* in: "passwd" password string with which to modify keys
*/
void bf_crypt_init_keys(char_u *passwd)
{
char_u *p;
for (p = passwd; *p != NUL; p++) {
BF_CFB_UPDATE(*p);
}
}
static int save_randbyte_offset;
static int save_update_offset;
static char_u save_cfb_buffer[BF_CFB_LEN];
static uint32_t save_pax[18];
static uint32_t save_sbx[4][256];
/*
* Save the current crypt state. Can only be used once before
* bf_crypt_restore().
*/
void bf_crypt_save(void)
{
save_randbyte_offset = randbyte_offset;
save_update_offset = update_offset;
memmove(save_cfb_buffer, cfb_buffer, BF_CFB_LEN);
memmove(save_pax, pax, 4 * 18);
memmove(save_sbx, sbx, 4 * 4 * 256);
}
/*
* Restore the current crypt state. Can only be used after
* bf_crypt_save().
*/
void bf_crypt_restore(void)
{
randbyte_offset = save_randbyte_offset;
update_offset = save_update_offset;
memmove(cfb_buffer, save_cfb_buffer, BF_CFB_LEN);
memmove(pax, save_pax, 4 * 18);
memmove(sbx, save_sbx, 4 * 4 * 256);
}
/*
* Run a test to check if the encryption works as expected.
* Give an error and return FAIL when not.
*/
int blowfish_self_test(void)
{
if (sha256_self_test() == FAIL) {
EMSG(_("E818: sha256 test failed"));
return FAIL;
}
if (bf_self_test() == FAIL) {
EMSG(_("E819: Blowfish test failed"));
return FAIL;
}
return OK;
}

13
src/nvim/blowfish.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef NEOVIM_BLOWFISH_H
#define NEOVIM_BLOWFISH_H
void bf_key_init(char_u *password, char_u *salt, int salt_len);
void bf_cfb_init(char_u *iv, int iv_len);
void bf_crypt_encode(char_u *from, size_t len, char_u *to);
void bf_crypt_decode(char_u *ptr, long len);
void bf_crypt_init_keys(char_u *passwd);
void bf_crypt_save(void);
void bf_crypt_restore(void);
int blowfish_self_test(void);
#endif // NEOVIM_BLOWFISH_H

4657
src/nvim/buffer.c Normal file

File diff suppressed because it is too large Load Diff

81
src/nvim/buffer.h Normal file
View File

@@ -0,0 +1,81 @@
#ifndef NEOVIM_BUFFER_H
#define NEOVIM_BUFFER_H
/* buffer.c */
int open_buffer(int read_stdin, exarg_T *eap, int flags);
int buf_valid(buf_T *buf);
void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last);
void buf_clear_file(buf_T *buf);
void buf_freeall(buf_T *buf, int flags);
void goto_buffer(exarg_T *eap, int start, int dir, int count);
void handle_swap_exists(buf_T *old_curbuf);
char_u *do_bufdel(int command, char_u *arg, int addr_count,
int start_bnr, int end_bnr,
int forceit);
int do_buffer(int action, int start, int dir, int count, int forceit);
void set_curbuf(buf_T *buf, int action);
void enter_buffer(buf_T *buf);
void do_autochdir(void);
buf_T *buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum,
int flags);
void free_buf_options(buf_T *buf, int free_p_ff);
int buflist_getfile(int n, linenr_T lnum, int options, int forceit);
void buflist_getfpos(void);
buf_T *buflist_findname_exp(char_u *fname);
buf_T *buflist_findname(char_u *ffname);
int buflist_findpat(char_u *pattern, char_u *pattern_end, int unlisted,
int diffmode,
int curtab_only);
int ExpandBufnames(char_u *pat, int *num_file, char_u ***file,
int options);
buf_T *buflist_findnr(int nr);
char_u *buflist_nr2name(int n, int fullname, int helptail);
void get_winopts(buf_T *buf);
pos_T *buflist_findfpos(buf_T *buf);
linenr_T buflist_findlnum(buf_T *buf);
void buflist_list(exarg_T *eap);
int buflist_name_nr(int fnum, char_u **fname, linenr_T *lnum);
int setfname(buf_T *buf, char_u *ffname, char_u *sfname, int message);
void buf_set_name(int fnum, char_u *name);
void buf_name_changed(buf_T *buf);
buf_T *setaltfname(char_u *ffname, char_u *sfname, linenr_T lnum);
char_u *getaltfname(int errmsg);
int buflist_add(char_u *fname, int flags);
void buflist_slash_adjust(void);
void buflist_altfpos(win_T *win);
int otherfile(char_u *ffname);
void buf_setino(buf_T *buf);
void fileinfo(int fullname, int shorthelp, int dont_truncate);
void col_print(char_u *buf, size_t buflen, int col, int vcol);
void maketitle(void);
void resettitle(void);
void free_titles(void);
int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt,
int use_sandbox, int fillchar, int maxwidth,
struct stl_hlrec *hltab,
struct stl_hlrec *tabtab);
void get_rel_pos(win_T *wp, char_u *buf, int buflen);
void fname_expand(buf_T *buf, char_u **ffname, char_u **sfname);
char_u *alist_name(aentry_T *aep);
void do_arg_all(int count, int forceit, int keep_tabs);
void ex_buffer_all(exarg_T *eap);
void do_modelines(int flags);
int read_viminfo_bufferlist(vir_T *virp, int writing);
void write_viminfo_bufferlist(FILE *fp);
char_u *buf_spname(buf_T *buf);
int find_win_for_buf(buf_T *buf, win_T **wp, tabpage_T **tp);
void buf_addsign(buf_T *buf, int id, linenr_T lnum, int typenr);
linenr_T buf_change_sign_type(buf_T *buf, int markId, int typenr);
int buf_getsigntype(buf_T *buf, linenr_T lnum, int type);
linenr_T buf_delsign(buf_T *buf, int id);
int buf_findsign(buf_T *buf, int id);
int buf_findsign_id(buf_T *buf, linenr_T lnum);
void buf_delete_signs(buf_T *buf);
void buf_delete_all_signs(void);
void sign_list_placed(buf_T *rbuf);
void sign_mark_adjust(linenr_T line1, linenr_T line2, long amount,
long amount_after);
void set_buflisted(int on);
int buf_contents_changed(buf_T *buf);
void wipe_buffer(buf_T *buf, int aucmd);
#endif /* NEOVIM_BUFFER_H */

1081
src/nvim/buffer_defs.h Normal file

File diff suppressed because it is too large Load Diff

1918
src/nvim/charset.c Normal file

File diff suppressed because it is too large Load Diff

66
src/nvim/charset.h Normal file
View File

@@ -0,0 +1,66 @@
#ifndef NEOVIM_CHARSET_H
#define NEOVIM_CHARSET_H
int init_chartab(void);
int buf_init_chartab(buf_T *buf, int global);
void trans_characters(char_u *buf, int bufsize);
char_u *transstr(char_u *s);
char_u *str_foldcase(char_u *str, int orglen, char_u *buf, int buflen);
char_u *transchar(int c);
char_u *transchar_byte(int c);
void transchar_nonprint(char_u *buf, int c);
void transchar_hex(char_u *buf, int c);
int byte2cells(int b);
int char2cells(int c);
int ptr2cells(char_u *p);
int vim_strsize(char_u *s);
int vim_strnsize(char_u *s, int len);
int chartabsize(char_u *p, colnr_T col);
int linetabsize(char_u *s);
int linetabsize_col(int startcol, char_u *s);
int win_linetabsize(win_T *wp, char_u *p, colnr_T len);
int vim_isIDc(int c);
int vim_iswordc(int c);
int vim_iswordc_buf(int c, buf_T *buf);
int vim_iswordp(char_u *p);
int vim_iswordp_buf(char_u *p, buf_T *buf);
int vim_isfilec(int c);
int vim_isfilec_or_wc(int c);
int vim_isprintc(int c);
int vim_isprintc_strict(int c);
int lbr_chartabsize(unsigned char *s, colnr_T col);
int lbr_chartabsize_adv(char_u **s, colnr_T col);
int win_lbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp);
int in_win_border(win_T *wp, colnr_T vcol);
void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
colnr_T *end);
colnr_T getvcol_nolist(pos_T *posp);
void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
colnr_T *end);
void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left,
colnr_T *right);
char_u *skipwhite(char_u *q);
char_u *skipdigits(char_u *q);
char_u *skiphex(char_u *q);
char_u *skiptodigit(char_u *q);
char_u *skiptohex(char_u *q);
int vim_isdigit(int c);
int vim_isxdigit(int c);
int vim_islower(int c);
int vim_isupper(int c);
int vim_toupper(int c);
int vim_tolower(int c);
char_u *skiptowhite(char_u *p);
char_u *skiptowhite_esc(char_u *p);
long getdigits(char_u **pp);
int vim_isblankline(char_u *lbuf);
void vim_str2nr(char_u *start, int *hexp, int *len, int dooct,
int dohex, long *nptr,
unsigned long *unptr);
int hex2nr(int c);
int hexhex2nr(char_u *p);
int rem_backslash(char_u *str);
void backslash_halve(char_u *p);
char_u *backslash_halve_save(char_u *p);
#endif // NEOVIM_CHARSET_H

236
src/nvim/crypt.c Normal file
View File

@@ -0,0 +1,236 @@
// Optional encryption support.
// Mohsin Ahmed, mosh@sasi.com, 98-09-24
// Based on zip/crypt sources.
//
// NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
// most countries. There are a few exceptions, but that still should not be a
// problem since this code was originally created in Europe and India.
//
// Blowfish addition originally made by Mohsin Ahmed,
// http://www.cs.albany.edu/~mosh 2010-03-14
// Based on blowfish by Bruce Schneier (http://www.schneier.com/blowfish.html)
// and sha256 by Christophe Devine.
#include "vim.h"
#include "misc2.h"
#include "blowfish.h"
#include "ex_getln.h"
#include "message.h"
#include "option.h"
static void make_crc_tab(void);
static uint32_t crc_32_tab[256];
// Fills the CRC table.
static void make_crc_tab(void)
{
uint32_t s;
uint32_t t;
uint32_t v;
static bool done = false;
if (done) {
return;
}
for (t = 0; t < 256; t++) {
v = t;
for (s = 0; s < 8; s++) {
v = (v >> 1) ^ ((v & 1) * (uint32_t)0xedb88320L);
}
crc_32_tab[t] = v;
}
done = true;
}
#define CRC32(c, b) (crc_32_tab[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
static uint32_t keys[3]; // keys defining the pseudo-random sequence
// Returns the next byte in the pseudo-random sequence.
#define DECRYPT_BYTE_ZIP(t) { \
uint16_t temp; \
temp = (uint16_t)keys[2] | 2; \
t = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff); \
}
// Updates the encryption keys with the next byte of plain text.
#define UPDATE_KEYS_ZIP(c) { \
keys[0] = CRC32(keys[0], (c)); \
keys[1] += keys[0] & 0xff; \
keys[1] = keys[1] * 134775813L + 1; \
keys[2] = CRC32(keys[2], (int)(keys[1] >> 24)); \
}
static int crypt_busy = 0;
static uint32_t saved_keys[3];
static int saved_crypt_method;
int crypt_method_from_string(char_u *s)
{
return *s == 'b' ? 1 : 0;
}
int get_crypt_method(buf_T *buf)
{
return crypt_method_from_string(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
}
void set_crypt_method(buf_T *buf, int method)
{
free_string_option(buf->b_p_cm);
buf->b_p_cm = vim_strsave((char_u *)(method == 0 ? "zip" : "blowfish"));
}
void crypt_push_state(void)
{
if (crypt_busy == 1) {
// Save the state
if (use_crypt_method == 0) {
saved_keys[0] = keys[0];
saved_keys[1] = keys[1];
saved_keys[2] = keys[2];
} else {
bf_crypt_save();
}
saved_crypt_method = use_crypt_method;
} else if (crypt_busy > 1) {
EMSG2(_(e_intern2), "crypt_push_state()");
}
crypt_busy++;
}
void crypt_pop_state(void)
{
crypt_busy--;
if (crypt_busy == 1) {
use_crypt_method = saved_crypt_method;
if (use_crypt_method == 0) {
keys[0] = saved_keys[0];
keys[1] = saved_keys[1];
keys[2] = saved_keys[2];
} else {
bf_crypt_restore();
}
}
}
void crypt_encode(char_u *from, size_t len, char_u *to)
{
size_t i;
int ztemp;
int t;
if (use_crypt_method == 0) {
for (i = 0; i < len; i++) {
ztemp = from[i];
DECRYPT_BYTE_ZIP(t);
UPDATE_KEYS_ZIP(ztemp);
to[i] = t ^ ztemp;
}
} else {
bf_crypt_encode(from, len, to);
}
}
void crypt_decode(char_u *ptr, long len)
{
char_u *p;
if (use_crypt_method == 0) {
for (p = ptr; p < ptr + len; p++) {
uint16_t temp;
temp = (uint16_t)keys[2] | 2;
temp = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff);
UPDATE_KEYS_ZIP(*p ^= temp);
}
} else {
bf_crypt_decode(ptr, len);
}
}
void crypt_init_keys(char_u *passwd)
{
if ((passwd != NULL) && (*passwd != NUL)) {
if (use_crypt_method == 0) {
char_u *p;
make_crc_tab();
keys[0] = 305419896L;
keys[1] = 591751049L;
keys[2] = 878082192L;
for (p = passwd; *p != NUL; p++) {
UPDATE_KEYS_ZIP((int)*p);
}
} else {
bf_crypt_init_keys(passwd);
}
}
}
void free_crypt_key(char_u *key)
{
char_u *p;
if (key != NULL) {
for (p = key; *p != NUL; p++) {
*p = 0;
}
free(key);
}
}
char_u *get_crypt_key(int store, int twice)
{
char_u *p1;
char_u *p2 = NULL;
int round;
for (round = 0;; round++) {
cmdline_star = TRUE;
cmdline_row = msg_row;
char_u *prompt = (round == 0)
? (char_u *) _("Enter encryption key: ")
: (char_u *) _("Enter same key again: ");
p1 = getcmdline_prompt(NUL, prompt, 0, EXPAND_NOTHING, NULL);
cmdline_star = FALSE;
if (p1 == NULL) {
break;
}
if (round == twice) {
if ((p2 != NULL) && (STRCMP(p1, p2) != 0)) {
MSG(_("Keys don't match!"));
free_crypt_key(p1);
free_crypt_key(p2);
p2 = NULL;
round = -1; // Do it again
continue;
}
if (store) {
set_option_value((char_u *) "key", 0L, p1, OPT_LOCAL);
free_crypt_key(p1);
p1 = curbuf->b_p_key;
}
break;
}
p2 = p1;
}
// Since the user typed this, no need to wait for return.
if (msg_didout) {
msg_putchar('\n');
}
need_wait_return = FALSE;
msg_didout = FALSE;
free_crypt_key(p2);
return p1;
}

82
src/nvim/crypt.h Normal file
View File

@@ -0,0 +1,82 @@
#ifndef NEOVIM_CRYPT_H
#define NEOVIM_CRYPT_H
/// Returns the crypt method string as a number.
///
/// @param s Pointer to the crypt method string.
///
/// @return An integer value of the crypt method:
/// 0 for "zip", the old method. Also for any non-valid value.
/// 1 for "blowfish".
int crypt_method_from_string(char_u *s);
/// Returns the crypt method of the buffer "buf" as a number.
///
/// @param buf Pointer to the buffer.
///
/// @return An integer value of the crypt method:
/// 0 for "zip", the old method. Also for any non-valid value.
/// 1 for "blowfish".
int get_crypt_method(buf_T *buf);
/// Sets the crypt method for buffer "buf" to "method" using the
/// int value as returned by crypt_method_from_string().
///
/// @param buf Pointer to the buffer.
/// @param method Crypt method.
void set_crypt_method(buf_T *buf, int method);
/// Prepares for initializing the encryption. If already doing encryption,
/// then save the state.
///
/// This function must always be called symmetrically with crypt_pop_state().
void crypt_push_state(void);
/// Ends encryption. If already doing encryption before crypt_push_state(),
/// then restore the saved state.
///
/// This function must always be called symmetrically with crypt_push_state().
void crypt_pop_state(void);
/// Encrypts "from[len]" into "to[len]".
/// For in-place encryption, "from" and "len" must be the same.
///
/// @param from Pointer to the source string.
/// @param len Length of the strings.
/// @param to Pointer to the destination string.
void crypt_encode(char_u *from, size_t len, char_u *to);
/// Decrypts "ptr[len]" in-place.
///
/// @param ptr Pointer to the string.
/// @param len Length of the string.
void crypt_decode(char_u *ptr, long len);
/// Initializes the encryption keys and the random header according to
/// the given password.
///
/// If "password" is NULL or empty, the function doesn't do anything.
///
/// @param passwd The password string with which to modify keys.
void crypt_init_keys(char_u *passwd);
/// Frees an allocated crypt key and clears the text to make sure
/// nothing stays in memory.
///
/// @param key The crypt key to be freed.
void free_crypt_key(char_u *key);
/// Asks the user for the crypt key.
///
/// When "store" is TRUE, the new key is stored in the 'key' option
/// and the 'key' option value is returned, which MUST NOT be freed
/// manually, but using free_crypt_key().
/// When "store" is FALSE, the typed key is returned in allocated memory.
///
/// @param store Determines, whether the new crypt key is stored.
/// @param twice Ask for the key twice.
///
/// @return The crypt key. On failure, NULL is returned.
char_u *get_crypt_key(int store, int twice);
#endif // NEOVIM_CRYPT_H

209
src/nvim/cursor_shape.c Normal file
View File

@@ -0,0 +1,209 @@
#include "vim.h"
#include "cursor_shape.h"
#include "misc2.h"
#include "ex_getln.h"
#include "charset.h"
#include "syntax.h"
/*
* Handling of cursor and mouse pointer shapes in various modes.
*/
static cursorentry_T shape_table[SHAPE_IDX_COUNT] =
{
/* The values will be filled in from the 'guicursor' and 'mouseshape'
* defaults when Vim starts.
* Adjust the SHAPE_IDX_ defines when making changes! */
{0, 0, 0, 700L, 400L, 250L, 0, 0, "n", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "v", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "i", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "r", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "c", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 0L, 0L, 0L, 0, 0, "e", SHAPE_MOUSE},
{0, 0, 0, 0L, 0L, 0L, 0, 0, "s", SHAPE_MOUSE},
{0, 0, 0, 0L, 0L, 0L, 0, 0, "sd", SHAPE_MOUSE},
{0, 0, 0, 0L, 0L, 0L, 0, 0, "vs", SHAPE_MOUSE},
{0, 0, 0, 0L, 0L, 0L, 0, 0, "vd", SHAPE_MOUSE},
{0, 0, 0, 0L, 0L, 0L, 0, 0, "m", SHAPE_MOUSE},
{0, 0, 0, 0L, 0L, 0L, 0, 0, "ml", SHAPE_MOUSE},
{0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR},
};
/*
* Parse the 'guicursor' option ("what" is SHAPE_CURSOR) or 'mouseshape'
* ("what" is SHAPE_MOUSE).
* Returns error message for an illegal option, NULL otherwise.
*/
char_u *parse_shape_opt(int what)
{
char_u *modep;
char_u *colonp;
char_u *commap;
char_u *slashp;
char_u *p, *endp;
int idx = 0; /* init for GCC */
int all_idx;
int len;
int i;
long n;
int found_ve = FALSE; /* found "ve" flag */
int round;
/*
* First round: check for errors; second round: do it for real.
*/
for (round = 1; round <= 2; ++round) {
/*
* Repeat for all comma separated parts.
*/
modep = p_guicursor;
while (*modep != NUL) {
colonp = vim_strchr(modep, ':');
if (colonp == NULL)
return (char_u *)N_("E545: Missing colon");
if (colonp == modep)
return (char_u *)N_("E546: Illegal mode");
commap = vim_strchr(modep, ',');
/*
* Repeat for all mode's before the colon.
* For the 'a' mode, we loop to handle all the modes.
*/
all_idx = -1;
while (modep < colonp || all_idx >= 0) {
if (all_idx < 0) {
/* Find the mode. */
if (modep[1] == '-' || modep[1] == ':')
len = 1;
else
len = 2;
if (len == 1 && TOLOWER_ASC(modep[0]) == 'a')
all_idx = SHAPE_IDX_COUNT - 1;
else {
for (idx = 0; idx < SHAPE_IDX_COUNT; ++idx)
if (STRNICMP(modep, shape_table[idx].name, len)
== 0)
break;
if (idx == SHAPE_IDX_COUNT
|| (shape_table[idx].used_for & what) == 0)
return (char_u *)N_("E546: Illegal mode");
if (len == 2 && modep[0] == 'v' && modep[1] == 'e')
found_ve = TRUE;
}
modep += len + 1;
}
if (all_idx >= 0)
idx = all_idx--;
else if (round == 2) {
{
/* Set the defaults, for the missing parts */
shape_table[idx].shape = SHAPE_BLOCK;
shape_table[idx].blinkwait = 700L;
shape_table[idx].blinkon = 400L;
shape_table[idx].blinkoff = 250L;
}
}
/* Parse the part after the colon */
for (p = colonp + 1; *p && *p != ','; ) {
{
/*
* First handle the ones with a number argument.
*/
i = *p;
len = 0;
if (STRNICMP(p, "ver", 3) == 0)
len = 3;
else if (STRNICMP(p, "hor", 3) == 0)
len = 3;
else if (STRNICMP(p, "blinkwait", 9) == 0)
len = 9;
else if (STRNICMP(p, "blinkon", 7) == 0)
len = 7;
else if (STRNICMP(p, "blinkoff", 8) == 0)
len = 8;
if (len != 0) {
p += len;
if (!VIM_ISDIGIT(*p))
return (char_u *)N_("E548: digit expected");
n = getdigits(&p);
if (len == 3) { /* "ver" or "hor" */
if (n == 0)
return (char_u *)N_("E549: Illegal percentage");
if (round == 2) {
if (TOLOWER_ASC(i) == 'v')
shape_table[idx].shape = SHAPE_VER;
else
shape_table[idx].shape = SHAPE_HOR;
shape_table[idx].percentage = n;
}
} else if (round == 2) {
if (len == 9)
shape_table[idx].blinkwait = n;
else if (len == 7)
shape_table[idx].blinkon = n;
else
shape_table[idx].blinkoff = n;
}
} else if (STRNICMP(p, "block", 5) == 0) {
if (round == 2)
shape_table[idx].shape = SHAPE_BLOCK;
p += 5;
} else { /* must be a highlight group name then */
endp = vim_strchr(p, '-');
if (commap == NULL) { /* last part */
if (endp == NULL)
endp = p + STRLEN(p); /* find end of part */
} else if (endp > commap || endp == NULL)
endp = commap;
slashp = vim_strchr(p, '/');
if (slashp != NULL && slashp < endp) {
/* "group/langmap_group" */
i = syn_check_group(p, (int)(slashp - p));
p = slashp + 1;
}
if (round == 2) {
shape_table[idx].id = syn_check_group(p,
(int)(endp - p));
shape_table[idx].id_lm = shape_table[idx].id;
if (slashp != NULL && slashp < endp)
shape_table[idx].id = i;
}
p = endp;
}
} /* if (what != SHAPE_MOUSE) */
if (*p == '-')
++p;
}
}
modep = p;
if (*modep == ',')
++modep;
}
}
/* If the 's' flag is not given, use the 'v' cursor for 's' */
if (!found_ve) {
{
shape_table[SHAPE_IDX_VE].shape = shape_table[SHAPE_IDX_V].shape;
shape_table[SHAPE_IDX_VE].percentage =
shape_table[SHAPE_IDX_V].percentage;
shape_table[SHAPE_IDX_VE].blinkwait =
shape_table[SHAPE_IDX_V].blinkwait;
shape_table[SHAPE_IDX_VE].blinkon =
shape_table[SHAPE_IDX_V].blinkon;
shape_table[SHAPE_IDX_VE].blinkoff =
shape_table[SHAPE_IDX_V].blinkoff;
shape_table[SHAPE_IDX_VE].id = shape_table[SHAPE_IDX_V].id;
shape_table[SHAPE_IDX_VE].id_lm = shape_table[SHAPE_IDX_V].id_lm;
}
}
return NULL;
}

52
src/nvim/cursor_shape.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef NEOVIM_CURSOR_SHAPE_H
#define NEOVIM_CURSOR_SHAPE_H
/*
* struct to store values from 'guicursor' and 'mouseshape'
*/
/* Indexes in shape_table[] */
#define SHAPE_IDX_N 0 /* Normal mode */
#define SHAPE_IDX_V 1 /* Visual mode */
#define SHAPE_IDX_I 2 /* Insert mode */
#define SHAPE_IDX_R 3 /* Replace mode */
#define SHAPE_IDX_C 4 /* Command line Normal mode */
#define SHAPE_IDX_CI 5 /* Command line Insert mode */
#define SHAPE_IDX_CR 6 /* Command line Replace mode */
#define SHAPE_IDX_O 7 /* Operator-pending mode */
#define SHAPE_IDX_VE 8 /* Visual mode with 'selection' exclusive */
#define SHAPE_IDX_CLINE 9 /* On command line */
#define SHAPE_IDX_STATUS 10 /* A status line */
#define SHAPE_IDX_SDRAG 11 /* dragging a status line */
#define SHAPE_IDX_VSEP 12 /* A vertical separator line */
#define SHAPE_IDX_VDRAG 13 /* dragging a vertical separator line */
#define SHAPE_IDX_MORE 14 /* Hit-return or More */
#define SHAPE_IDX_MOREL 15 /* Hit-return or More in last line */
#define SHAPE_IDX_SM 16 /* showing matching paren */
#define SHAPE_IDX_COUNT 17
#define SHAPE_BLOCK 0 /* block cursor */
#define SHAPE_HOR 1 /* horizontal bar cursor */
#define SHAPE_VER 2 /* vertical bar cursor */
#define MSHAPE_NUMBERED 1000 /* offset for shapes identified by number */
#define MSHAPE_HIDE 1 /* hide mouse pointer */
#define SHAPE_MOUSE 1 /* used for mouse pointer shape */
#define SHAPE_CURSOR 2 /* used for text cursor shape */
typedef struct cursor_entry {
int shape; /* one of the SHAPE_ defines */
int mshape; /* one of the MSHAPE defines */
int percentage; /* percentage of cell for bar */
long blinkwait; /* blinking, wait time before blinking starts */
long blinkon; /* blinking, on time */
long blinkoff; /* blinking, off time */
int id; /* highlight group ID */
int id_lm; /* highlight group ID for :lmap mode */
char *name; /* mode name (fixed) */
char used_for; /* SHAPE_MOUSE and/or SHAPE_CURSOR */
} cursorentry_T;
char_u *parse_shape_opt(int what);
#endif /* NEOVIM_CURSOR_SHAPE_H */

2611
src/nvim/diff.c Normal file

File diff suppressed because it is too large Load Diff

33
src/nvim/diff.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef NEOVIM_DIFF_H
#define NEOVIM_DIFF_H
void diff_buf_delete(buf_T *buf);
void diff_buf_adjust(win_T *win);
void diff_buf_add(buf_T *buf);
void diff_invalidate(buf_T *buf);
void diff_mark_adjust(linenr_T line1, linenr_T line2, long amount,
long amount_after);
void ex_diffupdate(exarg_T *eap);
void ex_diffpatch(exarg_T *eap);
void ex_diffsplit(exarg_T *eap);
void ex_diffthis(exarg_T *eap);
void diff_win_options(win_T *wp, int addbuf);
void ex_diffoff(exarg_T *eap);
void diff_clear(tabpage_T *tp);
int diff_check(win_T *wp, linenr_T lnum);
int diff_check_fill(win_T *wp, linenr_T lnum);
void diff_set_topline(win_T *fromwin, win_T *towin);
int diffopt_changed(void);
int diffopt_horizontal(void);
int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp);
int diff_infold(win_T *wp, linenr_T lnum);
void nv_diffgetput(int put);
void ex_diffgetput(exarg_T *eap);
int diff_mode_buf(buf_T *buf);
int diff_move_to(int dir, long count);
linenr_T diff_get_corresponding_line(buf_T *buf1, linenr_T lnum1,
buf_T *buf2,
linenr_T lnum3);
linenr_T diff_lnum_win(linenr_T lnum, win_T *wp);
#endif // NEOVIM_DIFF_H

1881
src/nvim/digraph.c Normal file

File diff suppressed because it is too large Load Diff

12
src/nvim/digraph.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef NEOVIM_DIGRAPH_H
#define NEOVIM_DIGRAPH_H
int do_digraph(int c);
int get_digraph(int cmdline);
int getdigraph(int char1, int char2, int meta_char);
void putdigraph(char_u *str);
void listdigraphs(void);
char_u *keymap_init(void);
void ex_loadkeymap(exarg_T *eap);
#endif // NEOVIM_DIGRAPH_H

8444
src/nvim/edit.c Normal file

File diff suppressed because it is too large Load Diff

58
src/nvim/edit.h Normal file
View File

@@ -0,0 +1,58 @@
#ifndef NEOVIM_EDIT_H
#define NEOVIM_EDIT_H
#include "vim.h"
/*
* Array indexes used for cptext argument of ins_compl_add().
*/
#define CPT_ABBR 0 /* "abbr" */
#define CPT_MENU 1 /* "menu" */
#define CPT_KIND 2 /* "kind" */
#define CPT_INFO 3 /* "info" */
#define CPT_COUNT 4 /* Number of entries */
int edit(int cmdchar, int startln, long count);
void edit_putchar(int c, int highlight);
void edit_unputchar(void);
void display_dollar(colnr_T col);
void change_indent(int type, int amount, int round, int replaced,
int call_changed_bytes);
void truncate_spaces(char_u *line);
void backspace_until_column(int col);
int vim_is_ctrl_x_key(int c);
int ins_compl_add_infercase(char_u *str, int len, int icase,
char_u *fname, int dir,
int flags);
void set_completion(colnr_T startcol, list_T *list);
void ins_compl_show_pum(void);
char_u *find_word_start(char_u *ptr);
char_u *find_word_end(char_u *ptr);
int ins_compl_active(void);
int ins_compl_add_tv(typval_T *tv, int dir);
void ins_compl_check_keys(int frequency);
int get_literal(void);
void insertchar(int c, int flags, int second_indent);
void auto_format(int trailblank, int prev_line);
int comp_textwidth(int ff);
int stop_arrow(void);
void set_last_insert(int c);
void free_last_insert(void);
char_u *add_char2buf(int c, char_u *s);
void beginline(int flags);
int oneright(void);
int oneleft(void);
int cursor_up(long n, int upd_topline);
int cursor_down(long n, int upd_topline);
int stuff_inserted(int c, long count, int no_esc);
char_u *get_last_insert(void);
char_u *get_last_insert_save(void);
void replace_push(int c);
int replace_push_mb(char_u *p);
void fixthisline(int (*get_the_indent)(void));
void fix_indent(void);
int in_cinkeys(int keytyped, int when, int line_is_empty);
int hkmap(int c);
int ins_copychar(linenr_T lnum);
#endif /* NEOVIM_EDIT_H */

19819
src/nvim/eval.c Normal file

File diff suppressed because it is too large Load Diff

152
src/nvim/eval.h Normal file
View File

@@ -0,0 +1,152 @@
#ifndef NEOVIM_EVAL_H
#define NEOVIM_EVAL_H
/* eval.c */
void eval_init(void);
void eval_clear(void);
char_u *func_name(void *cookie);
linenr_T *func_breakpoint(void *cookie);
int *func_dbg_tick(void *cookie);
int func_level(void *cookie);
int current_func_returned(void);
void set_internal_string_var(char_u *name, char_u *value);
int var_redir_start(char_u *name, int append);
void var_redir_str(char_u *value, int value_len);
void var_redir_stop(void);
int eval_charconvert(char_u *enc_from, char_u *enc_to, char_u *
fname_from,
char_u *fname_to);
int eval_printexpr(char_u *fname, char_u *args);
void eval_diff(char_u *origfile, char_u *newfile, char_u *outfile);
void eval_patch(char_u *origfile, char_u *difffile, char_u *outfile);
int eval_to_bool(char_u *arg, int *error, char_u **nextcmd, int skip);
char_u *eval_to_string_skip(char_u *arg, char_u **nextcmd, int skip);
int skip_expr(char_u **pp);
char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert);
char_u *eval_to_string_safe(char_u *arg, char_u **nextcmd,
int use_sandbox);
int eval_to_number(char_u *expr);
list_T *eval_spell_expr(char_u *badword, char_u *expr);
int get_spellword(list_T *list, char_u **pp);
typval_T *eval_expr(char_u *arg, char_u **nextcmd);
int call_vim_function(char_u *func, int argc, char_u **argv, int safe,
int str_arg_only,
typval_T *rettv);
long call_func_retnr(char_u *func, int argc, char_u **argv, int safe);
void *call_func_retstr(char_u *func, int argc, char_u **argv, int safe);
void *call_func_retlist(char_u *func, int argc, char_u **argv, int safe);
void *save_funccal(void);
void restore_funccal(void *vfc);
void prof_child_enter(proftime_T *tm);
void prof_child_exit(proftime_T *tm);
int eval_foldexpr(char_u *arg, int *cp);
void ex_let(exarg_T *eap);
void list_add_watch(list_T *l, listwatch_T *lw);
void list_rem_watch(list_T *l, listwatch_T *lwrem);
void *eval_for_line(char_u *arg, int *errp, char_u **nextcmdp, int skip);
int next_for_item(void *fi_void, char_u *arg);
void free_for_info(void *fi_void);
void set_context_for_expression(expand_T *xp, char_u *arg,
cmdidx_T cmdidx);
void ex_call(exarg_T *eap);
void ex_unlet(exarg_T *eap);
void ex_lockvar(exarg_T *eap);
int do_unlet(char_u *name, int forceit);
void del_menutrans_vars(void);
char_u *get_user_var_name(expand_T *xp, int idx);
list_T *list_alloc(void);
void list_unref(list_T *l);
void list_free(list_T *l, int recurse);
listitem_T *listitem_alloc(void);
void listitem_free(listitem_T *item);
void listitem_remove(list_T *l, listitem_T *item);
dictitem_T *dict_lookup(hashitem_T *hi);
listitem_T *list_find(list_T *l, long n);
char_u *list_find_str(list_T *l, long idx);
void list_append(list_T *l, listitem_T *item);
void list_append_tv(list_T *l, typval_T *tv);
void list_append_dict(list_T *list, dict_T *dict);
void list_append_string(list_T *l, char_u *str, int len);
int list_insert_tv(list_T *l, typval_T *tv, listitem_T *item);
void list_remove(list_T *l, listitem_T *item, listitem_T *item2);
void list_insert(list_T *l, listitem_T *ni, listitem_T *item);
int garbage_collect(void);
void set_ref_in_ht(hashtab_T *ht, int copyID);
void set_ref_in_list(list_T *l, int copyID);
void set_ref_in_item(typval_T *tv, int copyID);
dict_T *dict_alloc(void);
void dict_unref(dict_T *d);
void dict_free(dict_T *d, int recurse);
dictitem_T *dictitem_alloc(char_u *key);
void dictitem_free(dictitem_T *item);
int dict_add(dict_T *d, dictitem_T *item);
int dict_add_nr_str(dict_T *d, char *key, long nr, char_u *str);
int dict_add_list(dict_T *d, char *key, list_T *list);
dictitem_T *dict_find(dict_T *d, char_u *key, int len);
char_u *get_dict_string(dict_T *d, char_u *key, int save);
long get_dict_number(dict_T *d, char_u *key);
char_u *get_function_name(expand_T *xp, int idx);
char_u *get_expr_name(expand_T *xp, int idx);
int func_call(char_u *name, typval_T *args, dict_T *selfdict,
typval_T *rettv);
void dict_extend(dict_T *d1, dict_T *d2, char_u *action);
float_T vim_round(float_T f);
long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir,
char_u *skip, int flags, pos_T *match_pos,
linenr_T lnum_stop,
long time_limit);
void set_vim_var_nr(int idx, long val);
long get_vim_var_nr(int idx);
char_u *get_vim_var_str(int idx);
list_T *get_vim_var_list(int idx);
void set_vim_var_char(int c);
void set_vcount(long count, long count1, int set_prevcount);
void set_vim_var_string(int idx, char_u *val, int len);
void set_vim_var_list(int idx, list_T *val);
void set_reg_var(int c);
char_u *v_exception(char_u *oldval);
char_u *v_throwpoint(char_u *oldval);
char_u *set_cmdarg(exarg_T *eap, char_u *oldarg);
void free_tv(typval_T *varp);
void clear_tv(typval_T *varp);
long get_tv_number_chk(typval_T *varp, int *denote);
char_u *get_tv_string_chk(typval_T *varp);
char_u *get_var_value(char_u *name);
void new_script_vars(scid_T id);
void init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope);
void unref_var_dict(dict_T *dict);
void vars_clear(hashtab_T *ht);
void copy_tv(typval_T *from, typval_T *to);
void ex_echo(exarg_T *eap);
void ex_echohl(exarg_T *eap);
void ex_execute(exarg_T *eap);
void ex_function(exarg_T *eap);
void free_all_functions(void);
int translated_function_exists(char_u *name);
char_u *get_expanded_name(char_u *name, int check);
void func_dump_profile(FILE *fd);
char_u *get_user_func_name(expand_T *xp, int idx);
void ex_delfunction(exarg_T *eap);
void func_unref(char_u *name);
void func_ref(char_u *name);
void ex_return(exarg_T *eap);
int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv);
void discard_pending_return(void *rettv);
char_u *get_return_cmd(void *rettv);
char_u *get_func_line(int c, void *cookie, int indent);
void func_line_start(void *cookie);
void func_line_exec(void *cookie);
void func_line_end(void *cookie);
int func_has_ended(void *cookie);
int func_has_abort(void *cookie);
int read_viminfo_varlist(vir_T *virp, int writing);
void write_viminfo_varlist(FILE *fp);
int store_session_globals(FILE *fd);
void last_set_msg(scid_T scriptID);
void ex_oldfiles(exarg_T *eap);
int modify_fname(char_u *src, int *usedlen, char_u **fnamep,
char_u **bufp,
int *fnamelen);
char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub,
char_u *flags);
#endif /* NEOVIM_EVAL_H */

116
src/nvim/eval_defs.h Normal file
View File

@@ -0,0 +1,116 @@
#ifndef NEOVIM_EVAL_DEFS_H
#define NEOVIM_EVAL_DEFS_H
#include "hashtab.h"
typedef int varnumber_T;
typedef double float_T;
typedef struct listvar_S list_T;
typedef struct dictvar_S dict_T;
/*
* Structure to hold an internal variable without a name.
*/
typedef struct {
char v_type; /* see below: VAR_NUMBER, VAR_STRING, etc. */
char v_lock; /* see below: VAR_LOCKED, VAR_FIXED */
union {
varnumber_T v_number; /* number value */
float_T v_float; /* floating number value */
char_u *v_string; /* string value (can be NULL!) */
list_T *v_list; /* list value (can be NULL!) */
dict_T *v_dict; /* dict value (can be NULL!) */
} vval;
} typval_T;
/* Values for "v_type". */
#define VAR_UNKNOWN 0
#define VAR_NUMBER 1 /* "v_number" is used */
#define VAR_STRING 2 /* "v_string" is used */
#define VAR_FUNC 3 /* "v_string" is function name */
#define VAR_LIST 4 /* "v_list" is used */
#define VAR_DICT 5 /* "v_dict" is used */
#define VAR_FLOAT 6 /* "v_float" is used */
/* Values for "dv_scope". */
#define VAR_SCOPE 1 /* a:, v:, s:, etc. scope dictionaries */
#define VAR_DEF_SCOPE 2 /* l:, g: scope dictionaries: here funcrefs are not
allowed to mask existing functions */
/* Values for "v_lock". */
#define VAR_LOCKED 1 /* locked with lock(), can use unlock() */
#define VAR_FIXED 2 /* locked forever */
/*
* Structure to hold an item of a list: an internal variable without a name.
*/
typedef struct listitem_S listitem_T;
struct listitem_S {
listitem_T *li_next; /* next item in list */
listitem_T *li_prev; /* previous item in list */
typval_T li_tv; /* type and value of the variable */
};
/*
* Struct used by those that are using an item in a list.
*/
typedef struct listwatch_S listwatch_T;
struct listwatch_S {
listitem_T *lw_item; /* item being watched */
listwatch_T *lw_next; /* next watcher */
};
/*
* Structure to hold info about a list.
*/
struct listvar_S {
listitem_T *lv_first; /* first item, NULL if none */
listitem_T *lv_last; /* last item, NULL if none */
int lv_refcount; /* reference count */
int lv_len; /* number of items */
listwatch_T *lv_watch; /* first watcher, NULL if none */
int lv_idx; /* cached index of an item */
listitem_T *lv_idx_item; /* when not NULL item at index "lv_idx" */
int lv_copyID; /* ID used by deepcopy() */
list_T *lv_copylist; /* copied list used by deepcopy() */
char lv_lock; /* zero, VAR_LOCKED, VAR_FIXED */
list_T *lv_used_next; /* next list in used lists list */
list_T *lv_used_prev; /* previous list in used lists list */
};
/*
* Structure to hold an item of a Dictionary.
* Also used for a variable.
* The key is copied into "di_key" to avoid an extra alloc/free for it.
*/
struct dictitem_S {
typval_T di_tv; /* type and value of the variable */
char_u di_flags; /* flags (only used for variable) */
char_u di_key[1]; /* key (actually longer!) */
};
typedef struct dictitem_S dictitem_T;
#define DI_FLAGS_RO 1 /* "di_flags" value: read-only variable */
#define DI_FLAGS_RO_SBX 2 /* "di_flags" value: read-only in the sandbox */
#define DI_FLAGS_FIX 4 /* "di_flags" value: fixed variable, not allocated */
#define DI_FLAGS_LOCK 8 /* "di_flags" value: locked variable */
/*
* Structure to hold info about a Dictionary.
*/
struct dictvar_S {
char dv_lock; /* zero, VAR_LOCKED, VAR_FIXED */
char dv_scope; /* zero, VAR_SCOPE, VAR_DEF_SCOPE */
int dv_refcount; /* reference count */
int dv_copyID; /* ID used by deepcopy() */
hashtab_T dv_hashtab; /* hashtab that refers to the items */
dict_T *dv_copydict; /* copied dict used by deepcopy() */
dict_T *dv_used_next; /* next dict in used dicts list */
dict_T *dv_used_prev; /* previous dict in used dicts list */
};
#endif // NEOVIM_EVAL_DEFS_H

6374
src/nvim/ex_cmds.c Normal file

File diff suppressed because it is too large Load Diff

75
src/nvim/ex_cmds.h Normal file
View File

@@ -0,0 +1,75 @@
#ifndef NEOVIM_EX_CMDS_H
#define NEOVIM_EX_CMDS_H
/* ex_cmds.c */
void do_ascii(exarg_T *eap);
void ex_align(exarg_T *eap);
void ex_sort(exarg_T *eap);
void ex_retab(exarg_T *eap);
int do_move(linenr_T line1, linenr_T line2, linenr_T dest);
void ex_copy(linenr_T line1, linenr_T line2, linenr_T n);
void free_prev_shellcmd(void);
void do_bang(int addr_count, exarg_T *eap, int forceit, int do_in,
int do_out);
void do_shell(char_u *cmd, int flags);
char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp);
void append_redir(char_u *buf, int buflen, char_u *opt, char_u *fname);
int viminfo_error(char *errnum, char *message, char_u *line);
int read_viminfo(char_u *file, int flags);
void write_viminfo(char_u *file, int forceit);
int viminfo_readline(vir_T *virp);
char_u *viminfo_readstring(vir_T *virp, int off, int convert);
void viminfo_writestring(FILE *fd, char_u *p);
void do_fixdel(exarg_T *eap);
void print_line_no_prefix(linenr_T lnum, int use_number, int list);
void print_line(linenr_T lnum, int use_number, int list);
int rename_buffer(char_u *new_fname);
void ex_file(exarg_T *eap);
void ex_update(exarg_T *eap);
void ex_write(exarg_T *eap);
int do_write(exarg_T *eap);
int check_overwrite(exarg_T *eap, buf_T *buf, char_u *fname, char_u *
ffname,
int other);
void ex_wnext(exarg_T *eap);
void do_wqall(exarg_T *eap);
int not_writing(void);
int getfile(int fnum, char_u *ffname, char_u *sfname, int setpm,
linenr_T lnum,
int forceit);
int do_ecmd(int fnum, char_u *ffname, char_u *sfname, exarg_T *eap,
linenr_T newlnum, int flags,
win_T *oldwin);
void ex_append(exarg_T *eap);
void ex_change(exarg_T *eap);
void ex_z(exarg_T *eap);
int check_restricted(void);
int check_secure(void);
void do_sub(exarg_T *eap);
int do_sub_msg(int count_only);
void ex_global(exarg_T *eap);
void global_exe(char_u *cmd);
int read_viminfo_sub_string(vir_T *virp, int force);
void write_viminfo_sub_string(FILE *fp);
void free_old_sub(void);
int prepare_tagpreview(int undo_sync);
void ex_help(exarg_T *eap);
char_u *check_help_lang(char_u *arg);
int help_heuristic(char_u *matched_string, int offset, int wrong_case);
int find_help_tags(char_u *arg, int *num_matches, char_u ***matches,
int keep_lang);
void fix_help_buffer(void);
void ex_exusage(exarg_T *eap);
void ex_viusage(exarg_T *eap);
void ex_helptags(exarg_T *eap);
void ex_sign(exarg_T *eap);
int sign_get_attr(int typenr, int line);
char_u *sign_get_text(int typenr);
void *sign_get_image(int typenr);
char_u *sign_typenr2name(int typenr);
void free_signs(void);
char_u *get_sign_name(expand_T *xp, int idx);
void set_context_in_sign_cmd(expand_T *xp, char_u *arg);
void ex_drop(exarg_T *eap);
#endif /* NEOVIM_EX_CMDS_H */

3541
src/nvim/ex_cmds2.c Normal file

File diff suppressed because it is too large Load Diff

95
src/nvim/ex_cmds2.h Normal file
View File

@@ -0,0 +1,95 @@
#ifndef NEOVIM_EX_CMDS2_H
#define NEOVIM_EX_CMDS2_H
/* ex_cmds2.c */
void do_debug(char_u *cmd);
void ex_debug(exarg_T *eap);
void dbg_check_breakpoint(exarg_T *eap);
int dbg_check_skipped(exarg_T *eap);
void ex_breakadd(exarg_T *eap);
void ex_debuggreedy(exarg_T *eap);
void ex_breakdel(exarg_T *eap);
void ex_breaklist(exarg_T *eap);
linenr_T dbg_find_breakpoint(int file, char_u *fname, linenr_T after);
int has_profiling(int file, char_u *fname, int *fp);
void dbg_breakpoint(char_u *name, linenr_T lnum);
void profile_start(proftime_T *tm);
void profile_end(proftime_T *tm);
void profile_sub(proftime_T *tm, proftime_T *tm2);
char *profile_msg(proftime_T *tm);
void profile_setlimit(long msec, proftime_T *tm);
int profile_passed_limit(proftime_T *tm);
void profile_zero(proftime_T *tm);
void profile_divide(proftime_T *tm, int count, proftime_T *tm2);
void profile_add(proftime_T *tm, proftime_T *tm2);
void profile_self(proftime_T *self, proftime_T *total,
proftime_T *children);
void profile_get_wait(proftime_T *tm);
void profile_sub_wait(proftime_T *tm, proftime_T *tma);
int profile_equal(proftime_T *tm1, proftime_T *tm2);
int profile_cmp(const proftime_T *tm1, const proftime_T *tm2);
void ex_profile(exarg_T *eap);
char_u *get_profile_name(expand_T *xp, int idx);
void set_context_in_profile_cmd(expand_T *xp, char_u *arg);
void profile_dump(void);
void script_prof_save(proftime_T *tm);
void script_prof_restore(proftime_T *tm);
void prof_inchar_enter(void);
void prof_inchar_exit(void);
int prof_def_func(void);
int autowrite(buf_T *buf, int forceit);
void autowrite_all(void);
int check_changed(buf_T *buf, int flags);
void dialog_changed(buf_T *buf, int checkall);
int can_abandon(buf_T *buf, int forceit);
int check_changed_any(int hidden);
int check_fname(void);
int buf_write_all(buf_T *buf, int forceit);
void get_arglist(garray_T *gap, char_u *str);
int get_arglist_exp(char_u *str, int *fcountp, char_u ***fnamesp,
int wig);
void check_arg_idx(win_T *win);
void ex_args(exarg_T *eap);
void ex_previous(exarg_T *eap);
void ex_rewind(exarg_T *eap);
void ex_last(exarg_T *eap);
void ex_argument(exarg_T *eap);
void do_argfile(exarg_T *eap, int argn);
void ex_next(exarg_T *eap);
void ex_argedit(exarg_T *eap);
void ex_argadd(exarg_T *eap);
void ex_argdelete(exarg_T *eap);
void ex_listdo(exarg_T *eap);
void ex_compiler(exarg_T *eap);
void ex_runtime(exarg_T *eap);
int source_runtime(char_u *name, int all);
int do_in_runtimepath(char_u *name, int all,
void (*callback)(char_u *fname, void *ck),
void *cookie);
void ex_options(exarg_T *eap);
void ex_source(exarg_T *eap);
linenr_T *source_breakpoint(void *cookie);
int *source_dbg_tick(void *cookie);
int source_level(void *cookie);
int do_source(char_u *fname, int check_other, int is_vimrc);
void ex_scriptnames(exarg_T *eap);
void scriptnames_slash_adjust(void);
char_u *get_scriptname(scid_T id);
void free_scriptnames(void);
char *fgets_cr(char *s, int n, FILE *stream);
char_u *getsourceline(int c, void *cookie, int indent);
void script_line_start(void);
void script_line_exec(void);
void script_line_end(void);
void ex_scriptencoding(exarg_T *eap);
void ex_finish(exarg_T *eap);
void do_finish(exarg_T *eap, int reanimate);
int source_finished(char_u *(*fgetline)(int, void *, int), void *cookie);
void ex_checktime(exarg_T *eap);
char_u *get_mess_lang(void);
void set_lang_var(void);
void ex_language(exarg_T *eap);
void free_locales(void);
char_u *get_lang_arg(expand_T *xp, int idx);
char_u *get_locales(expand_T *xp, int idx);
#endif /* NEOVIM_EX_CMDS2_H */

1191
src/nvim/ex_cmds_defs.h Normal file

File diff suppressed because it is too large Load Diff

9109
src/nvim/ex_docmd.c Normal file

File diff suppressed because it is too large Load Diff

69
src/nvim/ex_docmd.h Normal file
View File

@@ -0,0 +1,69 @@
#ifndef NEOVIM_EX_DOCMD_H
#define NEOVIM_EX_DOCMD_H
/* ex_docmd.c */
void do_exmode(int improved);
int do_cmdline_cmd(char_u *cmd);
int do_cmdline(char_u *cmdline, char_u *
(*fgetline)(int, void *, int), void *cookie,
int flags);
int getline_equal(char_u *
(*fgetline)(int, void *, int), void *cookie, char_u *
(*func)(int, void *, int));
void *getline_cookie(char_u *(*fgetline)(int, void *, int), void *cookie);
int checkforcmd(char_u **pp, char *cmd, int len);
int modifier_len(char_u *cmd);
int cmd_exists(char_u *name);
char_u *set_one_cmd_context(expand_T *xp, char_u *buff);
char_u *skip_range(char_u *cmd, int *ctx);
void ex_ni(exarg_T *eap);
int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp);
void separate_nextcmd(exarg_T *eap);
int ends_excmd(int c);
char_u *find_nextcmd(char_u *p);
char_u *check_nextcmd(char_u *p);
char_u *get_command_name(expand_T *xp, int idx);
void ex_comclear(exarg_T *eap);
void ex_may_print(exarg_T *eap);
void uc_clear(garray_T *gap);
char_u *get_user_commands(expand_T *xp, int idx);
char_u *get_user_cmd_flags(expand_T *xp, int idx);
char_u *get_user_cmd_nargs(expand_T *xp, int idx);
char_u *get_user_cmd_complete(expand_T *xp, int idx);
int parse_compl_arg(char_u *value, int vallen, int *complp, long *argt,
char_u **compl_arg);
void not_exiting(void);
void tabpage_close(int forceit);
void tabpage_close_other(tabpage_T *tp, int forceit);
void ex_all(exarg_T *eap);
void alist_clear(alist_T *al);
void alist_init(alist_T *al);
void alist_unlink(alist_T *al);
void alist_new(void);
void alist_expand(int *fnum_list, int fnum_len);
void alist_set(alist_T *al, int count, char_u **files, int use_curbuf,
int *fnum_list,
int fnum_len);
void alist_add(alist_T *al, char_u *fname, int set_fnum);
void alist_slash_adjust(void);
void ex_splitview(exarg_T *eap);
void tabpage_new(void);
void do_exedit(exarg_T *eap, win_T *old_curwin);
void free_cd_dir(void);
void post_chdir(int local);
void ex_cd(exarg_T *eap);
void do_sleep(long msec);
int vim_mkdir_emsg(char_u *name, int prot);
FILE *open_exfile(char_u *fname, int forceit, char *mode);
void update_topline_cursor(void);
void exec_normal_cmd(char_u *cmd, int remap, int silent);
int find_cmdline_var(char_u *src, int *usedlen);
char_u *eval_vars(char_u *src, char_u *srcstart, int *usedlen,
linenr_T *lnump, char_u **errormsg,
int *escaped);
char_u *expand_sfile(char_u *arg);
int put_eol(FILE *fd);
int put_line(FILE *fd, char *s);
void dialog_msg(char_u *buff, char *format, char_u *fname);
char_u *get_behave_arg(expand_T *xp, int idx);
#endif /* NEOVIM_EX_DOCMD_H */

2073
src/nvim/ex_eval.c Normal file

File diff suppressed because it is too large Load Diff

159
src/nvim/ex_eval.h Normal file
View File

@@ -0,0 +1,159 @@
#ifndef NEOVIM_EX_EVAL_H
#define NEOVIM_EX_EVAL_H
/*
* A list used for saving values of "emsg_silent". Used by ex_try() to save the
* value of "emsg_silent" if it was non-zero. When this is done, the CSF_SILENT
* flag below is set.
*/
typedef struct eslist_elem eslist_T;
struct eslist_elem {
int saved_emsg_silent; /* saved value of "emsg_silent" */
eslist_T *next; /* next element on the list */
};
/*
* For conditional commands a stack is kept of nested conditionals.
* When cs_idx < 0, there is no conditional command.
*/
#define CSTACK_LEN 50
struct condstack {
short cs_flags[CSTACK_LEN]; /* CSF_ flags */
char cs_pending[CSTACK_LEN]; /* CSTP_: what's pending in ":finally"*/
union {
void *csp_rv[CSTACK_LEN]; /* return typeval for pending return */
void *csp_ex[CSTACK_LEN]; /* exception for pending throw */
} cs_pend;
void *cs_forinfo[CSTACK_LEN]; /* info used by ":for" */
int cs_line[CSTACK_LEN]; /* line nr of ":while"/":for" line */
int cs_idx; /* current entry, or -1 if none */
int cs_looplevel; /* nr of nested ":while"s and ":for"s */
int cs_trylevel; /* nr of nested ":try"s */
eslist_T *cs_emsg_silent_list; /* saved values of "emsg_silent" */
char cs_lflags; /* loop flags: CSL_ flags */
};
# define cs_rettv cs_pend.csp_rv
# define cs_exception cs_pend.csp_ex
/* There is no CSF_IF, the lack of CSF_WHILE, CSF_FOR and CSF_TRY means ":if"
* was used. */
# define CSF_TRUE 0x0001 /* condition was TRUE */
# define CSF_ACTIVE 0x0002 /* current state is active */
# define CSF_ELSE 0x0004 /* ":else" has been passed */
# define CSF_WHILE 0x0008 /* is a ":while" */
# define CSF_FOR 0x0010 /* is a ":for" */
# define CSF_TRY 0x0100 /* is a ":try" */
# define CSF_FINALLY 0x0200 /* ":finally" has been passed */
# define CSF_THROWN 0x0400 /* exception thrown to this try conditional */
# define CSF_CAUGHT 0x0800 /* exception caught by this try conditional */
# define CSF_SILENT 0x1000 /* "emsg_silent" reset by ":try" */
/* Note that CSF_ELSE is only used when CSF_TRY and CSF_WHILE are unset
* (an ":if"), and CSF_SILENT is only used when CSF_TRY is set. */
/*
* What's pending for being reactivated at the ":endtry" of this try
* conditional:
*/
# define CSTP_NONE 0 /* nothing pending in ":finally" clause */
# define CSTP_ERROR 1 /* an error is pending */
# define CSTP_INTERRUPT 2 /* an interrupt is pending */
# define CSTP_THROW 4 /* a throw is pending */
# define CSTP_BREAK 8 /* ":break" is pending */
# define CSTP_CONTINUE 16 /* ":continue" is pending */
# define CSTP_RETURN 24 /* ":return" is pending */
# define CSTP_FINISH 32 /* ":finish" is pending */
/*
* Flags for the cs_lflags item in struct condstack.
*/
# define CSL_HAD_LOOP 1 /* just found ":while" or ":for" */
# define CSL_HAD_ENDLOOP 2 /* just found ":endwhile" or ":endfor" */
# define CSL_HAD_CONT 4 /* just found ":continue" */
# define CSL_HAD_FINA 8 /* just found ":finally" */
/*
* A list of error messages that can be converted to an exception. "throw_msg"
* is only set in the first element of the list. Usually, it points to the
* original message stored in that element, but sometimes it points to a later
* message in the list. See cause_errthrow() below.
*/
struct msglist {
char_u *msg; /* original message */
char_u *throw_msg; /* msg to throw: usually original one */
struct msglist *next; /* next of several messages in a row */
};
/*
* Structure describing an exception.
* (don't use "struct exception", it's used by the math library).
*/
typedef struct vim_exception except_T;
struct vim_exception {
int type; /* exception type */
char_u *value; /* exception value */
struct msglist *messages; /* message(s) causing error exception */
char_u *throw_name; /* name of the throw point */
linenr_T throw_lnum; /* line number of the throw point */
except_T *caught; /* next exception on the caught stack */
};
/*
* The exception types.
*/
#define ET_USER 0 /* exception caused by ":throw" command */
#define ET_ERROR 1 /* error exception */
#define ET_INTERRUPT 2 /* interrupt exception triggered by Ctrl-C */
/*
* Structure to save the error/interrupt/exception state between calls to
* enter_cleanup() and leave_cleanup(). Must be allocated as an automatic
* variable by the (common) caller of these functions.
*/
typedef struct cleanup_stuff cleanup_T;
struct cleanup_stuff {
int pending; /* error/interrupt/exception state */
except_T *exception; /* exception value */
};
/* ex_eval.c */
int aborting(void);
void update_force_abort(void);
int should_abort(int retcode);
int aborted_in_try(void);
int cause_errthrow(char_u *mesg, int severe, int *ignore);
void free_global_msglist(void);
void do_errthrow(struct condstack *cstack, char_u *cmdname);
int do_intthrow(struct condstack *cstack);
char_u *get_exception_string(void *value, int type, char_u *cmdname,
int *should_free);
void discard_current_exception(void);
void report_make_pending(int pending, void *value);
void report_resume_pending(int pending, void *value);
void report_discard_pending(int pending, void *value);
void ex_if(exarg_T *eap);
void ex_endif(exarg_T *eap);
void ex_else(exarg_T *eap);
void ex_while(exarg_T *eap);
void ex_continue(exarg_T *eap);
void ex_break(exarg_T *eap);
void ex_endwhile(exarg_T *eap);
void ex_throw(exarg_T *eap);
void do_throw(struct condstack *cstack);
void ex_try(exarg_T *eap);
void ex_catch(exarg_T *eap);
void ex_finally(exarg_T *eap);
void ex_endtry(exarg_T *eap);
void enter_cleanup(cleanup_T *csp);
void leave_cleanup(cleanup_T *csp);
int cleanup_conditionals(struct condstack *cstack, int searched_cond,
int inclusive);
void rewind_conditionals(struct condstack *cstack, int idx,
int cond_type,
int *cond_level);
void ex_endfunction(exarg_T *eap);
int has_loop_cmd(char_u *p);
#endif /* NEOVIM_EX_EVAL_H */

5443
src/nvim/ex_getln.c Normal file

File diff suppressed because it is too large Load Diff

66
src/nvim/ex_getln.h Normal file
View File

@@ -0,0 +1,66 @@
#ifndef NEOVIM_EX_GETLN_H
#define NEOVIM_EX_GETLN_H
/* ex_getln.c */
char_u *getcmdline(int firstc, long count, int indent);
char_u *getcmdline_prompt(int firstc, char_u *prompt, int attr,
int xp_context,
char_u *xp_arg);
int text_locked(void);
void text_locked_msg(void);
int curbuf_locked(void);
int allbuf_locked(void);
char_u *getexline(int c, void *cookie, int indent);
char_u *getexmodeline(int promptc, void *cookie, int indent);
void free_cmdline_buf(void);
void putcmdline(int c, int shift);
void unputcmdline(void);
int put_on_cmdline(char_u *str, int len, int redraw);
char_u *save_cmdline_alloc(void);
void restore_cmdline_alloc(char_u *p);
void cmdline_paste_str(char_u *s, int literally);
void redrawcmdline(void);
void redrawcmd(void);
void compute_cmdrow(void);
void gotocmdline(int clr);
char_u *ExpandOne(expand_T *xp, char_u *str, char_u *orig, int options,
int mode);
void ExpandInit(expand_T *xp);
void ExpandCleanup(expand_T *xp);
void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u *
*files,
int options);
char_u *vim_strsave_fnameescape(char_u *fname, int shell);
void tilde_replace(char_u *orig_pat, int num_files, char_u **files);
char_u *sm_gettail(char_u *s);
char_u *addstar(char_u *fname, int len, int context);
void set_cmd_context(expand_T *xp, char_u *str, int len, int col);
int expand_cmdline(expand_T *xp, char_u *str, int col, int *matchcount,
char_u ***matches);
int ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file,
char_u ***file, char_u *((*func)(expand_T *, int)),
int escaped);
char_u *globpath(char_u *path, char_u *file, int expand_options);
void init_history(void);
int get_histtype(char_u *name);
void add_to_history(int histype, char_u *new_entry, int in_map, int sep);
int get_history_idx(int histype);
char_u *get_cmdline_str(void);
int get_cmdline_pos(void);
int set_cmdline_pos(int pos);
int get_cmdline_type(void);
char_u *get_history_entry(int histype, int idx);
int clr_history(int histype);
int del_history_entry(int histype, char_u *str);
int del_history_idx(int histype, int idx);
void remove_key_from_history(void);
int get_list_range(char_u **str, int *num1, int *num2);
void ex_history(exarg_T *eap);
void prepare_viminfo_history(int asklen, int writing);
int read_viminfo_history(vir_T *virp, int writing);
void finish_viminfo_history(void);
void write_viminfo_history(FILE *fp, int merge);
void cmd_pchar(int c, int offset);
int cmd_gchar(int offset);
char_u *script_get(exarg_T *eap, char_u *cmd);
#endif /* NEOVIM_EX_GETLN_H */

2994
src/nvim/farsi.c Normal file

File diff suppressed because it is too large Load Diff

183
src/nvim/farsi.h Normal file
View File

@@ -0,0 +1,183 @@
/// @file farsi.h
///
/// Farsi characters are categorized into following types:
///
/// TyA (for capital letter representation)
/// TyB (for types that look like _X e.g. AYN)
/// TyC (for types that look like X_ e.g. YE_)
/// TyD (for types that look like _X_ e.g. _AYN_)
/// TyE (for types that look like X e.g. RE)
#ifndef NEOVIM_FARSI_H
#define NEOVIM_FARSI_H
#include "normal.h"
#include "types.h"
// Farsi character set definition
// Begin of the non-standard part
#define TEE_ 0x80
#define ALEF_U_H_ 0x81
#define ALEF_ 0x82
#define _BE 0x83
#define _PE 0x84
#define _TE 0x85
#define _SE 0x86
#define _JIM 0x87
#define _CHE 0x88
#define _HE_J 0x89
#define _XE 0x8a
#define _SIN 0x8b
#define _SHIN 0x8c
#define _SAD 0x8d
#define _ZAD 0x8e
#define _AYN 0x8f
#define _AYN_ 0x90
#define AYN_ 0x91
#define _GHAYN 0x92
#define _GHAYN_ 0x93
#define GHAYN_ 0x94
#define _FE 0x95
#define _GHAF 0x96
#define _KAF 0x97
#define _GAF 0x98
#define _LAM 0x99
#define LA 0x9a
#define _MIM 0x9b
#define _NOON 0x9c
#define _HE 0x9d
#define _HE_ 0x9e
#define _YE 0x9f
#define _IE 0xec
#define IE_ 0xed
#define IE 0xfb
#define _YEE 0xee
#define YEE_ 0xef
#define YE_ 0xff
// End of the non-standard part
// Standard part
#define F_BLANK 0xa0 // Farsi ' ' (SP) character
#define F_PSP 0xa1 // PSP for capitalizing of a character
#define F_PCN 0xa2 // PCN for redefining of the hamye meaning
#define F_EXCL 0xa3 // Farsi ! character
#define F_CURRENCY 0xa4 // Farsi Rial character
#define F_PERCENT 0xa5 // Farsi % character
#define F_PERIOD 0xa6 // Farsi '.' character
#define F_COMMA 0xa7 // Farsi ',' character
#define F_LPARENT 0xa8 // Farsi '(' character
#define F_RPARENT 0xa9 // Farsi ')' character
#define F_MUL 0xaa // Farsi 'x' character
#define F_PLUS 0xab // Farsi '+' character
#define F_BCOMMA 0xac // Farsi comma character
#define F_MINUS 0xad // Farsi '-' character
#define F_DIVIDE 0xae // Farsi divide (/) character
#define F_SLASH 0xaf // Farsi '/' character
#define FARSI_0 0xb0
#define FARSI_1 0xb1
#define FARSI_2 0xb2
#define FARSI_3 0xb3
#define FARSI_4 0xb4
#define FARSI_5 0xb5
#define FARSI_6 0xb6
#define FARSI_7 0xb7
#define FARSI_8 0xb8
#define FARSI_9 0xb9
#define F_DCOLON 0xba // Farsi ':' character
#define F_SEMICOLON 0xbb // Farsi ';' character
#define F_GREATER 0xbc // Farsi '>' character
#define F_EQUALS 0xbd // Farsi '=' character
#define F_LESS 0xbe // Farsi '<' character
#define F_QUESTION 0xbf // Farsi ? character
#define ALEF_A 0xc0
#define ALEF 0xc1
#define HAMZE 0xc2
#define BE 0xc3
#define PE 0xc4
#define TE 0xc5
#define SE 0xc6
#define JIM 0xc7
#define CHE 0xc8
#define HE_J 0xc9
#define XE 0xca
#define DAL 0xcb
#define ZAL 0xcc
#define RE 0xcd
#define ZE 0xce
#define JE 0xcf
#define SIN 0xd0
#define SHIN 0xd1
#define SAD 0xd2
#define ZAD 0xd3
#define _TA 0xd4
#define _ZA 0xd5
#define AYN 0xd6
#define GHAYN 0xd7
#define FE 0xd8
#define GHAF 0xd9
#define KAF 0xda
#define GAF 0xdb
#define LAM 0xdc
#define MIM 0xdd
#define NOON 0xde
#define WAW 0xdf
#define F_HE 0xe0 // F_ added for name clash with Perl
#define YE 0xe1
#define TEE 0xfc
#define _KAF_H 0xfd
#define YEE 0xfe
#define F_LBRACK 0xe2 // Farsi '[' character
#define F_RBRACK 0xe3 // Farsi ']' character
#define F_LBRACE 0xe4 // Farsi '{' character
#define F_RBRACE 0xe5 // Farsi '}' character
#define F_LQUOT 0xe6 // Farsi left quotation character
#define F_RQUOT 0xe7 // Farsi right quotation character
#define F_STAR 0xe8 // Farsi '*' character
#define F_UNDERLINE 0xe9 // Farsi '_' character
#define F_PIPE 0xea // Farsi '|' character
#define F_BSLASH 0xeb // Farsi '\' character
#define MAD 0xf0
#define JAZR 0xf1
#define OW 0xf2
#define MAD_N 0xf3
#define JAZR_N 0xf4
#define OW_OW 0xf5
#define TASH 0xf6
#define OO 0xf7
#define ALEF_U_H 0xf8
#define WAW_H 0xf9
#define ALEF_D_H 0xfa
// definitions for the window dependent functions (w_farsi).
#define W_CONV 0x1
#define W_R_L 0x2
// special Farsi text messages
extern const char_u farsi_text_1[];
extern const char_u farsi_text_2[];
extern const char_u farsi_text_3[];
extern const char_u farsi_text_5[];
int toF_TyA(int c);
int fkmap(int c);
void conv_to_pvim(void);
void conv_to_pstd(void);
char_u *lrswap(char_u *ibuf);
char_u *lrFswap(char_u *cmdbuf, int len);
char_u *lrF_sub(char_u *ibuf);
int cmdl_fkmap(int c);
int F_isalpha(int c);
int F_isdigit(int c);
int F_ischar(int c);
void farsi_fkey(cmdarg_T *cap);
#endif // NEOVIM_FARSI_H

1565
src/nvim/file_search.c Normal file

File diff suppressed because it is too large Load Diff

23
src/nvim/file_search.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef NEOVIM_FILE_SEARCH_H
#define NEOVIM_FILE_SEARCH_H
void *vim_findfile_init(char_u *path, char_u *filename, char_u *
stopdirs, int level, int free_visited,
int find_what, void *search_ctx_arg,
int tagfile,
char_u *rel_fname);
char_u *vim_findfile_stopdir(char_u *buf);
void vim_findfile_cleanup(void *ctx);
char_u *vim_findfile(void *search_ctx_arg);
void vim_findfile_free_visited(void *search_ctx_arg);
char_u *find_file_in_path(char_u *ptr, int len, int options, int first,
char_u *rel_fname);
void free_findfile(void);
char_u *find_directory_in_path(char_u *ptr, int len, int options,
char_u *rel_fname);
char_u *find_file_in_path_option(char_u *ptr, int len, int options,
int first, char_u *path_option,
int find_what, char_u *rel_fname,
char_u *suffixes);
#endif /* NEOVIM_FILE_SEARCH_H */

8148
src/nvim/fileio.c Normal file

File diff suppressed because it is too large Load Diff

94
src/nvim/fileio.h Normal file
View File

@@ -0,0 +1,94 @@
#ifndef NEOVIM_FILEIO_H
#define NEOVIM_FILEIO_H
#include "buffer_defs.h"
#include "os/os.h"
/*
* Struct to save values in before executing autocommands for a buffer that is
* not the current buffer. Without FEAT_AUTOCMD only "curbuf" is remembered.
*/
typedef struct {
buf_T *save_curbuf; /* saved curbuf */
int use_aucmd_win; /* using aucmd_win */
win_T *save_curwin; /* saved curwin */
win_T *new_curwin; /* new curwin */
buf_T *new_curbuf; /* new curbuf */
char_u *globaldir; /* saved value of globaldir */
} aco_save_T;
/* fileio.c */
void filemess(buf_T *buf, char_u *name, char_u *s, int attr);
int readfile(char_u *fname, char_u *sfname, linenr_T from,
linenr_T lines_to_skip, linenr_T lines_to_read, exarg_T *eap,
int flags);
void prep_exarg(exarg_T *eap, buf_T *buf);
void set_file_options(int set_options, exarg_T *eap);
void set_forced_fenc(exarg_T *eap);
int prepare_crypt_read(FILE *fp);
char_u *prepare_crypt_write(buf_T *buf, int *lenp);
int buf_write(buf_T *buf, char_u *fname, char_u *sfname, linenr_T start,
linenr_T end, exarg_T *eap, int append, int forceit,
int reset_changed,
int filtering);
void msg_add_fname(buf_T *buf, char_u *fname);
void msg_add_lines(int insert_space, long lnum, off_t nchars);
void shorten_fnames(int force);
char_u *modname(char_u *fname, char_u *ext, int prepend_dot);
int vim_fgets(char_u *buf, int size, FILE *fp);
int tag_fgets(char_u *buf, int size, FILE *fp);
int vim_rename(char_u *from, char_u *to);
int check_timestamps(int focus);
int buf_check_timestamp(buf_T *buf, int focus);
void buf_reload(buf_T *buf, int orig_mode);
void buf_store_file_info(buf_T *buf, FileInfo *file_info);
void write_lnum_adjust(linenr_T offset);
void vim_deltempdir(void);
char_u *vim_tempname(int extra_char);
void forward_slash(char_u *fname);
void aubuflocal_remove(buf_T *buf);
int au_has_group(char_u *name);
void do_augroup(char_u *arg, int del_group);
void free_all_autocmds(void);
int check_ei(void);
char_u *au_event_disable(char *what);
void au_event_restore(char_u *old_ei);
void do_autocmd(char_u *arg, int forceit);
int do_doautocmd(char_u *arg, int do_msg);
void ex_doautoall(exarg_T *eap);
int check_nomodeline(char_u **argp);
void aucmd_prepbuf(aco_save_T *aco, buf_T *buf);
void aucmd_restbuf(aco_save_T *aco);
int apply_autocmds(event_T event, char_u *fname, char_u *fname_io,
int force,
buf_T *buf);
int apply_autocmds_retval(event_T event, char_u *fname, char_u *fname_io,
int force, buf_T *buf,
int *retval);
int has_cursorhold(void);
int trigger_cursorhold(void);
int has_cursormoved(void);
int has_cursormovedI(void);
int has_textchanged(void);
int has_textchangedI(void);
int has_insertcharpre(void);
void block_autocmds(void);
void unblock_autocmds(void);
char_u *getnextac(int c, void *cookie, int indent);
int has_autocmd(event_T event, char_u *sfname, buf_T *buf);
char_u *get_augroup_name(expand_T *xp, int idx);
char_u *set_context_in_autocmd(expand_T *xp, char_u *arg, int doautocmd);
char_u *get_event_name(expand_T *xp, int idx);
int autocmd_supported(char_u *name);
int au_exists(char_u *arg);
int match_file_pat(char_u *pattern, regprog_T *prog, char_u *fname,
char_u *sfname, char_u *tail,
int allow_dirs);
int match_file_list(char_u *list, char_u *sfname, char_u *ffname);
char_u *file_pat_to_reg_pat(char_u *pat, char_u *pat_end,
char *allow_dirs,
int no_bslash);
long read_eintr(int fd, void *buf, size_t bufsize);
long write_eintr(int fd, void *buf, size_t bufsize);
#endif /* NEOVIM_FILEIO_H */

3033
src/nvim/fold.c Normal file

File diff suppressed because it is too large Load Diff

65
src/nvim/fold.h Normal file
View File

@@ -0,0 +1,65 @@
#ifndef NEOVIM_FOLD_H
#define NEOVIM_FOLD_H
/*
* Info used to pass info about a fold from the fold-detection code to the
* code that displays the foldcolumn.
*/
typedef struct foldinfo {
int fi_level; /* level of the fold; when this is zero the
other fields are invalid */
int fi_lnum; /* line number where fold starts */
int fi_low_level; /* lowest fold level that starts in the same
line */
} foldinfo_T;
void copyFoldingState(win_T *wp_from, win_T *wp_to);
int hasAnyFolding(win_T *win);
int hasFolding(linenr_T lnum, linenr_T *firstp, linenr_T *lastp);
int hasFoldingWin(win_T *win, linenr_T lnum, linenr_T *firstp,
linenr_T *lastp, int cache,
foldinfo_T *infop);
int foldLevel(linenr_T lnum);
int lineFolded(win_T *win, linenr_T lnum);
long foldedCount(win_T *win, linenr_T lnum, foldinfo_T *infop);
int foldmethodIsManual(win_T *wp);
int foldmethodIsIndent(win_T *wp);
int foldmethodIsExpr(win_T *wp);
int foldmethodIsMarker(win_T *wp);
int foldmethodIsSyntax(win_T *wp);
int foldmethodIsDiff(win_T *wp);
void closeFold(linenr_T lnum, long count);
void closeFoldRecurse(linenr_T lnum);
void opFoldRange(linenr_T first, linenr_T last, int opening,
int recurse,
int had_visual);
void openFold(linenr_T lnum, long count);
void openFoldRecurse(linenr_T lnum);
void foldOpenCursor(void);
void newFoldLevel(void);
void foldCheckClose(void);
int foldManualAllowed(int create);
void foldCreate(linenr_T start, linenr_T end);
void deleteFold(linenr_T start, linenr_T end, int recursive,
int had_visual);
void clearFolding(win_T *win);
void foldUpdate(win_T *wp, linenr_T top, linenr_T bot);
void foldUpdateAll(win_T *win);
int foldMoveTo(int updown, int dir, long count);
void foldInitWin(win_T *new_win);
int find_wl_entry(win_T *win, linenr_T lnum);
void foldAdjustVisual(void);
void foldAdjustCursor(void);
void cloneFoldGrowArray(garray_T *from, garray_T *to);
void deleteFoldRecurse(garray_T *gap);
void foldMarkAdjust(win_T *wp, linenr_T line1, linenr_T line2,
long amount,
long amount_after);
int getDeepestNesting(void);
char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume,
foldinfo_T *foldinfo,
char_u *buf);
void foldtext_cleanup(char_u *str);
int put_folds(FILE *fd, win_T *wp);
#endif /* NEOVIM_FOLD_H */

110
src/nvim/func_attr.h Normal file
View File

@@ -0,0 +1,110 @@
#ifndef NEOVIM_FUNC_ATTR_H
#define NEOVIM_FUNC_ATTR_H
// gcc and clang expose their version as follows:
//
// gcc 4.7.2:
// __GNUC__ = 4
// __GNUC_MINOR__ = 7
// __GNUC_PATCHLEVEL = 2
//
// clang 3.4 (claims compat with gcc 4.2.1):
// __GNUC__ = 4
// __GNUC_MINOR__ = 2
// __GNUC_PATCHLEVEL = 1
// __clang__ = 1
// __clang_major__ = 3
// __clang_minor__ = 4
//
// To view the default defines of these compilers, you can perform:
//
// $ gcc -E -dM - </dev/null
// $ echo | clang -dM -E -
#ifdef __GNUC__
// place defines for all gnulikes here, for now that's gcc, clang and
// intel.
// place these after the argument list of the function declaration
// (not definition), like so:
// void myfunc(void) FUNC_ATTR_ALWAYS_INLINE;
#define FUNC_ATTR_MALLOC __attribute__((malloc))
#define FUNC_ATTR_ALLOC_ALIGN(x) __attribute__((alloc_align(x)))
#define FUNC_ATTR_PURE __attribute__ ((pure))
#define FUNC_ATTR_CONST __attribute__((const))
#define FUNC_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#define FUNC_ATTR_ALWAYS_INLINE __attribute__((always_inline))
#define FUNC_ATTR_UNUSED __attribute__((unused))
#ifdef __clang__
// clang only
#elif defined(__INTEL_COMPILER)
// intel only
#else
#define GCC_VERSION \
(__GNUC__ * 10000 + \
__GNUC_MINOR__ * 100 + \
__GNUC_PATCHLEVEL__)
// gcc only
#define FUNC_ATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x)))
#define FUNC_ATTR_ALLOC_SIZE_PROD(x,y) __attribute__((alloc_size(x,y)))
#define FUNC_ATTR_NONNULL_ALL __attribute__((nonnull))
#define FUNC_ATTR_NONNULL_ARG(...) __attribute__((nonnull(__VA_ARGS__)))
#if GCC_VERSION >= 40900
#define FUNC_ATTR_NONNULL_RET __attribute__((returns_nonnull))
#endif
#endif
#endif
// define function attributes that haven't been defined for this specific
// compiler.
#ifndef FUNC_ATTR_MALLOC
#define FUNC_ATTR_MALLOC
#endif
#ifndef FUNC_ATTR_ALLOC_SIZE
#define FUNC_ATTR_ALLOC_SIZE(x)
#endif
#ifndef FUNC_ATTR_ALLOC_SIZE_PROD
#define FUNC_ATTR_ALLOC_SIZE_PROD(x,y)
#endif
#ifndef FUNC_ATTR_ALLOC_ALIGN
#define FUNC_ATTR_ALLOC_ALIGN(x)
#endif
#ifndef FUNC_ATTR_PURE
#define FUNC_ATTR_PURE
#endif
#ifndef FUNC_ATTR_CONST
#define FUNC_ATTR_CONST
#endif
#ifndef FUNC_ATTR_WARN_UNUSED_RESULT
#define FUNC_ATTR_WARN_UNUSED_RESULT
#endif
#ifndef FUNC_ATTR_ALWAYS_INLINE
#define FUNC_ATTR_ALWAYS_INLINE
#endif
#ifndef FUNC_ATTR_UNUSED
#define FUNC_ATTR_UNUSED
#endif
#ifndef FUNC_ATTR_NONNULL_ALL
#define FUNC_ATTR_NONNULL_ALL
#endif
#ifndef FUNC_ATTR_NONNULL_ARG
#define FUNC_ATTR_NONNULL_ARG(...)
#endif
#ifndef FUNC_ATTR_NONNULL_RET
#define FUNC_ATTR_NONNULL_RET
#endif
#endif // NEOVIM_FUNC_ATTR_H

197
src/nvim/garray.c Normal file
View File

@@ -0,0 +1,197 @@
/// @file garray.c
///
/// Functions for handling growing arrays.
#include <string.h>
#include "vim.h"
#include "ascii.h"
#include "misc2.h"
#include "memory.h"
#include "path.h"
#include "garray.h"
// #include "globals.h"
#include "memline.h"
/// Clear an allocated growing array.
void ga_clear(garray_T *gap)
{
free(gap->ga_data);
// Initialize growing array without resetting itemsize or growsize
gap->ga_data = NULL;
gap->ga_maxlen = 0;
gap->ga_len = 0;
}
/// Clear a growing array that contains a list of strings.
///
/// @param gap
void ga_clear_strings(garray_T *gap)
{
int i;
for (i = 0; i < gap->ga_len; ++i) {
free(((char_u **)(gap->ga_data))[i]);
}
ga_clear(gap);
}
/// Initialize a growing array.
///
/// @param gap
/// @param itemsize
/// @param growsize
void ga_init(garray_T *gap, int itemsize, int growsize)
{
gap->ga_data = NULL;
gap->ga_maxlen = 0;
gap->ga_len = 0;
gap->ga_itemsize = itemsize;
gap->ga_growsize = growsize;
}
/// Make room in growing array "gap" for at least "n" items.
///
/// @param gap
/// @param n
void ga_grow(garray_T *gap, int n)
{
if (gap->ga_maxlen - gap->ga_len >= n) {
// the garray still has enough space, do nothing
return;
}
// the garray grows by at least growsize (do we have a MIN macro somewhere?)
n = (n < gap->ga_growsize) ? gap->ga_growsize : n;
size_t new_size = (size_t)(gap->ga_itemsize * (gap->ga_len + n));
size_t old_size = (size_t)(gap->ga_itemsize * gap->ga_maxlen);
// reallocate and clear the new memory
char_u *pp = xrealloc(gap->ga_data, new_size);
memset(pp + old_size, 0, new_size - old_size);
gap->ga_maxlen = gap->ga_len + n;
gap->ga_data = pp;
}
/// Sort "gap" and remove duplicate entries. "gap" is expected to contain a
/// list of file names in allocated memory.
///
/// @param gap
void ga_remove_duplicate_strings(garray_T *gap)
{
char_u **fnames = gap->ga_data;
// sort the growing array, which puts duplicates next to each other
sort_strings(fnames, gap->ga_len);
// loop over the growing array in reverse
for (int i = gap->ga_len - 1; i > 0; i--) {
if (fnamecmp(fnames[i - 1], fnames[i]) == 0) {
free(fnames[i]);
// close the gap (move all strings one slot lower)
for (int j = i + 1; j < gap->ga_len; j++) {
fnames[j - 1] = fnames[j];
}
--gap->ga_len;
}
}
}
/// For a growing array that contains a list of strings: concatenate all the
/// strings with sep as separator.
///
/// @param gap
///
/// @returns the concatenated strings
char_u *ga_concat_strings_sep(const garray_T *gap, const char *sep)
{
const size_t nelem = (size_t) gap->ga_len;
const char **strings = gap->ga_data;
if (nelem == 0) {
return (char_u *) xstrdup("");
}
size_t len = 0;
for (size_t i = 0; i < nelem; i++) {
len += strlen(strings[i]);
}
// add some space for the (num - 1) separators
len += (nelem - 1) * strlen(sep);
char *const ret = xmallocz(len);
char *s = ret;
for (size_t i = 0; i < nelem - 1; i++) {
s = xstpcpy(s, strings[i]);
s = xstpcpy(s, sep);
}
s = xstpcpy(s, strings[nelem - 1]);
return (char_u *) ret;
}
/// For a growing array that contains a list of strings: concatenate all the
/// strings with a separating comma.
///
/// @param gap
///
/// @returns the concatenated strings
char_u* ga_concat_strings(const garray_T *gap)
{
return ga_concat_strings_sep(gap, ",");
}
/// Concatenate a string to a growarray which contains characters.
///
/// WARNING:
/// - Does NOT copy the NUL at the end!
/// - The parameter may not overlap with the growing array
///
/// @param gap
/// @param s
void ga_concat(garray_T *gap, const char_u *restrict s)
{
int len = (int)strlen((char *) s);
ga_grow(gap, len);
char *data = gap->ga_data;
memcpy(data + gap->ga_len, s, (size_t) len);
gap->ga_len += len;
}
/// Append one byte to a growarray which contains bytes.
///
/// @param gap
/// @param c
void ga_append(garray_T *gap, char c)
{
ga_grow(gap, 1);
char *str = gap->ga_data;
str[gap->ga_len] = c;
gap->ga_len++;
}
#if defined(UNIX) || defined(WIN3264)
/// Append the text in "gap" below the cursor line and clear "gap".
///
/// @param gap
void append_ga_line(garray_T *gap)
{
// Remove trailing CR.
if ((gap->ga_len > 0)
&& !curbuf->b_p_bin
&& (((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)) {
gap->ga_len--;
}
ga_append(gap, NUL);
ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
gap->ga_len = 0;
}
#endif // if defined(UNIX) || defined(WIN3264)

31
src/nvim/garray.h Normal file
View File

@@ -0,0 +1,31 @@
#ifndef NEOVIM_GARRAY_H
#define NEOVIM_GARRAY_H
#include "func_attr.h"
/// Structure used for growing arrays.
/// This is used to store information that only grows, is deleted all at
/// once, and needs to be accessed by index. See ga_clear() and ga_grow().
typedef struct growarray {
int ga_len; // current number of items used
int ga_maxlen; // maximum number of items possible
int ga_itemsize; // sizeof(item)
int ga_growsize; // number of items to grow each time
void *ga_data; // pointer to the first item
} garray_T;
#define GA_EMPTY { 0, 0, 0, 0, NULL }
void ga_clear(garray_T *gap);
void ga_clear_strings(garray_T *gap);
void ga_init(garray_T *gap, int itemsize, int growsize);
void ga_grow(garray_T *gap, int n);
char_u *ga_concat_strings_sep(const garray_T *gap, const char *sep)
FUNC_ATTR_NONNULL_RET;
char_u *ga_concat_strings(const garray_T *gap) FUNC_ATTR_NONNULL_RET;
void ga_remove_duplicate_strings(garray_T *gap);
void ga_concat(garray_T *gap, const char_u *restrict s);
void ga_append(garray_T *gap, char c);
void append_ga_line(garray_T *gap);
#endif // NEOVIM_GARRAY_H

4333
src/nvim/getchar.c Normal file

File diff suppressed because it is too large Load Diff

77
src/nvim/getchar.h Normal file
View File

@@ -0,0 +1,77 @@
#ifndef NEOVIM_GETCHAR_H
#define NEOVIM_GETCHAR_H
/* getchar.c */
void free_buff(buffheader_T *buf);
char_u *get_recorded(void);
char_u *get_inserted(void);
int stuff_empty(void);
int readbuf1_empty(void);
void typeahead_noflush(int c);
void flush_buffers(int flush_typeahead);
void ResetRedobuff(void);
void CancelRedo(void);
void saveRedobuff(void);
void restoreRedobuff(void);
void AppendToRedobuff(char_u *s);
void AppendToRedobuffLit(char_u *str, int len);
void AppendCharToRedobuff(int c);
void AppendNumberToRedobuff(long n);
void stuffReadbuff(char_u *s);
void stuffReadbuffLen(char_u *s, long len);
void stuffReadbuffSpec(char_u *s);
void stuffcharReadbuff(int c);
void stuffnumReadbuff(long n);
int start_redo(long count, int old_redo);
int start_redo_ins(void);
void stop_redo_ins(void);
int ins_typebuf(char_u *str, int noremap, int offset, int nottyped,
int silent);
void ins_char_typebuf(int c);
int typebuf_changed(int tb_change_cnt);
int typebuf_typed(void);
int typebuf_maplen(void);
void del_typebuf(int len, int offset);
int alloc_typebuf(void);
void free_typebuf(void);
int save_typebuf(void);
void save_typeahead(tasave_T *tp);
void restore_typeahead(tasave_T *tp);
void openscript(char_u *name, int directly);
void close_all_scripts(void);
int using_script(void);
void before_blocking(void);
void updatescript(int c);
int vgetc(void);
int safe_vgetc(void);
int plain_vgetc(void);
int vpeekc(void);
int vpeekc_nomap(void);
int vpeekc_any(void);
int char_avail(void);
void vungetc(int c);
int inchar(char_u *buf, int maxlen, long wait_time, int tb_change_cnt);
int fix_input_buffer(char_u *buf, int len, int script);
int input_available(void);
int do_map(int maptype, char_u *arg, int mode, int abbrev);
int get_map_mode(char_u **cmdp, int forceit);
void map_clear(char_u *cmdp, char_u *arg, int forceit, int abbr);
void map_clear_int(buf_T *buf, int mode, int local, int abbr);
char_u *map_mode_to_chars(int mode);
int map_to_exists(char_u *str, char_u *modechars, int abbr);
int map_to_exists_mode(char_u *rhs, int mode, int abbr);
char_u *set_context_in_map_cmd(expand_T *xp, char_u *cmd, char_u *arg,
int forceit, int isabbrev, int isunmap,
cmdidx_T cmdidx);
int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file);
int check_abbr(int c, char_u *ptr, int col, int mincol);
char_u *vim_strsave_escape_csi(char_u *p);
void vim_unescape_csi(char_u *p);
int makemap(FILE *fd, buf_T *buf);
int put_escstr(FILE *fd, char_u *strstart, int what);
void check_map_keycodes(void);
char_u *check_map(char_u *keys, int mode, int exact, int ign_mod,
int abbr, mapblock_T **mp_ptr,
int *local_ptr);
void add_map(char_u *map, int mode);
#endif /* NEOVIM_GETCHAR_H */

1140
src/nvim/globals.h Normal file

File diff suppressed because it is too large Load Diff

3175
src/nvim/hardcopy.c Normal file

File diff suppressed because it is too large Load Diff

93
src/nvim/hardcopy.h Normal file
View File

@@ -0,0 +1,93 @@
#ifndef NEOVIM_HARDCOPY_H
#define NEOVIM_HARDCOPY_H
/*
* Structure to hold printing color and font attributes.
*/
typedef struct {
long_u fg_color;
long_u bg_color;
int bold;
int italic;
int underline;
int undercurl;
} prt_text_attr_T;
/*
* Structure passed back to the generic printer code.
*/
typedef struct {
int n_collated_copies;
int n_uncollated_copies;
int duplex;
int chars_per_line;
int lines_per_page;
int has_color;
prt_text_attr_T number;
int modec;
int do_syntax;
int user_abort;
char_u *jobname;
char_u *outfile;
char_u *arguments;
} prt_settings_T;
/*
* Generic option table item, only used for printer at the moment.
*/
typedef struct {
const char *name;
int hasnum;
long number;
char_u *string; /* points into option string */
int strlen;
int present;
} option_table_T;
#define OPT_PRINT_TOP 0
#define OPT_PRINT_BOT 1
#define OPT_PRINT_LEFT 2
#define OPT_PRINT_RIGHT 3
#define OPT_PRINT_HEADERHEIGHT 4
#define OPT_PRINT_SYNTAX 5
#define OPT_PRINT_NUMBER 6
#define OPT_PRINT_WRAP 7
#define OPT_PRINT_DUPLEX 8
#define OPT_PRINT_PORTRAIT 9
#define OPT_PRINT_PAPER 10
#define OPT_PRINT_COLLATE 11
#define OPT_PRINT_JOBSPLIT 12
#define OPT_PRINT_FORMFEED 13
#define OPT_PRINT_NUM_OPTIONS 14
/* For prt_get_unit(). */
#define PRT_UNIT_NONE -1
#define PRT_UNIT_PERC 0
#define PRT_UNIT_INCH 1
#define PRT_UNIT_MM 2
#define PRT_UNIT_POINT 3
#define PRT_UNIT_NAMES {"pc", "in", "mm", "pt"}
#define PRINT_NUMBER_WIDTH 8
char_u *parse_printoptions(void);
char_u *parse_printmbfont(void);
int prt_header_height(void);
int prt_use_number(void);
int prt_get_unit(int idx);
void ex_hardcopy(exarg_T *eap);
void mch_print_cleanup(void);
int mch_print_init(prt_settings_T *psettings, char_u *jobname,
int forceit);
int mch_print_begin(prt_settings_T *psettings);
void mch_print_end(prt_settings_T *psettings);
int mch_print_end_page(void);
int mch_print_begin_page(char_u *str);
int mch_print_blank_page(void);
void mch_print_start_line(int margin, int page_line);
int mch_print_text_out(char_u *p, int len);
void mch_print_set_font(int iBold, int iItalic, int iUnderline);
void mch_print_set_bg(long_u bgcol);
void mch_print_set_fg(long_u fgcol);
#endif /* NEOVIM_HARDCOPY_H */

431
src/nvim/hashtab.c Normal file
View File

@@ -0,0 +1,431 @@
/// @file hashtab.c
///
/// Handling of a hashtable with Vim-specific properties.
///
/// Each item in a hashtable has a NUL terminated string key. A key can appear
/// only once in the table.
///
/// A hash number is computed from the key for quick lookup. When the hashes
/// of two different keys point to the same entry an algorithm is used to
/// iterate over other entries in the table until the right one is found.
/// To make the iteration work removed keys are different from entries where a
/// key was never present.
///
/// The mechanism has been partly based on how Python Dictionaries are
/// implemented. The algorithm is from Knuth Vol. 3, Sec. 6.4.
///
/// The hashtable grows to accommodate more entries when needed. At least 1/3
/// of the entries is empty to keep the lookup efficient (at the cost of extra
/// memory).
#include <string.h>
#include "vim.h"
#include "hashtab.h"
#include "message.h"
#include "memory.h"
#include "misc2.h"
// Magic value for algorithm that walks through the array.
#define PERTURB_SHIFT 5
static int hash_may_resize(hashtab_T *ht, int minitems);
/// Initialize an empty hash table.
///
/// @param ht
void hash_init(hashtab_T *ht)
{
// This zeroes all "ht_" entries and all the "hi_key" in "ht_smallarray".
memset(ht, 0, sizeof(hashtab_T));
ht->ht_array = ht->ht_smallarray;
ht->ht_mask = HT_INIT_SIZE - 1;
}
/// Free the array of a hash table. Does not free the items it contains!
/// If "ht" is not freed then you should call hash_init() next!
///
/// @param ht
void hash_clear(hashtab_T *ht)
{
if (ht->ht_array != ht->ht_smallarray) {
free(ht->ht_array);
}
}
/// Free the array of a hash table and all the keys it contains. The keys must
/// have been allocated. "off" is the offset from the start of the allocate
/// memory to the location of the key (it's always positive).
///
/// @param ht
/// @param off
void hash_clear_all(hashtab_T *ht, int off)
{
long todo;
hashitem_T *hi;
todo = (long)ht->ht_used;
for (hi = ht->ht_array; todo > 0; ++hi) {
if (!HASHITEM_EMPTY(hi)) {
free(hi->hi_key - off);
todo--;
}
}
hash_clear(ht);
}
/// Find "key" in hashtable "ht". "key" must not be NULL.
/// Always returns a pointer to a hashitem. If the item was not found then
/// HASHITEM_EMPTY() is TRUE. The pointer is then the place where the key
/// would be added.
/// WARNING: The returned pointer becomes invalid when the hashtable is changed
/// (adding, setting or removing an item)!
///
/// @param ht
/// @param key
///
/// @return Pointer to the hashitem stored with the given key.
hashitem_T* hash_find(hashtab_T *ht, char_u *key)
{
return hash_lookup(ht, key, hash_hash(key));
}
/// Like hash_find(), but caller computes "hash".
///
/// @param ht
/// @param key
/// @param hash
///
/// @return Pointer to the hashitem stored with the given key.
hashitem_T* hash_lookup(hashtab_T *ht, char_u *key, hash_T hash)
{
hash_T perturb;
hashitem_T *freeitem;
hashitem_T *hi;
unsigned idx;
#ifdef HT_DEBUG
hash_count_lookup++;
#endif // ifdef HT_DEBUG
// Quickly handle the most common situations:
// - return if there is no item at all
// - skip over a removed item
// - return if the item matches
idx = (unsigned)(hash & ht->ht_mask);
hi = &ht->ht_array[idx];
if (hi->hi_key == NULL) {
return hi;
}
if (hi->hi_key == HI_KEY_REMOVED) {
freeitem = hi;
} else if ((hi->hi_hash == hash) && (STRCMP(hi->hi_key, key) == 0)) {
return hi;
} else {
freeitem = NULL;
}
// Need to search through the table to find the key. The algorithm
// to step through the table starts with large steps, gradually becoming
// smaller down to (1/4 table size + 1). This means it goes through all
// table entries in the end.
// When we run into a NULL key it's clear that the key isn't there.
// Return the first available slot found (can be a slot of a removed
// item).
for (perturb = hash;; perturb >>= PERTURB_SHIFT) {
#ifdef HT_DEBUG
// count a "miss" for hashtab lookup
hash_count_perturb++;
#endif // ifdef HT_DEBUG
idx = 5 * idx + perturb + 1;
hi = &ht->ht_array[idx & ht->ht_mask];
if (hi->hi_key == NULL) {
return freeitem == NULL ? hi : freeitem;
}
if ((hi->hi_hash == hash)
&& (hi->hi_key != HI_KEY_REMOVED)
&& (STRCMP(hi->hi_key, key) == 0)) {
return hi;
}
if ((hi->hi_key == HI_KEY_REMOVED) && (freeitem == NULL)) {
freeitem = hi;
}
}
}
/// Print the efficiency of hashtable lookups.
/// Useful when trying different hash algorithms.
/// Called when exiting.
void hash_debug_results(void)
{
#ifdef HT_DEBUG
fprintf(stderr, "\r\n\r\n\r\n\r\n");
fprintf(stderr, "Number of hashtable lookups: %" PRId64 "\r\n",
(int64_t)hash_count_lookup);
fprintf(stderr, "Number of perturb loops: %" PRId64 "\r\n",
(int64_t)hash_count_perturb);
fprintf(stderr, "Percentage of perturb loops: %" PRId64 "%%\r\n",
(int64_t)(hash_count_perturb * 100 / hash_count_lookup));
#endif // ifdef HT_DEBUG
}
/// Add item with key "key" to hashtable "ht".
///
/// @param ht
/// @param key
///
/// @returns FAIL when out of memory or the key is already present.
int hash_add(hashtab_T *ht, char_u *key)
{
hash_T hash = hash_hash(key);
hashitem_T *hi = hash_lookup(ht, key, hash);
if (!HASHITEM_EMPTY(hi)) {
EMSG2(_(e_intern2), "hash_add()");
return FAIL;
}
return hash_add_item(ht, hi, key, hash);
}
/// Add item "hi" with "key" to hashtable "ht". "key" must not be NULL and
/// "hi" must have been obtained with hash_lookup() and point to an empty item.
/// "hi" is invalid after this!
///
/// @param ht
/// @param hi
/// @param key
/// @param hash
///
/// @returns OK or FAIL (out of memory).
int hash_add_item(hashtab_T *ht, hashitem_T *hi, char_u *key, hash_T hash)
{
// If resizing failed before and it fails again we can't add an item.
if (ht->ht_error && (hash_may_resize(ht, 0) == FAIL)) {
return FAIL;
}
ht->ht_used++;
if (hi->hi_key == NULL) {
ht->ht_filled++;
}
hi->hi_key = key;
hi->hi_hash = hash;
// When the space gets low may resize the array.
return hash_may_resize(ht, 0);
}
/// Remove item "hi" from hashtable "ht". "hi" must have been obtained with
/// hash_lookup().
///
/// The caller must take care of freeing the item itself.
///
/// @param ht
/// @param hi
void hash_remove(hashtab_T *ht, hashitem_T *hi)
{
ht->ht_used--;
hi->hi_key = HI_KEY_REMOVED;
hash_may_resize(ht, 0);
}
/// Lock a hashtable: prevent that ht_array changes.
/// Don't use this when items are to be added!
/// Must call hash_unlock() later.
///
/// @param ht
void hash_lock(hashtab_T *ht)
{
ht->ht_locked++;
}
/// Unlock a hashtable: allow ht_array changes again.
/// Table will be resized (shrink) when necessary.
/// This must balance a call to hash_lock().
void hash_unlock(hashtab_T *ht)
{
ht->ht_locked--;
(void)hash_may_resize(ht, 0);
}
/// Shrink a hashtable when there is too much empty space.
/// Grow a hashtable when there is not enough empty space.
///
/// @param ht
/// @param minitems minimal number of items
///
/// @returns OK or FAIL (out of memory).
static int hash_may_resize(hashtab_T *ht, int minitems)
{
hashitem_T temparray[HT_INIT_SIZE];
hashitem_T *oldarray, *newarray;
hashitem_T *olditem, *newitem;
unsigned newi;
int todo;
long_u oldsize, newsize;
long_u minsize;
long_u newmask;
hash_T perturb;
// Don't resize a locked table.
if (ht->ht_locked > 0) {
return OK;
}
#ifdef HT_DEBUG
if (ht->ht_used > ht->ht_filled) {
EMSG("hash_may_resize(): more used than filled");
}
if (ht->ht_filled >= ht->ht_mask + 1) {
EMSG("hash_may_resize(): table completely filled");
}
#endif // ifdef HT_DEBUG
if (minitems == 0) {
// Return quickly for small tables with at least two NULL items. NULL
// items are required for the lookup to decide a key isn't there.
if ((ht->ht_filled < HT_INIT_SIZE - 1)
&& (ht->ht_array == ht->ht_smallarray)) {
return OK;
}
// Grow or refill the array when it's more than 2/3 full (including
// removed items, so that they get cleaned up).
// Shrink the array when it's less than 1/5 full. When growing it is
// at least 1/4 full (avoids repeated grow-shrink operations)
oldsize = ht->ht_mask + 1;
if ((ht->ht_filled * 3 < oldsize * 2) && (ht->ht_used > oldsize / 5)) {
return OK;
}
if (ht->ht_used > 1000) {
// it's big, don't make too much room
minsize = ht->ht_used * 2;
} else {
// make plenty of room
minsize = ht->ht_used * 4;
}
} else {
// Use specified size.
if ((long_u)minitems < ht->ht_used) {
// just in case...
minitems = (int)ht->ht_used;
}
// array is up to 2/3 full
minsize = minitems * 3 / 2;
}
newsize = HT_INIT_SIZE;
while (newsize < minsize) {
// make sure it's always a power of 2
newsize <<= 1;
if (newsize == 0) {
// overflow
return FAIL;
}
}
if (newsize == HT_INIT_SIZE) {
// Use the small array inside the hashdict structure.
newarray = ht->ht_smallarray;
if (ht->ht_array == newarray) {
// Moving from ht_smallarray to ht_smallarray! Happens when there
// are many removed items. Copy the items to be able to clean up
// removed items.
memmove(temparray, newarray, sizeof(temparray));
oldarray = temparray;
} else {
oldarray = ht->ht_array;
}
} else {
// Allocate an array.
newarray = (hashitem_T *)alloc((unsigned)(sizeof(hashitem_T) * newsize));
if (newarray == NULL) {
// Out of memory. When there are NULL items still return OK.
// Otherwise set ht_error, because lookup may result in a hang if
// we add another item.
if (ht->ht_filled < ht->ht_mask) {
return OK;
}
ht->ht_error = TRUE;
return FAIL;
}
oldarray = ht->ht_array;
}
memset(newarray, 0, (size_t)(sizeof(hashitem_T) * newsize));
// Move all the items from the old array to the new one, placing them in
// the right spot. The new array won't have any removed items, thus this
// is also a cleanup action.
newmask = newsize - 1;
todo = (int)ht->ht_used;
for (olditem = oldarray; todo > 0; ++olditem) {
if (!HASHITEM_EMPTY(olditem)) {
// The algorithm to find the spot to add the item is identical to
// the algorithm to find an item in hash_lookup(). But we only
// need to search for a NULL key, thus it's simpler.
newi = (unsigned)(olditem->hi_hash & newmask);
newitem = &newarray[newi];
if (newitem->hi_key != NULL) {
for (perturb = olditem->hi_hash;; perturb >>= PERTURB_SHIFT) {
newi = 5 * newi + perturb + 1;
newitem = &newarray[newi & newmask];
if (newitem->hi_key == NULL) {
break;
}
}
}
*newitem = *olditem;
todo--;
}
}
if (ht->ht_array != ht->ht_smallarray) {
free(ht->ht_array);
}
ht->ht_array = newarray;
ht->ht_mask = newmask;
ht->ht_filled = ht->ht_used;
ht->ht_error = FALSE;
return OK;
}
/// Get the hash number for a key.
/// If you think you know a better hash function: Compile with HT_DEBUG set and
/// run a script that uses hashtables a lot. Vim will then print statistics
/// when exiting. Try that with the current hash algorithm and yours. The
/// lower the percentage the better.
///
/// @param key
///
/// @return Hash number for the key.
hash_T hash_hash(char_u *key)
{
hash_T hash;
char_u *p;
if ((hash = *key) == 0) {
// Empty keys are not allowed, but we don't want to crash if we get one.
return (hash_T) 0;
}
p = key + 1;
// A simplistic algorithm that appears to do very well.
// Suggested by George Reilly.
while (*p != NUL) {
hash = hash * 101 + *p++;
}
return hash;
}

56
src/nvim/hashtab.h Normal file
View File

@@ -0,0 +1,56 @@
#ifndef NEOVIM_HASHTAB_H
#define NEOVIM_HASHTAB_H
/* Item for a hashtable. "hi_key" can be one of three values:
* NULL: Never been used
* HI_KEY_REMOVED: Entry was removed
* Otherwise: Used item, pointer to the actual key; this usually is
* inside the item, subtract an offset to locate the item.
* This reduces the size of hashitem by 1/3.
*/
typedef struct hashitem_S {
long_u hi_hash; /* cached hash number of hi_key */
char_u *hi_key;
} hashitem_T;
/* The address of "hash_removed" is used as a magic number for hi_key to
* indicate a removed item. */
#define HI_KEY_REMOVED &hash_removed
#define HASHITEM_EMPTY(hi) ((hi)->hi_key == NULL || (hi)->hi_key == \
&hash_removed)
/* Initial size for a hashtable. Our items are relatively small and growing
* is expensive, thus use 16 as a start. Must be a power of 2. */
#define HT_INIT_SIZE 16
typedef struct hashtable_S {
long_u ht_mask; /* mask used for hash value (nr of items in
* array is "ht_mask" + 1) */
long_u ht_used; /* number of items used */
long_u ht_filled; /* number of items used + removed */
int ht_locked; /* counter for hash_lock() */
int ht_error; /* when set growing failed, can't add more
items before growing works */
hashitem_T *ht_array; /* points to the array, allocated when it's
not "ht_smallarray" */
hashitem_T ht_smallarray[HT_INIT_SIZE]; /* initial array */
} hashtab_T;
typedef long_u hash_T; /* Type for hi_hash */
/* hashtab.c */
void hash_init(hashtab_T *ht);
void hash_clear(hashtab_T *ht);
void hash_clear_all(hashtab_T *ht, int off);
hashitem_T *hash_find(hashtab_T *ht, char_u *key);
hashitem_T *hash_lookup(hashtab_T *ht, char_u *key, hash_T hash);
void hash_debug_results(void);
int hash_add(hashtab_T *ht, char_u *key);
int hash_add_item(hashtab_T *ht, hashitem_T *hi, char_u *key,
hash_T hash);
void hash_remove(hashtab_T *ht, hashitem_T *hi);
void hash_lock(hashtab_T *ht);
void hash_unlock(hashtab_T *ht);
hash_T hash_hash(char_u *key);
#endif /* NEOVIM_HASHTAB_H */

2167
src/nvim/if_cscope.c Normal file

File diff suppressed because it is too large Load Diff

16
src/nvim/if_cscope.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef NEOVIM_IF_CSCOPE_H
#define NEOVIM_IF_CSCOPE_H
/* if_cscope.c */
char_u *get_cscope_name(expand_T *xp, int idx);
void set_context_in_cscope_cmd(expand_T *xp, char_u *arg,
cmdidx_T cmdidx);
void do_cscope(exarg_T *eap);
void do_scscope(exarg_T *eap);
void do_cstag(exarg_T *eap);
int cs_fgets(char_u *buf, int size);
void cs_free_tags(void);
void cs_print_tags(void);
int cs_connection(int num, char_u *dbpath, char_u *ppath);
void cs_end(void);
#endif /* NEOVIM_IF_CSCOPE_H */

71
src/nvim/if_cscope_defs.h Normal file
View File

@@ -0,0 +1,71 @@
#ifndef NEOVIM_IF_CSCOPE_DEFS_H
#define NEOVIM_IF_CSCOPE_DEFS_H
/*
* CSCOPE support for Vim added by Andy Kahn <kahn@zk3.dec.com>
* Ported to Win32 by Sergey Khorev <sergey.khorev@gmail.com>
*
* The basic idea/structure of cscope for Vim was borrowed from Nvi.
* There might be a few lines of code that look similar to what Nvi
* has. If this is a problem and requires inclusion of the annoying
* BSD license, then sue me; I'm not worth much anyway.
*/
#if defined(UNIX)
# include <sys/types.h> /* pid_t */
# include <sys/stat.h> /* dev_t, ino_t */
#else
#endif
#define CSCOPE_SUCCESS 0
#define CSCOPE_FAILURE -1
#define CSCOPE_DBFILE "cscope.out"
#define CSCOPE_PROMPT ">> "
/*
* s 0name Find this C symbol
* g 1name Find this definition
* d 2name Find functions called by this function
* c 3name Find functions calling this function
* t 4string find text string (cscope 12.9)
* t 4name Find assignments to (cscope 13.3)
* 5pattern change pattern -- NOT USED
* e 6pattern Find this egrep pattern
* f 7name Find this file
* i 8name Find files #including this file
*/
typedef struct {
char * name;
int (*func)(exarg_T *eap);
char * help;
char * usage;
int cansplit; /* if supports splitting window */
} cscmd_T;
typedef struct csi {
char * fname; /* cscope db name */
char * ppath; /* path to prepend (the -P option) */
char * flags; /* additional cscope flags/options (e.g, -p2) */
#if defined(UNIX)
pid_t pid; /* PID of the connected cscope process. */
#endif
uint64_t st_dev; /* ID of dev containing cscope db */
uint64_t st_ino; /* inode number of cscope db */
FILE * fr_fp; /* from cscope: FILE. */
FILE * to_fp; /* to cscope: FILE. */
} csinfo_T;
typedef enum { Add, Find, Help, Kill, Reset, Show } csid_e;
typedef enum {
Store,
Get,
Free,
Print
} mcmd_e;
#endif // NEOVIM_IF_CSCOPE_DEFS_H

696
src/nvim/indent.c Normal file
View File

@@ -0,0 +1,696 @@
#include "indent.h"
#include "eval.h"
#include "charset.h"
#include "memline.h"
#include "memory.h"
#include "misc1.h"
#include "misc2.h"
#include "option.h"
#include "regexp.h"
#include "search.h"
#include "undo.h"
static int lisp_match(char_u *p);
// Count the size (in window cells) of the indent in the current line.
int get_indent(void)
{
return get_indent_str(ml_get_curline(), (int)curbuf->b_p_ts);
}
// Count the size (in window cells) of the indent in line "lnum".
int get_indent_lnum(linenr_T lnum)
{
return get_indent_str(ml_get(lnum), (int)curbuf->b_p_ts);
}
// Count the size (in window cells) of the indent in line "lnum" of buffer
// "buf".
int get_indent_buf(buf_T *buf, linenr_T lnum)
{
return get_indent_str(ml_get_buf(buf, lnum, false), (int)buf->b_p_ts);
}
// Count the size (in window cells) of the indent in line "ptr", with
// 'tabstop' at "ts".
int get_indent_str(char_u *ptr, int ts)
{
int count = 0;
for (; *ptr; ++ptr) {
// Count a tab for what it is worth.
if (*ptr == TAB) {
count += ts - (count % ts);
} else if (*ptr == ' ') {
// Count a space for one.
count++;
} else {
break;
}
}
return count;
}
// Set the indent of the current line.
// Leaves the cursor on the first non-blank in the line.
// Caller must take care of undo.
// "flags":
// SIN_CHANGED: call changed_bytes() if the line was changed.
// SIN_INSERT: insert the indent in front of the line.
// SIN_UNDO: save line for undo before changing it.
// @param size measured in spaces
// Returns true if the line was changed.
int set_indent(int size, int flags)
{
char_u *p;
char_u *newline;
char_u *oldline;
char_u *s;
int todo;
int ind_len; // Measured in characters.
int line_len;
int doit = false;
int ind_done = 0; // Measured in spaces.
int tab_pad;
int retval = false;
// Number of initial whitespace chars when 'et' and 'pi' are both set.
int orig_char_len = -1;
// First check if there is anything to do and compute the number of
// characters needed for the indent.
todo = size;
ind_len = 0;
p = oldline = ml_get_curline();
// Calculate the buffer size for the new indent, and check to see if it
// isn't already set.
// If 'expandtab' isn't set: use TABs; if both 'expandtab' and
// 'preserveindent' are set count the number of characters at the
// beginning of the line to be copied.
if (!curbuf->b_p_et || (!(flags & SIN_INSERT) && curbuf->b_p_pi)) {
// If 'preserveindent' is set then reuse as much as possible of
// the existing indent structure for the new indent.
if (!(flags & SIN_INSERT) && curbuf->b_p_pi) {
ind_done = 0;
// Count as many characters as we can use.
while (todo > 0 && vim_iswhite(*p)) {
if (*p == TAB) {
tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
// Stop if this tab will overshoot the target.
if (todo < tab_pad) {
break;
}
todo -= tab_pad;
ind_len++;
ind_done += tab_pad;
} else {
todo--;
ind_len++;
ind_done++;
}
p++;
}
// Set initial number of whitespace chars to copy if we are
// preserving indent but expandtab is set.
if (curbuf->b_p_et) {
orig_char_len = ind_len;
}
// Fill to next tabstop with a tab, if possible.
tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
if ((todo >= tab_pad) && (orig_char_len == -1)) {
doit = true;
todo -= tab_pad;
ind_len++;
// ind_done += tab_pad;
}
}
// Count tabs required for indent.
while (todo >= (int)curbuf->b_p_ts) {
if (*p != TAB) {
doit = true;
} else {
p++;
}
todo -= (int)curbuf->b_p_ts;
ind_len++;
// ind_done += (int)curbuf->b_p_ts;
}
}
// Count spaces required for indent.
while (todo > 0) {
if (*p != ' ') {
doit = true;
} else {
p++;
}
todo--;
ind_len++;
// ind_done++;
}
// Return if the indent is OK already.
if (!doit && !vim_iswhite(*p) && !(flags & SIN_INSERT)) {
return false;
}
// Allocate memory for the new line.
if (flags & SIN_INSERT) {
p = oldline;
} else {
p = skipwhite(p);
}
line_len = (int)STRLEN(p) + 1;
// If 'preserveindent' and 'expandtab' are both set keep the original
// characters and allocate accordingly. We will fill the rest with spaces
// after the if (!curbuf->b_p_et) below.
if (orig_char_len != -1) {
newline = alloc(orig_char_len + size - ind_done + line_len);
todo = size - ind_done;
// Set total length of indent in characters, which may have been
// undercounted until now.
ind_len = orig_char_len + todo;
p = oldline;
s = newline;
while (orig_char_len > 0) {
*s++ = *p++;
orig_char_len--;
}
// Skip over any additional white space (useful when newindent is less
// than old).
while (vim_iswhite(*p)) {
p++;
}
} else {
todo = size;
newline = alloc(ind_len + line_len);
s = newline;
}
// Put the characters in the new line.
// if 'expandtab' isn't set: use TABs
if (!curbuf->b_p_et) {
// If 'preserveindent' is set then reuse as much as possible of
// the existing indent structure for the new indent.
if (!(flags & SIN_INSERT) && curbuf->b_p_pi) {
p = oldline;
ind_done = 0;
while (todo > 0 && vim_iswhite(*p)) {
if (*p == TAB) {
tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
// Stop if this tab will overshoot the target.
if (todo < tab_pad) {
break;
}
todo -= tab_pad;
ind_done += tab_pad;
} else {
todo--;
ind_done++;
}
*s++ = *p++;
}
// Fill to next tabstop with a tab, if possible.
tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
if (todo >= tab_pad) {
*s++ = TAB;
todo -= tab_pad;
}
p = skipwhite(p);
}
while (todo >= (int)curbuf->b_p_ts) {
*s++ = TAB;
todo -= (int)curbuf->b_p_ts;
}
}
while (todo > 0) {
*s++ = ' ';
todo--;
}
memmove(s, p, (size_t)line_len);
// Replace the line (unless undo fails).
if (!(flags & SIN_UNDO) || (u_savesub(curwin->w_cursor.lnum) == OK)) {
ml_replace(curwin->w_cursor.lnum, newline, false);
if (flags & SIN_CHANGED) {
changed_bytes(curwin->w_cursor.lnum, 0);
}
// Correct saved cursor position if it is in this line.
if (saved_cursor.lnum == curwin->w_cursor.lnum) {
if (saved_cursor.col >= (colnr_T)(p - oldline)) {
// Cursor was after the indent, adjust for the number of
// bytes added/removed.
saved_cursor.col += ind_len - (colnr_T)(p - oldline);
} else if (saved_cursor.col >= (colnr_T)(s - newline)) {
// Cursor was in the indent, and is now after it, put it back
// at the start of the indent (replacing spaces with TAB).
saved_cursor.col = (colnr_T)(s - newline);
}
}
retval = true;
} else {
free(newline);
}
curwin->w_cursor.col = ind_len;
return retval;
}
// Copy the indent from ptr to the current line (and fill to size).
// Leaves the cursor on the first non-blank in the line.
// @return true if the line was changed.
int copy_indent(int size, char_u *src)
{
char_u *p = NULL;
char_u *line = NULL;
char_u *s;
int todo;
int ind_len;
int line_len = 0;
int tab_pad;
int ind_done;
int round;
// Round 1: compute the number of characters needed for the indent
// Round 2: copy the characters.
for (round = 1; round <= 2; ++round) {
todo = size;
ind_len = 0;
ind_done = 0;
s = src;
// Count/copy the usable portion of the source line.
while (todo > 0 && vim_iswhite(*s)) {
if (*s == TAB) {
tab_pad = (int)curbuf->b_p_ts
- (ind_done % (int)curbuf->b_p_ts);
// Stop if this tab will overshoot the target.
if (todo < tab_pad) {
break;
}
todo -= tab_pad;
ind_done += tab_pad;
} else {
todo--;
ind_done++;
}
ind_len++;
if (p != NULL) {
*p++ = *s;
}
s++;
}
// Fill to next tabstop with a tab, if possible.
tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
if ((todo >= tab_pad) && !curbuf->b_p_et) {
todo -= tab_pad;
ind_len++;
if (p != NULL) {
*p++ = TAB;
}
}
// Add tabs required for indent.
while (todo >= (int)curbuf->b_p_ts && !curbuf->b_p_et) {
todo -= (int)curbuf->b_p_ts;
ind_len++;
if (p != NULL) {
*p++ = TAB;
}
}
// Count/add spaces required for indent.
while (todo > 0) {
todo--;
ind_len++;
if (p != NULL) {
*p++ = ' ';
}
}
if (p == NULL) {
// Allocate memory for the result: the copied indent, new indent
// and the rest of the line.
line_len = (int)STRLEN(ml_get_curline()) + 1;
line = alloc(ind_len + line_len);
p = line;
}
}
// Append the original line
memmove(p, ml_get_curline(), (size_t)line_len);
// Replace the line
ml_replace(curwin->w_cursor.lnum, line, false);
// Put the cursor after the indent.
curwin->w_cursor.col = ind_len;
return true;
}
// Return the indent of the current line after a number. Return -1 if no
// number was found. Used for 'n' in 'formatoptions': numbered list.
// Since a pattern is used it can actually handle more than numbers.
int get_number_indent(linenr_T lnum)
{
colnr_T col;
pos_T pos;
regmatch_T regmatch;
int lead_len = 0; // Length of comment leader.
if (lnum > curbuf->b_ml.ml_line_count) {
return -1;
}
pos.lnum = 0;
// In format_lines() (i.e. not insert mode), fo+=q is needed too...
if ((State & INSERT) || has_format_option(FO_Q_COMS)) {
lead_len = get_leader_len(ml_get(lnum), NULL, false, true);
}
regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC);
if (regmatch.regprog != NULL) {
regmatch.rm_ic = false;
// vim_regexec() expects a pointer to a line. This lets us
// start matching for the flp beyond any comment leader...
if (vim_regexec(&regmatch, ml_get(lnum) + lead_len, (colnr_T)0)) {
pos.lnum = lnum;
pos.col = (colnr_T)(*regmatch.endp - ml_get(lnum));
pos.coladd = 0;
}
vim_regfree(regmatch.regprog);
}
if ((pos.lnum == 0) || (*ml_get_pos(&pos) == NUL)) {
return -1;
}
getvcol(curwin, &pos, &col, NULL, NULL);
return (int)col;
}
// When extra == 0: Return true if the cursor is before or on the first
// non-blank in the line.
// When extra == 1: Return true if the cursor is before the first non-blank in
// the line.
int inindent(int extra)
{
char_u *ptr;
colnr_T col;
for (col = 0, ptr = ml_get_curline(); vim_iswhite(*ptr); ++col) {
ptr++;
}
if (col >= curwin->w_cursor.col + extra) {
return true;
} else {
return false;
}
}
// Get indent level from 'indentexpr'.
int get_expr_indent(void)
{
int indent;
pos_T save_pos;
colnr_T save_curswant;
int save_set_curswant;
int save_State;
int use_sandbox = was_set_insecurely((char_u *)"indentexpr", OPT_LOCAL);
// Save and restore cursor position and curswant, in case it was changed
// * via :normal commands.
save_pos = curwin->w_cursor;
save_curswant = curwin->w_curswant;
save_set_curswant = curwin->w_set_curswant;
set_vim_var_nr(VV_LNUM, curwin->w_cursor.lnum);
if (use_sandbox) {
sandbox++;
}
textlock++;
indent = eval_to_number(curbuf->b_p_inde);
if (use_sandbox) {
sandbox--;
}
textlock--;
// Restore the cursor position so that 'indentexpr' doesn't need to.
// Pretend to be in Insert mode, allow cursor past end of line for "o"
// command.
save_State = State;
State = INSERT;
curwin->w_cursor = save_pos;
curwin->w_curswant = save_curswant;
curwin->w_set_curswant = save_set_curswant;
check_cursor();
State = save_State;
// If there is an error, just keep the current indent.
if (indent < 0) {
indent = get_indent();
}
return indent;
}
// When 'p' is present in 'cpoptions, a Vi compatible method is used.
// The incompatible newer method is quite a bit better at indenting
// code in lisp-like languages than the traditional one; it's still
// mostly heuristics however -- Dirk van Deun, dirk@rave.org
// TODO(unknown):
// Findmatch() should be adapted for lisp, also to make showmatch
// work correctly: now (v5.3) it seems all C/C++ oriented:
// - it does not recognize the #\( and #\) notations as character literals
// - it doesn't know about comments starting with a semicolon
// - it incorrectly interprets '(' as a character literal
// All this messes up get_lisp_indent in some rare cases.
// Update from Sergey Khorev:
// I tried to fix the first two issues.
int get_lisp_indent(void)
{
pos_T *pos, realpos, paren;
int amount;
char_u *that;
colnr_T col;
colnr_T firsttry;
int parencount;
int quotecount;
int vi_lisp;
// Set vi_lisp to use the vi-compatible method.
vi_lisp = (vim_strchr(p_cpo, CPO_LISP) != NULL);
realpos = curwin->w_cursor;
curwin->w_cursor.col = 0;
if ((pos = findmatch(NULL, '(')) == NULL) {
pos = findmatch(NULL, '[');
} else {
paren = *pos;
pos = findmatch(NULL, '[');
if ((pos == NULL) || ltp(pos, &paren)) {
pos = &paren;
}
}
if (pos != NULL) {
// Extra trick: Take the indent of the first previous non-white
// line that is at the same () level.
amount = -1;
parencount = 0;
while (--curwin->w_cursor.lnum >= pos->lnum) {
if (linewhite(curwin->w_cursor.lnum)) {
continue;
}
for (that = ml_get_curline(); *that != NUL; ++that) {
if (*that == ';') {
while (*(that + 1) != NUL) {
that++;
}
continue;
}
if (*that == '\\') {
if (*(that + 1) != NUL) {
that++;
}
continue;
}
if ((*that == '"') && (*(that + 1) != NUL)) {
while (*++that && *that != '"') {
// Skipping escaped characters in the string
if (*that == '\\') {
if (*++that == NUL) {
break;
}
if (that[1] == NUL) {
that++;
break;
}
}
}
}
if ((*that == '(') || (*that == '[')) {
parencount++;
} else if ((*that == ')') || (*that == ']')) {
parencount--;
}
}
if (parencount == 0) {
amount = get_indent();
break;
}
}
if (amount == -1) {
curwin->w_cursor.lnum = pos->lnum;
curwin->w_cursor.col = pos->col;
col = pos->col;
that = ml_get_curline();
if (vi_lisp && (get_indent() == 0)) {
amount = 2;
} else {
amount = 0;
while (*that && col) {
amount += lbr_chartabsize_adv(&that, (colnr_T)amount);
col--;
}
// Some keywords require "body" indenting rules (the
// non-standard-lisp ones are Scheme special forms):
// (let ((a 1)) instead (let ((a 1))
// (...)) of (...))
if (!vi_lisp && ((*that == '(') || (*that == '['))
&& lisp_match(that + 1)) {
amount += 2;
} else {
that++;
amount++;
firsttry = amount;
while (vim_iswhite(*that)) {
amount += lbr_chartabsize(that, (colnr_T)amount);
that++;
}
if (*that && (*that != ';')) {
// Not a comment line.
// Test *that != '(' to accommodate first let/do
// argument if it is more than one line.
if (!vi_lisp && (*that != '(') && (*that != '[')) {
firsttry++;
}
parencount = 0;
quotecount = 0;
if (vi_lisp || ((*that != '"') && (*that != '\'')
&& (*that != '#') && ((*that < '0') || (*that > '9')))) {
while (*that && (!vim_iswhite(*that) || quotecount || parencount)
&& (!((*that == '(' || *that == '[')
&& !quotecount && !parencount && vi_lisp))) {
if (*that == '"') {
quotecount = !quotecount;
}
if (((*that == '(') || (*that == '[')) && !quotecount) {
parencount++;
}
if (((*that == ')') || (*that == ']')) && !quotecount) {
parencount--;
}
if ((*that == '\\') && (*(that + 1) != NUL)) {
amount += lbr_chartabsize_adv(&that, (colnr_T)amount);
}
amount += lbr_chartabsize_adv(&that, (colnr_T)amount);
}
}
while (vim_iswhite(*that)) {
amount += lbr_chartabsize(that, (colnr_T)amount);
that++;
}
if (!*that || (*that == ';')) {
amount = firsttry;
}
}
}
}
}
} else {
amount = 0; // No matching '(' or '[' found, use zero indent.
}
curwin->w_cursor = realpos;
return amount;
}
static int lisp_match(char_u *p)
{
char_u buf[LSIZE];
int len;
char_u *word = p_lispwords;
while (*word != NUL) {
(void)copy_option_part(&word, buf, LSIZE, ",");
len = (int)STRLEN(buf);
if ((STRNCMP(buf, p, len) == 0) && (p[len] == ' ')) {
return true;
}
}
return false;
}

14
src/nvim/indent.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef NEOVIM_INDENT_H
#define NEOVIM_INDENT_H
#include "vim.h"
int get_indent(void);
int get_indent_lnum(linenr_T lnum);
int get_indent_buf(buf_T *buf, linenr_T lnum);
int get_indent_str(char_u *ptr, int ts);
int set_indent(int size, int flags);
int copy_indent(int size, char_u *src);
int get_number_indent(linenr_T lnum);
int inindent(int extra);
int get_expr_indent(void);
int get_lisp_indent(void);
#endif // NEOVIM_INDENT_H

3316
src/nvim/indent_c.c Normal file

File diff suppressed because it is too large Load Diff

12
src/nvim/indent_c.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef NEOVIM_INDENT_C_H
#define NEOVIM_INDENT_C_H
#include "vim.h"
int cin_islabel(void);
int cin_iscase(char_u *s, int strict);
int cin_isscopedecl(char_u *s);
int cin_is_cinword(char_u *line);
int get_c_indent(void);
void do_c_expr_indent(void);
void parse_cino(buf_T *buf);
pos_T * find_start_comment(int ind_maxcomment);
#endif

777
src/nvim/keymap.c Normal file
View File

@@ -0,0 +1,777 @@
/************************************************************************
* functions that use lookup tables for various things, generally to do with
* special key codes.
*/
#include "vim.h"
#include "keymap.h"
#include "charset.h"
#include "edit.h"
#include "term.h"
/*
* Some useful tables.
*/
static struct modmasktable {
short mod_mask; /* Bit-mask for particular key modifier */
short mod_flag; /* Bit(s) for particular key modifier */
char_u name; /* Single letter name of modifier */
} mod_mask_table[] =
{
{MOD_MASK_ALT, MOD_MASK_ALT, (char_u)'M'},
{MOD_MASK_META, MOD_MASK_META, (char_u)'T'},
{MOD_MASK_CTRL, MOD_MASK_CTRL, (char_u)'C'},
{MOD_MASK_SHIFT, MOD_MASK_SHIFT, (char_u)'S'},
{MOD_MASK_MULTI_CLICK, MOD_MASK_2CLICK, (char_u)'2'},
{MOD_MASK_MULTI_CLICK, MOD_MASK_3CLICK, (char_u)'3'},
{MOD_MASK_MULTI_CLICK, MOD_MASK_4CLICK, (char_u)'4'},
/* 'A' must be the last one */
{MOD_MASK_ALT, MOD_MASK_ALT, (char_u)'A'},
{0, 0, NUL}
};
/*
* Shifted key terminal codes and their unshifted equivalent.
* Don't add mouse codes here, they are handled separately!
*/
#define MOD_KEYS_ENTRY_SIZE 5
static char_u modifier_keys_table[] =
{
/* mod mask with modifier without modifier */
MOD_MASK_SHIFT, '&', '9', '@', '1', /* begin */
MOD_MASK_SHIFT, '&', '0', '@', '2', /* cancel */
MOD_MASK_SHIFT, '*', '1', '@', '4', /* command */
MOD_MASK_SHIFT, '*', '2', '@', '5', /* copy */
MOD_MASK_SHIFT, '*', '3', '@', '6', /* create */
MOD_MASK_SHIFT, '*', '4', 'k', 'D', /* delete char */
MOD_MASK_SHIFT, '*', '5', 'k', 'L', /* delete line */
MOD_MASK_SHIFT, '*', '7', '@', '7', /* end */
MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_END, '@', '7', /* end */
MOD_MASK_SHIFT, '*', '9', '@', '9', /* exit */
MOD_MASK_SHIFT, '*', '0', '@', '0', /* find */
MOD_MASK_SHIFT, '#', '1', '%', '1', /* help */
MOD_MASK_SHIFT, '#', '2', 'k', 'h', /* home */
MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_HOME, 'k', 'h', /* home */
MOD_MASK_SHIFT, '#', '3', 'k', 'I', /* insert */
MOD_MASK_SHIFT, '#', '4', 'k', 'l', /* left arrow */
MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_LEFT, 'k', 'l', /* left arrow */
MOD_MASK_SHIFT, '%', 'a', '%', '3', /* message */
MOD_MASK_SHIFT, '%', 'b', '%', '4', /* move */
MOD_MASK_SHIFT, '%', 'c', '%', '5', /* next */
MOD_MASK_SHIFT, '%', 'd', '%', '7', /* options */
MOD_MASK_SHIFT, '%', 'e', '%', '8', /* previous */
MOD_MASK_SHIFT, '%', 'f', '%', '9', /* print */
MOD_MASK_SHIFT, '%', 'g', '%', '0', /* redo */
MOD_MASK_SHIFT, '%', 'h', '&', '3', /* replace */
MOD_MASK_SHIFT, '%', 'i', 'k', 'r', /* right arr. */
MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_RIGHT, 'k', 'r', /* right arr. */
MOD_MASK_SHIFT, '%', 'j', '&', '5', /* resume */
MOD_MASK_SHIFT, '!', '1', '&', '6', /* save */
MOD_MASK_SHIFT, '!', '2', '&', '7', /* suspend */
MOD_MASK_SHIFT, '!', '3', '&', '8', /* undo */
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_UP, 'k', 'u', /* up arrow */
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_DOWN, 'k', 'd', /* down arrow */
/* vt100 F1 */
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF1, KS_EXTRA, (int)KE_XF1,
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF2, KS_EXTRA, (int)KE_XF2,
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF3, KS_EXTRA, (int)KE_XF3,
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF4, KS_EXTRA, (int)KE_XF4,
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F1, 'k', '1', /* F1 */
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F2, 'k', '2',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F3, 'k', '3',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F4, 'k', '4',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F5, 'k', '5',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F6, 'k', '6',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F7, 'k', '7',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F8, 'k', '8',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F9, 'k', '9',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F10, 'k', ';', /* F10 */
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F11, 'F', '1',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F12, 'F', '2',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F13, 'F', '3',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F14, 'F', '4',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F15, 'F', '5',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F16, 'F', '6',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F17, 'F', '7',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F18, 'F', '8',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F19, 'F', '9',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F20, 'F', 'A',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F21, 'F', 'B',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F22, 'F', 'C',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F23, 'F', 'D',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F24, 'F', 'E',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F25, 'F', 'F',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F26, 'F', 'G',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F27, 'F', 'H',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F28, 'F', 'I',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F29, 'F', 'J',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F30, 'F', 'K',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F31, 'F', 'L',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F32, 'F', 'M',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F33, 'F', 'N',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F34, 'F', 'O',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F35, 'F', 'P',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F36, 'F', 'Q',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F37, 'F', 'R',
/* TAB pseudo code*/
MOD_MASK_SHIFT, 'k', 'B', KS_EXTRA, (int)KE_TAB,
NUL
};
static struct key_name_entry {
int key; /* Special key code or ascii value */
char_u *name; /* Name of key */
} key_names_table[] =
{
{' ', (char_u *)"Space"},
{TAB, (char_u *)"Tab"},
{K_TAB, (char_u *)"Tab"},
{NL, (char_u *)"NL"},
{NL, (char_u *)"NewLine"}, /* Alternative name */
{NL, (char_u *)"LineFeed"}, /* Alternative name */
{NL, (char_u *)"LF"}, /* Alternative name */
{CAR, (char_u *)"CR"},
{CAR, (char_u *)"Return"}, /* Alternative name */
{CAR, (char_u *)"Enter"}, /* Alternative name */
{K_BS, (char_u *)"BS"},
{K_BS, (char_u *)"BackSpace"}, /* Alternative name */
{ESC, (char_u *)"Esc"},
{CSI, (char_u *)"CSI"},
{K_CSI, (char_u *)"xCSI"},
{'|', (char_u *)"Bar"},
{'\\', (char_u *)"Bslash"},
{K_DEL, (char_u *)"Del"},
{K_DEL, (char_u *)"Delete"}, /* Alternative name */
{K_KDEL, (char_u *)"kDel"},
{K_UP, (char_u *)"Up"},
{K_DOWN, (char_u *)"Down"},
{K_LEFT, (char_u *)"Left"},
{K_RIGHT, (char_u *)"Right"},
{K_XUP, (char_u *)"xUp"},
{K_XDOWN, (char_u *)"xDown"},
{K_XLEFT, (char_u *)"xLeft"},
{K_XRIGHT, (char_u *)"xRight"},
{K_F1, (char_u *)"F1"},
{K_F2, (char_u *)"F2"},
{K_F3, (char_u *)"F3"},
{K_F4, (char_u *)"F4"},
{K_F5, (char_u *)"F5"},
{K_F6, (char_u *)"F6"},
{K_F7, (char_u *)"F7"},
{K_F8, (char_u *)"F8"},
{K_F9, (char_u *)"F9"},
{K_F10, (char_u *)"F10"},
{K_F11, (char_u *)"F11"},
{K_F12, (char_u *)"F12"},
{K_F13, (char_u *)"F13"},
{K_F14, (char_u *)"F14"},
{K_F15, (char_u *)"F15"},
{K_F16, (char_u *)"F16"},
{K_F17, (char_u *)"F17"},
{K_F18, (char_u *)"F18"},
{K_F19, (char_u *)"F19"},
{K_F20, (char_u *)"F20"},
{K_F21, (char_u *)"F21"},
{K_F22, (char_u *)"F22"},
{K_F23, (char_u *)"F23"},
{K_F24, (char_u *)"F24"},
{K_F25, (char_u *)"F25"},
{K_F26, (char_u *)"F26"},
{K_F27, (char_u *)"F27"},
{K_F28, (char_u *)"F28"},
{K_F29, (char_u *)"F29"},
{K_F30, (char_u *)"F30"},
{K_F31, (char_u *)"F31"},
{K_F32, (char_u *)"F32"},
{K_F33, (char_u *)"F33"},
{K_F34, (char_u *)"F34"},
{K_F35, (char_u *)"F35"},
{K_F36, (char_u *)"F36"},
{K_F37, (char_u *)"F37"},
{K_XF1, (char_u *)"xF1"},
{K_XF2, (char_u *)"xF2"},
{K_XF3, (char_u *)"xF3"},
{K_XF4, (char_u *)"xF4"},
{K_HELP, (char_u *)"Help"},
{K_UNDO, (char_u *)"Undo"},
{K_INS, (char_u *)"Insert"},
{K_INS, (char_u *)"Ins"}, /* Alternative name */
{K_KINS, (char_u *)"kInsert"},
{K_HOME, (char_u *)"Home"},
{K_KHOME, (char_u *)"kHome"},
{K_XHOME, (char_u *)"xHome"},
{K_ZHOME, (char_u *)"zHome"},
{K_END, (char_u *)"End"},
{K_KEND, (char_u *)"kEnd"},
{K_XEND, (char_u *)"xEnd"},
{K_ZEND, (char_u *)"zEnd"},
{K_PAGEUP, (char_u *)"PageUp"},
{K_PAGEDOWN, (char_u *)"PageDown"},
{K_KPAGEUP, (char_u *)"kPageUp"},
{K_KPAGEDOWN, (char_u *)"kPageDown"},
{K_KPLUS, (char_u *)"kPlus"},
{K_KMINUS, (char_u *)"kMinus"},
{K_KDIVIDE, (char_u *)"kDivide"},
{K_KMULTIPLY, (char_u *)"kMultiply"},
{K_KENTER, (char_u *)"kEnter"},
{K_KPOINT, (char_u *)"kPoint"},
{K_K0, (char_u *)"k0"},
{K_K1, (char_u *)"k1"},
{K_K2, (char_u *)"k2"},
{K_K3, (char_u *)"k3"},
{K_K4, (char_u *)"k4"},
{K_K5, (char_u *)"k5"},
{K_K6, (char_u *)"k6"},
{K_K7, (char_u *)"k7"},
{K_K8, (char_u *)"k8"},
{K_K9, (char_u *)"k9"},
{'<', (char_u *)"lt"},
{K_MOUSE, (char_u *)"Mouse"},
{K_NETTERM_MOUSE, (char_u *)"NetMouse"},
{K_DEC_MOUSE, (char_u *)"DecMouse"},
#ifdef FEAT_MOUSE_JSB
{K_JSBTERM_MOUSE, (char_u *)"JsbMouse"},
#endif
{K_URXVT_MOUSE, (char_u *)"UrxvtMouse"},
{K_SGR_MOUSE, (char_u *)"SgrMouse"},
{K_LEFTMOUSE, (char_u *)"LeftMouse"},
{K_LEFTMOUSE_NM, (char_u *)"LeftMouseNM"},
{K_LEFTDRAG, (char_u *)"LeftDrag"},
{K_LEFTRELEASE, (char_u *)"LeftRelease"},
{K_LEFTRELEASE_NM, (char_u *)"LeftReleaseNM"},
{K_MIDDLEMOUSE, (char_u *)"MiddleMouse"},
{K_MIDDLEDRAG, (char_u *)"MiddleDrag"},
{K_MIDDLERELEASE, (char_u *)"MiddleRelease"},
{K_RIGHTMOUSE, (char_u *)"RightMouse"},
{K_RIGHTDRAG, (char_u *)"RightDrag"},
{K_RIGHTRELEASE, (char_u *)"RightRelease"},
{K_MOUSEDOWN, (char_u *)"ScrollWheelUp"},
{K_MOUSEUP, (char_u *)"ScrollWheelDown"},
{K_MOUSELEFT, (char_u *)"ScrollWheelRight"},
{K_MOUSERIGHT, (char_u *)"ScrollWheelLeft"},
{K_MOUSEDOWN, (char_u *)"MouseDown"}, /* OBSOLETE: Use */
{K_MOUSEUP, (char_u *)"MouseUp"}, /* ScrollWheelXXX instead */
{K_X1MOUSE, (char_u *)"X1Mouse"},
{K_X1DRAG, (char_u *)"X1Drag"},
{K_X1RELEASE, (char_u *)"X1Release"},
{K_X2MOUSE, (char_u *)"X2Mouse"},
{K_X2DRAG, (char_u *)"X2Drag"},
{K_X2RELEASE, (char_u *)"X2Release"},
{K_DROP, (char_u *)"Drop"},
{K_ZERO, (char_u *)"Nul"},
{K_SNR, (char_u *)"SNR"},
{K_PLUG, (char_u *)"Plug"},
{0, NULL}
};
#define KEY_NAMES_TABLE_LEN (sizeof(key_names_table) / \
sizeof(struct key_name_entry))
static struct mousetable {
int pseudo_code; /* Code for pseudo mouse event */
int button; /* Which mouse button is it? */
int is_click; /* Is it a mouse button click event? */
int is_drag; /* Is it a mouse drag event? */
} mouse_table[] =
{
{(int)KE_LEFTMOUSE, MOUSE_LEFT, TRUE, FALSE},
{(int)KE_LEFTDRAG, MOUSE_LEFT, FALSE, TRUE},
{(int)KE_LEFTRELEASE, MOUSE_LEFT, FALSE, FALSE},
{(int)KE_MIDDLEMOUSE, MOUSE_MIDDLE, TRUE, FALSE},
{(int)KE_MIDDLEDRAG, MOUSE_MIDDLE, FALSE, TRUE},
{(int)KE_MIDDLERELEASE, MOUSE_MIDDLE, FALSE, FALSE},
{(int)KE_RIGHTMOUSE, MOUSE_RIGHT, TRUE, FALSE},
{(int)KE_RIGHTDRAG, MOUSE_RIGHT, FALSE, TRUE},
{(int)KE_RIGHTRELEASE, MOUSE_RIGHT, FALSE, FALSE},
{(int)KE_X1MOUSE, MOUSE_X1, TRUE, FALSE},
{(int)KE_X1DRAG, MOUSE_X1, FALSE, TRUE},
{(int)KE_X1RELEASE, MOUSE_X1, FALSE, FALSE},
{(int)KE_X2MOUSE, MOUSE_X2, TRUE, FALSE},
{(int)KE_X2DRAG, MOUSE_X2, FALSE, TRUE},
{(int)KE_X2RELEASE, MOUSE_X2, FALSE, FALSE},
/* DRAG without CLICK */
{(int)KE_IGNORE, MOUSE_RELEASE, FALSE, TRUE},
/* RELEASE without CLICK */
{(int)KE_IGNORE, MOUSE_RELEASE, FALSE, FALSE},
{0, 0, 0, 0},
};
/*
* Return the modifier mask bit (MOD_MASK_*) which corresponds to the given
* modifier name ('S' for Shift, 'C' for Ctrl etc).
*/
int name_to_mod_mask(int c)
{
int i;
c = TOUPPER_ASC(c);
for (i = 0; mod_mask_table[i].mod_mask != 0; i++)
if (c == mod_mask_table[i].name)
return mod_mask_table[i].mod_flag;
return 0;
}
/*
* Check if if there is a special key code for "key" that includes the
* modifiers specified.
*/
int simplify_key(int key, int *modifiers)
{
int i;
int key0;
int key1;
if (*modifiers & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT)) {
/* TAB is a special case */
if (key == TAB && (*modifiers & MOD_MASK_SHIFT)) {
*modifiers &= ~MOD_MASK_SHIFT;
return K_S_TAB;
}
key0 = KEY2TERMCAP0(key);
key1 = KEY2TERMCAP1(key);
for (i = 0; modifier_keys_table[i] != NUL; i += MOD_KEYS_ENTRY_SIZE)
if (key0 == modifier_keys_table[i + 3]
&& key1 == modifier_keys_table[i + 4]
&& (*modifiers & modifier_keys_table[i])) {
*modifiers &= ~modifier_keys_table[i];
return TERMCAP2KEY(modifier_keys_table[i + 1],
modifier_keys_table[i + 2]);
}
}
return key;
}
/*
* Change <xHome> to <Home>, <xUp> to <Up>, etc.
*/
int handle_x_keys(int key)
{
switch (key) {
case K_XUP: return K_UP;
case K_XDOWN: return K_DOWN;
case K_XLEFT: return K_LEFT;
case K_XRIGHT: return K_RIGHT;
case K_XHOME: return K_HOME;
case K_ZHOME: return K_HOME;
case K_XEND: return K_END;
case K_ZEND: return K_END;
case K_XF1: return K_F1;
case K_XF2: return K_F2;
case K_XF3: return K_F3;
case K_XF4: return K_F4;
case K_S_XF1: return K_S_F1;
case K_S_XF2: return K_S_F2;
case K_S_XF3: return K_S_F3;
case K_S_XF4: return K_S_F4;
}
return key;
}
/*
* Return a string which contains the name of the given key when the given
* modifiers are down.
*/
char_u *get_special_key_name(int c, int modifiers)
{
static char_u string[MAX_KEY_NAME_LEN + 1];
int i, idx;
int table_idx;
char_u *s;
string[0] = '<';
idx = 1;
/* Key that stands for a normal character. */
if (IS_SPECIAL(c) && KEY2TERMCAP0(c) == KS_KEY)
c = KEY2TERMCAP1(c);
/*
* Translate shifted special keys into unshifted keys and set modifier.
* Same for CTRL and ALT modifiers.
*/
if (IS_SPECIAL(c)) {
for (i = 0; modifier_keys_table[i] != 0; i += MOD_KEYS_ENTRY_SIZE)
if ( KEY2TERMCAP0(c) == (int)modifier_keys_table[i + 1]
&& (int)KEY2TERMCAP1(c) == (int)modifier_keys_table[i + 2]) {
modifiers |= modifier_keys_table[i];
c = TERMCAP2KEY(modifier_keys_table[i + 3],
modifier_keys_table[i + 4]);
break;
}
}
/* try to find the key in the special key table */
table_idx = find_special_key_in_table(c);
/*
* When not a known special key, and not a printable character, try to
* extract modifiers.
*/
if (c > 0
&& (*mb_char2len)(c) == 1
) {
if (table_idx < 0
&& (!vim_isprintc(c) || (c & 0x7f) == ' ')
&& (c & 0x80)) {
c &= 0x7f;
modifiers |= MOD_MASK_ALT;
/* try again, to find the un-alted key in the special key table */
table_idx = find_special_key_in_table(c);
}
if (table_idx < 0 && !vim_isprintc(c) && c < ' ') {
c += '@';
modifiers |= MOD_MASK_CTRL;
}
}
/* translate the modifier into a string */
for (i = 0; mod_mask_table[i].name != 'A'; i++)
if ((modifiers & mod_mask_table[i].mod_mask)
== mod_mask_table[i].mod_flag) {
string[idx++] = mod_mask_table[i].name;
string[idx++] = (char_u)'-';
}
if (table_idx < 0) { /* unknown special key, may output t_xx */
if (IS_SPECIAL(c)) {
string[idx++] = 't';
string[idx++] = '_';
string[idx++] = KEY2TERMCAP0(c);
string[idx++] = KEY2TERMCAP1(c);
}
/* Not a special key, only modifiers, output directly */
else {
if (has_mbyte && (*mb_char2len)(c) > 1)
idx += (*mb_char2bytes)(c, string + idx);
else if (vim_isprintc(c))
string[idx++] = c;
else {
s = transchar(c);
while (*s)
string[idx++] = *s++;
}
}
} else { /* use name of special key */
STRCPY(string + idx, key_names_table[table_idx].name);
idx = (int)STRLEN(string);
}
string[idx++] = '>';
string[idx] = NUL;
return string;
}
/*
* Try translating a <> name at (*srcp)[] to dst[].
* Return the number of characters added to dst[], zero for no match.
* If there is a match, srcp is advanced to after the <> name.
* dst[] must be big enough to hold the result (up to six characters)!
*/
int
trans_special (
char_u **srcp,
char_u *dst,
int keycode /* prefer key code, e.g. K_DEL instead of DEL */
)
{
int modifiers = 0;
int key;
int dlen = 0;
key = find_special_key(srcp, &modifiers, keycode, FALSE);
if (key == 0)
return 0;
/* Put the appropriate modifier in a string */
if (modifiers != 0) {
dst[dlen++] = K_SPECIAL;
dst[dlen++] = KS_MODIFIER;
dst[dlen++] = modifiers;
}
if (IS_SPECIAL(key)) {
dst[dlen++] = K_SPECIAL;
dst[dlen++] = KEY2TERMCAP0(key);
dst[dlen++] = KEY2TERMCAP1(key);
} else if (has_mbyte && !keycode)
dlen += (*mb_char2bytes)(key, dst + dlen);
else if (keycode)
dlen = (int)(add_char2buf(key, dst + dlen) - dst);
else
dst[dlen++] = key;
return dlen;
}
/*
* Try translating a <> name at (*srcp)[], return the key and modifiers.
* srcp is advanced to after the <> name.
* returns 0 if there is no match.
*/
int
find_special_key (
char_u **srcp,
int *modp,
int keycode, /* prefer key code, e.g. K_DEL instead of DEL */
int keep_x_key /* don't translate xHome to Home key */
)
{
char_u *last_dash;
char_u *end_of_name;
char_u *src;
char_u *bp;
int modifiers;
int bit;
int key;
unsigned long n;
int l;
src = *srcp;
if (src[0] != '<')
return 0;
/* Find end of modifier list */
last_dash = src;
for (bp = src + 1; *bp == '-' || vim_isIDc(*bp); bp++) {
if (*bp == '-') {
last_dash = bp;
if (bp[1] != NUL) {
if (has_mbyte)
l = mb_ptr2len(bp + 1);
else
l = 1;
if (bp[l + 1] == '>')
bp += l; /* anything accepted, like <C-?> */
}
}
if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3])
bp += 3; /* skip t_xx, xx may be '-' or '>' */
else if (STRNICMP(bp, "char-", 5) == 0) {
vim_str2nr(bp + 5, NULL, &l, TRUE, TRUE, NULL, NULL);
bp += l + 5;
break;
}
}
if (*bp == '>') { /* found matching '>' */
end_of_name = bp + 1;
/* Which modifiers are given? */
modifiers = 0x0;
for (bp = src + 1; bp < last_dash; bp++) {
if (*bp != '-') {
bit = name_to_mod_mask(*bp);
if (bit == 0x0)
break; /* Illegal modifier name */
modifiers |= bit;
}
}
/*
* Legal modifier name.
*/
if (bp >= last_dash) {
if (STRNICMP(last_dash + 1, "char-", 5) == 0
&& VIM_ISDIGIT(last_dash[6])) {
/* <Char-123> or <Char-033> or <Char-0x33> */
vim_str2nr(last_dash + 6, NULL, NULL, TRUE, TRUE, NULL, &n);
key = (int)n;
} else {
/*
* Modifier with single letter, or special key name.
*/
if (has_mbyte)
l = mb_ptr2len(last_dash + 1);
else
l = 1;
if (modifiers != 0 && last_dash[l + 1] == '>')
key = PTR2CHAR(last_dash + 1);
else {
key = get_special_key_code(last_dash + 1);
if (!keep_x_key)
key = handle_x_keys(key);
}
}
/*
* get_special_key_code() may return NUL for invalid
* special key name.
*/
if (key != NUL) {
/*
* Only use a modifier when there is no special key code that
* includes the modifier.
*/
key = simplify_key(key, &modifiers);
if (!keycode) {
/* don't want keycode, use single byte code */
if (key == K_BS)
key = BS;
else if (key == K_DEL || key == K_KDEL)
key = DEL;
}
/*
* Normal Key with modifier: Try to make a single byte code.
*/
if (!IS_SPECIAL(key))
key = extract_modifiers(key, &modifiers);
*modp = modifiers;
*srcp = end_of_name;
return key;
}
}
}
return 0;
}
/*
* Try to include modifiers in the key.
* Changes "Shift-a" to 'A', "Alt-A" to 0xc0, etc.
*/
int extract_modifiers(int key, int *modp)
{
int modifiers = *modp;
if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key)) {
key = TOUPPER_ASC(key);
modifiers &= ~MOD_MASK_SHIFT;
}
if ((modifiers & MOD_MASK_CTRL)
&& ((key >= '?' && key <= '_') || ASCII_ISALPHA(key))
) {
key = Ctrl_chr(key);
modifiers &= ~MOD_MASK_CTRL;
/* <C-@> is <Nul> */
if (key == 0)
key = K_ZERO;
}
if ((modifiers & MOD_MASK_ALT) && key < 0x80
&& !enc_dbcs /* avoid creating a lead byte */
) {
key |= 0x80;
modifiers &= ~MOD_MASK_ALT; /* remove the META modifier */
}
*modp = modifiers;
return key;
}
/*
* Try to find key "c" in the special key table.
* Return the index when found, -1 when not found.
*/
int find_special_key_in_table(int c)
{
int i;
for (i = 0; key_names_table[i].name != NULL; i++)
if (c == key_names_table[i].key)
break;
if (key_names_table[i].name == NULL)
i = -1;
return i;
}
/*
* Find the special key with the given name (the given string does not have to
* end with NUL, the name is assumed to end before the first non-idchar).
* If the name starts with "t_" the next two characters are interpreted as a
* termcap name.
* Return the key code, or 0 if not found.
*/
int get_special_key_code(char_u *name)
{
char_u *table_name;
char_u string[3];
int i, j;
/*
* If it's <t_xx> we get the code for xx from the termcap
*/
if (name[0] == 't' && name[1] == '_' && name[2] != NUL && name[3] != NUL) {
string[0] = name[2];
string[1] = name[3];
string[2] = NUL;
if (add_termcap_entry(string, FALSE) == OK)
return TERMCAP2KEY(name[2], name[3]);
} else
for (i = 0; key_names_table[i].name != NULL; i++) {
table_name = key_names_table[i].name;
for (j = 0; vim_isIDc(name[j]) && table_name[j] != NUL; j++)
if (TOLOWER_ASC(table_name[j]) != TOLOWER_ASC(name[j]))
break;
if (!vim_isIDc(name[j]) && table_name[j] == NUL)
return key_names_table[i].key;
}
return 0;
}
char_u *get_key_name(int i)
{
if (i >= (int)KEY_NAMES_TABLE_LEN)
return NULL;
return key_names_table[i].name;
}
/*
* Look up the given mouse code to return the relevant information in the other
* arguments. Return which button is down or was released.
*/
int get_mouse_button(int code, int *is_click, int *is_drag)
{
int i;
for (i = 0; mouse_table[i].pseudo_code; i++)
if (code == mouse_table[i].pseudo_code) {
*is_click = mouse_table[i].is_click;
*is_drag = mouse_table[i].is_drag;
return mouse_table[i].button;
}
return 0; /* Shouldn't get here */
}
/*
* Return the appropriate pseudo mouse event token (KE_LEFTMOUSE etc) based on
* the given information about which mouse button is down, and whether the
* mouse was clicked, dragged or released.
*/
int
get_pseudo_mouse_code (
int button, /* eg MOUSE_LEFT */
int is_click,
int is_drag
)
{
int i;
for (i = 0; mouse_table[i].pseudo_code; i++)
if (button == mouse_table[i].button
&& is_click == mouse_table[i].is_click
&& is_drag == mouse_table[i].is_drag) {
return mouse_table[i].pseudo_code;
}
return (int)KE_IGNORE; /* not recognized, ignore it */
}

515
src/nvim/keymap.h Normal file
View File

@@ -0,0 +1,515 @@
/*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
*/
#ifndef NEOVIM_KEYMAP_H
#define NEOVIM_KEYMAP_H
/*
* Keycode definitions for special keys.
*
* Any special key code sequences are replaced by these codes.
*/
/*
* For MSDOS some keys produce codes larger than 0xff. They are split into two
* chars, the first one is K_NUL (same value used in term_defs.h).
*/
#define K_NUL (0xce) /* for MSDOS: special key follows */
/*
* K_SPECIAL is the first byte of a special key code and is always followed by
* two bytes.
* The second byte can have any value. ASCII is used for normal termcap
* entries, 0x80 and higher for special keys, see below.
* The third byte is guaranteed to be between 0x02 and 0x7f.
*/
#define K_SPECIAL (0x80)
/*
* Positive characters are "normal" characters.
* Negative characters are special key codes. Only characters below -0x200
* are used to so that the absolute value can't be mistaken for a single-byte
* character.
*/
#define IS_SPECIAL(c) ((c) < 0)
/*
* Characters 0x0100 - 0x01ff have a special meaning for abbreviations.
* Multi-byte characters also have ABBR_OFF added, thus are above 0x0200.
*/
#define ABBR_OFF 0x100
/*
* NUL cannot be in the input string, therefore it is replaced by
* K_SPECIAL KS_ZERO KE_FILLER
*/
#define KS_ZERO 255
/*
* K_SPECIAL cannot be in the input string, therefore it is replaced by
* K_SPECIAL KS_SPECIAL KE_FILLER
*/
#define KS_SPECIAL 254
/*
* KS_EXTRA is used for keys that have no termcap name
* K_SPECIAL KS_EXTRA KE_xxx
*/
#define KS_EXTRA 253
/*
* KS_MODIFIER is used when a modifier is given for a (special) key
* K_SPECIAL KS_MODIFIER bitmask
*/
#define KS_MODIFIER 252
/*
* These are used for the GUI
* K_SPECIAL KS_xxx KE_FILLER
*/
#define KS_MOUSE 251
#define KS_MENU 250
#define KS_VER_SCROLLBAR 249
#define KS_HOR_SCROLLBAR 248
/*
* These are used for DEC mouse
*/
#define KS_NETTERM_MOUSE 247
#define KS_DEC_MOUSE 246
/*
* Used for switching Select mode back on after a mapping or menu.
*/
#define KS_SELECT 245
#define K_SELECT_STRING (char_u *)"\200\365X"
/*
* Used for tearing off a menu.
*/
#define KS_TEAROFF 244
/* Used for JSB term mouse. */
#define KS_JSBTERM_MOUSE 243
/* Used a termcap entry that produces a normal character. */
#define KS_KEY 242
/* Used for the qnx pterm mouse. */
#define KS_PTERM_MOUSE 241
/* Used for click in a tab pages label. */
#define KS_TABLINE 240
/* Used for menu in a tab pages line. */
#define KS_TABMENU 239
/* Used for the urxvt mouse. */
#define KS_URXVT_MOUSE 238
/* Used for the sgr mouse. */
#define KS_SGR_MOUSE 237
/*
* Filler used after KS_SPECIAL and others
*/
#define KE_FILLER ('X')
/*
* translation of three byte code "K_SPECIAL a b" into int "K_xxx" and back
*/
#define TERMCAP2KEY(a, b) (-((a) + ((int)(b) << 8)))
#define KEY2TERMCAP0(x) ((-(x)) & 0xff)
#define KEY2TERMCAP1(x) (((unsigned)(-(x)) >> 8) & 0xff)
/*
* get second or third byte when translating special key code into three bytes
*/
#define K_SECOND(c) ((c) == K_SPECIAL ? KS_SPECIAL : (c) == \
NUL ? KS_ZERO : KEY2TERMCAP0(c))
#define K_THIRD(c) (((c) == K_SPECIAL || (c) == \
NUL) ? KE_FILLER : KEY2TERMCAP1(c))
/*
* get single int code from second byte after K_SPECIAL
*/
#define TO_SPECIAL(a, b) ((a) == KS_SPECIAL ? K_SPECIAL : (a) == \
KS_ZERO ? K_ZERO : TERMCAP2KEY(a, b))
/*
* Codes for keys that do not have a termcap name.
*
* K_SPECIAL KS_EXTRA KE_xxx
*/
enum key_extra {
KE_NAME = 3 /* name of this terminal entry */
, KE_S_UP /* shift-up */
, KE_S_DOWN /* shift-down */
, KE_S_F1 /* shifted function keys */
, KE_S_F2
, KE_S_F3
, KE_S_F4
, KE_S_F5
, KE_S_F6
, KE_S_F7
, KE_S_F8
, KE_S_F9
, KE_S_F10
, KE_S_F11
, KE_S_F12
, KE_S_F13
, KE_S_F14
, KE_S_F15
, KE_S_F16
, KE_S_F17
, KE_S_F18
, KE_S_F19
, KE_S_F20
, KE_S_F21
, KE_S_F22
, KE_S_F23
, KE_S_F24
, KE_S_F25
, KE_S_F26
, KE_S_F27
, KE_S_F28
, KE_S_F29
, KE_S_F30
, KE_S_F31
, KE_S_F32
, KE_S_F33
, KE_S_F34
, KE_S_F35
, KE_S_F36
, KE_S_F37
, KE_MOUSE /* mouse event start */
/*
* Symbols for pseudo keys which are translated from the real key symbols
* above.
*/
, KE_LEFTMOUSE /* Left mouse button click */
, KE_LEFTDRAG /* Drag with left mouse button down */
, KE_LEFTRELEASE /* Left mouse button release */
, KE_MIDDLEMOUSE /* Middle mouse button click */
, KE_MIDDLEDRAG /* Drag with middle mouse button down */
, KE_MIDDLERELEASE /* Middle mouse button release */
, KE_RIGHTMOUSE /* Right mouse button click */
, KE_RIGHTDRAG /* Drag with right mouse button down */
, KE_RIGHTRELEASE /* Right mouse button release */
, KE_IGNORE /* Ignored mouse drag/release */
, KE_TAB /* unshifted TAB key */
, KE_S_TAB_OLD /* shifted TAB key (no longer used) */
, KE_XF1 /* extra vt100 function keys for xterm */
, KE_XF2
, KE_XF3
, KE_XF4
, KE_XEND /* extra (vt100) end key for xterm */
, KE_ZEND /* extra (vt100) end key for xterm */
, KE_XHOME /* extra (vt100) home key for xterm */
, KE_ZHOME /* extra (vt100) home key for xterm */
, KE_XUP /* extra vt100 cursor keys for xterm */
, KE_XDOWN
, KE_XLEFT
, KE_XRIGHT
, KE_LEFTMOUSE_NM /* non-mappable Left mouse button click */
, KE_LEFTRELEASE_NM /* non-mappable left mouse button release */
, KE_S_XF1 /* extra vt100 shifted function keys for xterm */
, KE_S_XF2
, KE_S_XF3
, KE_S_XF4
/* NOTE: The scroll wheel events are inverted: i.e. UP is the same as
* moving the actual scroll wheel down, LEFT is the same as moving the
* scroll wheel right. */
, KE_MOUSEDOWN /* scroll wheel pseudo-button Down */
, KE_MOUSEUP /* scroll wheel pseudo-button Up */
, KE_MOUSELEFT /* scroll wheel pseudo-button Left */
, KE_MOUSERIGHT /* scroll wheel pseudo-button Right */
, KE_KINS /* keypad Insert key */
, KE_KDEL /* keypad Delete key */
, KE_CSI /* CSI typed directly */
, KE_SNR /* <SNR> */
, KE_PLUG /* <Plug> */
, KE_CMDWIN /* open command-line window from Command-line Mode */
, KE_C_LEFT /* control-left */
, KE_C_RIGHT /* control-right */
, KE_C_HOME /* control-home */
, KE_C_END /* control-end */
, KE_X1MOUSE /* X1/X2 mouse-buttons */
, KE_X1DRAG
, KE_X1RELEASE
, KE_X2MOUSE
, KE_X2DRAG
, KE_X2RELEASE
, KE_DROP /* DnD data is available */
, KE_CURSORHOLD /* CursorHold event */
, KE_NOP /* doesn't do something */
, KE_FOCUSGAINED /* focus gained */
, KE_FOCUSLOST /* focus lost */
, KE_EVENT // event
};
/*
* the three byte codes are replaced with the following int when using vgetc()
*/
#define K_ZERO TERMCAP2KEY(KS_ZERO, KE_FILLER)
#define K_UP TERMCAP2KEY('k', 'u')
#define K_DOWN TERMCAP2KEY('k', 'd')
#define K_LEFT TERMCAP2KEY('k', 'l')
#define K_RIGHT TERMCAP2KEY('k', 'r')
#define K_S_UP TERMCAP2KEY(KS_EXTRA, KE_S_UP)
#define K_S_DOWN TERMCAP2KEY(KS_EXTRA, KE_S_DOWN)
#define K_S_LEFT TERMCAP2KEY('#', '4')
#define K_C_LEFT TERMCAP2KEY(KS_EXTRA, KE_C_LEFT)
#define K_S_RIGHT TERMCAP2KEY('%', 'i')
#define K_C_RIGHT TERMCAP2KEY(KS_EXTRA, KE_C_RIGHT)
#define K_S_HOME TERMCAP2KEY('#', '2')
#define K_C_HOME TERMCAP2KEY(KS_EXTRA, KE_C_HOME)
#define K_S_END TERMCAP2KEY('*', '7')
#define K_C_END TERMCAP2KEY(KS_EXTRA, KE_C_END)
#define K_TAB TERMCAP2KEY(KS_EXTRA, KE_TAB)
#define K_S_TAB TERMCAP2KEY('k', 'B')
/* extra set of function keys F1-F4, for vt100 compatible xterm */
#define K_XF1 TERMCAP2KEY(KS_EXTRA, KE_XF1)
#define K_XF2 TERMCAP2KEY(KS_EXTRA, KE_XF2)
#define K_XF3 TERMCAP2KEY(KS_EXTRA, KE_XF3)
#define K_XF4 TERMCAP2KEY(KS_EXTRA, KE_XF4)
/* extra set of cursor keys for vt100 compatible xterm */
#define K_XUP TERMCAP2KEY(KS_EXTRA, KE_XUP)
#define K_XDOWN TERMCAP2KEY(KS_EXTRA, KE_XDOWN)
#define K_XLEFT TERMCAP2KEY(KS_EXTRA, KE_XLEFT)
#define K_XRIGHT TERMCAP2KEY(KS_EXTRA, KE_XRIGHT)
#define K_F1 TERMCAP2KEY('k', '1') /* function keys */
#define K_F2 TERMCAP2KEY('k', '2')
#define K_F3 TERMCAP2KEY('k', '3')
#define K_F4 TERMCAP2KEY('k', '4')
#define K_F5 TERMCAP2KEY('k', '5')
#define K_F6 TERMCAP2KEY('k', '6')
#define K_F7 TERMCAP2KEY('k', '7')
#define K_F8 TERMCAP2KEY('k', '8')
#define K_F9 TERMCAP2KEY('k', '9')
#define K_F10 TERMCAP2KEY('k', ';')
#define K_F11 TERMCAP2KEY('F', '1')
#define K_F12 TERMCAP2KEY('F', '2')
#define K_F13 TERMCAP2KEY('F', '3')
#define K_F14 TERMCAP2KEY('F', '4')
#define K_F15 TERMCAP2KEY('F', '5')
#define K_F16 TERMCAP2KEY('F', '6')
#define K_F17 TERMCAP2KEY('F', '7')
#define K_F18 TERMCAP2KEY('F', '8')
#define K_F19 TERMCAP2KEY('F', '9')
#define K_F20 TERMCAP2KEY('F', 'A')
#define K_F21 TERMCAP2KEY('F', 'B')
#define K_F22 TERMCAP2KEY('F', 'C')
#define K_F23 TERMCAP2KEY('F', 'D')
#define K_F24 TERMCAP2KEY('F', 'E')
#define K_F25 TERMCAP2KEY('F', 'F')
#define K_F26 TERMCAP2KEY('F', 'G')
#define K_F27 TERMCAP2KEY('F', 'H')
#define K_F28 TERMCAP2KEY('F', 'I')
#define K_F29 TERMCAP2KEY('F', 'J')
#define K_F30 TERMCAP2KEY('F', 'K')
#define K_F31 TERMCAP2KEY('F', 'L')
#define K_F32 TERMCAP2KEY('F', 'M')
#define K_F33 TERMCAP2KEY('F', 'N')
#define K_F34 TERMCAP2KEY('F', 'O')
#define K_F35 TERMCAP2KEY('F', 'P')
#define K_F36 TERMCAP2KEY('F', 'Q')
#define K_F37 TERMCAP2KEY('F', 'R')
/* extra set of shifted function keys F1-F4, for vt100 compatible xterm */
#define K_S_XF1 TERMCAP2KEY(KS_EXTRA, KE_S_XF1)
#define K_S_XF2 TERMCAP2KEY(KS_EXTRA, KE_S_XF2)
#define K_S_XF3 TERMCAP2KEY(KS_EXTRA, KE_S_XF3)
#define K_S_XF4 TERMCAP2KEY(KS_EXTRA, KE_S_XF4)
#define K_S_F1 TERMCAP2KEY(KS_EXTRA, KE_S_F1) /* shifted func. keys */
#define K_S_F2 TERMCAP2KEY(KS_EXTRA, KE_S_F2)
#define K_S_F3 TERMCAP2KEY(KS_EXTRA, KE_S_F3)
#define K_S_F4 TERMCAP2KEY(KS_EXTRA, KE_S_F4)
#define K_S_F5 TERMCAP2KEY(KS_EXTRA, KE_S_F5)
#define K_S_F6 TERMCAP2KEY(KS_EXTRA, KE_S_F6)
#define K_S_F7 TERMCAP2KEY(KS_EXTRA, KE_S_F7)
#define K_S_F8 TERMCAP2KEY(KS_EXTRA, KE_S_F8)
#define K_S_F9 TERMCAP2KEY(KS_EXTRA, KE_S_F9)
#define K_S_F10 TERMCAP2KEY(KS_EXTRA, KE_S_F10)
#define K_S_F11 TERMCAP2KEY(KS_EXTRA, KE_S_F11)
#define K_S_F12 TERMCAP2KEY(KS_EXTRA, KE_S_F12)
/* K_S_F13 to K_S_F37 are currently not used */
#define K_HELP TERMCAP2KEY('%', '1')
#define K_UNDO TERMCAP2KEY('&', '8')
#define K_BS TERMCAP2KEY('k', 'b')
#define K_INS TERMCAP2KEY('k', 'I')
#define K_KINS TERMCAP2KEY(KS_EXTRA, KE_KINS)
#define K_DEL TERMCAP2KEY('k', 'D')
#define K_KDEL TERMCAP2KEY(KS_EXTRA, KE_KDEL)
#define K_HOME TERMCAP2KEY('k', 'h')
#define K_KHOME TERMCAP2KEY('K', '1') /* keypad home (upper left) */
#define K_XHOME TERMCAP2KEY(KS_EXTRA, KE_XHOME)
#define K_ZHOME TERMCAP2KEY(KS_EXTRA, KE_ZHOME)
#define K_END TERMCAP2KEY('@', '7')
#define K_KEND TERMCAP2KEY('K', '4') /* keypad end (lower left) */
#define K_XEND TERMCAP2KEY(KS_EXTRA, KE_XEND)
#define K_ZEND TERMCAP2KEY(KS_EXTRA, KE_ZEND)
#define K_PAGEUP TERMCAP2KEY('k', 'P')
#define K_PAGEDOWN TERMCAP2KEY('k', 'N')
#define K_KPAGEUP TERMCAP2KEY('K', '3') /* keypad pageup (upper R.) */
#define K_KPAGEDOWN TERMCAP2KEY('K', '5') /* keypad pagedown (lower R.) */
#define K_KPLUS TERMCAP2KEY('K', '6') /* keypad plus */
#define K_KMINUS TERMCAP2KEY('K', '7') /* keypad minus */
#define K_KDIVIDE TERMCAP2KEY('K', '8') /* keypad / */
#define K_KMULTIPLY TERMCAP2KEY('K', '9') /* keypad * */
#define K_KENTER TERMCAP2KEY('K', 'A') /* keypad Enter */
#define K_KPOINT TERMCAP2KEY('K', 'B') /* keypad . or ,*/
#define K_K0 TERMCAP2KEY('K', 'C') /* keypad 0 */
#define K_K1 TERMCAP2KEY('K', 'D') /* keypad 1 */
#define K_K2 TERMCAP2KEY('K', 'E') /* keypad 2 */
#define K_K3 TERMCAP2KEY('K', 'F') /* keypad 3 */
#define K_K4 TERMCAP2KEY('K', 'G') /* keypad 4 */
#define K_K5 TERMCAP2KEY('K', 'H') /* keypad 5 */
#define K_K6 TERMCAP2KEY('K', 'I') /* keypad 6 */
#define K_K7 TERMCAP2KEY('K', 'J') /* keypad 7 */
#define K_K8 TERMCAP2KEY('K', 'K') /* keypad 8 */
#define K_K9 TERMCAP2KEY('K', 'L') /* keypad 9 */
#define K_MOUSE TERMCAP2KEY(KS_MOUSE, KE_FILLER)
#define K_MENU TERMCAP2KEY(KS_MENU, KE_FILLER)
#define K_VER_SCROLLBAR TERMCAP2KEY(KS_VER_SCROLLBAR, KE_FILLER)
#define K_HOR_SCROLLBAR TERMCAP2KEY(KS_HOR_SCROLLBAR, KE_FILLER)
#define K_NETTERM_MOUSE TERMCAP2KEY(KS_NETTERM_MOUSE, KE_FILLER)
#define K_DEC_MOUSE TERMCAP2KEY(KS_DEC_MOUSE, KE_FILLER)
#define K_JSBTERM_MOUSE TERMCAP2KEY(KS_JSBTERM_MOUSE, KE_FILLER)
#define K_PTERM_MOUSE TERMCAP2KEY(KS_PTERM_MOUSE, KE_FILLER)
#define K_URXVT_MOUSE TERMCAP2KEY(KS_URXVT_MOUSE, KE_FILLER)
#define K_SGR_MOUSE TERMCAP2KEY(KS_SGR_MOUSE, KE_FILLER)
#define K_SELECT TERMCAP2KEY(KS_SELECT, KE_FILLER)
#define K_TEAROFF TERMCAP2KEY(KS_TEAROFF, KE_FILLER)
#define K_TABLINE TERMCAP2KEY(KS_TABLINE, KE_FILLER)
#define K_TABMENU TERMCAP2KEY(KS_TABMENU, KE_FILLER)
/*
* Symbols for pseudo keys which are translated from the real key symbols
* above.
*/
#define K_LEFTMOUSE TERMCAP2KEY(KS_EXTRA, KE_LEFTMOUSE)
#define K_LEFTMOUSE_NM TERMCAP2KEY(KS_EXTRA, KE_LEFTMOUSE_NM)
#define K_LEFTDRAG TERMCAP2KEY(KS_EXTRA, KE_LEFTDRAG)
#define K_LEFTRELEASE TERMCAP2KEY(KS_EXTRA, KE_LEFTRELEASE)
#define K_LEFTRELEASE_NM TERMCAP2KEY(KS_EXTRA, KE_LEFTRELEASE_NM)
#define K_MIDDLEMOUSE TERMCAP2KEY(KS_EXTRA, KE_MIDDLEMOUSE)
#define K_MIDDLEDRAG TERMCAP2KEY(KS_EXTRA, KE_MIDDLEDRAG)
#define K_MIDDLERELEASE TERMCAP2KEY(KS_EXTRA, KE_MIDDLERELEASE)
#define K_RIGHTMOUSE TERMCAP2KEY(KS_EXTRA, KE_RIGHTMOUSE)
#define K_RIGHTDRAG TERMCAP2KEY(KS_EXTRA, KE_RIGHTDRAG)
#define K_RIGHTRELEASE TERMCAP2KEY(KS_EXTRA, KE_RIGHTRELEASE)
#define K_X1MOUSE TERMCAP2KEY(KS_EXTRA, KE_X1MOUSE)
#define K_X1MOUSE TERMCAP2KEY(KS_EXTRA, KE_X1MOUSE)
#define K_X1DRAG TERMCAP2KEY(KS_EXTRA, KE_X1DRAG)
#define K_X1RELEASE TERMCAP2KEY(KS_EXTRA, KE_X1RELEASE)
#define K_X2MOUSE TERMCAP2KEY(KS_EXTRA, KE_X2MOUSE)
#define K_X2DRAG TERMCAP2KEY(KS_EXTRA, KE_X2DRAG)
#define K_X2RELEASE TERMCAP2KEY(KS_EXTRA, KE_X2RELEASE)
#define K_IGNORE TERMCAP2KEY(KS_EXTRA, KE_IGNORE)
#define K_NOP TERMCAP2KEY(KS_EXTRA, KE_NOP)
#define K_MOUSEDOWN TERMCAP2KEY(KS_EXTRA, KE_MOUSEDOWN)
#define K_MOUSEUP TERMCAP2KEY(KS_EXTRA, KE_MOUSEUP)
#define K_MOUSELEFT TERMCAP2KEY(KS_EXTRA, KE_MOUSELEFT)
#define K_MOUSERIGHT TERMCAP2KEY(KS_EXTRA, KE_MOUSERIGHT)
#define K_CSI TERMCAP2KEY(KS_EXTRA, KE_CSI)
#define K_SNR TERMCAP2KEY(KS_EXTRA, KE_SNR)
#define K_PLUG TERMCAP2KEY(KS_EXTRA, KE_PLUG)
#define K_CMDWIN TERMCAP2KEY(KS_EXTRA, KE_CMDWIN)
#define K_DROP TERMCAP2KEY(KS_EXTRA, KE_DROP)
#define K_FOCUSGAINED TERMCAP2KEY(KS_EXTRA, KE_FOCUSGAINED)
#define K_FOCUSLOST TERMCAP2KEY(KS_EXTRA, KE_FOCUSLOST)
#define K_CURSORHOLD TERMCAP2KEY(KS_EXTRA, KE_CURSORHOLD)
#define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT)
/* Bits for modifier mask */
/* 0x01 cannot be used, because the modifier must be 0x02 or higher */
#define MOD_MASK_SHIFT 0x02
#define MOD_MASK_CTRL 0x04
#define MOD_MASK_ALT 0x08 /* aka META */
#define MOD_MASK_META 0x10 /* META when it's different from ALT */
#define MOD_MASK_2CLICK 0x20 /* use MOD_MASK_MULTI_CLICK */
#define MOD_MASK_3CLICK 0x40 /* use MOD_MASK_MULTI_CLICK */
#define MOD_MASK_4CLICK 0x60 /* use MOD_MASK_MULTI_CLICK */
#define MOD_MASK_MULTI_CLICK (MOD_MASK_2CLICK|MOD_MASK_3CLICK| \
MOD_MASK_4CLICK)
/*
* The length of the longest special key name, including modifiers.
* Current longest is <M-C-S-T-4-MiddleRelease> (length includes '<' and '>').
*/
#define MAX_KEY_NAME_LEN 25
/* Maximum length of a special key event as tokens. This includes modifiers.
* The longest event is something like <M-C-S-T-4-LeftDrag> which would be the
* following string of tokens:
*
* <K_SPECIAL> <KS_MODIFIER> bitmask <K_SPECIAL> <KS_EXTRA> <KT_LEFTDRAG>.
*
* This is a total of 6 tokens, and is currently the longest one possible.
*/
#define MAX_KEY_CODE_LEN 6
int name_to_mod_mask(int c);
int simplify_key(int key, int *modifiers);
int handle_x_keys(int key);
char_u *get_special_key_name(int c, int modifiers);
int trans_special(char_u **srcp, char_u *dst, int keycode);
int find_special_key(char_u **srcp, int *modp, int keycode,
int keep_x_key);
int extract_modifiers(int key, int *modp);
int find_special_key_in_table(int c);
int get_special_key_code(char_u *name);
char_u *get_key_name(int i);
int get_mouse_button(int code, int *is_click, int *is_drag);
int get_pseudo_mouse_code(int button, int is_click, int is_drag);
#endif /* NEOVIM_KEYMAP_H */

632
src/nvim/lib/khash.h Normal file
View File

@@ -0,0 +1,632 @@
/* The MIT License
Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
An example:
#include "khash.h"
KHASH_MAP_INIT_INT(32, char)
int main() {
int ret, is_missing;
khiter_t k;
khash_t(32) *h = kh_init(32);
k = kh_put(32, h, 5, &ret);
kh_value(h, k) = 10;
k = kh_get(32, h, 10);
is_missing = (k == kh_end(h));
k = kh_get(32, h, 5);
kh_del(32, h, k);
for (k = kh_begin(h); k != kh_end(h); ++k)
if (kh_exist(h, k)) kh_value(h, k) = 1;
kh_destroy(32, h);
return 0;
}
*/
/*
2013-05-02 (0.2.8):
* Use quadratic probing. When the capacity is power of 2, stepping function
i*(i+1)/2 guarantees to traverse each bucket. It is better than double
hashing on cache performance and is more robust than linear probing.
In theory, double hashing should be more robust than quadratic probing.
However, my implementation is probably not for large hash tables, because
the second hash function is closely tied to the first hash function,
which reduce the effectiveness of double hashing.
Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php
2011-12-29 (0.2.7):
* Minor code clean up; no actual effect.
2011-09-16 (0.2.6):
* The capacity is a power of 2. This seems to dramatically improve the
speed for simple keys. Thank Zilong Tan for the suggestion. Reference:
- http://code.google.com/p/ulib/
- http://nothings.org/computer/judy/
* Allow to optionally use linear probing which usually has better
performance for random input. Double hashing is still the default as it
is more robust to certain non-random input.
* Added Wang's integer hash function (not used by default). This hash
function is more robust to certain non-random input.
2011-02-14 (0.2.5):
* Allow to declare global functions.
2009-09-26 (0.2.4):
* Improve portability
2008-09-19 (0.2.3):
* Corrected the example
* Improved interfaces
2008-09-11 (0.2.2):
* Improved speed a little in kh_put()
2008-09-10 (0.2.1):
* Added kh_clear()
* Fixed a compiling error
2008-09-02 (0.2.0):
* Changed to token concatenation which increases flexibility.
2008-08-31 (0.1.2):
* Fixed a bug in kh_get(), which has not been tested previously.
2008-08-31 (0.1.1):
* Added destructor
*/
#ifndef __AC_KHASH_H
#define __AC_KHASH_H
/*!
@header
Generic hash table library.
*/
#define AC_VERSION_KHASH_H "0.2.8"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "func_attr.h"
#include "memory.h"
/* compiler specific configuration */
#if UINT_MAX == 0xffffffffu
typedef unsigned int khint32_t;
#elif ULONG_MAX == 0xffffffffu
typedef unsigned long khint32_t;
#endif
#if ULONG_MAX == ULLONG_MAX
typedef unsigned long khint64_t;
#else
typedef unsigned long long khint64_t;
#endif
#ifdef _MSC_VER
#define kh_inline __inline
#else
#define kh_inline inline
#endif
typedef khint32_t khint_t;
typedef khint_t khiter_t;
#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
#ifndef kroundup32
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
#endif
#ifndef kcalloc
#define kcalloc(N,Z) xcalloc(N,Z)
#endif
#ifndef kmalloc
#define kmalloc(Z) xmalloc(Z)
#endif
#ifndef krealloc
#define krealloc(P,Z) xrealloc(P,Z)
#endif
#ifndef kfree
#define kfree(P) free(P)
#endif
static const double __ac_HASH_UPPER = 0.77;
#define __KHASH_TYPE(name, khkey_t, khval_t) \
typedef struct { \
khint_t n_buckets, size, n_occupied, upper_bound; \
khint32_t *flags; \
khkey_t *keys; \
khval_t *vals; \
} kh_##name##_t;
#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
extern kh_##name##_t *kh_init_##name(void); \
extern void kh_destroy_##name(kh_##name##_t *h); \
extern void kh_clear_##name(kh_##name##_t *h); \
extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
extern void kh_del_##name(kh_##name##_t *h, khint_t x);
#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
SCOPE kh_##name##_t *kh_init_##name(void) { \
return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \
} \
SCOPE void kh_destroy_##name(kh_##name##_t *h) \
FUNC_ATTR_UNUSED; \
SCOPE void kh_destroy_##name(kh_##name##_t *h) \
{ \
if (h) { \
kfree((void *)h->keys); kfree(h->flags); \
kfree((void *)h->vals); \
kfree(h); \
} \
} \
SCOPE void kh_clear_##name(kh_##name##_t *h) \
FUNC_ATTR_UNUSED; \
SCOPE void kh_clear_##name(kh_##name##_t *h) \
{ \
if (h && h->flags) { \
memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
h->size = h->n_occupied = 0; \
} \
} \
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
FUNC_ATTR_UNUSED; \
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
{ \
if (h->n_buckets) { \
khint_t k, i, last, mask, step = 0; \
mask = h->n_buckets - 1; \
k = __hash_func(key); i = k & mask; \
last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
i = (i + (++step)) & mask; \
if (i == last) return h->n_buckets; \
} \
return __ac_iseither(h->flags, i)? h->n_buckets : i; \
} else return 0; \
} \
SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
FUNC_ATTR_UNUSED; \
SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
{ /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
khint32_t *new_flags = 0; \
khint_t j = 1; \
{ \
kroundup32(new_n_buckets); \
if (new_n_buckets < 4) new_n_buckets = 4; \
if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
else { /* hash table size to be changed (shrink or expand); rehash */ \
new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (!new_flags) return -1; \
memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (h->n_buckets < new_n_buckets) { /* expand */ \
khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (!new_keys) return -1; \
h->keys = new_keys; \
if (kh_is_map) { \
khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
if (!new_vals) return -1; \
h->vals = new_vals; \
} \
} /* otherwise shrink */ \
} \
} \
if (j) { /* rehashing is needed */ \
for (j = 0; j != h->n_buckets; ++j) { \
if (__ac_iseither(h->flags, j) == 0) { \
khkey_t key = h->keys[j]; \
khval_t val; \
khint_t new_mask; \
new_mask = new_n_buckets - 1; \
if (kh_is_map) val = h->vals[j]; \
__ac_set_isdel_true(h->flags, j); \
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
khint_t k, i, step = 0; \
k = __hash_func(key); \
i = k & new_mask; \
while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
__ac_set_isempty_false(new_flags, i); \
if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
__ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
} else { /* write the element and jump out of the loop */ \
h->keys[i] = key; \
if (kh_is_map) h->vals[i] = val; \
break; \
} \
} \
} \
} \
if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
} \
kfree(h->flags); /* free the working space */ \
h->flags = new_flags; \
h->n_buckets = new_n_buckets; \
h->n_occupied = h->size; \
h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
} \
return 0; \
} \
SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
FUNC_ATTR_UNUSED; \
SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
{ \
khint_t x; \
if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
if (h->n_buckets > (h->size<<1)) { \
if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
*ret = -1; return h->n_buckets; \
} \
} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
*ret = -1; return h->n_buckets; \
} \
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
{ \
khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
else { \
last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
if (__ac_isdel(h->flags, i)) site = i; \
i = (i + (++step)) & mask; \
if (i == last) { x = site; break; } \
} \
if (x == h->n_buckets) { \
if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
else x = i; \
} \
} \
} \
if (__ac_isempty(h->flags, x)) { /* not present at all */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; ++h->n_occupied; \
*ret = 1; \
} else if (__ac_isdel(h->flags, x)) { /* deleted */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; \
*ret = 2; \
} else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
return x; \
} \
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
FUNC_ATTR_UNUSED; \
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
{ \
if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
__ac_set_isdel_true(h->flags, x); \
--h->size; \
} \
}
#define KHASH_DECLARE(name, khkey_t, khval_t) \
__KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_PROTOTYPES(name, khkey_t, khval_t)
#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
__KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
/* --- BEGIN OF HASH FUNCTIONS --- */
/*! @function
@abstract Integer hash function
@param key The integer [khint32_t]
@return The hash value [khint_t]
*/
#define kh_int_hash_func(key) (khint32_t)(key)
/*! @function
@abstract Integer comparison function
*/
#define kh_int_hash_equal(a, b) ((a) == (b))
/*! @function
@abstract 64-bit integer hash function
@param key The integer [khint64_t]
@return The hash value [khint_t]
*/
#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11)
/*! @function
@abstract 64-bit integer comparison function
*/
#define kh_int64_hash_equal(a, b) ((a) == (b))
/*! @function
@abstract const char* hash function
@param s Pointer to a null terminated string
@return The hash value
*/
static kh_inline khint_t __ac_X31_hash_string(const char *s)
{
khint_t h = (khint_t)*s;
if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
return h;
}
/*! @function
@abstract Another interface to const char* hash function
@param key Pointer to a null terminated string [const char*]
@return The hash value [khint_t]
*/
#define kh_str_hash_func(key) __ac_X31_hash_string(key)
/*! @function
@abstract Const char* comparison function
*/
#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)
static kh_inline khint_t __ac_Wang_hash(khint_t key)
{
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
#define kh_int_hash_func2(k) __ac_Wang_hash((khint_t)key)
/* --- END OF HASH FUNCTIONS --- */
/* Other convenient macros... */
/*!
@abstract Type of the hash table.
@param name Name of the hash table [symbol]
*/
#define khash_t(name) kh_##name##_t
/*! @function
@abstract Initiate a hash table.
@param name Name of the hash table [symbol]
@return Pointer to the hash table [khash_t(name)*]
*/
#define kh_init(name) kh_init_##name()
/*! @function
@abstract Destroy a hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
*/
#define kh_destroy(name, h) kh_destroy_##name(h)
/*! @function
@abstract Reset a hash table without deallocating memory.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
*/
#define kh_clear(name, h) kh_clear_##name(h)
/*! @function
@abstract Resize a hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param s New size [khint_t]
*/
#define kh_resize(name, h, s) kh_resize_##name(h, s)
/*! @function
@abstract Insert a key to the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Key [type of keys]
@param r Extra return code: -1 if the operation failed;
0 if the key is present in the hash table;
1 if the bucket is empty (never used); 2 if the element in
the bucket has been deleted [int*]
@return Iterator to the inserted element [khint_t]
*/
#define kh_put(name, h, k, r) kh_put_##name(h, k, r)
/*! @function
@abstract Retrieve a key from the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Key [type of keys]
@return Iterator to the found element, or kh_end(h) if the element is absent [khint_t]
*/
#define kh_get(name, h, k) kh_get_##name(h, k)
/*! @function
@abstract Remove a key from the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Iterator to the element to be deleted [khint_t]
*/
#define kh_del(name, h, k) kh_del_##name(h, k)
/*! @function
@abstract Test whether a bucket contains data.
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return 1 if containing data; 0 otherwise [int]
*/
#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
/*! @function
@abstract Get key given an iterator
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return Key [type of keys]
*/
#define kh_key(h, x) ((h)->keys[x])
/*! @function
@abstract Get value given an iterator
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return Value [type of values]
@discussion For hash sets, calling this results in segfault.
*/
#define kh_val(h, x) ((h)->vals[x])
/*! @function
@abstract Alias of kh_val()
*/
#define kh_value(h, x) ((h)->vals[x])
/*! @function
@abstract Get the start iterator
@param h Pointer to the hash table [khash_t(name)*]
@return The start iterator [khint_t]
*/
#define kh_begin(h) (khint_t)(0)
/*! @function
@abstract Get the end iterator
@param h Pointer to the hash table [khash_t(name)*]
@return The end iterator [khint_t]
*/
#define kh_end(h) ((h)->n_buckets)
/*! @function
@abstract Get the number of elements in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@return Number of elements in the hash table [khint_t]
*/
#define kh_size(h) ((h)->size)
/*! @function
@abstract Get the number of buckets in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@return Number of buckets in the hash table [khint_t]
*/
#define kh_n_buckets(h) ((h)->n_buckets)
/*! @function
@abstract Iterate over the entries in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@param kvar Variable to which key will be assigned
@param vvar Variable to which value will be assigned
@param code Block of code to execute
*/
#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(kvar) = kh_key(h,__i); \
(vvar) = kh_val(h,__i); \
code; \
} }
/*! @function
@abstract Iterate over the values in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@param vvar Variable to which value will be assigned
@param code Block of code to execute
*/
#define kh_foreach_value(h, vvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(vvar) = kh_val(h,__i); \
code; \
} }
/* More conenient interfaces */
/*! @function
@abstract Instantiate a hash set containing integer keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_INT(name) \
KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
/*! @function
@abstract Instantiate a hash map containing integer keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_INT(name, khval_t) \
KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
/*! @function
@abstract Instantiate a hash map containing 64-bit integer keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_INT64(name) \
KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
/*! @function
@abstract Instantiate a hash map containing 64-bit integer keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_INT64(name, khval_t) \
KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)
typedef const char *kh_cstr_t;
/*! @function
@abstract Instantiate a hash map containing const char* keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_STR(name) \
KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
/*! @function
@abstract Instantiate a hash map containing const char* keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_STR(name, khval_t) \
KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
#endif /* __AC_KHASH_H */

128
src/nvim/lib/klist.h Normal file
View File

@@ -0,0 +1,128 @@
/* The MIT License
Copyright (c) 2008-2009, by Attractive Chaos <attractor@live.co.uk>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef _AC_KLIST_H
#define _AC_KLIST_H
#include <stdbool.h>
#include <stdlib.h>
#include "func_attr.h"
#include "memory.h"
#define KMEMPOOL_INIT(name, kmptype_t, kmpfree_f) \
typedef struct { \
size_t cnt, n, max; \
kmptype_t **buf; \
} kmp_##name##_t; \
static inline kmp_##name##_t *kmp_init_##name() { \
return xcalloc(1, sizeof(kmp_##name##_t)); \
} \
static inline void kmp_destroy_##name(kmp_##name##_t *mp) { \
size_t k; \
for (k = 0; k < mp->n; ++k) { \
kmpfree_f(mp->buf[k]); free(mp->buf[k]); \
} \
free(mp->buf); free(mp); \
} \
static inline kmptype_t *kmp_alloc_##name(kmp_##name##_t *mp) { \
++mp->cnt; \
if (mp->n == 0) return xcalloc(1, sizeof(kmptype_t)); \
return mp->buf[--mp->n]; \
} \
static inline void kmp_free_##name(kmp_##name##_t *mp, kmptype_t *p) { \
--mp->cnt; \
if (mp->n == mp->max) { \
mp->max = mp->max? mp->max<<1 : 16; \
mp->buf = xrealloc(mp->buf, sizeof(void*) * mp->max); \
} \
mp->buf[mp->n++] = p; \
}
#define kmempool_t(name) kmp_##name##_t
#define kmp_init(name) kmp_init_##name()
#define kmp_destroy(name, mp) kmp_destroy_##name(mp)
#define kmp_alloc(name, mp) kmp_alloc_##name(mp)
#define kmp_free(name, mp, p) kmp_free_##name(mp, p)
#define KLIST_INIT(name, kltype_t, kmpfree_t) \
struct __kl1_##name { \
kltype_t data; \
struct __kl1_##name *next; \
}; \
typedef struct __kl1_##name kl1_##name; \
KMEMPOOL_INIT(name, kl1_##name, kmpfree_t) \
typedef struct { \
kl1_##name *head, *tail; \
kmp_##name##_t *mp; \
size_t size; \
} kl_##name##_t; \
static inline kl_##name##_t *kl_init_##name() { \
kl_##name##_t *kl = xcalloc(1, sizeof(kl_##name##_t)); \
kl->mp = kmp_init(name); \
kl->head = kl->tail = kmp_alloc(name, kl->mp); \
kl->head->next = 0; \
return kl; \
} \
static inline void kl_destroy_##name(kl_##name##_t *kl) \
FUNC_ATTR_UNUSED; \
static inline void kl_destroy_##name(kl_##name##_t *kl) { \
kl1_##name *p; \
for (p = kl->head; p != kl->tail; p = p->next) \
kmp_free(name, kl->mp, p); \
kmp_free(name, kl->mp, p); \
kmp_destroy(name, kl->mp); \
free(kl); \
} \
static inline kltype_t *kl_pushp_##name(kl_##name##_t *kl) { \
kl1_##name *q, *p = kmp_alloc(name, kl->mp); \
q = kl->tail; p->next = 0; kl->tail->next = p; kl->tail = p; \
++kl->size; \
return &q->data; \
} \
static inline int kl_shift_##name(kl_##name##_t *kl, kltype_t *d) { \
kl1_##name *p; \
if (kl->head->next == 0) return -1; \
--kl->size; \
p = kl->head; kl->head = kl->head->next; \
if (d) *d = p->data; \
kmp_free(name, kl->mp, p); \
return 0; \
}
#define kliter_t(name) kl1_##name
#define klist_t(name) kl_##name##_t
#define kl_val(iter) ((iter)->data)
#define kl_next(iter) ((iter)->next)
#define kl_begin(kl) ((kl)->head)
#define kl_end(kl) ((kl)->tail)
#define kl_init(name) kl_init_##name()
#define kl_destroy(name, kl) kl_destroy_##name(kl)
#define kl_pushp(name, kl) kl_pushp_##name(kl)
#define kl_shift(name, kl, d) kl_shift_##name(kl, d)
#define kl_empty(kl) ((kl)->size == 0)
#endif

147
src/nvim/log.c Normal file
View File

@@ -0,0 +1,147 @@
#include <assert.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include "log.h"
#include "misc1.h"
#include "types.h"
#include "os/os.h"
#include "os/time.h"
#define USR_LOG_FILE "$HOME/.nvimlog"
static FILE *open_log_file(void);
static bool do_log_to_file(FILE *log_file, int log_level,
const char *func_name, int line_num,
const char* fmt, ...);
static bool v_do_log_to_file(FILE *log_file, int log_level,
const char *func_name, int line_num,
const char* fmt, va_list args);
bool do_log(int log_level, const char *func_name, int line_num,
const char* fmt, ...)
{
FILE *log_file = open_log_file();
if (log_file == NULL) {
return false;
}
va_list args;
va_start(args, fmt);
bool ret = v_do_log_to_file(log_file, log_level, func_name, line_num, fmt,
args);
va_end(args);
if (log_file != stderr && log_file != stdout) {
fclose(log_file);
}
return ret;
}
/// Open the log file for appending.
///
/// @return The FILE* specified by the USR_LOG_FILE path or stderr in case of
/// error
static FILE *open_log_file(void)
{
static bool opening_log_file = false;
// check if it's a recursive call
if (opening_log_file) {
do_log_to_file(stderr, ERROR_LOG_LEVEL, __func__, __LINE__,
"Trying to LOG() recursively! Please fix it.");
return stderr;
}
// expand USR_LOG_FILE and open the file
FILE *log_file;
opening_log_file = true;
{
static char expanded_log_file_path[MAXPATHL + 1];
expand_env((char_u *)USR_LOG_FILE, (char_u *)expanded_log_file_path,
MAXPATHL);
// if the log file path expansion failed then fall back to stderr
if (strcmp(USR_LOG_FILE, expanded_log_file_path) == 0) {
goto open_log_file_error;
}
log_file = fopen(expanded_log_file_path, "a");
if (log_file == NULL) {
goto open_log_file_error;
}
}
opening_log_file = false;
return log_file;
open_log_file_error:
opening_log_file = false;
do_log_to_file(stderr, ERROR_LOG_LEVEL, __func__, __LINE__,
"Couldn't open USR_LOG_FILE, logging to stderr! This may be "
"caused by attempting to LOG() before initialization "
"functions are called (e.g. init_homedir()).");
return stderr;
}
static bool do_log_to_file(FILE *log_file, int log_level,
const char *func_name, int line_num,
const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
bool ret = v_do_log_to_file(log_file, log_level, func_name, line_num, fmt,
args);
va_end(args);
return ret;
}
static bool v_do_log_to_file(FILE *log_file, int log_level,
const char *func_name, int line_num,
const char* fmt, va_list args)
{
static const char *log_levels[] = {
[DEBUG_LOG_LEVEL] = "debug",
[INFO_LOG_LEVEL] = "info",
[WARNING_LOG_LEVEL] = "warning",
[ERROR_LOG_LEVEL] = "error"
};
assert(log_level >= DEBUG_LOG_LEVEL && log_level <= ERROR_LOG_LEVEL);
// format current timestamp in local time
struct tm local_time;
if (os_get_localtime(&local_time) == NULL) {
return false;
}
char date_time[20];
if (strftime(date_time, sizeof(date_time), "%Y/%m/%d %H:%M:%S",
&local_time) == 0) {
return false;
}
// print the log message prefixed by the current timestamp and pid
int64_t pid = os_get_pid();
if (fprintf(log_file, "%s [%s @ %s:%d] %" PRId64 " - ", date_time,
log_levels[log_level], func_name, line_num, pid) < 0) {
return false;
}
if (vfprintf(log_file, fmt, args) < 0) {
return false;
}
fputc('\n', log_file);
if (fflush(log_file) == EOF) {
return false;
}
return true;
}

57
src/nvim/log.h Normal file
View File

@@ -0,0 +1,57 @@
#ifndef NEOVIM_LOG_H
#define NEOVIM_LOG_H
#include <stdbool.h>
#include "func_attr.h"
#define DEBUG_LOG_LEVEL 0
#define INFO_LOG_LEVEL 1
#define WARNING_LOG_LEVEL 2
#define ERROR_LOG_LEVEL 3
bool do_log(int log_level, const char *func_name, int line_num,
const char* fmt, ...) FUNC_ATTR_UNUSED;
#define DLOG(...)
#define ILOG(...)
#define WLOG(...)
#define ELOG(...)
// Logging is disabled if NDEBUG or DISABLE_LOG is defined.
#ifdef NDEBUG
# define DISABLE_LOG
#endif
// MIN_LOG_LEVEL can be defined during compilation to adjust the desired level
// of logging. DEBUG_LOG_LEVEL is used by default.
#ifndef MIN_LOG_LEVEL
# define MIN_LOG_LEVEL DEBUG_LOG_LEVEL
#endif
#ifndef DISABLE_LOG
# if MIN_LOG_LEVEL <= DEBUG_LOG_LEVEL
# undef DLOG
# define DLOG(...) do_log(DEBUG_LOG_LEVEL, __func__, __LINE__, __VA_ARGS__)
# endif
# if MIN_LOG_LEVEL <= INFO_LOG_LEVEL
# undef ILOG
# define ILOG(...) do_log(INFO_LOG_LEVEL, __func__, __LINE__, __VA_ARGS__)
# endif
# if MIN_LOG_LEVEL <= WARNING_LOG_LEVEL
# undef WLOG
# define WLOG(...) do_log(WARNING_LOG_LEVEL, __func__, __LINE__, __VA_ARGS__)
# endif
# if MIN_LOG_LEVEL <= ERROR_LOG_LEVEL
# undef ELOG
# define ELOG(...) do_log(ERROR_LOG_LEVEL, __func__, __LINE__, __VA_ARGS__)
# endif
#endif
#endif // NEOVIM_LOG_H

151
src/nvim/macros.h Normal file
View File

@@ -0,0 +1,151 @@
#ifndef NEOVIM_MACROS_H
#define NEOVIM_MACROS_H
/*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
*/
/*
* macros.h: macro definitions for often used code
*/
/*
* Position comparisons
*/
# define lt(a, b) (((a).lnum != (b).lnum) \
? (a).lnum < (b).lnum \
: (a).col != (b).col \
? (a).col < (b).col \
: (a).coladd < (b).coladd)
# define ltp(a, b) (((a)->lnum != (b)->lnum) \
? (a)->lnum < (b)->lnum \
: (a)->col != (b)->col \
? (a)->col < (b)->col \
: (a)->coladd < (b)->coladd)
# define equalpos(a, b) (((a).lnum == (b).lnum) && ((a).col == (b).col) && \
((a).coladd == (b).coladd))
# define clearpos(a) {(a)->lnum = 0; (a)->col = 0; (a)->coladd = 0; }
#define ltoreq(a, b) (lt(a, b) || equalpos(a, b))
/*
* lineempty() - return TRUE if the line is empty
*/
#define lineempty(p) (*ml_get(p) == NUL)
/*
* bufempty() - return TRUE if the current buffer is empty
*/
#define bufempty() (curbuf->b_ml.ml_line_count == 1 && *ml_get((linenr_T)1) == \
NUL)
/*
* toupper() and tolower() that use the current locale.
* Careful: Only call TOUPPER_LOC() and TOLOWER_LOC() with a character in the
* range 0 - 255. toupper()/tolower() on some systems can't handle others.
* Note: It is often better to use vim_tolower() and vim_toupper(), because many
* toupper() and tolower() implementations only work for ASCII.
*/
#define TOUPPER_LOC toupper
#define TOLOWER_LOC tolower
/* toupper() and tolower() for ASCII only and ignore the current locale. */
# define TOUPPER_ASC(c) (((c) < 'a' || (c) > 'z') ? (c) : (c) - ('a' - 'A'))
# define TOLOWER_ASC(c) (((c) < 'A' || (c) > 'Z') ? (c) : (c) + ('a' - 'A'))
/* Use our own isdigit() replacement, because on MS-Windows isdigit() returns
* non-zero for superscript 1. Also avoids that isdigit() crashes for numbers
* below 0 and above 255. */
#define VIM_ISDIGIT(c) ((unsigned)(c) - '0' < 10)
/* Like isalpha() but reject non-ASCII characters. Can't be used with a
* special key (negative value). */
# define ASCII_ISLOWER(c) ((unsigned)(c) - 'a' < 26)
# define ASCII_ISUPPER(c) ((unsigned)(c) - 'A' < 26)
# define ASCII_ISALPHA(c) (ASCII_ISUPPER(c) || ASCII_ISLOWER(c))
# define ASCII_ISALNUM(c) (ASCII_ISALPHA(c) || VIM_ISDIGIT(c))
/* macro version of chartab().
* Only works with values 0-255!
* Doesn't work for UTF-8 mode with chars >= 0x80. */
#define CHARSIZE(c) (chartab[c] & CT_CELL_MASK)
/*
* Adjust chars in a language according to 'langmap' option.
* NOTE that there is no noticeable overhead if 'langmap' is not set.
* When set the overhead for characters < 256 is small.
* Don't apply 'langmap' if the character comes from the Stuff buffer.
* The do-while is just to ignore a ';' after the macro.
*/
# define LANGMAP_ADJUST(c, condition) \
do { \
if (*p_langmap && (condition) && !KeyStuffed && (c) >= 0) \
{ \
if ((c) < 256) \
c = langmap_mapchar[c]; \
else \
c = langmap_adjust_mb(c); \
} \
} while (0)
/*
* vim_isbreak() is used very often if 'linebreak' is set, use a macro to make
* it work fast.
*/
#define vim_isbreak(c) (breakat_flags[(char_u)(c)])
# define mch_fopen(n, p) fopen((n), (p))
# define mch_open(n, m, p) open((n), (m), (p))
/* mch_open_rw(): invoke mch_open() with third argument for user R/W. */
#if defined(UNIX) /* open in rw------- mode */
# define mch_open_rw(n, f) mch_open((n), (f), (mode_t)0600)
#else
# define mch_open_rw(n, f) mch_open((n), (f), 0)
#endif
#ifdef STARTUPTIME
# define TIME_MSG(s) { if (time_fd != NULL) time_msg(s, NULL); }
#else
# define TIME_MSG(s)
#endif
# define REPLACE_NORMAL(s) (((s) & REPLACE_FLAG) && !((s) & VREPLACE_FLAG))
# define UTF_COMPOSINGLIKE(p1, p2) utf_composinglike((p1), (p2))
/* Whether to draw the vertical bar on the right side of the cell. */
# define CURSOR_BAR_RIGHT (curwin->w_p_rl && (!(State & CMDLINE) || cmdmsg_rl))
/*
* mb_ptr_adv(): advance a pointer to the next character, taking care of
* multi-byte characters if needed.
* mb_ptr_back(): backup a pointer to the previous character, taking care of
* multi-byte characters if needed.
* MB_COPY_CHAR(f, t): copy one char from "f" to "t" and advance the pointers.
* PTR2CHAR(): get character from pointer.
*/
/* Get the length of the character p points to */
# define MB_PTR2LEN(p) (has_mbyte ? (*mb_ptr2len)(p) : 1)
/* Advance multi-byte pointer, skip over composing chars. */
# define mb_ptr_adv(p) p += has_mbyte ? (*mb_ptr2len)(p) : 1
/* Advance multi-byte pointer, do not skip over composing chars. */
# define mb_cptr_adv(p) p += \
enc_utf8 ? utf_ptr2len(p) : has_mbyte ? (*mb_ptr2len)(p) : 1
/* Backup multi-byte pointer. */
# define mb_ptr_back(s, p) p -= has_mbyte ? ((*mb_head_off)(s, p - 1) + 1) : 1
/* get length of multi-byte char, not including composing chars */
# define mb_cptr2len(p) (enc_utf8 ? utf_ptr2len(p) : (*mb_ptr2len)(p))
# define MB_COPY_CHAR(f, \
t) if (has_mbyte) mb_copy_char(&f, &t); else *t++ = *f++
# define MB_CHARLEN(p) (has_mbyte ? mb_charlen(p) : (int)STRLEN(p))
# define MB_CHAR2LEN(c) (has_mbyte ? mb_char2len(c) : 1)
# define PTR2CHAR(p) (has_mbyte ? mb_ptr2char(p) : (int)*(p))
# define RESET_BINDING(wp) (wp)->w_p_scb = FALSE; (wp)->w_p_crb = FALSE
#endif // NEOVIM_MACROS_H

2367
src/nvim/main.c Normal file

File diff suppressed because it is too large Load Diff

16
src/nvim/main.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef NEOVIM_MAIN_H
#define NEOVIM_MAIN_H
#include "normal.h"
void main_loop(int cmdwin, int noexmode);
void getout(int exitval);
int process_env(char_u *env, int is_viminit);
void mainerr_arg_missing(char_u *str);
void time_push(void *tv_rel, void *tv_start);
void time_pop(void *tp);
void time_msg(char *mesg, void *tv_start);
char_u *eval_client_expr_to_string(char_u *expr);
char_u *serverConvert(char_u *client_enc, char_u *data, char_u **tofree);
#endif /* NEOVIM_MAIN_H */

91
src/nvim/map.c Normal file
View File

@@ -0,0 +1,91 @@
#include <stdlib.h>
#include <stdbool.h>
#include "map.h"
#include "map_defs.h"
#include "vim.h"
#include "memory.h"
#include "lib/khash.h"
typedef struct {
void *ptr;
} Value;
KHASH_MAP_INIT_STR(Map, Value)
struct map {
khash_t(Map) *table;
};
Map *map_new()
{
Map *rv = xmalloc(sizeof(Map));
rv->table = kh_init(Map);
return rv;
}
void map_free(Map *map)
{
kh_clear(Map, map->table);
kh_destroy(Map, map->table);
free(map);
}
void *map_get(Map *map, const char *key)
{
khiter_t k;
if ((k = kh_get(Map, map->table, key)) == kh_end(map->table)) {
return NULL;
}
return kh_val(map->table, k).ptr;
}
bool map_has(Map *map, const char *key)
{
return map_get(map, key) != NULL;
}
void *map_put(Map *map, const char *key, void *value)
{
int ret;
void *rv = NULL;
khiter_t k = kh_put(Map, map->table, key, &ret);
Value val = {.ptr = value};
if (!ret) {
// key present, return the current value
rv = kh_val(map->table, k).ptr;
kh_del(Map, map->table, k);
}
kh_val(map->table, k) = val;
return rv;
}
void *map_del(Map *map, const char *key)
{
void *rv = NULL;
khiter_t k;
if ((k = kh_get(Map, map->table, key)) != kh_end(map->table)) {
rv = kh_val(map->table, k).ptr;
kh_del(Map, map->table, k);
}
return rv;
}
void map_foreach(Map *map, key_value_cb cb)
{
const char *key;
Value value;
kh_foreach(map->table, key, value, {
cb(map, (const char *)key, value.ptr);
});
}

57
src/nvim/map.h Normal file
View File

@@ -0,0 +1,57 @@
// General-purpose string->pointer associative array with a simple API
#ifndef NEOVIM_MAP_H
#define NEOVIM_MAP_H
#include <stdbool.h>
#include "map_defs.h"
/// Creates a new `Map` instance
///
/// @return a pointer to the new instance
Map *map_new(void);
/// Frees memory for a `Map` instance
///
/// @param map The `Map` instance
void map_free(Map *map);
/// Gets the value corresponding to a key in a `Map` instance
///
/// @param map The `Map` instance
/// @param key A key string
/// @return The value if the key exists in the map, or NULL if it doesn't
void *map_get(Map *map, const char *key);
/// Checks if a key exists in the map
///
/// @param map The `Map` instance
/// @param key A key string
/// @return true if the key exists, false otherwise
bool map_has(Map *map, const char *key);
/// Set the value corresponding to a key in a `Map` instance and returns
/// the old value.
///
/// @param map The `Map` instance
/// @param key A key string
/// @param value A value
/// @return The current value if exists or NULL otherwise
void *map_put(Map *map, const char *key, void *value);
/// Deletes the value corresponding to a key in a `Map` instance and returns
/// the old value.
///
/// @param map The `Map` instance
/// @param key A key string
/// @return The current value if exists or NULL otherwise
void *map_del(Map *map, const char *key);
/// Iterates through each key/value pair in the map
///
/// @param map The `Map` instance
/// @param cb A function that will be called for each key/value
void map_foreach(Map *map, key_value_cb cb);
#endif /* NEOVIM_MAP_H */

14
src/nvim/map_defs.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef NEOVIM_MAP_DEFS_H
#define NEOVIM_MAP_DEFS_H
typedef struct map Map;
/// Callback for iterating through each key/value pair in a map
///
/// @param map The `Map` instance
/// @param key A key string
/// @param value A value
typedef void (*key_value_cb)(Map *map, const char *key, void *value);
#endif /* NEOVIM_MAP_DEFS_H */

1539
src/nvim/mark.c Normal file

File diff suppressed because it is too large Load Diff

42
src/nvim/mark.h Normal file
View File

@@ -0,0 +1,42 @@
#ifndef NEOVIM_MARK_H
#define NEOVIM_MARK_H
#include "buffer_defs.h"
#include "mark_defs.h"
#include "pos.h"
/* mark.c */
int setmark(int c);
int setmark_pos(int c, pos_T *pos, int fnum);
void setpcmark(void);
void checkpcmark(void);
pos_T *movemark(int count);
pos_T *movechangelist(int count);
pos_T *getmark_buf(buf_T *buf, int c, int changefile);
pos_T *getmark(int c, int changefile);
pos_T *getmark_buf_fnum(buf_T *buf, int c, int changefile, int *fnum);
pos_T *getnextmark(pos_T *startpos, int dir, int begin_line);
void fmarks_check_names(buf_T *buf);
int check_mark(pos_T *pos);
void clrallmarks(buf_T *buf);
char_u *fm_getname(fmark_T *fmark, int lead_len);
void do_marks(exarg_T *eap);
void ex_delmarks(exarg_T *eap);
void ex_jumps(exarg_T *eap);
void ex_changes(exarg_T *eap);
void mark_adjust(linenr_T line1, linenr_T line2, long amount,
long amount_after);
void mark_col_adjust(linenr_T lnum, colnr_T mincol, long lnum_amount,
long col_amount);
void copy_jumplist(win_T *from, win_T *to);
void free_jumplist(win_T *wp);
void set_last_cursor(win_T *win);
void free_all_marks(void);
int read_viminfo_filemark(vir_T *virp, int force);
void write_viminfo_filemarks(FILE *fp);
int removable(char_u *name);
int write_viminfo_marks(FILE *fp_out);
void copy_viminfo_marks(vir_T *virp, FILE *fp_out, int count, int eof,
int flags);
#endif /* NEOVIM_MARK_H */

29
src/nvim/mark_defs.h Normal file
View File

@@ -0,0 +1,29 @@
#ifndef NEOVIM_MARK_DEFS_H
#define NEOVIM_MARK_DEFS_H
#include "pos.h"
/*
* marks: positions in a file
* (a normal mark is a lnum/col pair, the same as a file position)
*/
/* (Note: for EBCDIC there are more than 26, because there are gaps in the
* alphabet coding. To minimize changes to the code, I decided to just
* increase the number of possible marks. */
#define NMARKS ('z' - 'a' + 1) /* max. # of named marks */
#define JUMPLISTSIZE 100 /* max. # of marks in jump list */
#define TAGSTACKSIZE 20 /* max. # of tags in tag stack */
typedef struct filemark {
pos_T mark; /* cursor position */
int fnum; /* file number */
} fmark_T;
/* Xtended file mark: also has a file name */
typedef struct xfilemark {
fmark_T fmark;
char_u *fname; /* file name, used when fnum == 0 */
} xfmark_T;
#endif // NEOVIM_MARK_DEFS_H

4041
src/nvim/mbyte.c Normal file

File diff suppressed because it is too large Load Diff

87
src/nvim/mbyte.h Normal file
View File

@@ -0,0 +1,87 @@
#ifndef NEOVIM_MBYTE_H
#define NEOVIM_MBYTE_H
/* mbyte.c */
int enc_canon_props(char_u *name);
char_u *mb_init(void);
int bomb_size(void);
void remove_bom(char_u *s);
int mb_get_class(char_u *p);
int mb_get_class_buf(char_u *p, buf_T *buf);
int dbcs_class(unsigned lead, unsigned trail);
int latin_char2len(int c);
int latin_char2bytes(int c, char_u *buf);
int latin_ptr2len(char_u *p);
int latin_ptr2len_len(char_u *p, int size);
int utf_char2cells(int c);
int latin_ptr2cells(char_u *p);
int utf_ptr2cells(char_u *p);
int dbcs_ptr2cells(char_u *p);
int latin_ptr2cells_len(char_u *p, int size);
int latin_char2cells(int c);
int mb_string2cells(char_u *p, int len);
int latin_off2cells(unsigned off, unsigned max_off);
int dbcs_off2cells(unsigned off, unsigned max_off);
int utf_off2cells(unsigned off, unsigned max_off);
int latin_ptr2char(char_u *p);
int utf_ptr2char(char_u *p);
int mb_ptr2char_adv(char_u **pp);
int mb_cptr2char_adv(char_u **pp);
int arabic_combine(int one, int two);
int arabic_maycombine(int two);
int utf_composinglike(char_u *p1, char_u *p2);
int utfc_ptr2char(char_u *p, int *pcc);
int utfc_ptr2char_len(char_u *p, int *pcc, int maxlen);
int utfc_char2bytes(int off, char_u *buf);
int utf_ptr2len(char_u *p);
int utf_byte2len(int b);
int utf_ptr2len_len(char_u *p, int size);
int utfc_ptr2len(char_u *p);
int utfc_ptr2len_len(char_u *p, int size);
int utf_char2len(int c);
int utf_char2bytes(int c, char_u *buf);
int utf_iscomposing(int c);
int utf_printable(int c);
int utf_class(int c);
int utf_fold(int a);
int utf_toupper(int a);
int utf_islower(int a);
int utf_tolower(int a);
int utf_isupper(int a);
int mb_strnicmp(char_u *s1, char_u *s2, size_t nn);
void show_utf8(void);
int latin_head_off(char_u *base, char_u *p);
int dbcs_head_off(char_u *base, char_u *p);
int dbcs_screen_head_off(char_u *base, char_u *p);
int utf_head_off(char_u *base, char_u *p);
void mb_copy_char(char_u **fp, char_u **tp);
int mb_off_next(char_u *base, char_u *p);
int mb_tail_off(char_u *base, char_u *p);
void utf_find_illegal(void);
void mb_adjust_cursor(void);
void mb_adjustpos(buf_T *buf, pos_T *lp);
char_u *mb_prevptr(char_u *line, char_u *p);
int mb_charlen(char_u *str);
int mb_charlen_len(char_u *str, int len);
char_u *mb_unescape(char_u **pp);
int mb_lefthalve(int row, int col);
int mb_fix_col(int col, int row);
char_u *enc_skip(char_u *p);
char_u *enc_canonize(char_u *enc);
char_u *enc_locale(void);
void *my_iconv_open(char_u *to, char_u *from);
int iconv_enabled(int verbose);
void iconv_end(void);
void im_set_active(int active);
int im_get_status(void);
int convert_setup(vimconv_T *vcp, char_u *from, char_u *to);
int convert_setup_ext(vimconv_T *vcp, char_u *from,
int from_unicode_is_utf8, char_u *to,
int to_unicode_is_utf8);
int convert_input(char_u *ptr, int len, int maxlen);
int convert_input_safe(char_u *ptr, int len, int maxlen, char_u **restp,
int *restlenp);
char_u *string_convert(vimconv_T *vcp, char_u *ptr, int *lenp);
char_u *string_convert_ext(vimconv_T *vcp, char_u *ptr, int *lenp,
int *unconvlenp);
#endif /* NEOVIM_MBYTE_H */

1260
src/nvim/memfile.c Normal file

File diff suppressed because it is too large Load Diff

25
src/nvim/memfile.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef NEOVIM_MEMFILE_H
#define NEOVIM_MEMFILE_H
#include "buffer_defs.h"
#include "memfile_defs.h"
/* memfile.c */
memfile_T *mf_open(char_u *fname, int flags);
int mf_open_file(memfile_T *mfp, char_u *fname);
void mf_close(memfile_T *mfp, int del_file);
void mf_close_file(buf_T *buf, int getlines);
void mf_new_page_size(memfile_T *mfp, unsigned new_size);
bhdr_T *mf_new(memfile_T *mfp, int negative, int page_count);
bhdr_T *mf_get(memfile_T *mfp, blocknr_T nr, int page_count);
void mf_put(memfile_T *mfp, bhdr_T *hp, int dirty, int infile);
void mf_free(memfile_T *mfp, bhdr_T *hp);
int mf_sync(memfile_T *mfp, int flags);
void mf_set_dirty(memfile_T *mfp);
int mf_release_all(void);
blocknr_T mf_trans_del(memfile_T *mfp, blocknr_T old_nr);
void mf_set_ffname(memfile_T *mfp);
void mf_fullname(memfile_T *mfp);
int mf_need_trans(memfile_T *mfp);
#endif /* NEOVIM_MEMFILE_H */

107
src/nvim/memfile_defs.h Normal file
View File

@@ -0,0 +1,107 @@
#ifndef NEOVIM_MEMFILE_DEFS_H
#define NEOVIM_MEMFILE_DEFS_H
typedef struct block_hdr bhdr_T;
typedef long blocknr_T;
/*
* mf_hashtab_T is a chained hashtable with blocknr_T key and arbitrary
* structures as items. This is an intrusive data structure: we require
* that items begin with mf_hashitem_T which contains the key and linked
* list pointers. List of items in each bucket is doubly-linked.
*/
typedef struct mf_hashitem_S mf_hashitem_T;
struct mf_hashitem_S {
mf_hashitem_T *mhi_next;
mf_hashitem_T *mhi_prev;
blocknr_T mhi_key;
};
#define MHT_INIT_SIZE 64
typedef struct mf_hashtab_S {
long_u mht_mask; /* mask used for hash value (nr of items
* in array is "mht_mask" + 1) */
long_u mht_count; /* nr of items inserted into hashtable */
mf_hashitem_T **mht_buckets; /* points to mht_small_buckets or
*dynamically allocated array */
mf_hashitem_T *mht_small_buckets[MHT_INIT_SIZE]; /* initial buckets */
char mht_fixed; /* non-zero value forbids growth */
} mf_hashtab_T;
/*
* for each (previously) used block in the memfile there is one block header.
*
* The block may be linked in the used list OR in the free list.
* The used blocks are also kept in hash lists.
*
* The used list is a doubly linked list, most recently used block first.
* The blocks in the used list have a block of memory allocated.
* mf_used_count is the number of pages in the used list.
* The hash lists are used to quickly find a block in the used list.
* The free list is a single linked list, not sorted.
* The blocks in the free list have no block of memory allocated and
* the contents of the block in the file (if any) is irrelevant.
*/
struct block_hdr {
mf_hashitem_T bh_hashitem; /* header for hash table and key */
#define bh_bnum bh_hashitem.mhi_key /* block number, part of bh_hashitem */
bhdr_T *bh_next; /* next block_hdr in free or used list */
bhdr_T *bh_prev; /* previous block_hdr in used list */
char_u *bh_data; /* pointer to memory (for used block) */
int bh_page_count; /* number of pages in this block */
#define BH_DIRTY 1
#define BH_LOCKED 2
char bh_flags; /* BH_DIRTY or BH_LOCKED */
};
/*
* when a block with a negative number is flushed to the file, it gets
* a positive number. Because the reference to the block is still the negative
* number, we remember the translation to the new positive number in the
* double linked trans lists. The structure is the same as the hash lists.
*/
typedef struct nr_trans NR_TRANS;
struct nr_trans {
mf_hashitem_T nt_hashitem; /* header for hash table and key */
#define nt_old_bnum nt_hashitem.mhi_key /* old, negative, number */
blocknr_T nt_new_bnum; /* new, positive, number */
};
#define MF_SEED_LEN 8
struct memfile {
char_u *mf_fname; /* name of the file */
char_u *mf_ffname; /* idem, full path */
int mf_fd; /* file descriptor */
bhdr_T *mf_free_first; /* first block_hdr in free list */
bhdr_T *mf_used_first; /* mru block_hdr in used list */
bhdr_T *mf_used_last; /* lru block_hdr in used list */
unsigned mf_used_count; /* number of pages in used list */
unsigned mf_used_count_max; /* maximum number of pages in memory */
mf_hashtab_T mf_hash; /* hash lists */
mf_hashtab_T mf_trans; /* trans lists */
blocknr_T mf_blocknr_max; /* highest positive block number + 1*/
blocknr_T mf_blocknr_min; /* lowest negative block number - 1 */
blocknr_T mf_neg_count; /* number of negative blocks numbers */
blocknr_T mf_infile_count; /* number of pages in the file */
unsigned mf_page_size; /* number of bytes in a page */
int mf_dirty; /* TRUE if there are dirty blocks */
buf_T *mf_buffer; /* bufer this memfile is for */
char_u mf_seed[MF_SEED_LEN]; /* seed for encryption */
/* Values for key, method and seed used for reading data blocks when
* updating for a newly set key or method. Only when mf_old_key != NULL. */
char_u *mf_old_key;
int mf_old_cm;
char_u mf_old_seed[MF_SEED_LEN];
};
#endif // NEOVIM_MEMFILE_DEFS_H

4378
src/nvim/memline.c Normal file

File diff suppressed because it is too large Load Diff

47
src/nvim/memline.h Normal file
View File

@@ -0,0 +1,47 @@
#ifndef NEOVIM_MEMLINE_H
#define NEOVIM_MEMLINE_H
#include "types.h"
#include "func_attr.h"
int ml_open(buf_T *buf);
void ml_set_crypt_key(buf_T *buf, char_u *old_key, int old_cm);
void ml_setname(buf_T *buf);
void ml_open_files(void);
void ml_open_file(buf_T *buf);
void check_need_swap(int newfile);
void ml_close(buf_T *buf, int del_file);
void ml_close_all(int del_file);
void ml_close_notmod(void);
void ml_timestamp(buf_T *buf);
void ml_recover(void);
int recover_names(char_u *fname, int list, int nr, char_u **fname_out);
void ml_sync_all(int check_file, int check_char);
void ml_preserve(buf_T *buf, int message);
char_u *ml_get(linenr_T lnum);
char_u *ml_get_pos(pos_T *pos);
char_u *ml_get_curline(void);
char_u *ml_get_cursor(void);
char_u *ml_get_buf(buf_T *buf, linenr_T lnum, int will_change);
int ml_line_alloced(void);
int ml_append(linenr_T lnum, char_u *line, colnr_T len, int newfile);
int ml_append_buf(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len,
int newfile);
int ml_replace(linenr_T lnum, char_u *line, int copy);
int ml_delete(linenr_T lnum, int message);
void ml_setmarked(linenr_T lnum);
linenr_T ml_firstmarked(void);
void ml_clearmarked(void);
int resolve_symlink(char_u *fname, char_u *buf);
char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf,
char_u *dir_name);
char_u *get_file_in_dir(char_u *fname, char_u *dname);
void ml_setflags(buf_T *buf);
char_u *ml_encrypt_data(memfile_T *mfp, char_u *data, off_t offset,
unsigned size) FUNC_ATTR_NONNULL_RET;
void ml_decrypt_data(memfile_T *mfp, char_u *data, off_t offset,
unsigned size);
long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp);
void goto_byte(long cnt);
#endif /* NEOVIM_MEMLINE_H */

59
src/nvim/memline_defs.h Normal file
View File

@@ -0,0 +1,59 @@
#ifndef NEOVIM_MEMLINE_DEFS_H
#define NEOVIM_MEMLINE_DEFS_H
#include "memfile_defs.h"
/*
* When searching for a specific line, we remember what blocks in the tree
* are the branches leading to that block. This is stored in ml_stack. Each
* entry is a pointer to info in a block (may be data block or pointer block)
*/
typedef struct info_pointer {
blocknr_T ip_bnum; /* block number */
linenr_T ip_low; /* lowest lnum in this block */
linenr_T ip_high; /* highest lnum in this block */
int ip_index; /* index for block with current lnum */
} infoptr_T; /* block/index pair */
typedef struct ml_chunksize {
int mlcs_numlines;
long mlcs_totalsize;
} chunksize_T;
/* Flags when calling ml_updatechunk() */
#define ML_CHNK_ADDLINE 1
#define ML_CHNK_DELLINE 2
#define ML_CHNK_UPDLINE 3
/*
* the memline structure holds all the information about a memline
*/
typedef struct memline {
linenr_T ml_line_count; /* number of lines in the buffer */
memfile_T *ml_mfp; /* pointer to associated memfile */
#define ML_EMPTY 1 /* empty buffer */
#define ML_LINE_DIRTY 2 /* cached line was changed and allocated */
#define ML_LOCKED_DIRTY 4 /* ml_locked was changed */
#define ML_LOCKED_POS 8 /* ml_locked needs positive block number */
int ml_flags;
infoptr_T *ml_stack; /* stack of pointer blocks (array of IPTRs) */
int ml_stack_top; /* current top if ml_stack */
int ml_stack_size; /* total number of entries in ml_stack */
linenr_T ml_line_lnum; /* line number of cached line, 0 if not valid */
char_u *ml_line_ptr; /* pointer to cached line */
bhdr_T *ml_locked; /* block used by last ml_get */
linenr_T ml_locked_low; /* first line in ml_locked */
linenr_T ml_locked_high; /* last line in ml_locked */
int ml_locked_lineadd; /* number of lines inserted in ml_locked */
chunksize_T *ml_chunksize;
int ml_numchunks;
int ml_usedchunks;
} memline_T;
#endif // NEOVIM_MEMLINE_DEFS_H

388
src/nvim/memory.c Normal file
View File

@@ -0,0 +1,388 @@
// Various routines dealing with allocation and deallocation of memory.
#include <stdlib.h>
#include <string.h>
#include "vim.h"
#include "misc2.h"
#include "file_search.h"
#include "blowfish.h"
#include "buffer.h"
#include "charset.h"
#include "diff.h"
#include "edit.h"
#include "eval.h"
#include "ex_cmds.h"
#include "ex_docmd.h"
#include "ex_getln.h"
#include "fileio.h"
#include "fold.h"
#include "getchar.h"
#include "mark.h"
#include "mbyte.h"
#include "memfile.h"
#include "memline.h"
#include "memory.h"
#include "message.h"
#include "misc1.h"
#include "move.h"
#include "option.h"
#include "ops.h"
#include "os_unix.h"
#include "path.h"
#include "quickfix.h"
#include "regexp.h"
#include "screen.h"
#include "search.h"
#include "spell.h"
#include "syntax.h"
#include "tag.h"
#include "term.h"
#include "ui.h"
#include "window.h"
#include "os/os.h"
static void try_to_free_memory();
/*
* Note: if unsigned is 16 bits we can only allocate up to 64K with alloc().
*/
char_u *alloc(unsigned size)
{
return xmalloc(size);
}
/// Try to free memory. Used when trying to recover from out of memory errors.
/// @see {xmalloc}
static void try_to_free_memory()
{
static bool trying_to_free = false;
// avoid recursive calls
if (trying_to_free)
return;
trying_to_free = true;
// free any scrollback text
clear_sb_text();
// Try to save all buffers and release as many blocks as possible
mf_release_all();
// cleanup recursive lists/dicts
garbage_collect();
trying_to_free = false;
}
void *try_malloc(size_t size)
{
void *ret = malloc(size);
if (!ret && !size) {
ret = malloc(1);
}
if (!ret) {
try_to_free_memory();
ret = malloc(size);
if (!ret && !size) {
ret = malloc(1);
}
}
return ret;
}
void *verbose_try_malloc(size_t size)
{
void *ret = try_malloc(size);
if (!ret) {
do_outofmem_msg((long_u)size);
}
return ret;
}
void *xmalloc(size_t size)
{
void *ret = try_malloc(size);
if (!ret) {
OUT_STR("Vim: Error: Out of memory.\n");
preserve_exit();
}
return ret;
}
void *xcalloc(size_t count, size_t size)
{
void *ret = calloc(count, size);
if (!ret && (!count || !size))
ret = calloc(1, 1);
if (!ret) {
try_to_free_memory();
ret = calloc(count, size);
if (!ret && (!count || !size))
ret = calloc(1, 1);
if (!ret) {
OUT_STR("Vim: Error: Out of memory.\n");
preserve_exit();
}
}
return ret;
}
void *xrealloc(void *ptr, size_t size)
{
void *ret = realloc(ptr, size);
if (!ret && !size)
ret = realloc(ptr, 1);
if (!ret) {
try_to_free_memory();
ret = realloc(ptr, size);
if (!ret && !size)
ret = realloc(ptr, 1);
if (!ret) {
OUT_STR("Vim: Error: Out of memory.\n");
preserve_exit();
}
}
return ret;
}
void *xmallocz(size_t size)
{
size_t total_size = size + 1;
void *ret;
if (total_size < size) {
OUT_STR("Vim: Data too large to fit into virtual memory space\n");
preserve_exit();
}
ret = xmalloc(total_size);
((char*)ret)[size] = 0;
return ret;
}
void *xmemdupz(const void *data, size_t len)
{
return memcpy(xmallocz(len), data, len);
}
char *xstpcpy(char *restrict dst, const char *restrict src)
{
const size_t len = strlen(src);
return (char *)memcpy(dst, src, len + 1) + len;
}
char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen)
{
const char *p = memchr(src, '\0', maxlen);
if (p) {
size_t srclen = (size_t)(p - src);
memcpy(dst, src, srclen);
memset(dst + srclen, 0, maxlen - srclen);
return dst + srclen;
} else {
memcpy(dst, src, maxlen);
return dst + maxlen;
}
}
char * xstrdup(const char *str)
{
char *ret = strdup(str);
if (!ret) {
try_to_free_memory();
ret = strdup(str);
if (!ret) {
OUT_STR("Vim: Error: Out of memory.\n");
preserve_exit();
}
}
return ret;
}
char *xstrndup(const char *str, size_t len)
{
char *p = memchr(str, '\0', len);
return xmemdupz(str, p ? (size_t)(p - str) : len);
}
char *xmemdup(const char *data, size_t len)
{
return memcpy(xmalloc(len), data, len);
}
/*
* Avoid repeating the error message many times (they take 1 second each).
* Did_outofmem_msg is reset when a character is read.
*/
void do_outofmem_msg(long_u size)
{
if (!did_outofmem_msg) {
/* Don't hide this message */
emsg_silent = 0;
/* Must come first to avoid coming back here when printing the error
* message fails, e.g. when setting v:errmsg. */
did_outofmem_msg = TRUE;
EMSGU(_("E342: Out of memory! (allocating %" PRIu64 " bytes)"), size);
}
}
#if defined(EXITFREE) || defined(PROTO)
/*
* Free everything that we allocated.
* Can be used to detect memory leaks, e.g., with ccmalloc.
* NOTE: This is tricky! Things are freed that functions depend on. Don't be
* surprised if Vim crashes...
* Some things can't be freed, esp. things local to a library function.
*/
void free_all_mem(void)
{
buf_T *buf, *nextbuf;
static int entered = FALSE;
/* When we cause a crash here it is caught and Vim tries to exit cleanly.
* Don't try freeing everything again. */
if (entered)
return;
entered = TRUE;
block_autocmds(); /* don't want to trigger autocommands here */
/* Close all tabs and windows. Reset 'equalalways' to avoid redraws. */
p_ea = FALSE;
if (first_tabpage->tp_next != NULL)
do_cmdline_cmd((char_u *)"tabonly!");
if (firstwin != lastwin)
do_cmdline_cmd((char_u *)"only!");
/* Free all spell info. */
spell_free_all();
/* Clear user commands (before deleting buffers). */
ex_comclear(NULL);
/* Clear menus. */
do_cmdline_cmd((char_u *)"aunmenu *");
do_cmdline_cmd((char_u *)"menutranslate clear");
/* Clear mappings, abbreviations, breakpoints. */
do_cmdline_cmd((char_u *)"lmapclear");
do_cmdline_cmd((char_u *)"xmapclear");
do_cmdline_cmd((char_u *)"mapclear");
do_cmdline_cmd((char_u *)"mapclear!");
do_cmdline_cmd((char_u *)"abclear");
do_cmdline_cmd((char_u *)"breakdel *");
do_cmdline_cmd((char_u *)"profdel *");
do_cmdline_cmd((char_u *)"set keymap=");
free_titles();
free_findfile();
/* Obviously named calls. */
free_all_autocmds();
clear_termcodes();
free_all_options();
free_all_marks();
alist_clear(&global_alist);
free_homedir();
free_users();
free_search_patterns();
free_old_sub();
free_last_insert();
free_prev_shellcmd();
free_regexp_stuff();
free_tag_stuff();
free_cd_dir();
free_signs();
set_expr_line(NULL);
diff_clear(curtab);
clear_sb_text(); /* free any scrollback text */
/* Free some global vars. */
free(last_cmdline);
free(new_last_cmdline);
set_keep_msg(NULL, 0);
/* Clear cmdline history. */
p_hi = 0;
init_history();
{
win_T *win;
tabpage_T *tab;
qf_free_all(NULL);
/* Free all location lists */
FOR_ALL_TAB_WINDOWS(tab, win)
qf_free_all(win);
}
/* Close all script inputs. */
close_all_scripts();
/* Destroy all windows. Must come before freeing buffers. */
win_free_all();
/* Free all buffers. Reset 'autochdir' to avoid accessing things that
* were freed already. */
p_acd = FALSE;
for (buf = firstbuf; buf != NULL; ) {
nextbuf = buf->b_next;
close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
if (buf_valid(buf))
buf = nextbuf; /* didn't work, try next one */
else
buf = firstbuf;
}
free_cmdline_buf();
/* Clear registers. */
clear_registers();
ResetRedobuff();
ResetRedobuff();
/* highlight info */
free_highlight();
reset_last_sourcing();
free_tabpage(first_tabpage);
first_tabpage = NULL;
# ifdef UNIX
/* Machine-specific free. */
mch_free_mem();
# endif
/* message history */
for (;; )
if (delete_first_msg() == FAIL)
break;
eval_clear();
free_termoptions();
/* screenlines (can't display anything now!) */
free_screenlines();
clear_hl_tables();
free(NameBuff);
}
#endif

149
src/nvim/memory.h Normal file
View File

@@ -0,0 +1,149 @@
#ifndef NEOVIM_MEMORY_H
#define NEOVIM_MEMORY_H
#include "func_attr.h"
#include "types.h"
#include "vim.h"
char_u *alloc(unsigned size) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1);
/// malloc() wrapper
///
/// try_malloc() is a malloc() wrapper that tries to free some memory before
/// trying again.
///
/// @see {try_to_free_memory}
/// @param size
/// @return pointer to allocated space. NULL if out of memory
void *try_malloc(size_t size) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1);
/// try_malloc() wrapper that shows an out-of-memory error message to the user
/// before returning NULL
///
/// @see {try_malloc}
/// @param size
/// @return pointer to allocated space. NULL if out of memory
void *verbose_try_malloc(size_t size) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1);
/// malloc() wrapper that never returns NULL
///
/// xmalloc() succeeds or gracefully aborts when out of memory.
/// Before aborting try to free some memory and call malloc again.
///
/// @see {try_to_free_memory}
/// @param size
/// @return pointer to allocated space. Never NULL
void *xmalloc(size_t size)
FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1) FUNC_ATTR_NONNULL_RET;
/// calloc() wrapper
///
/// @see {xmalloc}
/// @param count
/// @param size
/// @return pointer to allocated space. Never NULL
void *xcalloc(size_t count, size_t size)
FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE_PROD(1, 2) FUNC_ATTR_NONNULL_RET;
/// realloc() wrapper
///
/// @see {xmalloc}
/// @param size
/// @return pointer to reallocated space. Never NULL
void *xrealloc(void *ptr, size_t size)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALLOC_SIZE(2) FUNC_ATTR_NONNULL_RET;
/// xmalloc() wrapper that allocates size + 1 bytes and zeroes the last byte
///
/// @see {xmalloc}
/// @param size
/// @return pointer to allocated space. Never NULL
void *xmallocz(size_t size) FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET;
/// Allocates (len + 1) bytes of memory, duplicates `len` bytes of
/// `data` to the allocated memory, zero terminates the allocated memory,
/// and returns a pointer to the allocated memory. If the allocation fails,
/// the program dies.
///
/// @see {xmalloc}
/// @param data Pointer to the data that will be copied
/// @param len number of bytes that will be copied
void *xmemdupz(const void *data, size_t len) FUNC_ATTR_NONNULL_RET;
/// strdup() wrapper
///
/// @see {xmalloc}
/// @param str 0-terminated string that will be copied
/// @return pointer to a copy of the string
char * xstrdup(const char *str)
FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET;
/// strndup() wrapper
///
/// @see {xmalloc}
/// @param str 0-terminated string that will be copied
/// @return pointer to a copy of the string
char * xstrndup(const char *str, size_t len)
FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET;
/// The xstpcpy() function shall copy the string pointed to by src (including
/// the terminating NUL character) into the array pointed to by dst.
///
/// The xstpcpy() function shall return a pointer to the terminating NUL
/// character copied into the dst buffer. This is the only difference with
/// strcpy(), which returns dst.
///
/// WARNING: If copying takes place between objects that overlap, the behavior is
/// undefined.
///
/// This is the Neovim version of stpcpy(3) as defined in POSIX 2008. We
/// don't require that supported platforms implement POSIX 2008, so we
/// implement our own version.
///
/// @param dst
/// @param src
char *xstpcpy(char *restrict dst, const char *restrict src);
/// The xstpncpy() function shall copy not more than n bytes (bytes that follow
/// a NUL character are not copied) from the array pointed to by src to the
/// array pointed to by dst.
///
/// If a NUL character is written to the destination, the xstpncpy() function
/// shall return the address of the first such NUL character. Otherwise, it
/// shall return &dst[maxlen].
///
/// WARNING: If copying takes place between objects that overlap, the behavior is
/// undefined.
///
/// WARNING: xstpncpy will ALWAYS write maxlen bytes. If src is shorter than
/// maxlen, zeroes will be written to the remaining bytes.
///
/// TODO(aktau): I don't see a good reason to have this last behaviour, and
/// it is potentially wasteful. Could we perhaps deviate from the standard
/// and not zero the rest of the buffer?
///
/// @param dst
/// @param src
/// @param maxlen
char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen);
/// Duplicates a chunk of memory using xmalloc
///
/// @see {xmalloc}
/// @param data pointer to the chunk
/// @param len size of the chunk
/// @return a pointer
char *xmemdup(const char *data, size_t len)
FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET;
/// Old low level memory allocation function.
///
/// @deprecated use xmalloc() directly instead
/// @param size
/// @return pointer to allocated space. Never NULL
char_u *lalloc(long_u size, int message) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1);
void do_outofmem_msg(long_u size);
void free_all_mem(void);
#endif

1616
src/nvim/menu.c Normal file

File diff suppressed because it is too large Load Diff

65
src/nvim/menu.h Normal file
View File

@@ -0,0 +1,65 @@
#ifndef NEOVIM_MENU_H
#define NEOVIM_MENU_H
/* Indices into vimmenu_T->strings[] and vimmenu_T->noremap[] for each mode */
#define MENU_INDEX_INVALID -1
#define MENU_INDEX_NORMAL 0
#define MENU_INDEX_VISUAL 1
#define MENU_INDEX_SELECT 2
#define MENU_INDEX_OP_PENDING 3
#define MENU_INDEX_INSERT 4
#define MENU_INDEX_CMDLINE 5
#define MENU_INDEX_TIP 6
#define MENU_MODES 7
/* Menu modes */
#define MENU_NORMAL_MODE (1 << MENU_INDEX_NORMAL)
#define MENU_VISUAL_MODE (1 << MENU_INDEX_VISUAL)
#define MENU_SELECT_MODE (1 << MENU_INDEX_SELECT)
#define MENU_OP_PENDING_MODE (1 << MENU_INDEX_OP_PENDING)
#define MENU_INSERT_MODE (1 << MENU_INDEX_INSERT)
#define MENU_CMDLINE_MODE (1 << MENU_INDEX_CMDLINE)
#define MENU_TIP_MODE (1 << MENU_INDEX_TIP)
#define MENU_ALL_MODES ((1 << MENU_INDEX_TIP) - 1)
/*note MENU_INDEX_TIP is not a 'real' mode*/
/* Start a menu name with this to not include it on the main menu bar */
#define MNU_HIDDEN_CHAR ']'
typedef struct VimMenu vimmenu_T;
struct VimMenu {
int modes; /* Which modes is this menu visible for? */
int enabled; /* for which modes the menu is enabled */
char_u *name; /* Name of menu, possibly translated */
char_u *dname; /* Displayed Name ("name" without '&') */
char_u *en_name; /* "name" untranslated, NULL when "name"
* was not translated */
char_u *en_dname; /* "dname" untranslated, NULL when "dname"
* was not translated */
int mnemonic; /* mnemonic key (after '&') */
char_u *actext; /* accelerator text (after TAB) */
int priority; /* Menu order priority */
char_u *strings[MENU_MODES]; /* Mapped string for each mode */
int noremap[MENU_MODES]; /* A REMAP_ flag for each mode */
char silent[MENU_MODES]; /* A silent flag for each mode */
vimmenu_T *children; /* Children of sub-menu */
vimmenu_T *parent; /* Parent of menu */
vimmenu_T *next; /* Next item in menu */
};
void ex_menu(exarg_T *eap);
char_u *set_context_in_menu_cmd(expand_T *xp, char_u *cmd, char_u *arg,
int forceit);
char_u *get_menu_name(expand_T *xp, int idx);
char_u *get_menu_names(expand_T *xp, int idx);
char_u *menu_name_skip(char_u *name);
int menu_is_menubar(char_u *name);
int menu_is_popup(char_u *name);
int menu_is_toolbar(char_u *name);
int menu_is_separator(char_u *name);
void ex_emenu(exarg_T *eap);
vimmenu_T *gui_find_menu(char_u *path_name);
void ex_menutranslate(exarg_T *eap);
#endif /* NEOVIM_MENU_H */

3881
src/nvim/message.c Normal file

File diff suppressed because it is too large Load Diff

85
src/nvim/message.h Normal file
View File

@@ -0,0 +1,85 @@
#ifndef NEOVIM_MESSAGE_H
#define NEOVIM_MESSAGE_H
/* message.c */
int msg(char_u *s);
int verb_msg(char_u *s);
int msg_attr(char_u *s, int attr);
int msg_attr_keep(char_u *s, int attr, int keep);
char_u *msg_strtrunc(char_u *s, int force);
void trunc_string(char_u *s, char_u *buf, int room, int buflen);
void reset_last_sourcing(void);
void msg_source(int attr);
int emsg_not_now(void);
int emsg(char_u *s);
int emsg2(char_u *s, char_u *a1);
void emsg_invreg(int name);
char_u *msg_trunc_attr(char_u *s, int force, int attr);
char_u *msg_may_trunc(int force, char_u *s);
int delete_first_msg(void);
void ex_messages(exarg_T *eap);
void msg_end_prompt(void);
void wait_return(int redraw);
void set_keep_msg(char_u *s, int attr);
void set_keep_msg_from_hist(void);
void msg_start(void);
void msg_starthere(void);
void msg_putchar(int c);
void msg_putchar_attr(int c, int attr);
void msg_outnum(long n);
void msg_home_replace(char_u *fname);
void msg_home_replace_hl(char_u *fname);
int msg_outtrans(char_u *str);
int msg_outtrans_attr(char_u *str, int attr);
int msg_outtrans_len(char_u *str, int len);
char_u *msg_outtrans_one(char_u *p, int attr);
int msg_outtrans_len_attr(char_u *msgstr, int len, int attr);
void msg_make(char_u *arg);
int msg_outtrans_special(char_u *strstart, int from);
char_u *str2special_save(char_u *str, int is_lhs);
char_u *str2special(char_u **sp, int from);
void str2specialbuf(char_u *sp, char_u *buf, int len);
void msg_prt_line(char_u *s, int list);
void msg_puts(char_u *s);
void msg_puts_title(char_u *s);
void msg_puts_long_attr(char_u *longstr, int attr);
void msg_puts_long_len_attr(char_u *longstr, int len, int attr);
void msg_puts_attr(char_u *s, int attr);
void may_clear_sb_text(void);
void clear_sb_text(void);
void show_sb_text(void);
void msg_sb_eol(void);
int msg_use_printf(void);
#ifdef USE_MCH_ERRMSG
void mch_errmsg(char *str);
void mch_msg(char *str);
#endif
void msg_moremsg(int full);
void repeat_message(void);
void msg_clr_eos(void);
void msg_clr_eos_force(void);
void msg_clr_cmdline(void);
int msg_end(void);
void msg_check(void);
int redirecting(void);
void verbose_enter(void);
void verbose_leave(void);
void verbose_enter_scroll(void);
void verbose_leave_scroll(void);
void verbose_stop(void);
int verbose_open(void);
void give_warning(char_u *message, int hl);
void msg_advance(int col);
int do_dialog(int type, char_u *title, char_u *message, char_u *buttons,
int dfltbutton, char_u *textfield,
int ex_cmd);
void display_confirm_msg(void);
int vim_dialog_yesno(int type, char_u *title, char_u *message, int dflt);
int vim_dialog_yesnocancel(int type, char_u *title, char_u *message,
int dflt);
int vim_dialog_yesnoallcancel(int type, char_u *title, char_u *message,
int dflt);
char_u *do_browse(int flags, char_u *title, char_u *dflt, char_u *ext,
char_u *initdir, char_u *filter,
buf_T *buf);
#endif /* NEOVIM_MESSAGE_H */

Some files were not shown because too many files have changed in this diff Show More