diff options
Diffstat (limited to 'src')
104 files changed, 9108 insertions, 3734 deletions
diff --git a/src/.asan-blacklist b/src/.asan-blacklist new file mode 100644 index 0000000000..63558170b3 --- /dev/null +++ b/src/.asan-blacklist @@ -0,0 +1,3 @@ +# libuv queue.h pointer arithmetic is not accepted by asan +fun:queue_node_data +fun:dictwatcher_node_data diff --git a/src/.valgrind.supp b/src/.valgrind.supp new file mode 100644 index 0000000000..8b630fcaaf --- /dev/null +++ b/src/.valgrind.supp @@ -0,0 +1,16 @@ +{ + nss_parse_service_list + Memcheck:Leak + fun:malloc + fun:nss_parse_service_list + fun:__nss_database_lookup +} +{ + uv_spawn_with_optimizations + Memcheck:Leak + fun:malloc + fun:uv_spawn + fun:pipe_process_spawn + fun:process_spawn + fun:job_start +} diff --git a/src/Doxyfile b/src/Doxyfile new file mode 100644 index 0000000000..de31c8355f --- /dev/null +++ b/src/Doxyfile @@ -0,0 +1,1890 @@ +# Doxyfile 1.8.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed +# in front of the TAG it is preceding . +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "Neovim" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = contrib/doxygen/logo-devdoc.png + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = build/doxygen + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian, +# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, +# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields or simple typedef fields will be shown +# inline in the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO (the default), structs, classes, and unions are shown on a separate +# page (for HTML and Man pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can +# be an expensive process and often the same symbol appear multiple times in +# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too +# small doxygen will become slower. If the cache is too large, memory is wasted. +# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid +# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536 +# symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if section-label ... \endif +# and \cond section-label ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. Do not use +# file names with spaces, bibtex cannot handle them. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = src/ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.h *.c + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be ignored. +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = contrib/doxygen/header.html + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = contrib/doxygen/footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = contrib/doxygen/customdoxygen.css + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = contrib/doxygen/extra.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and +# SVG. The default value is HTML-CSS, which is slower, but has the best +# compatibility. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript +# pieces of code that will be used on startup of the MathJax code. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. +# There are two flavours of web server based search depending on the +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for +# searching and an index file used by the script. When EXTERNAL_SEARCH is +# enabled the indexing and searching needs to be provided by external tools. +# See the manual for details. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain +# the search results. Doxygen ships with an example indexer (doxyindexer) and +# search engine (doxysearch.cgi) which are based on the open source search +# engine library Xapian. See the manual for configuration details. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will returned the search results when EXTERNAL_SEARCH is enabled. +# Doxygen ships with an example search engine (doxysearch) which is based on +# the open source search engine library Xapian. See the manual for configuration +# details. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id +# of to a relative location where the documentation can be found. +# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4 will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images +# or other source files which should be copied to the LaTeX output directory. +# Note that the files will be copied as-is; there are no commands or markers +# available. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files +# that can be used to generate PDF. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. If left blank docbook will be used as the default path. + +DOCBOOK_OUTPUT = docbook + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed +# in the related pages index. If set to NO, only the current project's +# pages will be listed. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate an inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# manageable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/src/clint.py b/src/clint.py new file mode 100755 index 0000000000..80e4c4ac39 --- /dev/null +++ b/src/clint.py @@ -0,0 +1,3544 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 +# +# Copyright (c) 2009 Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Does neovim-lint on c files. + +The goal of this script is to identify places in the code that *may* +be in non-compliance with neovim style. It does not attempt to fix +up these problems -- the point is to educate. It does also not +attempt to find all problems, or to ensure that everything it does +find is legitimately a problem. + +In particular, we can get very confused by /* and // inside strings! +We do a small hack, which is to ignore //'s with "'s after them on the +same line, but it is far from perfect (in either direction). +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import codecs +import copy +import getopt +import math # for log +import os +import re +import sre_compile +import string +import sys +import unicodedata +import json +import collections # for defaultdict + + +_USAGE = """ +Syntax: clint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...] + [--counting=total|toplevel|detailed] [--root=subdir] + [--linelength=digits] [--record-errors=file] + [--suppress-errors=file] + <file> [file] ... + + The style guidelines this tries to follow are those in + http://neovim.io/development-wiki/style-guide/style-guide.xml + + Note: This is Google's cpplint.py modified for use with the Neovim project, + which follows the Google C++ coding convention except with the following + modifications: + + * Function names are lower_case. + * Struct and enum names that are not typedef-ed are struct lower_case and + enum lower_case. + * The opening brace for functions appear on the next line. + * All control structures must always use braces. + + Neovim is a C project. As a result, for .c and .h files, the following rules + are suppressed: + + * [whitespace/braces] { should almost always be at the end of the previous + line + * [build/include] Include the directory when naming .h files + * [runtime/int] Use int16/int64/etc, rather than the C type. + + Every problem is given a confidence score from 1-5, with 5 meaning we are + certain of the problem, and 1 meaning it could be a legitimate construct. + This will miss some errors, and is not a substitute for a code review. + + To suppress false-positive errors of a certain category, add a + 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*) + suppresses errors of all categories on that line. + + The files passed in will be linted; at least one file must be provided. + Default linted extensions are .cc, .cpp, .cu, .cuh and .h. Change the + extensions with the --extensions flag. + + Flags: + + output=vs7 + By default, the output is formatted to ease emacs parsing. Visual Studio + compatible output (vs7) may also be used. Other formats are unsupported. + + verbose=# + Specify a number 0-5 to restrict errors to certain verbosity levels. + + filter=-x,+y,... + Specify a comma-separated list of category-filters to apply: only + error messages whose category names pass the filters will be printed. + (Category names are printed with the message and look like + "[whitespace/indent]".) Filters are evaluated left to right. + "-FOO" and "FOO" means "do not print categories that start with FOO". + "+FOO" means "do print categories that start with FOO". + + Examples: --filter=-whitespace,+whitespace/braces + --filter=whitespace,runtime/printf,+runtime/printf_format + --filter=-,+build/include_what_you_use + + To see a list of all the categories used in cpplint, pass no arg: + --filter= + + counting=total|toplevel|detailed + The total number of errors found is always printed. If + 'toplevel' is provided, then the count of errors in each of + the top-level categories like 'build' and 'whitespace' will + also be printed. If 'detailed' is provided, then a count + is provided for each category. + + root=subdir + The root directory used for deriving header guard CPP variable. + By default, the header guard CPP variable is calculated as the relative + path to the directory that contains .git, .hg, or .svn. When this flag + is specified, the relative path is calculated from the specified + directory. If the specified directory does not exist, this flag is + ignored. + + Examples: + Assuing that src/.git exists, the header guard CPP variables for + src/chrome/browser/ui/browser.h are: + + No flag => CHROME_BROWSER_UI_BROWSER_H_ + --root=chrome => BROWSER_UI_BROWSER_H_ + --root=chrome/browser => UI_BROWSER_H_ + + linelength=digits + This is the allowed line length for the project. The default value is + 80 characters. + + Examples: + --linelength=120 + + extensions=extension,extension,... + The allowed file extensions that cpplint will check + + Examples: + --extensions=hpp,cpp + + record-errors=file + Record errors to the given location. This file may later be used for error + suppression using suppress-errors flag. + + suppress-errors=file + Errors listed in the given file will not be reported. +""" + +# We categorize each error message we print. Here are the categories. +# We want an explicit list so we can list them all in cpplint --filter=. +# If you add a new error message with a new category, add it to the list +# here! cpplint_unittest.py should tell you if you forget to do this. +_ERROR_CATEGORIES = [ + 'build/deprecated', + 'build/endif_comment', + 'build/header_guard', + 'build/include', + 'build/include_alpha', + 'build/include_order', + 'build/printf_format', + 'build/storage_class', + 'readability/alt_tokens', + 'readability/bool', + 'readability/braces', + 'readability/fn_size', + 'readability/multiline_comment', + 'readability/multiline_string', + 'readability/nolint', + 'readability/nul', + 'readability/todo', + 'readability/utf8', + 'readability/increment', + 'runtime/arrays', + 'runtime/int', + 'runtime/invalid_increment', + 'runtime/memset', + 'runtime/printf', + 'runtime/printf_format', + 'runtime/threadsafe_fn', + 'syntax/parenthesis', + 'whitespace/alignment', + 'whitespace/blank_line', + 'whitespace/braces', + 'whitespace/comma', + 'whitespace/comments', + 'whitespace/empty_conditional_body', + 'whitespace/empty_loop_body', + 'whitespace/end_of_line', + 'whitespace/ending_newline', + 'whitespace/indent', + 'whitespace/line_length', + 'whitespace/newline', + 'whitespace/operators', + 'whitespace/parens', + 'whitespace/semicolon', + 'whitespace/tab', + 'whitespace/todo', + 'whitespace/line_continuation', + 'whitespace/cast', +] + +# The default state of the category filter. This is overrided by the --filter= +# flag. By default all errors are on, so only add here categories that should be +# off by default (i.e., categories that must be enabled by the --filter= flags). +# All entries here should start with a '-' or '+', as in the --filter= flag. +_DEFAULT_FILTERS = ['-build/include_alpha'] + +# We used to check for high-bit characters, but after much discussion we +# decided those were OK, as long as they were in UTF-8 and didn't represent +# hard-coded international strings, which belong in a separate i18n file. + +# Alternative tokens and their replacements. For full list, see section 2.5 +# Alternative tokens [lex.digraph] in the C++ standard. +# +# Digraphs (such as '%:') are not included here since it's a mess to +# match those on a word boundary. +_ALT_TOKEN_REPLACEMENT = { + 'and': '&&', + 'bitor': '|', + 'or': '||', + 'xor': '^', + 'compl': '~', + 'bitand': '&', + 'and_eq': '&=', + 'or_eq': '|=', + 'xor_eq': '^=', + 'not': '!', + 'not_eq': '!=' +} + +# Compile regular expression that matches all the above keywords. The "[ =()]" +# bit is meant to avoid matching these keywords outside of boolean expressions. +# +# False positives include C-style multi-line comments and multi-line strings +# but those have always been troublesome for cpplint. +_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile( + r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)') + + +# These constants define types of headers for use with +# _IncludeState.CheckNextIncludeOrder(). +_C_SYS_HEADER = 1 +_OTHER_HEADER = 5 + +# These constants define the current inline assembly state +_NO_ASM = 0 # Outside of inline assembly block +_INSIDE_ASM = 1 # Inside inline assembly block +_END_ASM = 2 # Last line of inline assembly block +_BLOCK_ASM = 3 # The whole block is an inline assembly block + +# Match start of assembly blocks +_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)' + r'(?:\s+(volatile|__volatile__))?' + r'\s*[{(]') + + +_regexp_compile_cache = {} + +# Finds occurrences of NOLINT or NOLINT(...). +_RE_SUPPRESSION = re.compile(r'\bNOLINT\b(\([^)]*\))?') + +# {str, set(int)}: a map from error categories to sets of linenumbers +# on which those errors are expected and should be suppressed. +_error_suppressions = {} + +# {(str, int)}: a set of error categories and line numbers which are expected to +# be suppressed +_error_suppressions_2 = set() + +# The allowed line length of files. +# This is set by --linelength flag. +_line_length = 80 + +# The allowed extensions for file names +# This is set by --extensions flag. +_valid_extensions = set(['c', 'h']) + + +def ParseNolintSuppressions(filename, raw_line, linenum, error): + """Updates the global list of error-suppressions. + + Parses any NOLINT comments on the current line, updating the global + error_suppressions store. Reports an error if the NOLINT comment + was malformed. + + Args: + filename: str, the name of the input file. + raw_line: str, the line of input text, with comments. + linenum: int, the number of the current line. + error: function, an error handler. + """ + # FIXME(adonovan): "NOLINT(" is misparsed as NOLINT(*). + matched = _RE_SUPPRESSION.search(raw_line) + if matched: + category = matched.group(1) + if category in (None, '(*)'): # => "suppress all" + _error_suppressions.setdefault(None, set()).add(linenum) + else: + if category.startswith('(') and category.endswith(')'): + category = category[1:-1] + if category in _ERROR_CATEGORIES: + _error_suppressions.setdefault( + category, set()).add(linenum) + else: + error(filename, linenum, 'readability/nolint', 5, + 'Unknown NOLINT error category: %s' % category) + + +def ParseKnownErrorSuppressions(filename, raw_lines, linenum): + """Updates the global list of error-suppressions from suppress-file. + + Args: + filename: str, the name of the input file. + raw_lines: list, all file lines + linenum: int, the number of the current line. + """ + key = tuple(raw_lines[linenum - 1 if linenum else 0:linenum + 2]) + if key in _cpplint_state.suppressed_errors[filename]: + for category in _cpplint_state.suppressed_errors[filename][key]: + _error_suppressions_2.add((category, linenum)) + + +def ResetNolintSuppressions(): + "Resets the set of NOLINT suppressions to empty." + _error_suppressions.clear() + + +def ResetKnownErrorSuppressions(): + "Resets the set of suppress-errors=file suppressions to empty." + _error_suppressions_2.clear() + + +def IsErrorSuppressedByNolint(category, linenum): + """Returns true if the specified error category is suppressed on this line. + + Consults the global error_suppressions map populated by + ParseNolintSuppressions/ResetNolintSuppressions. + + Args: + category: str, the category of the error. + linenum: int, the current line number. + Returns: + bool, True iff the error should be suppressed due to a NOLINT comment. + """ + return (linenum in _error_suppressions.get(category, set()) or + linenum in _error_suppressions.get(None, set())) + + +def IsErrorInSuppressedErrorsList(category, linenum): + """Returns true if the specified error is suppressed by suppress-errors=file + + Args: + category: str, the category of the error. + linenum: int, the current line number. + Returns: + bool, True iff the error should be suppressed due to presense in + suppressions file. + """ + return (category, linenum) in _error_suppressions_2 + + +def Match(pattern, s): + """Matches the string with the pattern, caching the compiled regexp.""" + # The regexp compilation caching is inlined in both Match and Search for + # performance reasons; factoring it out into a separate function turns out + # to be noticeably expensive. + if pattern not in _regexp_compile_cache: + _regexp_compile_cache[pattern] = sre_compile.compile(pattern) + return _regexp_compile_cache[pattern].match(s) + + +def Search(pattern, s): + """Searches the string for the pattern, caching the compiled regexp.""" + if pattern not in _regexp_compile_cache: + _regexp_compile_cache[pattern] = sre_compile.compile(pattern) + return _regexp_compile_cache[pattern].search(s) + + +class _IncludeState(dict): + + """Tracks line numbers for includes, and the order in which includes appear. + + As a dict, an _IncludeState object serves as a mapping between include + filename and line number on which that file was included. + + Call CheckNextIncludeOrder() once for each header in the file, passing + in the type constants defined above. + + """ + # self._section will move monotonically through this set. If it ever + # needs to move backwards, CheckNextIncludeOrder will raise an error. + _INITIAL_SECTION = 0 + _C_SECTION = 2 + _OTHER_H_SECTION = 4 + + _TYPE_NAMES = { + _C_SYS_HEADER: 'C system header', + _OTHER_HEADER: 'other header', + } + _SECTION_NAMES = { + _INITIAL_SECTION: "... nothing. (This can't be an error.)", + _C_SECTION: 'C system header', + _OTHER_H_SECTION: 'other header', + } + + def __init__(self): + dict.__init__(self) + self.ResetSection() + + def ResetSection(self): + # The name of the current section. + self._section = self._INITIAL_SECTION + # The path of last found header. + self._last_header = '' + + def SetLastHeader(self, header_path): + self._last_header = header_path + + def CanonicalizeAlphabeticalOrder(self, header_path): + """Returns a path canonicalized for alphabetical comparison. + + - replaces "-" with "_" so they both cmp the same. + - lowercase everything, just in case. + + Args: + header_path: Path to be canonicalized. + + Returns: + Canonicalized path. + """ + return header_path.replace('-', '_').lower() + + def CheckNextIncludeOrder(self, header_type): + """Returns a non-empty error message if the next header is out of order. + + This function also updates the internal state to be ready to check + the next include. + + Args: + header_type: One of the _XXX_HEADER constants defined above. + + Returns: + The empty string if the header is in the right order, or an + error message describing what's wrong. + + """ + error_message = ('Found %s after %s' % + (self._TYPE_NAMES[header_type], + self._SECTION_NAMES[self._section])) + + last_section = self._section + + if header_type == _C_SYS_HEADER: + if self._section <= self._C_SECTION: + self._section = self._C_SECTION + else: + self._last_header = '' + return error_message + else: + assert header_type == _OTHER_HEADER + self._section = self._OTHER_H_SECTION + + if last_section != self._section: + self._last_header = '' + + return '' + + +class _CppLintState(object): + + """Maintains module-wide state..""" + + def __init__(self): + self.verbose_level = 1 # global setting. + self.error_count = 0 # global count of reported errors + # filters to apply when emitting error messages + self.filters = _DEFAULT_FILTERS[:] + self.counting = 'total' # In what way are we counting errors? + self.errors_by_category = {} # string to int dict storing error counts + + # output format: + # "emacs" - format that emacs can parse (default) + # "vs7" - format that Microsoft Visual Studio 7 can parse + self.output_format = 'emacs' + + self.record_errors_file = None + self.suppressed_errors = collections.defaultdict( + lambda: collections.defaultdict(set)) + + def SetOutputFormat(self, output_format): + """Sets the output format for errors.""" + self.output_format = output_format + + def SetVerboseLevel(self, level): + """Sets the module's verbosity, and returns the previous setting.""" + last_verbose_level = self.verbose_level + self.verbose_level = level + return last_verbose_level + + def SetCountingStyle(self, counting_style): + """Sets the module's counting options.""" + self.counting = counting_style + + def SetFilters(self, filters): + """Sets the error-message filters. + + These filters are applied when deciding whether to emit a given + error message. + + Args: + filters: A string of comma-separated filters. + E.g. "+whitespace/indent". + Each filter should start with + or -; else we die. + + Raises: + ValueError: The comma-separated filters did not all start with + '+' or '-'. + E.g. "-,+whitespace,-whitespace/indent,whitespace/bad" + """ + # Default filters always have less priority than the flag ones. + self.filters = _DEFAULT_FILTERS[:] + for filt in filters.split(','): + clean_filt = filt.strip() + if clean_filt: + self.filters.append(clean_filt) + for filt in self.filters: + if not (filt.startswith('+') or filt.startswith('-')): + raise ValueError('Every filter in --filters must start with ' + '+ or - (%s does not)' % filt) + + def ResetErrorCounts(self): + """Sets the module's error statistic back to zero.""" + self.error_count = 0 + self.errors_by_category = {} + + def IncrementErrorCount(self, category): + """Bumps the module's error statistic.""" + self.error_count += 1 + if self.counting in ('toplevel', 'detailed'): + if self.counting != 'detailed': + category = category.split('/')[0] + if category not in self.errors_by_category: + self.errors_by_category[category] = 0 + self.errors_by_category[category] += 1 + + def PrintErrorCounts(self): + """Print a summary of errors by category, and the total.""" + for category, count in self.errors_by_category.items(): + sys.stderr.write('Category \'%s\' errors found: %d\n' % + (category, count)) + sys.stderr.write('Total errors found: %d\n' % self.error_count) + + def SuppressErrorsFrom(self, fname): + """Open file and read a list of suppressed errors from it""" + if fname is None: + return + try: + with open(fname) as fp: + for line in fp: + fname, lines, category = json.loads(line) + lines = tuple(lines) + self.suppressed_errors[fname][lines].add(category) + except IOError: + pass + + def RecordErrorsTo(self, fname): + """Open file with suppressed errors for writing""" + if fname is None: + return + self.record_errors_file = open(fname, 'w') + +_cpplint_state = _CppLintState() + + +def _OutputFormat(): + """Gets the module's output format.""" + return _cpplint_state.output_format + + +def _SetOutputFormat(output_format): + """Sets the module's output format.""" + _cpplint_state.SetOutputFormat(output_format) + + +def _VerboseLevel(): + """Returns the module's verbosity setting.""" + return _cpplint_state.verbose_level + + +def _SetVerboseLevel(level): + """Sets the module's verbosity, and returns the previous setting.""" + return _cpplint_state.SetVerboseLevel(level) + + +def _SetCountingStyle(level): + """Sets the module's counting options.""" + _cpplint_state.SetCountingStyle(level) + + +def _SuppressErrorsFrom(fname): + """Sets the file containing suppressed errors.""" + _cpplint_state.SuppressErrorsFrom(fname) + + +def _RecordErrorsTo(fname): + """Sets the file containing suppressed errors to write to.""" + _cpplint_state.RecordErrorsTo(fname) + + +def _Filters(): + """Returns the module's list of output filters, as a list.""" + return _cpplint_state.filters + + +def _SetFilters(filters): + """Sets the module's error-message filters. + + These filters are applied when deciding whether to emit a given + error message. + + Args: + filters: A string of comma-separated filters (eg "whitespace/indent"). + Each filter should start with + or -; else we die. + """ + _cpplint_state.SetFilters(filters) + + +class _FunctionState(object): + + """Tracks current function name and the number of lines in its body.""" + + _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc. + _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER. + + def __init__(self): + self.in_a_function = False + self.lines_in_function = 0 + self.current_function = '' + + def Begin(self, function_name): + """Start analyzing function body. + + Args: + function_name: The name of the function being tracked. + """ + self.in_a_function = True + self.lines_in_function = 0 + self.current_function = function_name + + def Count(self): + """Count line in current function body.""" + if self.in_a_function: + self.lines_in_function += 1 + + def Check(self, error, filename, linenum): + """Report if too many lines in function body. + + Args: + error: The function to call with any errors found. + filename: The name of the current file. + linenum: The number of the line to check. + """ + if Match(r'T(EST|est)', self.current_function): + base_trigger = self._TEST_TRIGGER + else: + base_trigger = self._NORMAL_TRIGGER + trigger = base_trigger * 2**_VerboseLevel() + + if self.lines_in_function > trigger: + error_level = int( + math.log(self.lines_in_function / base_trigger, 2)) + # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ... + if error_level > 5: + error_level = 5 + error(filename, linenum, 'readability/fn_size', error_level, + 'Small and focused functions are preferred:' + ' %s has %d non-comment lines' + ' (error triggered by exceeding %d lines).' % ( + self.current_function, self.lines_in_function, trigger)) + + def End(self): + """Stop analyzing function body.""" + self.in_a_function = False + + +class FileInfo: + + """Provides utility functions for filenames. + + FileInfo provides easy access to the components of a file's path + relative to the project root. + """ + + def __init__(self, filename): + self._filename = filename + + def FullName(self): + """Make Windows paths like Unix.""" + return os.path.abspath(self._filename).replace('\\', '/') + + def RelativePath(self): + """FullName with <prefix>/src/nvim/ chopped off.""" + fullname = self.FullName() + + if os.path.exists(fullname): + project_dir = os.path.dirname(fullname) + + root_dir = os.path.dirname(fullname) + while (root_dir != os.path.dirname(root_dir) and + not os.path.exists(os.path.join(root_dir, ".git"))): + root_dir = os.path.dirname(root_dir) + + if os.path.exists(os.path.join(root_dir, ".git")): + root_dir = os.path.join(root_dir, "src", "nvim") + prefix = os.path.commonprefix([root_dir, project_dir]) + return fullname[len(prefix) + 1:] + + # Don't know what to do; header guard warnings may be wrong... + return fullname + + def Split(self): + """Splits the file into the directory, basename, and extension. + + For 'chrome/browser/browser.cc', Split() would + return ('chrome/browser', 'browser', '.cc') + + Returns: + A tuple of (directory, basename, extension). + """ + + googlename = self.RelativePath() + project, rest = os.path.split(googlename) + return (project,) + os.path.splitext(rest) + + def BaseName(self): + """File base name - text after the final slash, before final period.""" + return self.Split()[1] + + def Extension(self): + """File extension - text following the final period.""" + return self.Split()[2] + + +def _ShouldPrintError(category, confidence, linenum): + """If confidence >= verbose, category passes filter and isn't suppressed.""" + + # There are three ways we might decide not to print an error message: + # a "NOLINT(category)" comment appears in the source, + # the verbosity level isn't high enough, or the filters filter it out. + if IsErrorSuppressedByNolint(category, linenum): + return False + if IsErrorInSuppressedErrorsList(category, linenum): + return False + if confidence < _cpplint_state.verbose_level: + return False + + is_filtered = False + for one_filter in _Filters(): + if one_filter.startswith('-'): + if category.startswith(one_filter[1:]): + is_filtered = True + elif one_filter.startswith('+'): + if category.startswith(one_filter[1:]): + is_filtered = False + else: + assert False # should have been checked for in SetFilter. + if is_filtered: + return False + + return True + + +def Error(filename, linenum, category, confidence, message): + """Logs the fact we've found a lint error. + + We log where the error was found, and also our confidence in the error, + that is, how certain we are this is a legitimate style regression, and + not a misidentification or a use that's sometimes justified. + + False positives can be suppressed by the use of + "cpplint(category)" comments on the offending line. These are + parsed into _error_suppressions. + + Args: + filename: The name of the file containing the error. + linenum: The number of the line containing the error. + category: A string used to describe the "category" this bug + falls under: "whitespace", say, or "runtime". Categories + may have a hierarchy separated by slashes: "whitespace/indent". + confidence: A number from 1-5 representing a confidence score for + the error, with 5 meaning that we are certain of the problem, + and 1 meaning that it could be a legitimate construct. + message: The error message. + """ + if _ShouldPrintError(category, confidence, linenum): + _cpplint_state.IncrementErrorCount(category) + if _cpplint_state.output_format == 'vs7': + sys.stderr.write('%s(%s): %s [%s] [%d]\n' % ( + filename, linenum, message, category, confidence)) + elif _cpplint_state.output_format == 'eclipse': + sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % ( + filename, linenum, message, category, confidence)) + else: + sys.stderr.write('%s:%s: %s [%s] [%d]\n' % ( + filename, linenum, message, category, confidence)) + + +# Matches standard C++ escape sequences per 2.13.2.3 of the C++ standard. +_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile( + r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)') +# Matches strings. Escape codes should already be removed by ESCAPES. +_RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES = re.compile(r'"([^"]*)"') +# Matches characters. Escape codes should already be removed by ESCAPES. +_RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES = re.compile(r"'(.)'") +# Matches multi-line C++ comments. +# This RE is a little bit more complicated than one might expect, because we +# have to take care of space removals tools so we can handle comments inside +# statements better. +# The current rule is: We only clear spaces from both sides when we're at the +# end of the line. Otherwise, we try to remove spaces from the right side, +# if this doesn't work we try on left side but only if there's a non-character +# on the right. +_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile( + r"""(\s*/\*.*\*/\s*$| + /\*.*\*/\s+| + \s+/\*.*\*/(?=\W)| + /\*.*\*/)""", re.VERBOSE) + + +def IsCppString(line): + """Does line terminate so, that the next symbol is in string constant. + + This function does not consider single-line nor multi-line comments. + + Args: + line: is a partial line of code starting from the 0..n. + + Returns: + True, if next character appended to 'line' is inside a + string constant. + """ + + line = line.replace(r'\\', 'XX') # after this, \\" does not match to \" + return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1 + + +def FindNextMultiLineCommentStart(lines, lineix): + """Find the beginning marker for a multiline comment.""" + while lineix < len(lines): + if lines[lineix].strip().startswith('/*'): + # Only return this marker if the comment goes beyond this line + if lines[lineix].strip().find('*/', 2) < 0: + return lineix + lineix += 1 + return len(lines) + + +def FindNextMultiLineCommentEnd(lines, lineix): + """We are inside a comment, find the end marker.""" + while lineix < len(lines): + if lines[lineix].strip().endswith('*/'): + return lineix + lineix += 1 + return len(lines) + + +def RemoveMultiLineCommentsFromRange(lines, begin, end): + """Clears a range of lines for multi-line comments.""" + # Having // dummy comments makes the lines non-empty, so we will not get + # unnecessary blank line warnings later in the code. + for i in range(begin, end): + lines[i] = '// dummy' + + +def RemoveMultiLineComments(filename, lines, error): + """Removes multiline (c-style) comments from lines.""" + lineix = 0 + while lineix < len(lines): + lineix_begin = FindNextMultiLineCommentStart(lines, lineix) + if lineix_begin >= len(lines): + return + lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin) + if lineix_end >= len(lines): + error(filename, lineix_begin + 1, 'readability/multiline_comment', + 5, 'Could not find end of multi-line comment') + return + RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1) + lineix = lineix_end + 1 + + +def CleanseComments(line): + """Removes //-comments and single-line C-style /* */ comments. + + Args: + line: A line of C++ source. + + Returns: + The line with single-line comments removed. + """ + commentpos = line.find('//') + if commentpos != -1 and not IsCppString(line[:commentpos]): + line = line[:commentpos].rstrip() + # get rid of /* ... */ + return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line) + + +class CleansedLines(object): + + """Holds 5 copies of all lines with different preprocessing applied to them. + + 1) elided member contains lines without strings and comments, + 2) lines member contains lines without comments, and + 3) raw_lines member contains all the lines with multiline comments replaced. + 4) init_lines member contains all the lines without processing. + 5) elided_with_space_strings is like elided, but with string literals + looking like `" "`. + All these three members are of <type 'list'>, and of the same length. + """ + + def __init__(self, lines, init_lines): + self.elided = [] + self.lines = [] + self.raw_lines = lines + self.num_lines = len(lines) + self.init_lines = init_lines + self.lines_without_raw_strings = lines + self.elided_with_space_strings = [] + for linenum in range(len(self.lines_without_raw_strings)): + self.lines.append(CleanseComments( + self.lines_without_raw_strings[linenum])) + elided = self._CollapseStrings( + self.lines_without_raw_strings[linenum]) + self.elided.append(CleanseComments(elided)) + elided = CleanseComments(self._CollapseStrings( + self.lines_without_raw_strings[linenum], True)) + self.elided_with_space_strings.append(elided) + + def NumLines(self): + """Returns the number of lines represented.""" + return self.num_lines + + @staticmethod + def _CollapseStrings(elided, keep_spaces=False): + """Collapses strings and chars on a line to simple "" or '' blocks. + + We nix strings first so we're not fooled by text like '"http://"' + + Args: + elided: The line being processed. + keep_spaces: If true, collapse to + + Returns: + The line with collapsed strings. + """ + if not _RE_PATTERN_INCLUDE.match(elided): + # Remove escaped characters first to make quote/single quote + # collapsing basic. Things that look like escaped characters + # shouldn't occur outside of strings and chars. + elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub( + '' if not keep_spaces else lambda m: ' ' * len(m.group(0)), + elided) + elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub( + "''" if not keep_spaces + else lambda m: "'" + (' ' * len(m.group(1))) + "'", + elided) + elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub( + '""' if not keep_spaces + else lambda m: '"' + (' ' * len(m.group(1))) + '"', + elided) + return elided + + +BRACES = { + '(': ')', + '{': '}', + '[': ']', + # '<': '>', C++-specific pair removed +} + + +CLOSING_BRACES = dict(((v, k) for k, v in BRACES.items())) + + +def GetExprBracesPosition(clean_lines, linenum, pos): + """List positions of all kinds of braces + + If input points to ( or { or [ then function proceeds until finding the + position which closes it. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: Current line number. + pos: A position on the line. + + Yields: + A tuple (linenum, pos, brace, depth) that points to each brace. + Additionally each new line (linenum, pos, 's', depth) is yielded, for each + line end (linenum, pos, 'e', depth) is yielded and at the very end it + yields (linenum, pos, None, None). + """ + depth = 0 + yielded_line_start = True + startpos = pos + while linenum < clean_lines.NumLines() - 1: + line = clean_lines.elided_with_space_strings[linenum] + if not line.startswith('#') or yielded_line_start: + # Ignore #ifdefs, but not if it is macros that are checked + for i, brace in enumerate(line[startpos:]): + pos = i + startpos + if brace != ' ' and not yielded_line_start: + yield (linenum, pos, 's', depth) + yielded_line_start = True + if brace in BRACES: + depth += 1 + yield (linenum, pos, brace, depth) + elif brace in CLOSING_BRACES: + yield (linenum, pos, brace, depth) + depth -= 1 + if depth == 0: + yield (linenum, pos, None, None) + return + yield (linenum, len(line) - 1, 'e', depth) + yielded_line_start = False + startpos = 0 + linenum += 1 + + +def FindEndOfExpressionInLine(line, startpos, depth, startchar, endchar): + """Find the position just after the matching endchar. + + Args: + line: a CleansedLines line. + startpos: start searching at this position. + depth: nesting level at startpos. + startchar: expression opening character. + endchar: expression closing character. + + Returns: + On finding matching endchar: (index just after matching endchar, 0) + Otherwise: (-1, new depth at end of this line) + """ + for i in range(startpos, len(line)): + if line[i] == startchar: + depth += 1 + elif line[i] == endchar: + depth -= 1 + if depth == 0: + return (i + 1, 0) + return (-1, depth) + + +def CloseExpression(clean_lines, linenum, pos): + """If input points to ( or { or [, finds the position that closes it. + + If lines[linenum][pos] points to a '(' or '{' or '[', finds the + linenum/pos that correspond to the closing of the expression. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + pos: A position on the line. + + Returns: + A tuple (line, linenum, pos) pointer *past* the closing brace, or + (line, len(lines), -1) if we never find a close. Note we ignore + strings and comments when matching; and the line we return is the + 'cleansed' line at linenum. + """ + + line = clean_lines.elided[linenum] + startchar = line[pos] + if startchar not in BRACES: + return (line, clean_lines.NumLines(), -1) + endchar = BRACES[startchar] + + # Check first line + (end_pos, num_open) = FindEndOfExpressionInLine( + line, pos, 0, startchar, endchar) + if end_pos > -1: + return (line, linenum, end_pos) + + # Continue scanning forward + while linenum < clean_lines.NumLines() - 1: + linenum += 1 + line = clean_lines.elided[linenum] + (end_pos, num_open) = FindEndOfExpressionInLine( + line, 0, num_open, startchar, endchar) + if end_pos > -1: + return (line, linenum, end_pos) + + # Did not find endchar before end of file, give up + return (line, clean_lines.NumLines(), -1) + + +def FindStartOfExpressionInLine(line, endpos, depth, startchar, endchar): + """Find position at the matching startchar. + + This is almost the reverse of FindEndOfExpressionInLine, but note + that the input position and returned position differs by 1. + + Args: + line: a CleansedLines line. + endpos: start searching at this position. + depth: nesting level at endpos. + startchar: expression opening character. + endchar: expression closing character. + + Returns: + On finding matching startchar: (index at matching startchar, 0) + Otherwise: (-1, new depth at beginning of this line) + """ + for i in range(endpos, -1, -1): + if line[i] == endchar: + depth += 1 + elif line[i] == startchar: + depth -= 1 + if depth == 0: + return (i, 0) + return (-1, depth) + + +def ReverseCloseExpression(clean_lines, linenum, pos): + """If input points to ) or } or ] or >, finds the position that opens it. + + If lines[linenum][pos] points to a ')' or '}' or ']' or '>', finds the + linenum/pos that correspond to the opening of the expression. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + pos: A position on the line. + + Returns: + A tuple (line, linenum, pos) pointer *at* the opening brace, or + (line, 0, -1) if we never find the matching opening brace. Note + we ignore strings and comments when matching; and the line we + return is the 'cleansed' line at linenum. + """ + line = clean_lines.elided[linenum] + endchar = line[pos] + if endchar not in ')}]>': + return (line, 0, -1) + if endchar == ')': + startchar = '(' + if endchar == ']': + startchar = '[' + if endchar == '}': + startchar = '{' + if endchar == '>': + startchar = '<' + + # Check last line + (start_pos, num_open) = FindStartOfExpressionInLine( + line, pos, 0, startchar, endchar) + if start_pos > -1: + return (line, linenum, start_pos) + + # Continue scanning backward + while linenum > 0: + linenum -= 1 + line = clean_lines.elided[linenum] + (start_pos, num_open) = FindStartOfExpressionInLine( + line, len(line) - 1, num_open, startchar, endchar) + if start_pos > -1: + return (line, linenum, start_pos) + + # Did not find startchar before beginning of file, give up + return (line, 0, -1) + + +def GetHeaderGuardCPPVariable(filename): + """Returns the CPP variable that should be used as a header guard. + + Args: + filename: The name of a C++ header file. + + Returns: + The CPP variable that should be used as a header guard in the + named file. + + """ + + # Restores original filename in case that cpplint is invoked from Emacs's + # flymake. + filename = re.sub(r'_flymake\.h$', '.h', filename) + filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename) + + fileinfo = FileInfo(filename) + file_path_from_root = fileinfo.RelativePath() + return 'NVIM_' + re.sub(r'[-./\s]', '_', file_path_from_root).upper() + + +def CheckForHeaderGuard(filename, lines, error): + """Checks that the file contains a header guard. + + Logs an error if no #ifndef header guard is present. For other + headers, checks that the full pathname is used. + + Args: + filename: The name of the C++ header file. + lines: An array of strings, each representing a line of the file. + error: The function to call with any errors found. + """ + + cppvar = GetHeaderGuardCPPVariable(filename) + + ifndef = None + ifndef_linenum = 0 + define = None + endif = None + endif_linenum = 0 + for linenum, line in enumerate(lines): + linesplit = line.split() + if len(linesplit) >= 2: + # find the first occurrence of #ifndef and #define, save arg + if not ifndef and linesplit[0] == '#ifndef': + # set ifndef to the header guard presented on the #ifndef line. + ifndef = linesplit[1] + ifndef_linenum = linenum + if not define and linesplit[0] == '#define': + define = linesplit[1] + # find the last occurrence of #endif, save entire line + if line.startswith('#endif'): + endif = line + endif_linenum = linenum + + if not ifndef: + error(filename, 0, 'build/header_guard', 5, + 'No #ifndef header guard found, suggested CPP variable is: %s' % + cppvar) + return + + if not define: + error(filename, 0, 'build/header_guard', 5, + 'No #define header guard found, suggested CPP variable is: %s' % + cppvar) + return + + # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__ + # for backward compatibility. + if ifndef != cppvar: + error_level = 0 + if ifndef != cppvar + '_': + error_level = 5 + + ParseNolintSuppressions(filename, lines[ifndef_linenum], ifndef_linenum, + error) + error(filename, ifndef_linenum, 'build/header_guard', error_level, + '#ifndef header guard has wrong style, please use: %s' % cppvar) + + if define != ifndef: + error(filename, 0, 'build/header_guard', 5, + '#ifndef and #define don\'t match, suggested CPP variable is: %s' + % cppvar) + return + + if endif != ('#endif // %s' % cppvar): + error_level = 0 + if endif != ('#endif // %s' % (cppvar + '_')): + error_level = 5 + + ParseNolintSuppressions(filename, lines[endif_linenum], endif_linenum, + error) + error(filename, endif_linenum, 'build/header_guard', error_level, + '#endif line should be "#endif // %s"' % cppvar) + + +def CheckForBadCharacters(filename, lines, error): + """Logs an error for each line containing bad characters. + + Two kinds of bad characters: + + 1. Unicode replacement characters: These indicate that either the file + contained invalid UTF-8 (likely) or Unicode replacement characters (which + it shouldn't). Note that it's possible for this to throw off line + numbering if the invalid UTF-8 occurred adjacent to a newline. + + 2. NUL bytes. These are problematic for some tools. + + Args: + filename: The name of the current file. + lines: An array of strings, each representing a line of the file. + error: The function to call with any errors found. + """ + for linenum, line in enumerate(lines): + if u'\ufffd' in line: + error(filename, linenum, 'readability/utf8', 5, + 'Line contains invalid UTF-8' + ' (or Unicode replacement character).') + if '\0' in line: + error(filename, linenum, 'readability/nul', + 5, 'Line contains NUL byte.') + + +def CheckForNewlineAtEOF(filename, lines, error): + """Logs an error if there is no newline char at the end of the file. + + Args: + filename: The name of the current file. + lines: An array of strings, each representing a line of the file. + error: The function to call with any errors found. + """ + + # The array lines() was created by adding two newlines to the + # original file (go figure), then splitting on \n. + # To verify that the file ends in \n, we just have to make sure the + # last-but-two element of lines() exists and is empty. + if len(lines) < 3 or lines[-2]: + error(filename, len(lines) - 2, 'whitespace/ending_newline', 5, + 'Could not find a newline character at the end of the file.') + + +def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error): + """Logs an error if we see /* ... */ or "..." that extend past one line. + + /* ... */ comments are legit inside macros, for one line. + Otherwise, we prefer // comments, so it's ok to warn about the + other. Likewise, it's ok for strings to extend across multiple + lines, as long as a line continuation character (backslash) + terminates each line. Although not currently prohibited by the C++ + style guide, it's ugly and unnecessary. We don't do well with either + in this lint program, so we warn about both. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Remove all \\ (escaped backslashes) from the line. They are OK, and the + # second (escaped) slash may trigger later \" detection erroneously. + line = line.replace('\\\\', '') + + if line.count('/*') > line.count('*/'): + error(filename, linenum, 'readability/multiline_comment', 5, + 'Complex multi-line /*...*/-style comment found. ' + 'Lint may give bogus warnings. ' + 'Consider replacing these with //-style comments, ' + 'with #if 0...#endif, ' + 'or with more clearly structured multi-line comments.') + + if (line.count('"') - line.count('\\"')) % 2: + error(filename, linenum, 'readability/multiline_string', 5, + 'Multi-line string ("...") found. This lint script doesn\'t ' + 'do well with such strings, and may give bogus warnings. ' + 'Use C++11 raw strings or concatenation instead.') + + +def CheckForOldStyleComments(filename, line, linenum, error): + """Logs an error if we see /*-style comment + + Args: + filename: The name of the current file. + line: The text of the line to check. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + if line.find('/*') >= 0 and line[-1] != '\\': + error(filename, linenum, 'readability/old_style_comment', 5, + '/*-style comment found, it should be replaced with //-style. ' + '/*-style comments are only allowed inside macros. ' + 'Note that you should not use /*-style comments to document ' + 'macros itself, use doxygen-style comments for this.') + + +threading_list = ( + ('asctime(', 'os_asctime_r('), + ('ctime(', 'os_ctime_r('), + ('getgrgid(', 'os_getgrgid_r('), + ('getgrnam(', 'os_getgrnam_r('), + ('getlogin(', 'os_getlogin_r('), + ('getpwnam(', 'os_getpwnam_r('), + ('getpwuid(', 'os_getpwuid_r('), + ('gmtime(', 'os_gmtime_r('), + ('localtime(', 'os_localtime_r('), + ('strtok(', 'os_strtok_r('), + ('ttyname(', 'os_ttyname_r('), + ('asctime_r(', 'os_asctime_r('), + ('ctime_r(', 'os_ctime_r('), + ('getgrgid_r(', 'os_getgrgid_r('), + ('getgrnam_r(', 'os_getgrnam_r('), + ('getlogin_r(', 'os_getlogin_r('), + ('getpwnam_r(', 'os_getpwnam_r('), + ('getpwuid_r(', 'os_getpwuid_r('), + ('gmtime_r(', 'os_gmtime_r('), + ('localtime_r(', 'os_localtime_r('), + ('strtok_r(', 'os_strtok_r('), + ('ttyname_r(', 'os_ttyname_r('), +) + + +def CheckPosixThreading(filename, clean_lines, linenum, error): + """Checks for calls to thread-unsafe functions. + + Much code has been originally written without consideration of + multi-threading. Also, engineers are relying on their old experience; + they have learned posix before threading extensions were added. These + tests guide the engineers to use thread-safe functions (when using + posix directly). + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + for single_thread_function, multithread_safe_function in threading_list: + ix = line.find(single_thread_function) + # Comparisons made explicit for clarity -- pylint: + # disable=g-explicit-bool-comparison + if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and + line[ix - 1] not in ('_', '.', '>'))): + error(filename, linenum, 'runtime/threadsafe_fn', 2, + 'Use ' + multithread_safe_function + + '...) instead of ' + single_thread_function + + '...). If it is missing, consider implementing it;' + + ' see os_localtime_r for an example.') + + +memory_functions = ( + ('malloc(', 'xmalloc('), + ('calloc(', 'xcalloc('), + ('realloc(', 'xrealloc('), + ('strdup(', 'xstrdup('), + ('free(', 'xfree('), +) +memory_ignore_pattern = re.compile(r'src/nvim/memory.c$') + + +def CheckMemoryFunctions(filename, clean_lines, linenum, error): + """Checks for calls to invalid functions. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + if memory_ignore_pattern.search(filename): + return + line = clean_lines.elided[linenum] + for function, suggested_function in memory_functions: + ix = line.find(function) + # Comparisons made explicit for clarity -- pylint: + # disable=g-explicit-bool-comparison + if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and + line[ix - 1] not in ('_', '.', '>'))): + error(filename, linenum, 'runtime/memory_fn', 2, + 'Use ' + suggested_function + + '...) instead of ' + function + '...).') + + +# Matches invalid increment: *count++, which moves pointer instead of +# incrementing a value. +_RE_PATTERN_INVALID_INCREMENT = re.compile( + r'^\s*\*\w+(\+\+|--);') + + +class _BlockInfo(object): + + """Stores information about a generic block of code.""" + + def __init__(self, seen_open_brace): + self.seen_open_brace = seen_open_brace + self.open_parentheses = 0 + self.inline_asm = _NO_ASM + + +class _PreprocessorInfo(object): + + """Stores checkpoints of nesting stacks when #if/#else is seen.""" + + def __init__(self, stack_before_if): + # The entire nesting stack before #if + self.stack_before_if = stack_before_if + + # The entire nesting stack up to #else + self.stack_before_else = [] + + # Whether we have already seen #else or #elif + self.seen_else = False + + +class _NestingState(object): + + """Holds states related to parsing braces.""" + + def __init__(self): + # Stack for tracking all braces. An object is pushed whenever we + # see a "{", and popped when we see a "}". Only 1 type of + # object is possible: + # - _BlockInfo: some type of block. + self.stack = [] + + # Stack of _PreprocessorInfo objects. + self.pp_stack = [] + + def SeenOpenBrace(self): + """Check if we have seen the opening brace for the innermost block. + + Returns: + True if we have seen the opening brace, False if the innermost + block is still expecting an opening brace. + """ + return (not self.stack) or self.stack[-1].seen_open_brace + + def UpdatePreprocessor(self, line): + """Update preprocessor stack. + + We need to handle preprocessors due to classes like this: + #ifdef SWIG + struct ResultDetailsPageElementExtensionPoint { + #else + struct ResultDetailsPageElementExtensionPoint : public Extension { + #endif + + We make the following assumptions (good enough for most files): + - Preprocessor condition evaluates to true from #if up to first + #else/#elif/#endif. + + - Preprocessor condition evaluates to false from #else/#elif up + to #endif. We still perform lint checks on these lines, but + these do not affect nesting stack. + + Args: + line: current line to check. + """ + if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line): + # Beginning of #if block, save the nesting stack here. The saved + # stack will allow us to restore the parsing state in the #else + # case. + self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack))) + elif Match(r'^\s*#\s*(else|elif)\b', line): + # Beginning of #else block + if self.pp_stack: + if not self.pp_stack[-1].seen_else: + # This is the first #else or #elif block. Remember the + # whole nesting stack up to this point. This is what we + # keep after the #endif. + self.pp_stack[-1].seen_else = True + self.pp_stack[-1].stack_before_else = copy.deepcopy( + self.stack) + + # Restore the stack to how it was before the #if + self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if) + else: + # TODO(unknown): unexpected #else, issue warning? + pass + elif Match(r'^\s*#\s*endif\b', line): + # End of #if or #else blocks. + if self.pp_stack: + # If we saw an #else, we will need to restore the nesting + # stack to its former state before the #else, otherwise we + # will just continue from where we left off. + if self.pp_stack[-1].seen_else: + # Here we can just use a shallow copy since we are the last + # reference to it. + self.stack = self.pp_stack[-1].stack_before_else + # Drop the corresponding #if + self.pp_stack.pop() + else: + # TODO(unknown): unexpected #endif, issue warning? + pass + + def Update(self, filename, clean_lines, linenum, error): + """Update nesting state with current line. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Update pp_stack first + self.UpdatePreprocessor(line) + + # Count parentheses. This is to avoid adding struct arguments to + # the nesting stack. + if self.stack: + inner_block = self.stack[-1] + depth_change = line.count('(') - line.count(')') + inner_block.open_parentheses += depth_change + + # Also check if we are starting or ending an inline assembly block. + if inner_block.inline_asm in (_NO_ASM, _END_ASM): + if (depth_change != 0 and + inner_block.open_parentheses == 1 and + _MATCH_ASM.match(line)): + # Enter assembly block + inner_block.inline_asm = _INSIDE_ASM + else: + # Not entering assembly block. If previous line was + # _END_ASM, we will now shift to _NO_ASM state. + inner_block.inline_asm = _NO_ASM + elif (inner_block.inline_asm == _INSIDE_ASM and + inner_block.open_parentheses == 0): + # Exit assembly block + inner_block.inline_asm = _END_ASM + + # Consume braces or semicolons from what's left of the line + while True: + # Match first brace, semicolon, or closed parenthesis. + matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line) + if not matched: + break + + token = matched.group(1) + if token == '{': + # If namespace or class hasn't seen an opening brace yet, mark + # namespace/class head as complete. Push a new block onto the + # stack otherwise. + if not self.SeenOpenBrace(): + self.stack[-1].seen_open_brace = True + else: + self.stack.append(_BlockInfo(True)) + if _MATCH_ASM.match(line): + self.stack[-1].inline_asm = _BLOCK_ASM + elif token == ';' or token == ')': + # If we haven't seen an opening brace yet, but we already saw + # a semicolon, this is probably a forward declaration. Pop + # the stack for these. + # + # Similarly, if we haven't seen an opening brace yet, but we + # already saw a closing parenthesis, then these are probably + # function arguments with extra "class" or "struct" keywords. + # Also pop these stack for these. + if not self.SeenOpenBrace(): + self.stack.pop() + else: # token == '}' + # Perform end of block checks and pop the stack. + if self.stack: + self.stack.pop() + line = matched.group(2) + + +def CheckForNonStandardConstructs(filename, clean_lines, linenum, + nesting_state, error): + r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2. + + Complain about several constructs which gcc-2 accepts, but which are + not standard C++. Warning about these in lint is one way to ease the + transition to new compilers. + - put storage class first (e.g. "static const" instead of "const static"). + - "%" PRId64 instead of %qd" in printf-type functions. + - "%1$d" is non-standard in printf-type functions. + - "\%" is an undefined character escape sequence. + - text after #endif is not allowed. + - invalid inner-style forward declaration. + - >? and <? operators, and their >?= and <?= cousins. + + Additionally, check for constructor/destructor style violations and + reference members, as it is very convenient to do so while checking for + gcc-2 compliance. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + nesting_state: A _NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: A callable to which errors are reported, which takes 4 arguments: + filename, line number, error level, and message + """ + + # Remove comments from the line, but leave in strings for now. + line = clean_lines.lines[linenum] + + if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line): + error(filename, linenum, 'runtime/printf_format', 3, + '"%q" in format strings is deprecated. Use "%" PRId64 instead.') + + if Search(r'printf\s*\(.*".*%\d+\$', line): + error(filename, linenum, 'runtime/printf_format', 2, + '%N$ formats are unconventional. Try rewriting to avoid them.') + + # Remove escaped backslashes before looking for undefined escapes. + line = line.replace('\\\\', '') + + if Search(r'("|\').*\\(%|\[|\(|{)', line): + error(filename, linenum, 'build/printf_format', 3, + '%, [, (, and { are undefined character escapes. Unescape them.') + + # For the rest, work with both comments and strings removed. + line = clean_lines.elided[linenum] + + if Search(r'\b(const|volatile|void|char|short|int|long' + r'|float|double|signed|unsigned' + r'|u?int8_t|u?int16_t|u?int32_t|u?int64_t' + r'|u?int_least8_t|u?int_least16_t|u?int_least32_t' + r'|u?int_least64_t' + r'|u?int_fast8_t|u?int_fast16_t|u?int_fast32_t' + r'|u?int_fast64_t' + r'|u?intptr_t|u?intmax_t)' + r'\s+(register|static|extern|typedef)\b', + line): + error(filename, linenum, 'build/storage_class', 5, + 'Storage class (static, extern, typedef, etc) should be first.') + + if Match(r'\s*#\s*endif\s*[^/\s]+', line): + error(filename, linenum, 'build/endif_comment', 5, + 'Uncommented text after #endif is non-standard. Use a comment.') + + if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', + line): + error(filename, linenum, 'build/deprecated', 3, + '>? and <? (max and min) operators are' + ' non-standard and deprecated.') + + +def CheckSpacingForFunctionCall(filename, line, linenum, error): + """Checks for the correctness of various spacing around function calls. + + Args: + filename: The name of the current file. + line: The text of the line to check. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + + # Since function calls often occur inside if/for/while/switch + # expressions - which have their own, more liberal conventions - we + # first see if we should be looking inside such an expression for a + # function call, to which we can apply more strict standards. + fncall = line # if there's no control flow construct, look at whole line + for pattern in (r'\bif\s*\((.*)\)\s*{', + r'\bfor\s*\((.*)\)\s*{', + r'\bwhile\s*\((.*)\)\s*[{;]', + r'\bswitch\s*\((.*)\)\s*{'): + match = Search(pattern, line) + if match: + # look inside the parens for function calls + fncall = match.group(1) + break + + # Except in if/for/while/switch, there should never be space + # immediately inside parens (eg "f( 3, 4 )"). We make an exception + # for nested parens ( (a+b) + c ). Likewise, there should never be + # a space before a ( when it's a function argument. I assume it's a + # function argument when the char before the whitespace is legal in + # a function name (alnum + _) and we're not starting a macro. Also ignore + # pointers and references to arrays and functions coz they're too tricky: + # we use a very simple way to recognize these: + # " (something)(maybe-something)" or + # " (something)(maybe-something," or + # " (something)[something]" + # Note that we assume the contents of [] to be short enough that + # they'll never need to wrap. + if ( # Ignore control structures. + not Search(r'\b(if|for|while|switch|return|sizeof)\b', fncall) and + # Ignore pointers/references to functions. + not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and + # Ignore pointers/references to arrays. + not Search(r' \([^)]+\)\[[^\]]+\]', fncall)): + # a ( used for a fn call + if Search(r'\w\s*\(\s(?!\s*\\$)', fncall): + error(filename, linenum, 'whitespace/parens', 4, + 'Extra space after ( in function call') + elif Search(r'\(\s+(?!(\s*\\)|\()', fncall): + error(filename, linenum, 'whitespace/parens', 2, + 'Extra space after (') + if (Search(r'\w\s+\(', fncall) and + not Search(r'#\s*define|typedef', fncall) and + not Search(r'\w\s+\((\w+::)*\*\w+\)\(', fncall)): + error(filename, linenum, 'whitespace/parens', 4, + 'Extra space before ( in function call') + # If the ) is followed only by a newline or a { + newline, assume it's + # part of a control statement (if/while/etc), and don't complain + if Search(r'[^)]\s+\)\s*[^{\s]', fncall): + # If the closing parenthesis is preceded by only whitespaces, + # try to give a more descriptive error message. + if Search(r'^\s+\)', fncall): + error(filename, linenum, 'whitespace/parens', 2, + 'Closing ) should be moved to the previous line') + else: + error(filename, linenum, 'whitespace/parens', 2, + 'Extra space before )') + + +def IsBlankLine(line): + """Returns true if the given line is blank. + + We consider a line to be blank if the line is empty or consists of + only white spaces. + + Args: + line: A line of a string. + + Returns: + True, if the given line is blank. + """ + return not line or line.isspace() + + +def CheckForFunctionLengths(filename, clean_lines, linenum, + function_state, error): + """Reports for long function bodies. + + For an overview why this is done, see: + http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions + + Uses a simplistic algorithm assuming other style guidelines + (especially spacing) are followed. + Only checks unindented functions, so class members are unchecked. + Trivial bodies are unchecked, so constructors with huge initializer lists + may be missed. + Blank/comment lines are not counted so as to avoid encouraging the removal + of vertical space and comments just to get through a lint check. + NOLINT *on the last line of a function* disables this check. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + function_state: Current function name and lines in body so far. + error: The function to call with any errors found. + """ + lines = clean_lines.lines + line = lines[linenum] + joined_line = '' + + starting_func = False + regexp = r'(\w(\w|::|\*|\&|\s)*)\(' # decls * & space::name( ... + match_result = Match(regexp, line) + if match_result: + # If the name is all caps and underscores, figure it's a macro and + # ignore it, unless it's TEST or TEST_F. + function_name = match_result.group(1).split()[-1] + if function_name == 'TEST' or function_name == 'TEST_F' or ( + not Match(r'[A-Z_]+$', function_name)): + starting_func = True + + if starting_func: + body_found = False + for start_linenum in range(linenum, clean_lines.NumLines()): + start_line = lines[start_linenum] + joined_line += ' ' + start_line.lstrip() + # Declarations and trivial functions + if Search(r'(;|})', start_line): + body_found = True + break # ... ignore + elif Search(r'{', start_line): + body_found = True + function = Search(r'((\w|:)*)\(', line).group(1) + if Match(r'TEST', function): # Handle TEST... macros + parameter_regexp = Search(r'(\(.*\))', joined_line) + if parameter_regexp: # Ignore bad syntax + function += parameter_regexp.group(1) + else: + function += '()' + function_state.Begin(function) + break + if not body_found: + # No body for the function (or evidence of a non-function) was + # found. + error(filename, linenum, 'readability/fn_size', 5, + 'Lint failed to find start of function body.') + elif Match(r'^\}\s*$', line): # function end + function_state.Check(error, filename, linenum) + function_state.End() + elif not Match(r'^\s*$', line): + function_state.Count() # Count non-blank/non-comment lines. + + +_RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?(:?)(\s|$)?') + + +def CheckComment(comment, filename, linenum, error): + """Checks for common mistakes in TODO comments. + + Args: + comment: The text of the comment from the line in question. + filename: The name of the current file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + match = _RE_PATTERN_TODO.match(comment) + if match: + # One whitespace is correct; zero whitespace is handled elsewhere. + leading_whitespace = match.group(1) + if len(leading_whitespace) > 1: + error(filename, linenum, 'whitespace/todo', 2, + 'Too many spaces before TODO') + + username = match.group(2) + if not username: + error(filename, linenum, 'readability/todo', 2, + 'Missing username in TODO; it should look like ' + '"// TODO(my_username): Stuff."') + + colon = match.group(3) + if not colon: + error(filename, linenum, 'readability/todo', 2, + 'Missing colon in TODO; it should look like ' + '"// TODO(my_username): Stuff."') + + middle_whitespace = match.group(4) + # Comparisons made explicit for correctness -- pylint: + # disable=g-explicit-bool-comparison + if middle_whitespace != ' ' and middle_whitespace != '': + error(filename, linenum, 'whitespace/todo', 2, + 'TODO(my_username): should be followed by a space') + + +def FindNextMatchingAngleBracket(clean_lines, linenum, init_suffix): + """Find the corresponding > to close a template. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: Current line number. + init_suffix: Remainder of the current line after the initial <. + + Returns: + True if a matching bracket exists. + """ + line = init_suffix + nesting_stack = ['<'] + while True: + # Find the next operator that can tell us whether < is used as an + # opening bracket or as a less-than operator. We only want to + # warn on the latter case. + # + # We could also check all other operators and terminate the search + # early, e.g. if we got something like this "a<b+c", the "<" is + # most likely a less-than operator, but then we will get false + # positives for default arguments and other template expressions. + match = Search(r'^[^<>(),;\[\]]*([<>(),;\[\]])(.*)$', line) + if match: + # Found an operator, update nesting stack + operator = match.group(1) + line = match.group(2) + + if nesting_stack[-1] == '<': + # Expecting closing angle bracket + if operator in ('<', '(', '['): + nesting_stack.append(operator) + elif operator == '>': + nesting_stack.pop() + if not nesting_stack: + # Found matching angle bracket + return True + elif operator == ',': + # Got a comma after a bracket, this is most likely a + # template argument. We have not seen a closing angle + # bracket yet, but it's probably a few lines later if we + # look for it, so just return early here. + return True + else: + # Got some other operator. + return False + + else: + # Expecting closing parenthesis or closing bracket + if operator in ('<', '(', '['): + nesting_stack.append(operator) + elif operator in (')', ']'): + # We don't bother checking for matching () or []. If we got + # something like (] or [), it would have been a syntax + # error. + nesting_stack.pop() + + else: + # Scan the next line + linenum += 1 + if linenum >= len(clean_lines.elided): + break + line = clean_lines.elided[linenum] + + # Exhausted all remaining lines and still no matching angle bracket. + # Most likely the input was incomplete, otherwise we should have + # seen a semicolon and returned early. + return True + + +def FindPreviousMatchingAngleBracket(clean_lines, linenum, init_prefix): + """Find the corresponding < that started a template. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: Current line number. + init_prefix: Part of the current line before the initial >. + + Returns: + True if a matching bracket exists. + """ + line = init_prefix + nesting_stack = ['>'] + while True: + # Find the previous operator + match = Search(r'^(.*)([<>(),;\[\]])[^<>(),;\[\]]*$', line) + if match: + # Found an operator, update nesting stack + operator = match.group(2) + line = match.group(1) + + if nesting_stack[-1] == '>': + # Expecting opening angle bracket + if operator in ('>', ')', ']'): + nesting_stack.append(operator) + elif operator == '<': + nesting_stack.pop() + if not nesting_stack: + # Found matching angle bracket + return True + elif operator == ',': + # Got a comma before a bracket, this is most likely a + # template argument. The opening angle bracket is probably + # there if we look for it, so just return early here. + return True + else: + # Got some other operator. + return False + + else: + # Expecting opening parenthesis or opening bracket + if operator in ('>', ')', ']'): + nesting_stack.append(operator) + elif operator in ('(', '['): + nesting_stack.pop() + + else: + # Scan the previous line + linenum -= 1 + if linenum < 0: + break + line = clean_lines.elided[linenum] + + # Exhausted all earlier lines and still no matching angle bracket. + return False + + +def CheckExpressionAlignment(filename, clean_lines, linenum, error, startpos=0): + """Checks for the correctness of alignment inside expressions + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + startpos: Position where to start searching for expression start. + """ + level_starts = {} + line = clean_lines.elided_with_space_strings[linenum] + prev_line_start = Search(r'\S', line).start() + depth_line_starts = {} + pos = min([ + idx + for idx in ( + line.find(k, startpos) + for k in BRACES + if k != '{' + ) + if idx >= 0 + ] + [len(line) + 1]) + if pos == len(line) + 1: + return + ignore_error_levels = set() + firstlinenum = linenum + for linenum, pos, brace, depth in GetExprBracesPosition( + clean_lines, linenum, pos + ): + line = clean_lines.elided_with_space_strings[linenum] + if depth is None: + if pos < len(line) - 1: + CheckExpressionAlignment(filename, clean_lines, linenum, error, + pos + 1) + return + elif depth <= 0: + error(filename, linenum, 'syntax/parenthesis', 4, + 'Unbalanced parenthesis') + return + if brace == 's': + assert firstlinenum != linenum + if level_starts[depth][1]: + if line[pos] == BRACES[depth_line_starts[depth][1]]: + if pos != depth_line_starts[depth][0]: + if depth not in ignore_error_levels: + error(filename, linenum, 'whitespace/indent', 2, + 'End of the inner expression should have ' + 'the same indent as start') + else: + if (pos != depth_line_starts[depth][0] + 4 + and not (depth_line_starts[depth][1] == '{' + and pos == depth_line_starts[depth][0] + 2)): + if depth not in ignore_error_levels: + error(filename, linenum, 'whitespace/indent', 2, + 'Inner expression indentation should be 4') + else: + if (pos != level_starts[depth][0] + 1 + + (level_starts[depth][2] == '{')): + if depth not in ignore_error_levels: + error(filename, linenum, 'whitespace/alignment', 2, + 'Inner expression should be aligned ' + 'as opening brace + 1 (+ 2 in case of {)') + prev_line_start = pos + elif brace == 'e': + pass + else: + opening = brace in BRACES + if opening: + # Only treat {} as part of the expression if it is preceded by + # "=" (brace initializer) or "(type)" (construct like (struct + # foo) { ... }). + if brace == '{' and not (Search( + r'(?:= *|\((?:struct )?\w+(\s*\[\w*\])?\)) *$', + line[:pos]) + ): + ignore_error_levels.add(depth) + line_ended_with_opening = ( + pos == len(line) - 2 * (line.endswith(' \\')) - 1) + level_starts[depth] = (pos, line_ended_with_opening, brace) + if line_ended_with_opening: + depth_line_starts[depth] = (prev_line_start, brace) + else: + del level_starts[depth] + + +def CheckSpacing(filename, clean_lines, linenum, nesting_state, error): + """Checks for the correctness of various spacing issues in the code. + + Things we check for: spaces around operators, spaces after + if/for/while/switch, no spaces around parens in function calls, two + spaces between code and comment, don't start a block with a blank + line, don't end a function with a blank line, don't add a blank line + after public/protected/private, don't have too many blank lines in a row, + spaces after {, spaces before }. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + nesting_state: A _NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: The function to call with any errors found. + """ + + # Don't use "elided" lines here, otherwise we can't check commented lines. + # Don't want to use "raw" either, because we don't want to check inside + # C++11 raw strings, + raw = clean_lines.lines_without_raw_strings + line = raw[linenum] + + # Before nixing comments, check if the line is blank for no good + # reason. This includes the first line after a block is opened, and + # blank lines at the end of a function (ie, right before a line like '}' + # + # Skip all the blank line checks if we are immediately inside a + # namespace body. In other words, don't issue blank line warnings + # for this block: + # namespace { + # + # } + # + # A warning about missing end of namespace comments will be issued instead. + if IsBlankLine(line): + elided = clean_lines.elided + prev_line = elided[linenum - 1] + prevbrace = prev_line.rfind('{') + # TODO(unknown): Don't complain if line before blank line, and line + # after,both start with alnums and are indented the same + # amount. This ignores whitespace at the start of a + # namespace block because those are not usually indented. + if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1: + # OK, we have a blank line at the start of a code block. Before we + # complain, we check if it is an exception to the rule: The previous + # non-empty line has the parameters of a function header that are + # indented 4 spaces (because they did not fit in a 80 column line + # when placed on the same line as the function name). We also check + # for the case where the previous line is indented 6 spaces, which + # may happen when the initializers of a constructor do not fit into + # a 80 column line. + exception = False + if Match(r' {6}\w', prev_line): # Initializer list? + # We are looking for the opening column of initializer list, + # which should be indented 4 spaces to cause 6 space indentation + # afterwards. + search_position = linenum - 2 + while (search_position >= 0 + and Match(r' {6}\w', elided[search_position])): + search_position -= 1 + exception = (search_position >= 0 + and elided[search_position][:5] == ' :') + else: + # Search for the function arguments or an initializer list. We + # use a simple heuristic here: If the line is indented 4 spaces; + # and we have a closing paren, without the opening paren, + # followed by an opening brace or colon (for initializer lists) + # we assume that it is the last line of a function header. If + # we have a colon indented 4 spaces, it is an initializer list. + exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)', + prev_line) + or Match(r' {4}:', prev_line)) + + if not exception: + error(filename, linenum, 'whitespace/blank_line', 2, + 'Redundant blank line at the start of a code block ' + 'should be deleted.') + # Ignore blank lines at the end of a block in a long if-else + # chain, like this: + # if (condition1) { + # // Something followed by a blank line + # + # } else if (condition2) { + # // Something else + # } + if linenum + 1 < clean_lines.NumLines(): + next_line = raw[linenum + 1] + if (next_line + and Match(r'\s*}', next_line) + and next_line.find('} else ') == -1): + error(filename, linenum, 'whitespace/blank_line', 3, + 'Redundant blank line at the end of a code block ' + 'should be deleted.') + + # Next, we complain if there's a comment too near the text + commentpos = line.find('//') + if commentpos != -1: + # Check if the // may be in quotes. If so, ignore it + # Comparisons made explicit for clarity -- pylint: + # disable=g-explicit-bool-comparison + if (line.count('"', 0, commentpos) - + line.count('\\"', 0, commentpos)) % 2 == 0: # not in quotes + # Allow one space for new scopes, two spaces otherwise: + if (not Match(r'^\s*{ //', line) and + ((commentpos >= 1 and + line[commentpos - 1] not in string.whitespace) or + (commentpos >= 2 and + line[commentpos - 2] not in string.whitespace))): + error(filename, linenum, 'whitespace/comments', 2, + 'At least two spaces is best between code and comments') + # There should always be a space between the // and the comment + commentend = commentpos + 2 + if commentend < len(line) and not line[commentend] == ' ': + # but some lines are exceptions -- e.g. if they're big + # comment delimiters like: + # //---------------------------------------------------------- + # or are an empty C++ style Doxygen comment, like: + # /// + # or C++ style Doxygen comments placed after the variable: + # ///< Header comment + # //!< Header comment + # or they begin with multiple slashes followed by a space: + # //////// Header comment + match = (Search(r'[=/-]{4,}\s*$', line[commentend:]) or + Search(r'^/$', line[commentend:]) or + Search(r'^!< ', line[commentend:]) or + Search(r'^/< ', line[commentend:]) or + Search(r'^/+ ', line[commentend:])) + if not match: + error(filename, linenum, 'whitespace/comments', 4, + 'Should have a space between // and comment') + CheckComment(line[commentpos:], filename, linenum, error) + + line = clean_lines.elided[linenum] # get rid of comments and strings + + # Don't try to do spacing checks for operator methods + line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line) + + # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )". + # Otherwise not. Note we only check for non-spaces on *both* sides; + # sometimes people put non-spaces on one side when aligning ='s among + # many lines (not that this is behavior that I approve of...) + if Search(r'[\w.]=[\w.]', line) and not Search(r'\b(if|while) ', line): + error(filename, linenum, 'whitespace/operators', 4, + 'Missing spaces around =') + + # It's ok not to have spaces around binary operators like + - * /, but if + # there's too little whitespace, we get concerned. It's hard to tell, + # though, so we punt on this one for now. TODO. + + match = Search(r'(?:[^ (*/![])+(?<!\+\+|--)\*', line) + if match: + error(filename, linenum, 'whitespace/operators', 2, + 'Missing space before asterisk in %s' % match.group(0)) + + # You should always have whitespace around binary operators. + # + # Check <= and >= first to avoid false positives with < and >, then + # check non-include lines for spacing around < and >. + match = Search(r'[^<>=!\s](==|!=|<=|>=)[^<>=!\s]', line) + if match: + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around %s' % match.group(1)) + + # Boolean operators should be placed on the next line. + if Search(r'(?:&&|\|\|)$', line): + error(filename, linenum, 'whitespace/operators', 4, + 'Boolean operator should be placed on the same line as the start ' + 'of its right operand') + + # We allow no-spaces around << when used like this: 10<<20, but + # not otherwise (particularly, not when used as streams) + # Also ignore using ns::operator<<; + match = Search(r'(operator|\S)(?:L|UL|ULL|l|ul|ull)?<<(\S)', line) + if (match and + not (match.group(1).isdigit() and match.group(2).isdigit()) and + not (match.group(1) == 'operator' and match.group(2) == ';')): + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around <<') + elif not Match(r'#.*include', line): + # Avoid false positives on -> + reduced_line = line.replace('->', '') + + # Look for < that is not surrounded by spaces. This is only + # triggered if both sides are missing spaces, even though + # technically should should flag if at least one side is missing a + # space. This is done to avoid some false positives with shifts. + match = Search(r'[^\s<]<([^\s=<].*)', reduced_line) + if (match and not FindNextMatchingAngleBracket(clean_lines, linenum, + match.group(1))): + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around <') + + # Look for > that is not surrounded by spaces. Similar to the + # above, we only trigger if both sides are missing spaces to avoid + # false positives with shifts. + match = Search(r'^(.*[^\s>])>[^\s=>]', reduced_line) + if (match and + not FindPreviousMatchingAngleBracket(clean_lines, linenum, + match.group(1))): + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around >') + + # We allow no-spaces around >> for almost anything. This is because + # C++11 allows ">>" to close nested templates, which accounts for + # most cases when ">>" is not followed by a space. + # + # We still warn on ">>" followed by alpha character, because that is + # likely due to ">>" being used for right shifts, e.g.: + # value >> alpha + # + # When ">>" is used to close templates, the alphanumeric letter that + # follows would be part of an identifier, and there should still be + # a space separating the template type and the identifier. + # type<type<type>> alpha + match = Search(r'>>[a-zA-Z_]', line) + if match: + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around >>') + + # There shouldn't be space around unary operators + match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line) + if match: + error(filename, linenum, 'whitespace/operators', 4, + 'Extra space for operator %s' % match.group(1)) + + # A pet peeve of mine: no spaces after an if, while, switch, or for + match = Search(r' (if\(|for\(|while\(|switch\()', line) + if match: + error(filename, linenum, 'whitespace/parens', 5, + 'Missing space before ( in %s' % match.group(1)) + + # For if/for/while/switch, the left and right parens should be + # consistent about how many spaces are inside the parens, and + # there should either be zero or one spaces inside the parens. + # We don't want: "if ( foo)" or "if ( foo )". + # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed. + match = Search(r'\b(if|for|while|switch)\s*' + r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$', + line) + if match: + if len(match.group(2)) != len(match.group(4)): + if not (match.group(3) == ';' and + len(match.group(2)) == 1 + len(match.group(4)) or + not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)): + error(filename, linenum, 'whitespace/parens', 5, + 'Mismatching spaces inside () in %s' % match.group(1)) + if len(match.group(2)) not in [0, 1]: + error(filename, linenum, 'whitespace/parens', 5, + 'Should have zero or one spaces inside ( and ) in %s' % + match.group(1)) + + # You should always have a space after a comma (either as fn arg or + # operator). + # + # This does not apply when the non-space character following the + # comma is another comma, since the only time when that happens is + # for empty macro arguments. + # + # We run this check in two passes: first pass on elided lines to + # verify that lines contain missing whitespaces, second pass on raw + # lines to confirm that those missing whitespaces are not due to + # elided comments. + if Search(r',[^,\s]', line) and Search(r',[^,\s]', raw[linenum]): + error(filename, linenum, 'whitespace/comma', 3, + 'Missing space after ,') + + # You should always have a space after a semicolon + # except for few corner cases + # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more + # space after ; + if Search(r';[^\s};\\)/]', line): + error(filename, linenum, 'whitespace/semicolon', 3, + 'Missing space after ;') + + # Next we will look for issues with function calls. + CheckSpacingForFunctionCall(filename, line, linenum, error) + + # Check whether everything inside expressions is aligned correctly + if any((line.find(k) >= 0 for k in BRACES if k != '{')): + CheckExpressionAlignment(filename, clean_lines, linenum, error) + + # Except after an opening paren, or after another opening brace (in case of + # an initializer list, for instance), you should have spaces before your + # braces. And since you should never have braces at the beginning of a line, + # this is an easy test. + match = Match(r'^(.*[^ ({]){', line) + if match: + # Try a bit harder to check for brace initialization. This + # happens in one of the following forms: + # Constructor() : initializer_list_{} { ... } + # Constructor{}.MemberFunction() + # Type variable{}; + # FunctionCall(type{}, ...); + # LastArgument(..., type{}); + # LOG(INFO) << type{} << " ..."; + # map_of_type[{...}] = ...; + # + # We check for the character following the closing brace, and + # silence the warning if it's one of those listed above, i.e. + # "{.;,)<]". + # + # To account for nested initializer list, we allow any number of + # closing braces up to "{;,)<". We can't simply silence the + # warning on first sight of closing brace, because that would + # cause false negatives for things that are not initializer lists. + # Silence this: But not this: + # Outer{ if (...) { + # Inner{...} if (...){ // Missing space before { + # }; } + # + # There is a false negative with this approach if people inserted + # spurious semicolons, e.g. "if (cond){};", but we will catch the + # spurious semicolon with a separate check. + (endline, endlinenum, endpos) = CloseExpression( + clean_lines, linenum, len(match.group(1))) + trailing_text = '' + if endpos > -1: + trailing_text = endline[endpos:] + for offset in range(endlinenum + 1, + min(endlinenum + 3, clean_lines.NumLines() - 1)): + trailing_text += clean_lines.elided[offset] + if not Match(r'^[\s}]*[{.;,)<\]]', trailing_text): + error(filename, linenum, 'whitespace/braces', 5, + 'Missing space before {') + + # Make sure '} else {' has spaces. + if Search(r'}else', line): + error(filename, linenum, 'whitespace/braces', 5, + 'Missing space before else') + + # You shouldn't have spaces before your brackets, except maybe after + # 'delete []' or 'new char * []'. + if Search(r'\w\s+\[', line): + error(filename, linenum, 'whitespace/braces', 5, + 'Extra space before [') + + # You shouldn't have a space before a semicolon at the end of the line. + if Search(r':\s*;\s*$', line): + error(filename, linenum, 'whitespace/semicolon', 5, + 'Semicolon defining empty statement. Use {} instead.') + elif Search(r'^\s*;\s*$', line): + error(filename, linenum, 'whitespace/semicolon', 5, + 'Line contains only semicolon. If this should be an empty' + ' statement, use {} instead.') + elif Search(r'\s+;\s*$', line): + error(filename, linenum, 'whitespace/semicolon', 5, + 'Extra space before last semicolon. If this should be an empty ' + 'statement, use {} instead.') + + if Search(r'\{(?!\})\S', line): + error(filename, linenum, 'whitespace/braces', 5, + 'Missing space after {') + if Search(r'\S(?<!\{)\}', line): + error(filename, linenum, 'whitespace/braces', 5, + 'Missing space before }') + + if Search(r'\S {2,}\\$', line): + error(filename, linenum, 'whitespace/line_continuation', 5, + 'Too many spaces before \\, line continuation character must be ' + 'preceded by exactly one space. For “blank lines†' + 'it is preferred to use the same amount of spaces as preceding ' + 'indent') + + if Match(r'^ +#', line): + error(filename, linenum, 'whitespace/indent', 5, + 'Must not indent preprocessor directives, use 1-space indent ' + 'after the hash') + + cast_line = re.sub(r'^# *define +\w+\([^)]*\)', '', line) + match = Search(r'\((?:const )?(?:struct )?[a-zA-Z_]\w*(?: *\*(?:const)?)*\)' + r' +' + r'-?(?:\*+|&)?(?:\w+|\+\+|--|\()', cast_line) + if match and line[0] == ' ': + error(filename, linenum, 'whitespace/cast', 2, + 'Should leave no spaces after a cast: {!r}'.format( + match.group(0))) + + +def GetPreviousNonBlankLine(clean_lines, linenum): + """Return the most recent non-blank line and its line number. + + Args: + clean_lines: A CleansedLines instance containing the file contents. + linenum: The number of the line to check. + + Returns: + A tuple with two elements. The first element is the contents of the last + non-blank line before the current line, or the empty string if this is the + first non-blank line. The second is the line number of that line, or -1 + if this is the first non-blank line. + """ + + prevlinenum = linenum - 1 + while prevlinenum >= 0: + prevline = clean_lines.elided[prevlinenum] + if not IsBlankLine(prevline): # if not a blank line... + return (prevline, prevlinenum) + prevlinenum -= 1 + return ('', -1) + + +def CheckBraces(filename, clean_lines, linenum, error): + """Looks for misplaced braces (e.g. at the end of line). + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + + line = clean_lines.elided[linenum] # get rid of comments and strings + + if not (filename.endswith('.c') or filename.endswith('.h')): + if Match(r'\s*{\s*$', line): + # We allow an open brace to start a line in the case where someone + # is using braces in a block to explicitly create a new scope, which + # is commonly used to control the lifetime of stack-allocated + # variables. Braces are also used for brace initializers inside + # function calls. We don't detect this perfectly: we just don't + # complain if the last non-whitespace character on the previous + # non-blank line is ',', ';', ':', '(', '{', or '}', or if the + # previous line starts a preprocessor block. + prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] + if (not Search(r'[,;:}{(]\s*$', prevline) and + not Match(r'\s*#', prevline)): + error(filename, linenum, 'whitespace/braces', 4, + '{ should almost always be at the end' + ' of the previous line') + + # An else clause should be on the same line as the preceding closing brace. + # If there is no preceding closing brace, there should be one. + if Match(r'\s*else\s*', line): + prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] + if Match(r'\s*}\s*$', prevline): + error(filename, linenum, 'whitespace/newline', 4, + 'An else should appear on the same line as the preceding }') + else: + error(filename, linenum, 'readability/braces', 5, + 'An else should always have braces before it') + + # If should always have a brace + for blockstart in ('if', 'while', 'for'): + if Match(r'\s*{0}(?!\w)[^{{]*$'.format(blockstart), line): + pos = line.find(blockstart) + pos = line.find('(', pos) + if pos > 0: + (endline, _, endpos) = CloseExpression( + clean_lines, linenum, pos) + if endline[endpos:].find('{') == -1: + error(filename, linenum, 'readability/braces', 5, + '{0} should always use braces'.format(blockstart)) + + # If braces come on one side of an else, they should be on both. + # However, we have to worry about "else if" that spans multiple lines! + if Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line): + if Search(r'}\s*else if([^{]*)$', line): # could be multi-line if + # find the ( after the if + pos = line.find('else if') + pos = line.find('(', pos) + if pos > 0: + (endline, _, endpos) = CloseExpression( + clean_lines, linenum, pos) + # must be brace after if + if endline[endpos:].find('{') == -1: + error(filename, linenum, 'readability/braces', 5, + 'If an else has a brace on one side,' + ' it should have it on both') + else: # common case: else not followed by a multi-line if + error(filename, linenum, 'readability/braces', 5, + 'If an else has a brace on one side,' + ' it should have it on both') + + # Likewise, an else should never have the else clause on the same line + if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line): + error(filename, linenum, 'whitespace/newline', 4, + 'Else clause should never be on same line as else (use 2 lines)') + + # In the same way, a do/while should never be on one line + if Match(r'\s*do [^\s{]', line): + error(filename, linenum, 'whitespace/newline', 4, + 'do/while clauses should not be on a single line') + + # Block bodies should not be followed by a semicolon. Due to C++11 + # brace initialization, there are more places where semicolons are + # required than not, so we use a whitelist approach to check these + # rather than a blacklist. These are the places where "};" should + # be replaced by just "}": + # 1. Some flavor of block following closing parenthesis: + # for (;;) {}; + # while (...) {}; + # switch (...) {}; + # Function(...) {}; + # if (...) {}; + # if (...) else if (...) {}; + # + # 2. else block: + # if (...) else {}; + # + # 3. const member function: + # Function(...) const {}; + # + # 4. Block following some statement: + # x = 42; + # {}; + # + # 5. Block at the beginning of a function: + # Function(...) { + # {}; + # } + # + # Note that naively checking for the preceding "{" will also match + # braces inside multi-dimensional arrays, but this is fine since + # that expression will not contain semicolons. + # + # 6. Block following another block: + # while (true) {} + # {}; + # + # 7. End of namespaces: + # namespace {}; + # + # These semicolons seems far more common than other kinds of + # redundant semicolons, possibly due to people converting classes + # to namespaces. For now we do not warn for this case. + # + # Try matching case 1 first. + match = Match(r'^(.*\)\s*)\{', line) + if match: + # Matched closing parenthesis (case 1). Check the token before the + # matching opening parenthesis, and don't warn if it looks like a + # macro. This avoids these false positives: + # - macro that defines a base class + # - multi-line macro that defines a base class + # - macro that defines the whole class-head + # + # But we still issue warnings for macros that we know are safe to + # warn, specifically: + # - TEST, TEST_F, TEST_P, MATCHER, MATCHER_P + # - TYPED_TEST + # - INTERFACE_DEF + # - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED: + # + # We implement a whitelist of safe macros instead of a blacklist of + # unsafe macros, even though the latter appears less frequently in + # google code and would have been easier to implement. This is because + # the downside for getting the whitelist wrong means some extra + # semicolons, while the downside for getting the blacklist wrong + # would result in compile errors. + # + # In addition to macros, we also don't want to warn on compound + # literals. + closing_brace_pos = match.group(1).rfind(')') + opening_parenthesis = ReverseCloseExpression( + clean_lines, linenum, closing_brace_pos) + if opening_parenthesis[2] > -1: + line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]] + macro = Search(r'\b([A-Z_]+)\s*$', line_prefix) + if ((macro and + macro.group(1) not in ( + 'TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST', + 'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED', + 'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or + Search(r'\s+=\s*$', line_prefix) or + Search(r'^\s*return\s*$', line_prefix)): + match = None + + else: + # Try matching cases 2-3. + match = Match(r'^(.*(?:else|\)\s*const)\s*)\{', line) + if not match: + # Try matching cases 4-6. These are always matched on separate + # lines. + # + # Note that we can't simply concatenate the previous line to the + # current line and do a single match, otherwise we may output + # duplicate warnings for the blank line case: + # if (cond) { + # // blank line + # } + prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] + if prevline and Search(r'[;{}]\s*$', prevline): + match = Match(r'^(\s*)\{', line) + + # Check matching closing brace + if match: + (endline, endlinenum, endpos) = CloseExpression( + clean_lines, linenum, len(match.group(1))) + if endpos > -1 and Match(r'^\s*;', endline[endpos:]): + # Current {} pair is eligible for semicolon check, and we have found + # the redundant semicolon, output warning here. + # + # Note: because we are scanning forward for opening braces, and + # outputting warnings for the matching closing brace, if there are + # nested blocks with trailing semicolons, we will get the error + # messages in reversed order. + error(filename, endlinenum, 'readability/braces', 4, + "You don't need a ; after a }") + + +def CheckEmptyBlockBody(filename, clean_lines, linenum, error): + """Look for empty loop/conditional body with only a single semicolon. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + + # Search for loop keywords at the beginning of the line. Because only + # whitespaces are allowed before the keywords, this will also ignore most + # do-while-loops, since those lines should start with closing brace. + # + # We also check "if" blocks here, since an empty conditional block + # is likely an error. + line = clean_lines.elided[linenum] + matched = Match(r'\s*(for|while|if)\s*\(', line) + if matched: + # Find the end of the conditional expression + (end_line, end_linenum, end_pos) = CloseExpression( + clean_lines, linenum, line.find('(')) + + # Output warning if what follows the condition expression is a + # semicolon. No warning for all other cases, including whitespace or + # newline, since we have a separate check for semicolons preceded by + # whitespace. + if end_pos >= 0 and Match(r';', end_line[end_pos:]): + if matched.group(1) == 'if': + error(filename, end_linenum, + 'whitespace/empty_conditional_body', 5, + 'Empty conditional bodies should use {}') + else: + error(filename, end_linenum, 'whitespace/empty_loop_body', 5, + 'Empty loop bodies should use {} or continue') + + +def CheckAltTokens(filename, clean_lines, linenum, error): + """Check alternative keywords being used in boolean expressions. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Avoid preprocessor lines + if Match(r'^\s*#', line): + return + + # Last ditch effort to avoid multi-line comments. This will not help + # if the comment started before the current line or ended after the + # current line, but it catches most of the false positives. At least, + # it provides a way to workaround this warning for people who use + # multi-line comments in preprocessor macros. + # + # TODO(unknown): remove this once cpplint has better support for + # multi-line comments. + if line.find('/*') >= 0 or line.find('*/') >= 0: + return + + for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line): + error(filename, linenum, 'readability/alt_tokens', 2, + 'Use operator %s instead of %s' % ( + _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1))) + + +def GetLineWidth(line): + """Determines the width of the line in column positions. + + Args: + line: A string, which may be a Unicode string. + + Returns: + The width of the line in column positions, accounting for Unicode + combining characters and wide characters. + """ + if isinstance(line, str): + width = 0 + for uc in unicodedata.normalize('NFC', line): + if unicodedata.east_asian_width(uc) in ('W', 'F'): + width += 2 + elif not unicodedata.combining(uc): + width += 1 + return width + else: + return len(line) + + +def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state, + error): + """Checks rules from the 'C++ style rules' section of cppguide.html. + + Most of these rules are hard to test (naming, comment style), but we + do what we can. In particular we check for 2-space indents, line lengths, + tab usage, spaces inside code, etc. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + file_extension: The extension (without the dot) of the filename. + nesting_state: A _NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: The function to call with any errors found. + """ + + # Don't use "elided" lines here, otherwise we can't check commented lines. + # Don't want to use "raw" either, because we don't want to check inside + # C++11 raw strings, + raw_lines = clean_lines.lines_without_raw_strings + line = raw_lines[linenum] + + if line.find('\t') != -1: + error(filename, linenum, 'whitespace/tab', 1, + 'Tab found; better to use spaces') + + # One or three blank spaces at the beginning of the line is weird; it's + # hard to reconcile that with 2-space indents. + # NOTE: here are the conditions rob pike used for his tests. Mine aren't + # as sophisticated, but it may be worth becoming so: + # RLENGTH==initial_spaces + # if(RLENGTH > 20) complain = 0; + # if(match($0, " +(error|private|public|protected):")) complain = 0; + # if(match(prev, "&& *$")) complain = 0; + # if(match(prev, "\\|\\| *$")) complain = 0; + # if(match(prev, "[\",=><] *$")) complain = 0; + # if(match($0, " <<")) complain = 0; + # if(match(prev, " +for \\(")) complain = 0; + # if(prevodd && match(prevprev, " +for \\(")) complain = 0; + initial_spaces = 0 + cleansed_line = clean_lines.elided[linenum] + while initial_spaces < len(line) and line[initial_spaces] == ' ': + initial_spaces += 1 + if line and line[-1].isspace(): + error(filename, linenum, 'whitespace/end_of_line', 4, + 'Line ends in whitespace. Consider deleting these extra spaces.') + # There are certain situations we allow one space, notably for section + # labels + elif ((initial_spaces == 1 or initial_spaces == 3) and + not Match(r'\s*\w+\s*:\s*$', cleansed_line)): + error(filename, linenum, 'whitespace/indent', 3, + 'Weird number of spaces at line-start. ' + 'Are you using a 2-space indent?') + + # Check if the line is a header guard. + is_header_guard = False + if file_extension == 'h': + cppvar = GetHeaderGuardCPPVariable(filename) + if (line.startswith('#ifndef %s' % cppvar) or + line.startswith('#define %s' % cppvar) or + line.startswith('#endif // %s' % cppvar)): + is_header_guard = True + # #include lines and header guards can be long, since there's no clean way + # to split them. + # + # URLs can be long too. It's possible to split these, but it makes them + # harder to cut&paste. + # + # The "$Id:...$" comment may also get very long without it being the + # developers fault. + if (not line.startswith('#include') and not is_header_guard and + not Match(r'^\s*//.*http(s?)://\S*$', line) and + not Match(r'^// \$Id:.*#[0-9]+ \$$', line)): + line_width = GetLineWidth(line) + extended_length = int((_line_length * 1.25)) + if line_width > extended_length: + error(filename, linenum, 'whitespace/line_length', 4, + 'Lines should very rarely be longer than %i characters' % + extended_length) + elif line_width > _line_length: + error(filename, linenum, 'whitespace/line_length', 2, + 'Lines should be <= %i characters long' % _line_length) + + if (cleansed_line.count(';') > 1 and + # for loops are allowed two ;'s (and may run over two lines). + cleansed_line.find('for') == -1 and + (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or + GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and + # It's ok to have many commands in a switch case that fits in 1 line + not ((cleansed_line.find('case ') != -1 or + cleansed_line.find('default:') != -1) and + cleansed_line.find('break;') != -1)): + error(filename, linenum, 'whitespace/newline', 0, + 'More than one command on the same line') + + # Some more style checks + CheckBraces(filename, clean_lines, linenum, error) + CheckEmptyBlockBody(filename, clean_lines, linenum, error) + CheckSpacing(filename, clean_lines, linenum, nesting_state, error) + CheckAltTokens(filename, clean_lines, linenum, error) + + +_RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"') +_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$') +# Matches the first component of a filename delimited by -s and _s. That is: +# _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo' +# _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo' +# _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo' +# _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo' +_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+') + + +def _ClassifyInclude(fileinfo, include, is_system): + """Figures out what kind of header 'include' is. + + Args: + fileinfo: The current file cpplint is running over. A FileInfo instance. + include: The path to a #included file. + is_system: True if the #include used <> rather than "". + + Returns: + One of the _XXX_HEADER constants. + """ + if is_system: + return _C_SYS_HEADER + return _OTHER_HEADER + + +def CheckIncludeLine(filename, clean_lines, linenum, include_state, error): + """Check rules that are applicable to #include lines. + + Strings on #include lines are NOT removed from elided line, to make + certain tasks easier. However, to prevent false positives, checks + applicable to #include lines in CheckLanguage must be put here. + + Args: + filename : The name of the current file. + clean_lines : A CleansedLines instance containing the file. + linenum : The number of the line to check. + include_state : An _IncludeState instance in which the headers are + inserted. + error : The function to call with any errors found. + """ + fileinfo = FileInfo(filename) + + line = clean_lines.lines[linenum] + + # "include" should use the new style "foo/bar.h" instead of just "bar.h" + # XXX: neovim doesn't currently use this style + # if _RE_PATTERN_INCLUDE_NEW_STYLE.search(line): + # error(filename, linenum, 'build/include', 4, + # 'Include the directory when naming .h files') + + # we shouldn't include a file more than once. actually, there are a + # handful of instances where doing so is okay, but in general it's + # not. + match = _RE_PATTERN_INCLUDE.search(line) + if match: + include = match.group(2) + is_system = (match.group(1) == '<') + if include in include_state: + error(filename, linenum, 'build/include', 4, + '"%s" already included at %s:%s' % + (include, filename, include_state[include])) + else: + include_state[include] = linenum + + # We want to ensure that headers appear in the right order: + # 1) for foo.cc, foo.h (preferred location) + # 2) c system files + # 3) cpp system files + # 4) for foo.cc, foo.h (deprecated location) + # 5) other google headers + # + # We classify each include statement as one of those 5 types + # using a number of techniques. The include_state object keeps + # track of the highest type seen, and complains if we see a + # lower type after that. + error_message = include_state.CheckNextIncludeOrder( + _ClassifyInclude(fileinfo, include, is_system)) + if error_message: + error(filename, linenum, 'build/include_order', 4, + '%s. Should be: c system, c++ system, other.' + % error_message) + canonical_include = include_state.CanonicalizeAlphabeticalOrder( + include) + include_state.SetLastHeader(canonical_include) + + +def _GetTextInside(text, start_pattern): + r"""Retrieves all the text between matching open and close parentheses. + + Given a string of lines and a regular expression string, retrieve all the + text following the expression and between opening punctuation symbols like + (, [, or {, and the matching close-punctuation symbol. This properly nested + occurrences of the punctuations, so for the text like + printf(a(), b(c())); + a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'. + start_pattern must match string having an open punctuation symbol at the + end. + + Args: + text: The lines to extract text. Its comments and strings must be elided. + It can be single line and can span multiple lines. + start_pattern: The regexp string indicating where to start extracting + the text. + Returns: + The extracted text. + None if either the opening string or ending punctuation couldn't be found. + """ + # TODO(sugawarayu): Audit cpplint.py to see what places could be profitably + # rewritten to use _GetTextInside (and use inferior regexp matching today). + + # Give opening punctuations to get the matching close-punctuations. + matching_punctuation = {'(': ')', '{': '}', '[': ']'} + closing_punctuation = set(matching_punctuation.values()) + + # Find the position to start extracting text. + match = re.search(start_pattern, text, re.M) + if not match: # start_pattern not found in text. + return None + start_position = match.end(0) + + assert start_position > 0, ( + 'start_pattern must ends with an opening punctuation.') + assert text[start_position - 1] in matching_punctuation, ( + 'start_pattern must ends with an opening punctuation.') + # Stack of closing punctuations we expect to have in text after position. + punctuation_stack = [matching_punctuation[text[start_position - 1]]] + position = start_position + while punctuation_stack and position < len(text): + if text[position] == punctuation_stack[-1]: + punctuation_stack.pop() + elif text[position] in closing_punctuation: + # A closing punctuation without matching opening punctuations. + return None + elif text[position] in matching_punctuation: + punctuation_stack.append(matching_punctuation[text[position]]) + position += 1 + if punctuation_stack: + # Opening punctuations left without matching close-punctuations. + return None + # punctuations match. + return text[start_position:position - 1] + + +def CheckLanguage(filename, clean_lines, linenum, file_extension, + include_state, nesting_state, error): + """Checks rules from the 'C++ language rules' section of cppguide.html. + + Some of these rules are hard to test (function overloading, using + uint32 inappropriately), but we do the best we can. + + Args: + filename : The name of the current file. + clean_lines : A CleansedLines instance containing the file. + linenum : The number of the line to check. + file_extension : The extension (without the dot) of the filename. + include_state : An _IncludeState instance in which the headers are + inserted. + nesting_state : A _NestingState instance which maintains information + about the current stack of nested blocks being parsed. + error : The function to call with any errors found. + """ + # If the line is empty or consists of entirely a comment, no need to + # check it. + line = clean_lines.elided[linenum] + if not line: + return + + match = _RE_PATTERN_INCLUDE.search(line) + if match: + CheckIncludeLine(filename, clean_lines, linenum, include_state, error) + return + + # Reset include state across preprocessor directives. This is meant + # to silence warnings for conditional includes. + if Match(r'^\s*#\s*(?:ifdef|elif|else|endif)\b', line): + include_state.ResetSection() + + # TODO(unknown): figure out if they're using default arguments in fn proto. + + # Check if people are using the verboten C basic types. + match = Search(r'\b(short|long long)\b', line) + if match: + error(filename, linenum, 'runtime/int', 4, + 'Use int16_t/int64_t/etc, rather than the C type %s' + % match.group(1)) + + # When snprintf is used, the second argument shouldn't be a literal. + match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line) + if match and match.group(2) != '0': + # If 2nd arg is zero, snprintf is used to calculate size. + error(filename, linenum, 'runtime/printf', 3, + 'If you can, use sizeof(%s) instead of %s as the 2nd arg ' + 'to snprintf.' % (match.group(1), match.group(2))) + + # Check if some verboten C functions are being used. + if Search(r'\bsprintf\b', line): + error(filename, linenum, 'runtime/printf', 5, + 'Never use sprintf. Use snprintf instead.') + match = Search(r'\b(strcpy|strcat)\b', line) + if match: + error(filename, linenum, 'runtime/printf', 4, + 'Almost always, snprintf is better than %s' % match.group(1)) + + # Check for suspicious usage of "if" like + # } if (a == b) { + if Search(r'\}\s*if\s*\(', line): + error(filename, linenum, 'readability/braces', 4, + 'Did you mean "else if"? If not, start a new line for "if".') + + # Check for potential format string bugs like printf(foo). + # We constrain the pattern not to pick things like DocidForPrintf(foo). + # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str()) + # TODO(sugawarayu): Catch the following case. Need to change the calling + # convention of the whole function to process multiple line to handle it. + # printf( + # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line); + printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(') + if printf_args: + match = Match(r'([\w.\->()]+)$', printf_args) + if match and match.group(1) != '__VA_ARGS__': + function_name = re.search(r'\b((?:string)?printf)\s*\(', + line, re.I).group(1) + error(filename, linenum, 'runtime/printf', 4, + 'Potential format string bug. Do %s("%%s", %s) instead.' + % (function_name, match.group(1))) + + # Check for potential memset bugs like memset(buf, sizeof(buf), 0). + match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line) + if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)): + error(filename, linenum, 'runtime/memset', 4, + 'Did you mean "memset(%s, 0, %s)"?' + % (match.group(1), match.group(2))) + + # Detect variable-length arrays. + match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line) + if (match and match.group(2) != 'return' and match.group(2) != 'delete' and + match.group(3).find(']') == -1): + # Split the size using space and arithmetic operators as delimiters. + # If any of the resulting tokens are not compile time constants then + # report the error. + tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3)) + is_const = True + skip_next = False + for tok in tokens: + if skip_next: + skip_next = False + continue + + if Search(r'sizeof\(.+\)', tok): + continue + if Search(r'arraysize\(\w+\)', tok): + continue + + tok = tok.lstrip('(') + tok = tok.rstrip(')') + if not tok: + continue + if Match(r'\d+', tok): + continue + if Match(r'0[xX][0-9a-fA-F]+', tok): + continue + if Match(r'k[A-Z0-9]\w*', tok): + continue + if Match(r'(.+::)?k[A-Z0-9]\w*', tok): + continue + if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): + continue + # A catch all for tricky sizeof cases, including + # 'sizeof expression', 'sizeof(*type)', 'sizeof(const type)', + # 'sizeof(struct StructName)' requires skipping the next token + # because we split on ' ' and '*'. + if tok.startswith('sizeof'): + skip_next = True + continue + is_const = False + break + if not is_const: + error(filename, linenum, 'runtime/arrays', 1, + "Do not use variable-length arrays. Use an appropriately" + " named ('k' followed by CamelCase) compile-time constant for" + " the size.") + + # Detect TRUE and FALSE. + match = Search(r'\b(TRUE|FALSE)\b', line) + if match: + token = match.group(1) + error(filename, linenum, 'readability/bool', 4, + 'Use %s instead of %s.' % (token.lower(), token)) + + # Detect preincrement/predecrement + match = Match(r'^\s*(?:\+\+|--)', line) + if match: + error(filename, linenum, 'readability/increment', 5, + 'Do not use preincrement in statements, ' + 'use postincrement instead') + # Detect preincrement/predecrement in for(;; preincrement) + match = Search(r';\s*(\+\+|--)', line) + if match: + end_pos, end_depth = FindEndOfExpressionInLine(line, match.start(1), 1, + '(', ')') + expr = line[match.start(1):end_pos] + if end_depth == 0 and ';' not in expr and ' = ' not in expr: + error(filename, linenum, 'readability/increment', 4, + 'Do not use preincrement in statements, including ' + 'for(;; action)') + + +def ProcessLine(filename, file_extension, clean_lines, line, + include_state, function_state, nesting_state, error, + extra_check_functions=[]): + """Processes a single line in the file. + + Args: + filename : Filename of the file that is being processed. + file_extension : The extension (dot not included) of the file. + clean_lines : An array of strings, each representing a line of + the file, with comments stripped. + line : Number of line being processed. + include_state : An _IncludeState instance in which the headers are + inserted. + function_state : A _FunctionState instance which counts function + lines, etc. + nesting_state : A _NestingState instance which maintains + information about the current stack of nested + blocks being parsed. + error : A callable to which errors are reported, which + takes 4 arguments: filename, line number, error + level, and message + extra_check_functions : An array of additional check functions that will + be run on each source line. Each function takes 4 + arguments : filename, clean_lines, line, error + """ + raw_lines = clean_lines.raw_lines + init_lines = clean_lines.init_lines + ParseNolintSuppressions(filename, raw_lines[line], line, error) + nesting_state.Update(filename, clean_lines, line, error) + if nesting_state.stack and nesting_state.stack[-1].inline_asm != _NO_ASM: + return + CheckForFunctionLengths(filename, clean_lines, line, function_state, error) + CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error) + CheckForOldStyleComments(filename, init_lines[line], line, error) + CheckStyle( + filename, clean_lines, line, file_extension, nesting_state, error) + CheckLanguage(filename, clean_lines, line, file_extension, include_state, + nesting_state, error) + CheckForNonStandardConstructs(filename, clean_lines, line, + nesting_state, error) + CheckPosixThreading(filename, clean_lines, line, error) + CheckMemoryFunctions(filename, clean_lines, line, error) + for check_fn in extra_check_functions: + check_fn(filename, clean_lines, line, error) + + +def ProcessFileData(filename, file_extension, lines, error, + extra_check_functions=[]): + """Performs lint checks and reports any errors to the given error function. + + Args: + filename: Filename of the file that is being processed. + file_extension: The extension (dot not included) of the file. + lines: An array of strings, each representing a line of the file, with the + last element being empty if the file is terminated with a newline. + error: A callable to which errors are reported, which takes 4 arguments: + filename, line number, error level, and message + extra_check_functions: An array of additional check functions that will be + run on each source line. Each function takes 4 + arguments: filename, clean_lines, line, error + """ + lines = (['// marker so line numbers and indices both start at 1'] + lines + + ['// marker so line numbers end in a known way']) + + include_state = _IncludeState() + function_state = _FunctionState() + nesting_state = _NestingState() + + ResetNolintSuppressions() + ResetKnownErrorSuppressions() + + for line in range(1, len(lines)): + ParseKnownErrorSuppressions(filename, lines, line) + + init_lines = lines[:] + + if _cpplint_state.record_errors_file: + def RecordedError(filename, linenum, category, confidence, message): + if not IsErrorSuppressedByNolint(category, linenum): + key = init_lines[linenum - 1 if linenum else 0:linenum + 2] + err = [filename, key, category] + json.dump(err, _cpplint_state.record_errors_file) + _cpplint_state.record_errors_file.write('\n') + Error(filename, linenum, category, confidence, message) + + error = RecordedError + + if file_extension == 'h': + CheckForHeaderGuard(filename, lines, error) + + RemoveMultiLineComments(filename, lines, error) + clean_lines = CleansedLines(lines, init_lines) + for line in range(clean_lines.NumLines()): + ProcessLine(filename, file_extension, clean_lines, line, + include_state, function_state, nesting_state, error, + extra_check_functions) + + # We check here rather than inside ProcessLine so that we see raw + # lines rather than "cleaned" lines. + CheckForBadCharacters(filename, lines, error) + + CheckForNewlineAtEOF(filename, lines, error) + + +def ProcessFile(filename, vlevel, extra_check_functions=[]): + """Does neovim-lint on a single file. + + Args: + filename: The name of the file to parse. + + vlevel: The level of errors to report. Every error of confidence + >= verbose_level will be reported. 0 is a good default. + + extra_check_functions: An array of additional check functions that will be + run on each source line. Each function takes 4 + arguments: filename, clean_lines, line, error + """ + + _SetVerboseLevel(vlevel) + + try: + # Support the Unix convention of using "-" for stdin. Note that + # we are not opening the file with universal newline support + # (which codecs doesn't support anyway), so the resulting lines do + # contain trailing '\r' characters if we are reading a file that + # has CRLF endings. + # If after the split a trailing '\r' is present, it is removed + # below. If it is not expected to be present (i.e. os.linesep != + # '\r\n' as in Windows), a warning is issued below if this file + # is processed. + + if filename == '-': + lines = codecs.StreamReaderWriter(sys.stdin, + codecs.getreader('utf8'), + codecs.getwriter('utf8'), + 'replace').read().split('\n') + else: + lines = codecs.open( + filename, 'r', 'utf8', 'replace').read().split('\n') + + carriage_return_found = False + # Remove trailing '\r'. + for linenum in range(len(lines)): + if lines[linenum].endswith('\r'): + lines[linenum] = lines[linenum].rstrip('\r') + carriage_return_found = True + + except IOError: + sys.stderr.write( + "Skipping input '%s': Can't open for reading\n" % filename) + return + + # Note, if no dot is found, this will give the entire filename as the ext. + file_extension = filename[filename.rfind('.') + 1:] + + # When reading from stdin, the extension is unknown, so no cpplint tests + # should rely on the extension. + if filename != '-' and file_extension not in _valid_extensions: + sys.stderr.write('Ignoring %s; not a valid file name ' + '(%s)\n' % (filename, ', '.join(_valid_extensions))) + else: + ProcessFileData(filename, file_extension, lines, Error, + extra_check_functions) + if carriage_return_found and os.linesep != '\r\n': + # Use 0 for linenum since outputting only one error for potentially + # several lines. + Error(filename, 0, 'whitespace/newline', 1, + 'One or more unexpected \\r (^M) found;' + 'better to use only a \\n') + + +def PrintUsage(message): + """Prints a brief usage string and exits, optionally with an error message. + + Args: + message: The optional error message. + """ + if message: + sys.stderr.write(_USAGE) + sys.exit('\nFATAL ERROR: ' + message) + else: + sys.stdout.write(_USAGE) + sys.exit(0) + + +def PrintCategories(): + """Prints a list of all the error-categories used by error messages. + + These are the categories used to filter messages via --filter. + """ + sys.stdout.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES)) + sys.exit(0) + + +def ParseArguments(args): + """Parses the command line arguments. + + This may set the output format and verbosity level as side-effects. + + Args: + args: The command line arguments: + + Returns: + The list of filenames to lint. + """ + try: + (opts, filenames) = getopt.getopt(args, '', ['help', + 'output=', + 'verbose=', + 'counting=', + 'filter=', + 'root=', + 'linelength=', + 'extensions=', + 'record-errors=', + 'suppress-errors=']) + except getopt.GetoptError: + PrintUsage('Invalid arguments.') + + verbosity = _VerboseLevel() + output_format = _OutputFormat() + filters = '' + counting_style = '' + record_errors_file = None + suppress_errors_file = None + + for (opt, val) in opts: + if opt == '--help': + PrintUsage(None) + elif opt == '--output': + if val not in ('emacs', 'vs7', 'eclipse'): + PrintUsage('The only allowed output formats are emacs,' + ' vs7 and eclipse.') + output_format = val + elif opt == '--verbose': + verbosity = int(val) + elif opt == '--filter': + filters = val + if not filters: + PrintCategories() + elif opt == '--counting': + if val not in ('total', 'toplevel', 'detailed'): + PrintUsage( + 'Valid counting options are total, toplevel, and detailed') + counting_style = val + elif opt == '--linelength': + global _line_length + try: + _line_length = int(val) + except ValueError: + PrintUsage('Line length must be digits.') + elif opt == '--extensions': + global _valid_extensions + try: + _valid_extensions = set(val.split(',')) + except ValueError: + PrintUsage('Extensions must be comma separated list.') + elif opt == '--record-errors': + record_errors_file = val + elif opt == '--suppress-errors': + suppress_errors_file = val + + if not filenames: + PrintUsage('No files were specified.') + + _SetOutputFormat(output_format) + _SetVerboseLevel(verbosity) + _SetFilters(filters) + _SetCountingStyle(counting_style) + _SuppressErrorsFrom(suppress_errors_file) + _RecordErrorsTo(record_errors_file) + + return filenames + + +def main(): + filenames = ParseArguments(sys.argv[1:]) + + _cpplint_state.ResetErrorCounts() + for filename in filenames: + ProcessFile(filename, _cpplint_state.verbose_level) + _cpplint_state.PrintErrorCounts() + + sys.exit(_cpplint_state.error_count > 0) + + +if __name__ == '__main__': + main() + +# vim: ts=4 sts=4 sw=4 + +# Ignore "too complex" warnings when using pymode. +# pylama:ignore=C901 diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 172643091a..feb17e070e 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -55,6 +55,10 @@ foreach(subdir event eval ) + if(${subdir} MATCHES "tui" AND NOT FEAT_TUI) + continue() + endif() + file(MAKE_DIRECTORY ${GENERATED_DIR}/${subdir}) file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/${subdir}) file(GLOB sources ${subdir}/*.c) @@ -74,6 +78,9 @@ foreach(sfile ${NEOVIM_SOURCES}) if(${f} MATCHES "^(regexp_nfa.c)$") list(APPEND to_remove ${sfile}) endif() + if(WIN32 AND ${f} MATCHES "^(pty_process_unix.c)$") + list(APPEND to_remove ${sfile}) + endif() endforeach() list(REMOVE_ITEM NEOVIM_SOURCES ${to_remove}) @@ -91,7 +98,6 @@ set(CONV_SOURCES mbyte.c memline.c message.c - ops.c regexp.c screen.c search.c @@ -265,7 +271,7 @@ if(CLANG_ASAN_UBSAN) set(SANITIZE_RECOVER -fno-sanitize-recover) # Clang 3.5- endif() set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-DEXITFREE ") - set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "${SANITIZE_RECOVER} -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/.asan-blacklist") + set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "${SANITIZE_RECOVER} -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/src/.asan-blacklist") set_property(TARGET nvim APPEND_STRING PROPERTY LINK_FLAGS "-fsanitize=address -fsanitize=undefined ") elseif(CLANG_MSAN) message(STATUS "Enabling Clang memory sanitizer for nvim.") diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index fbfa87d5ae..80a88becf4 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -12,8 +12,8 @@ #define REMOTE_TYPE(type) typedef uint64_t type #ifdef INCLUDE_GENERATED_DECLARATIONS - #define ArrayOf(...) Array - #define DictionaryOf(...) Dictionary +# define ArrayOf(...) Array +# define DictionaryOf(...) Dictionary #endif // Basic types diff --git a/src/nvim/api/private/handle.c b/src/nvim/api/private/handle.c index abbda95073..69df7294ad 100644 --- a/src/nvim/api/private/handle.c +++ b/src/nvim/api/private/handle.c @@ -7,24 +7,24 @@ #define HANDLE_INIT(name) name##_handles = pmap_new(uint64_t)() -#define HANDLE_IMPL(type, name) \ - static PMap(uint64_t) *name##_handles = NULL; \ - \ - type *handle_get_##name(uint64_t handle) \ - { \ - return pmap_get(uint64_t)(name##_handles, handle); \ - } \ - \ - void handle_register_##name(type *name) \ - { \ - assert(!name->handle); \ - name->handle = next_handle++; \ - pmap_put(uint64_t)(name##_handles, name->handle, name); \ - } \ - \ - void handle_unregister_##name(type *name) \ - { \ - pmap_del(uint64_t)(name##_handles, name->handle); \ +#define HANDLE_IMPL(type, name) \ + static PMap(uint64_t) *name##_handles = NULL; \ + \ + type *handle_get_##name(uint64_t handle) \ + { \ + return pmap_get(uint64_t)(name##_handles, handle); \ + } \ + \ + void handle_register_##name(type *name) \ + { \ + assert(!name->handle); \ + name->handle = next_handle++; \ + pmap_put(uint64_t)(name##_handles, name->handle, name); \ + } \ + \ + void handle_unregister_##name(type *name) \ + { \ + pmap_del(uint64_t)(name##_handles, name->handle); \ } static uint64_t next_handle = 1; diff --git a/src/nvim/api/private/handle.h b/src/nvim/api/private/handle.h index 1a196f6797..804e266dc3 100644 --- a/src/nvim/api/private/handle.h +++ b/src/nvim/api/private/handle.h @@ -4,9 +4,9 @@ #include "nvim/vim.h" #include "nvim/buffer_defs.h" -#define HANDLE_DECLS(type, name) \ - type *handle_get_##name(uint64_t handle); \ - void handle_register_##name(type *name); \ +#define HANDLE_DECLS(type, name) \ + type *handle_get_##name(uint64_t handle); \ + void handle_register_##name(type *name); \ void handle_unregister_##name(type *name); HANDLE_DECLS(buf_T, buffer) diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index a0f14ac7a4..731f186ecc 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -8,66 +8,56 @@ #include "nvim/memory.h" #include "nvim/lib/kvec.h" -#define api_set_error(err, errtype, ...) \ - do { \ - snprintf((err)->msg, \ - sizeof((err)->msg), \ - __VA_ARGS__); \ - (err)->set = true; \ - (err)->type = kErrorType##errtype; \ +#define api_set_error(err, errtype, ...) \ + do { \ + snprintf((err)->msg, \ + sizeof((err)->msg), \ + __VA_ARGS__); \ + (err)->set = true; \ + (err)->type = kErrorType##errtype; \ } while (0) #define OBJECT_OBJ(o) o -#define BOOLEAN_OBJ(b) ((Object) { \ - .type = kObjectTypeBoolean, \ - .data.boolean = b \ - }) - -#define INTEGER_OBJ(i) ((Object) { \ - .type = kObjectTypeInteger, \ - .data.integer = i \ - }) - -#define STRING_OBJ(s) ((Object) { \ - .type = kObjectTypeString, \ - .data.string = s \ - }) - -#define BUFFER_OBJ(s) ((Object) { \ - .type = kObjectTypeBuffer, \ - .data.buffer = s \ - }) - -#define WINDOW_OBJ(s) ((Object) { \ - .type = kObjectTypeWindow, \ - .data.window = s \ - }) - -#define TABPAGE_OBJ(s) ((Object) { \ - .type = kObjectTypeTabpage, \ - .data.tabpage = s \ - }) - -#define ARRAY_OBJ(a) ((Object) { \ - .type = kObjectTypeArray, \ - .data.array = a \ - }) - -#define DICTIONARY_OBJ(d) ((Object) { \ - .type = kObjectTypeDictionary, \ - .data.dictionary = d \ - }) +#define BOOLEAN_OBJ(b) ((Object) { \ + .type = kObjectTypeBoolean, \ + .data.boolean = b }) + +#define INTEGER_OBJ(i) ((Object) { \ + .type = kObjectTypeInteger, \ + .data.integer = i }) + +#define STRING_OBJ(s) ((Object) { \ + .type = kObjectTypeString, \ + .data.string = s }) + +#define BUFFER_OBJ(s) ((Object) { \ + .type = kObjectTypeBuffer, \ + .data.buffer = s }) + +#define WINDOW_OBJ(s) ((Object) { \ + .type = kObjectTypeWindow, \ + .data.window = s }) + +#define TABPAGE_OBJ(s) ((Object) { \ + .type = kObjectTypeTabpage, \ + .data.tabpage = s }) + +#define ARRAY_OBJ(a) ((Object) { \ + .type = kObjectTypeArray, \ + .data.array = a }) + +#define DICTIONARY_OBJ(d) ((Object) { \ + .type = kObjectTypeDictionary, \ + .data.dictionary = d }) #define NIL ((Object) {.type = kObjectTypeNil}) -#define PUT(dict, k, v) \ - kv_push(KeyValuePair, \ - dict, \ - ((KeyValuePair) {.key = cstr_to_string(k), .value = v})) +#define PUT(dict, k, v) \ + kv_push(dict, ((KeyValuePair) { .key = cstr_to_string(k), .value = v })) -#define ADD(array, item) \ - kv_push(Object, array, item) +#define ADD(array, item) \ + kv_push(array, item) #define STATIC_CSTR_AS_STRING(s) ((String) {.data = s, .size = sizeof(s) - 1}) diff --git a/src/nvim/msgpack_rpc/remote_ui.c b/src/nvim/api/ui.c index 6ffcffe2e1..1703d49296 100644 --- a/src/nvim/msgpack_rpc/remote_ui.c +++ b/src/nvim/api/ui.c @@ -7,13 +7,12 @@ #include "nvim/ui.h" #include "nvim/memory.h" #include "nvim/map.h" -#include "nvim/msgpack_rpc/remote_ui.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "msgpack_rpc/remote_ui.c.generated.h" +# include "api/ui.c.generated.h" #endif typedef struct { @@ -24,21 +23,13 @@ typedef struct { static PMap(uint64_t) *connected_uis = NULL; void remote_ui_init(void) + FUNC_API_NOEXPORT { connected_uis = pmap_new(uint64_t)(); - // Add handler for "attach_ui" - String method = cstr_as_string("ui_attach"); - MsgpackRpcRequestHandler handler = {.fn = remote_ui_attach, .async = false}; - msgpack_rpc_add_method_handler(method, handler); - method = cstr_as_string("ui_detach"); - handler.fn = remote_ui_detach; - msgpack_rpc_add_method_handler(method, handler); - method = cstr_as_string("ui_try_resize"); - handler.fn = remote_ui_try_resize; - msgpack_rpc_add_method_handler(method, handler); } void remote_ui_disconnect(uint64_t channel_id) + FUNC_API_NOEXPORT { UI *ui = pmap_get(uint64_t)(connected_uis, channel_id); if (!ui) { @@ -49,34 +40,30 @@ void remote_ui_disconnect(uint64_t channel_id) api_free_array(data->buffer); pmap_del(uint64_t)(connected_uis, channel_id); xfree(ui->data); - ui_detach(ui); + ui_detach_impl(ui); xfree(ui); } -static Object remote_ui_attach(uint64_t channel_id, uint64_t request_id, - Array args, Error *error) +void ui_attach(uint64_t channel_id, Integer width, Integer height, + Boolean enable_rgb, Error *err) { if (pmap_has(uint64_t)(connected_uis, channel_id)) { - api_set_error(error, Exception, _("UI already attached for channel")); - return NIL; + api_set_error(err, Exception, _("UI already attached for channel")); + return; } - if (args.size != 3 || args.items[0].type != kObjectTypeInteger - || args.items[1].type != kObjectTypeInteger - || args.items[2].type != kObjectTypeBoolean - || args.items[0].data.integer <= 0 || args.items[1].data.integer <= 0) { - api_set_error(error, Validation, - _("Invalid arguments. Expected: " - "(uint width > 0, uint height > 0, bool enable_rgb)")); - return NIL; + if (width <= 0 || height <= 0) { + api_set_error(err, Validation, + _("Expected width > 0 and height > 0")); + return; } UIData *data = xmalloc(sizeof(UIData)); data->channel_id = channel_id; data->buffer = (Array)ARRAY_DICT_INIT; UI *ui = xcalloc(1, sizeof(UI)); - ui->width = (int)args.items[0].data.integer; - ui->height = (int)args.items[1].data.integer; - ui->rgb = args.items[2].data.boolean; + ui->width = (int)width; + ui->height = (int)height; + ui->rgb = enable_rgb; ui->data = data; ui->resize = remote_ui_resize; ui->clear = remote_ui_clear; @@ -102,45 +89,38 @@ static Object remote_ui_attach(uint64_t channel_id, uint64_t request_id, ui->set_title = remote_ui_set_title; ui->set_icon = remote_ui_set_icon; pmap_put(uint64_t)(connected_uis, channel_id, ui); - ui_attach(ui); - return NIL; + ui_attach_impl(ui); + return; } -static Object remote_ui_detach(uint64_t channel_id, uint64_t request_id, - Array args, Error *error) +void ui_detach(uint64_t channel_id, Error *err) { if (!pmap_has(uint64_t)(connected_uis, channel_id)) { - api_set_error(error, Exception, _("UI is not attached for channel")); + api_set_error(err, Exception, _("UI is not attached for channel")); } remote_ui_disconnect(channel_id); - - return NIL; } -static Object remote_ui_try_resize(uint64_t channel_id, uint64_t request_id, - Array args, Error *error) +Object ui_try_resize(uint64_t channel_id, Integer width, + Integer height, Error *err) { if (!pmap_has(uint64_t)(connected_uis, channel_id)) { - api_set_error(error, Exception, _("UI is not attached for channel")); + api_set_error(err, Exception, _("UI is not attached for channel")); } - if (args.size != 2 || args.items[0].type != kObjectTypeInteger - || args.items[1].type != kObjectTypeInteger - || args.items[0].data.integer <= 0 || args.items[1].data.integer <= 0) { - api_set_error(error, Validation, - _("Invalid arguments. Expected: " - "(uint width > 0, uint height > 0)")); + if (width <= 0 || height <= 0) { + api_set_error(err, Validation, + _("Expected width > 0 and height > 0")); return NIL; } UI *ui = pmap_get(uint64_t)(connected_uis, channel_id); - ui->width = (int)args.items[0].data.integer; - ui->height = (int)args.items[1].data.integer; + ui->width = (int)width; + ui->height = (int)height; ui_refresh(); return NIL; } - static void push_call(UI *ui, char *name, Array args) { Array call = ARRAY_DICT_INIT; @@ -236,7 +216,7 @@ static void remote_ui_mode_change(UI *ui, int mode) } static void remote_ui_set_scroll_region(UI *ui, int top, int bot, int left, - int right) + int right) { Array args = ARRAY_DICT_INIT; ADD(args, INTEGER_OBJ(top)); @@ -297,7 +277,7 @@ static void remote_ui_highlight_set(UI *ui, HlAttrs attrs) static void remote_ui_put(UI *ui, uint8_t *data, size_t size) { Array args = ARRAY_DICT_INIT; - String str = {.data = xmemdupz(data, size), .size = size}; + String str = { .data = xmemdupz(data, size), .size = size }; ADD(args, STRING_OBJ(str)); push_call(ui, "put", args); } diff --git a/src/nvim/api/ui.h b/src/nvim/api/ui.h new file mode 100644 index 0000000000..b3af14f8a8 --- /dev/null +++ b/src/nvim/api/ui.h @@ -0,0 +1,11 @@ +#ifndef NVIM_API_UI_H +#define NVIM_API_UI_H + +#include <stdint.h> + +#include "nvim/api/private/defs.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "api/ui.h.generated.h" +#endif +#endif // NVIM_API_UI_H diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 46ac3c9022..ac7cc65ee4 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -57,6 +57,7 @@ void vim_feedkeys(String keys, String mode, Boolean escape_csi) bool remap = true; bool insert = false; bool typed = false; + bool execute = false; if (keys.size == 0) { return; @@ -68,6 +69,7 @@ void vim_feedkeys(String keys, String mode, Boolean escape_csi) case 'm': remap = true; break; case 't': typed = true; break; case 'i': insert = true; break; + case 'x': execute = true; break; } } @@ -86,8 +88,12 @@ void vim_feedkeys(String keys, String mode, Boolean escape_csi) xfree(keys_esc); } - if (vgetc_busy) + if (vgetc_busy) { typebuf_was_filled = true; + } + if (execute) { + exec_normal(true); + } } /// Passes input keys to Neovim. Unlike `vim_feedkeys`, this will use a @@ -98,7 +104,7 @@ void vim_feedkeys(String keys, String mode, Boolean escape_csi) /// @return The number of bytes actually written, which can be lower than /// requested if the buffer becomes full. Integer vim_input(String keys) - FUNC_ATTR_ASYNC + FUNC_API_ASYNC { return (Integer)input_enqueue(keys); } @@ -618,7 +624,7 @@ Dictionary vim_get_color_map(void) Array vim_get_api_info(uint64_t channel_id) - FUNC_ATTR_ASYNC + FUNC_API_ASYNC { Array rv = ARRAY_DICT_INIT; @@ -641,14 +647,14 @@ static void write_msg(String message, bool to_err) static size_t out_pos = 0, err_pos = 0; static char out_line_buf[LINE_BUFFER_SIZE], err_line_buf[LINE_BUFFER_SIZE]; -#define PUSH_CHAR(i, pos, line_buf, msg) \ - if (message.data[i] == NL || pos == LINE_BUFFER_SIZE - 1) { \ - line_buf[pos] = NUL; \ - msg((uint8_t *)line_buf); \ - pos = 0; \ - continue; \ - } \ - \ +#define PUSH_CHAR(i, pos, line_buf, msg) \ + if (message.data[i] == NL || pos == LINE_BUFFER_SIZE - 1) { \ + line_buf[pos] = NUL; \ + msg((uint8_t *)line_buf); \ + pos = 0; \ + continue; \ + } \ + \ line_buf[pos++] = message.data[i]; ++no_wait_return; diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 72716daf0e..72724b0ffd 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1534,6 +1534,7 @@ void free_buf_options(buf_T *buf, int free_p_ff) clear_string_option(&buf->b_p_cms); clear_string_option(&buf->b_p_nf); clear_string_option(&buf->b_p_syn); + clear_string_option(&buf->b_s.b_syn_isk); clear_string_option(&buf->b_s.b_p_spc); clear_string_option(&buf->b_s.b_p_spf); vim_regfree(buf->b_s.b_cap_prog); @@ -2848,7 +2849,7 @@ typedef enum { /// is "curwin". /// /// Items are drawn interspersed with the text that surrounds it -/// Specials: %-<wid>(xxx%) => group, %= => middle marker, %< => truncation +/// Specials: %-<wid>(xxx%) => group, %= => separation marker, %< => truncation /// Item: %-<minwid>.<maxwid><itemch> All but <itemch> are optional /// /// If maxwidth is not zero, the string will be filled at any middle marker @@ -2892,7 +2893,7 @@ int build_stl_str_hl( Normal, Empty, Group, - Middle, + Separate, Highlight, TabPage, ClickFunc, @@ -2993,14 +2994,14 @@ int build_stl_str_hl( continue; } - // STL_MIDDLEMARK: Separation place between left and right aligned items. - if (*fmt_p == STL_MIDDLEMARK) { + // STL_SEPARATE: Separation place between left and right aligned items. + if (*fmt_p == STL_SEPARATE) { fmt_p++; // Ignored when we are inside of a grouping if (groupdepth > 0) { continue; } - item[curitem].type = Middle; + item[curitem].type = Separate; item[curitem++].start = out_p; continue; } @@ -3839,27 +3840,53 @@ int build_stl_str_hl( width = maxwidth; // If there is room left in our statusline, and room left in our buffer, - // add characters at the middle marker (if there is one) to + // add characters at the separate marker (if there is one) to // fill up the available space. } else if (width < maxwidth - && STRLEN(out) + maxwidth - width + 1 < outlen) { - for (int item_idx = 0; item_idx < itemcnt; item_idx++) { - if (item[item_idx].type == Middle) { - // Move the statusline to make room for the middle characters - char_u *middle_end = item[item_idx].start + (maxwidth - width); - STRMOVE(middle_end, item[item_idx].start); - - // Fill the middle section with our fill character - for (char_u *s = item[item_idx].start; s < middle_end; s++) - *s = fillchar; + && STRLEN(out) + maxwidth - width + 1 < outlen) { + // Find how many separators there are, which we will use when + // figuring out how many groups there are. + int num_separators = 0; + for (int i = 0; i < itemcnt; i++) { + if (item[i].type == Separate) { + num_separators++; + } + } - // Adjust the offset of any items after the middle - for (item_idx++; item_idx < itemcnt; item_idx++) - item[item_idx].start += maxwidth - width; + // If we have separated groups, then we deal with it now + if (num_separators) { + // Create an array of the start location for each + // separator mark. + int separator_locations[STL_MAX_ITEM]; + int index = 0; + for (int i = 0; i < itemcnt; i++) { + if (item[i].type == Separate) { + separator_locations[index] = i; + index++; + } + } - width = maxwidth; - break; + int standard_spaces = (maxwidth - width) / num_separators; + int final_spaces = (maxwidth - width) - + standard_spaces * (num_separators - 1); + + for (int i = 0; i < num_separators; i++) { + int dislocation = (i == (num_separators - 1)) ? + final_spaces : standard_spaces; + char_u *sep_loc = item[separator_locations[i]].start + dislocation; + STRMOVE(sep_loc, item[separator_locations[i]].start); + for (char_u *s = item[separator_locations[i]].start; s < sep_loc; s++) { + *s = fillchar; + } + + for (int item_idx = separator_locations[i] + 1; + item_idx < itemcnt; + item_idx++) { + item[item_idx].start += dislocation; + } } + + width = maxwidth; } } @@ -4950,7 +4977,7 @@ int bufhl_add_hl(buf_T *buf, bufhl_vec_T* lineinfo = map_ref(linenr_T, bufhl_vec_T)(buf->b_bufhl_info, lnum, true); - bufhl_hl_item_T *hlentry = kv_pushp(bufhl_hl_item_T, *lineinfo); + bufhl_hl_item_T *hlentry = kv_pushp(*lineinfo); hlentry->src_id = src_id; hlentry->hl_id = hl_id; hlentry->start = col_start; diff --git a/src/nvim/buffer.h b/src/nvim/buffer.h index d51a2f7dae..36cbec7e60 100644 --- a/src/nvim/buffer.h +++ b/src/nvim/buffer.h @@ -76,14 +76,14 @@ static inline void restore_win_for_buf(win_T *save_curwin, } } -#define WITH_BUFFER(b, code) \ - do { \ - buf_T *save_curbuf = NULL; \ - win_T *save_curwin = NULL; \ - tabpage_T *save_curtab = NULL; \ - switch_to_win_for_buf(b, &save_curwin, &save_curtab, &save_curbuf); \ - code; \ - restore_win_for_buf(save_curwin, save_curtab, save_curbuf); \ +#define WITH_BUFFER(b, code) \ + do { \ + buf_T *save_curbuf = NULL; \ + win_T *save_curwin = NULL; \ + tabpage_T *save_curtab = NULL; \ + switch_to_win_for_buf(b, &save_curwin, &save_curtab, &save_curbuf); \ + code; \ + restore_win_for_buf(save_curwin, save_curtab, save_curbuf); \ } while (0) diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 0324f6b88a..b515c4e1e4 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -438,15 +438,17 @@ typedef struct { linenr_T b_sst_check_lnum; uint16_t b_sst_lasttick; /* last display tick */ - /* for spell checking */ - garray_T b_langp; /* list of pointers to slang_T, see spell.c */ - bool b_spell_ismw[256]; /* flags: is midword char */ - char_u *b_spell_ismw_mb; /* multi-byte midword chars */ - char_u *b_p_spc; /* 'spellcapcheck' */ - regprog_T *b_cap_prog; /* program for 'spellcapcheck' */ - char_u *b_p_spf; /* 'spellfile' */ - char_u *b_p_spl; /* 'spelllang' */ - int b_cjk; /* all CJK letters as OK */ + // for spell checking + garray_T b_langp; // list of pointers to slang_T, see spell.c + bool b_spell_ismw[256]; // flags: is midword char + char_u *b_spell_ismw_mb; // multi-byte midword chars + char_u *b_p_spc; // 'spellcapcheck' + regprog_T *b_cap_prog; // program for 'spellcapcheck' + char_u *b_p_spf; // 'spellfile' + char_u *b_p_spl; // 'spelllang' + int b_cjk; // all CJK letters as OK + char_u b_syn_chartab[32]; // syntax iskeyword option + char_u *b_syn_isk; // iskeyword option } synblock_T; diff --git a/src/nvim/charset.c b/src/nvim/charset.c index d0dc7b66fc..5ae4416052 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1582,7 +1582,7 @@ static char_u latin1lower[257] = /// /// @param c character to check bool vim_islower(int c) - FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (c <= '@') { return false; @@ -1613,7 +1613,7 @@ bool vim_islower(int c) /// /// @param c character to check bool vim_isupper(int c) - FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (c <= '@') { return false; diff --git a/src/nvim/edit.c b/src/nvim/edit.c index e131da8fe0..03ef41f849 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -961,7 +961,7 @@ static int insert_handle_key(InsertState *s) break; case K_EVENT: // some event - queue_process_events(loop.events); + queue_process_events(main_loop.events); break; case K_FOCUSGAINED: // Neovim has been given focus @@ -6952,8 +6952,8 @@ static void ins_reg(void) AppendCharToRedobuff(literally); AppendCharToRedobuff(regname); - do_put(regname, NULL, BACKWARD, 1L, - (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND); + do_put(regname, NULL, BACKWARD, 1, + (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND); } else if (insert_reg(regname, literally) == FAIL) { vim_beep(BO_REG); need_redraw = true; // remove the '"' @@ -7701,7 +7701,7 @@ static void ins_mouse(int c) undisplay_dollar(); tpos = curwin->w_cursor; - if (do_mouse(NULL, c, BACKWARD, 1L, 0)) { + if (do_mouse(NULL, c, BACKWARD, 1, 0)) { win_T *new_curwin = curwin; if (curwin != old_curwin && win_valid(old_curwin)) { diff --git a/src/nvim/eval.c b/src/nvim/eval.c index e950dfb5c4..aa5cd676af 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -67,6 +67,7 @@ #include "nvim/syntax.h" #include "nvim/tag.h" #include "nvim/ui.h" +#include "nvim/main.h" #include "nvim/mouse.h" #include "nvim/terminal.h" #include "nvim/undo.h" @@ -76,7 +77,7 @@ #include "nvim/eval/decode.h" #include "nvim/os/os.h" #include "nvim/event/libuv_process.h" -#include "nvim/event/pty_process.h" +#include "nvim/os/pty_process.h" #include "nvim/event/rstream.h" #include "nvim/event/wstream.h" #include "nvim/event/time.h" @@ -507,6 +508,7 @@ void eval_init(void) /* add to compat scope dict */ hash_add(&compat_hashtab, p->vv_di.di_key); } + vimvars[VV_VERSION].vv_nr = VIM_VERSION_100; dict_T *const msgpack_types_dict = dict_alloc(); for (size_t i = 0; i < ARRAY_SIZE(msgpack_type_names); i++) { @@ -1889,7 +1891,7 @@ ex_let_one ( } } if (p != NULL) { - write_reg_contents(*arg == '@' ? '"' : *arg, p, -1, FALSE); + write_reg_contents(*arg == '@' ? '"' : *arg, p, STRLEN(p), false); arg_end = arg + 1; } xfree(ptofree); @@ -2977,11 +2979,16 @@ int do_unlet(char_u *name, int forceit) } else if (current_funccal != NULL && ht == ¤t_funccal->l_vars.dv_hashtab) { d = ¤t_funccal->l_vars; + } else if (ht == &compat_hashtab) { + d = &vimvardict; } else { di = find_var_in_ht(ht, *name, (char_u *)"", false); d = di->di_tv.vval.v_dict; } - + if (d == NULL) { + EMSG2(_(e_intern2), "do_unlet()"); + return FAIL; + } hi = hash_find(ht, varname); if (!HASHITEM_EMPTY(hi)) { di = HI2DI(hi); @@ -2990,6 +2997,11 @@ int do_unlet(char_u *name, int forceit) || tv_check_lock(d->dv_lock, name, false)) { return FAIL; } + + if (d == NULL || tv_check_lock(d->dv_lock, name, false)) { + return FAIL; + } + typval_T oldtv; bool watched = is_watched(dict); @@ -6672,6 +6684,7 @@ static struct fst { { "acos", 1, 1, f_acos }, // WJMc { "add", 2, 2, f_add }, { "and", 2, 2, f_and }, + { "api_info", 0, 0, f_api_info }, { "append", 2, 2, f_append }, { "argc", 0, 0, f_argc }, { "argidx", 0, 0, f_argidx }, @@ -6680,6 +6693,7 @@ static struct fst { { "asin", 1, 1, f_asin }, // WJMc { "assert_equal", 2, 3, f_assert_equal }, { "assert_exception", 1, 2, f_assert_exception }, + { "assert_fails", 1, 2, f_assert_fails }, { "assert_false", 1, 2, f_assert_false }, { "assert_true", 1, 2, f_assert_true }, { "atan", 1, 1, f_atan }, @@ -7454,6 +7468,15 @@ static void f_and(typval_T *argvars, typval_T *rettv) & get_tv_number_chk(&argvars[1], NULL); } + +/// "api_info()" function +static void f_api_info(typval_T *argvars, typval_T *rettv) +{ + Dictionary metadata = api_metadata(); + (void)object_to_vim(DICTIONARY_OBJ(metadata), rettv, NULL); + api_free_dictionary(metadata); +} + /* * "append(lnum, string/list)" function */ @@ -7529,25 +7552,9 @@ static void f_argidx(typval_T *argvars, typval_T *rettv) static void f_arglistid(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = -1; - if (argvars[0].v_type != VAR_UNKNOWN) { - tabpage_T *tp = NULL; - if (argvars[1].v_type != VAR_UNKNOWN) { - long n = get_tv_number(&argvars[1]); - if (n >= 0) { - tp = find_tabpage(n); - } - } else { - tp = curtab; - } - - if (tp != NULL) { - win_T *wp = find_win_by_nr(&argvars[0], tp); - if (wp != NULL) { - rettv->vval.v_number = wp->w_alist->id; - } - } - } else { - rettv->vval.v_number = curwin->w_alist->id; + win_T *wp = find_tabwin(&argvars[0], &argvars[1]); + if (wp != NULL) { + rettv->vval.v_number = wp->w_alist->id; } } @@ -7668,6 +7675,43 @@ static void f_assert_exception(typval_T *argvars, typval_T *rettv) } } +/// "assert_fails(cmd [, error])" function +static void f_assert_fails(typval_T *argvars, typval_T *rettv) +{ + char_u *cmd = get_tv_string_chk(&argvars[0]); + garray_T ga; + + called_emsg = false; + suppress_errthrow = true; + emsg_silent = true; + do_cmdline_cmd((char *)cmd); + if (!called_emsg) { + prepare_assert_error(&ga); + ga_concat(&ga, (char_u *)"command did not fail: "); + ga_concat(&ga, cmd); + assert_error(&ga); + ga_clear(&ga); + } else if (argvars[1].v_type != VAR_UNKNOWN) { + char_u buf[NUMBUFLEN]; + char *error = (char *)get_tv_string_buf_chk(&argvars[1], buf); + + if (error == NULL + || strstr((char *)vimvars[VV_ERRMSG].vv_str, error) == NULL) { + prepare_assert_error(&ga); + fill_assert_error(&ga, &argvars[2], NULL, &argvars[1], + &vimvars[VV_ERRMSG].vv_tv); + assert_error(&ga); + ga_clear(&ga); + } + } + + called_emsg = false; + suppress_errthrow = false; + emsg_silent = false; + emsg_on_display = false; + set_vim_var_string(VV_ERRMSG, NULL, 0); +} + // Common for assert_true() and assert_false(). static void assert_bool(typval_T *argvars, bool is_true) { @@ -9882,7 +9926,7 @@ static void f_getcmdwintype(typval_T *argvars, typval_T *rettv) static void f_getcwd(typval_T *argvars, typval_T *rettv) { // Possible scope of working directory to return. - CdScope scope = MIN_CD_SCOPE; + CdScope scope = kCdScopeInvalid; // Numbers of the scope objects (window, tab) we want the working directory // of. A `-1` means to skip this scope, a `0` means the current object. @@ -9911,26 +9955,27 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv) return; } scope_number[i] = argvars[i].vval.v_number; - // The scope is the current iteration step. - scope = i; // It is an error for the scope number to be less than `-1`. if (scope_number[i] < -1) { EMSG(_(e_invarg)); return; } + // Use the narrowest scope the user requested + if (scope_number[i] >= 0 && scope == kCdScopeInvalid) { + // The scope is the current iteration step. + scope = i; + } else if (scope_number[i] < 0) { + scope = i + 1; + } } - // Normalize scope, the number of the new scope will be 0. - if (scope_number[scope] < 0) { - // Arguments to `getcwd` always end at second-highest scope, so scope will - // always be <= `MAX_CD_SCOPE`. - scope++; + // If the user didn't specify anything, default to window scope + if (scope == kCdScopeInvalid) { + scope = MIN_CD_SCOPE; } // Find the tabpage by number - if (scope_number[kCdScopeTab] == -1) { - tp = NULL; - } else if (scope_number[kCdScopeTab] > 0) { + if (scope_number[kCdScopeTab] > 0) { tp = find_tabpage(scope_number[kCdScopeTab]); if (!tp) { EMSG(_("E5000: Cannot find tab number.")); @@ -9939,16 +9984,14 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv) } // Find the window in `tp` by number, `NULL` if none. - if (scope_number[kCdScopeWindow] == -1) { - win = NULL; - } else if (scope_number[kCdScopeWindow] >= 0) { - if (!tp) { + if (scope_number[kCdScopeWindow] >= 0) { + if (scope_number[kCdScopeTab] < 0) { EMSG(_("E5001: Higher scope cannot be -1 if lower scope is >= 0.")); return; } if (scope_number[kCdScopeWindow] > 0) { - win = find_win_by_nr(&argvars[0], curtab); + win = find_win_by_nr(&argvars[0], tp); if (!win) { EMSG(_("E5002: Cannot find window number.")); return; @@ -9983,6 +10026,9 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv) } } break; + case kCdScopeInvalid: + // We should never get here + assert(false); } if (from) { @@ -10454,9 +10500,33 @@ find_win_by_nr ( return NULL; } -/* - * "getwinvar()" function - */ +/// Find window specified by "wvp" in tabpage "tvp". +static win_T *find_tabwin(typval_T *wvp, typval_T *tvp) +{ + win_T *wp = NULL; + tabpage_T *tp = NULL; + + if (wvp->v_type != VAR_UNKNOWN) { + if (tvp->v_type != VAR_UNKNOWN) { + long n = get_tv_number(tvp); + if (n >= 0) { + tp = find_tabpage(n); + } + } else { + tp = curtab; + } + + if (tp != NULL) { + wp = find_win_by_nr(wvp, tp); + } + } else { + wp = curwin; + } + + return wp; +} + +/// "getwinvar()" function static void f_getwinvar(typval_T *argvars, typval_T *rettv) { getwinvar(argvars, rettv, 0); @@ -10830,7 +10900,7 @@ static void f_has_key(typval_T *argvars, typval_T *rettv) static void f_haslocaldir(typval_T *argvars, typval_T *rettv) { // Possible scope of working directory to return. - CdScope scope = MIN_CD_SCOPE; + CdScope scope = kCdScopeInvalid; // Numbers of the scope objects (window, tab) we want the working directory // of. A `-1` means to skip this scope, a `0` means the current object. @@ -10855,25 +10925,26 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv) return; } scope_number[i] = argvars[i].vval.v_number; - // The scope is the current iteration step. - scope = i; if (scope_number[i] < -1) { EMSG(_(e_invarg)); return; } + // Use the narrowest scope the user requested + if (scope_number[i] >= 0 && scope == kCdScopeInvalid) { + // The scope is the current iteration step. + scope = i; + } else if (scope_number[i] < 0) { + scope = i + 1; + } } - // Normalize scope, the number of the new scope will be 0. - if (scope_number[scope] < 0) { - // Arguments to `haslocaldir` always end at second-highest scope, so scope - // will always be <= `MAX_CD_SCOPE`. - scope++; + // If the user didn't specify anything, default to window scope + if (scope == kCdScopeInvalid) { + scope = MIN_CD_SCOPE; } // Find the tabpage by number - if (scope_number[kCdScopeTab] == -1) { - tp = NULL; - } else if (scope_number[kCdScopeTab] > 0) { + if (scope_number[kCdScopeTab] > 0) { tp = find_tabpage(scope_number[kCdScopeTab]); if (!tp) { EMSG(_("5000: Cannot find tab number.")); @@ -10882,16 +10953,14 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv) } // Find the window in `tp` by number, `NULL` if none. - if (scope_number[kCdScopeWindow] == -1) { - win = NULL; - } else if (scope_number[kCdScopeWindow] >= 0) { - if (!tp) { + if (scope_number[kCdScopeWindow] >= 0) { + if (scope_number[kCdScopeTab] < 0) { EMSG(_("E5001: Higher scope cannot be -1 if lower scope is >= 0.")); return; } if (scope_number[kCdScopeWindow] > 0) { - win = find_win_by_nr(&argvars[0], curtab); + win = find_win_by_nr(&argvars[0], tp); if (!win) { EMSG(_("E5002: Cannot find window number.")); return; @@ -10912,6 +10981,9 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv) // The global scope never has a local directory rettv->vval.v_number = 0; break; + case kCdScopeInvalid: + // We should never get here + assert(false); } } @@ -11721,8 +11793,21 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv) dict_T *job_opts = NULL; ufunc_T *on_stdout = NULL, *on_stderr = NULL, *on_exit = NULL; + char *cwd = NULL; if (argvars[1].v_type == VAR_DICT) { job_opts = argvars[1].vval.v_dict; + + char *new_cwd = (char *)get_dict_string(job_opts, (char_u *)"cwd", false); + if (new_cwd && strlen(new_cwd) > 0) { + cwd = new_cwd; + // The new cwd must be a directory. + if (!os_isdir((char_u *)cwd)) { + EMSG2(_(e_invarg2), "expected valid directory"); + shell_free_argv(argv); + return; + } + } + if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) { shell_free_argv(argv); return; @@ -11732,7 +11817,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv) bool pty = job_opts && get_dict_number(job_opts, (uint8_t *)"pty") != 0; bool detach = job_opts && get_dict_number(job_opts, (uint8_t *)"detach") != 0; TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit, - job_opts, pty, detach); + job_opts, pty, detach, cwd); Process *proc = (Process *)&data->proc; if (pty) { @@ -11807,7 +11892,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv) list_T *rv = list_alloc(); ui_busy_start(); - Queue *waiting_jobs = queue_new_parent(loop_on_put, &loop); + Queue *waiting_jobs = queue_new_parent(loop_on_put, &main_loop); // For each item in the input list append an integer to the output list. -3 // is used to represent an invalid job id, -2 is for a interrupted job and // -1 for jobs that were skipped or timed out. @@ -11885,7 +11970,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv) } // restore the parent queue for the job queue_process_events(data->events); - queue_replace_parent(data->events, loop.events); + queue_replace_parent(data->events, main_loop.events); } queue_free(waiting_jobs); @@ -14886,7 +14971,8 @@ static void f_setreg(typval_T *argvars, typval_T *rettv) } *curval++ = NULL; - write_reg_contents_lst(regname, lstval, -1, append, yank_type, block_len); + write_reg_contents_lst(regname, lstval, STRLEN(lstval), + append, yank_type, block_len); free_lstval: while (curallocval > allocval) @@ -14897,7 +14983,8 @@ free_lstval: if (strval == NULL) { return; } - write_reg_contents_ex(regname, strval, -1, append, yank_type, block_len); + write_reg_contents_ex(regname, strval, STRLEN(strval), + append, yank_type, block_len); } rettv->vval.v_number = 0; } @@ -15073,13 +15160,18 @@ typedef struct { int idx; } sortItem_T; -static int item_compare_ic; -static bool item_compare_numeric; -static bool item_compare_numbers; -static bool item_compare_float; -static char_u *item_compare_func; -static dict_T *item_compare_selfdict; -static int item_compare_func_err; +/// struct storing information about current sort +typedef struct { + int item_compare_ic; + bool item_compare_numeric; + bool item_compare_numbers; + bool item_compare_float; + char_u *item_compare_func; + dict_T *item_compare_selfdict; + int item_compare_func_err; +} sortinfo_T; +static sortinfo_T *sortinfo = NULL; + #define ITEM_COMPARE_FAIL 999 /* @@ -15099,14 +15191,14 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero) typval_T *tv1 = &si1->item->li_tv; typval_T *tv2 = &si2->item->li_tv; - if (item_compare_numbers) { + if (sortinfo->item_compare_numbers) { long v1 = get_tv_number(tv1); long v2 = get_tv_number(tv2); return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; } - if (item_compare_float) { + if (sortinfo->item_compare_float) { float_T v1 = get_tv_float(tv1); float_T v2 = get_tv_float(tv2); @@ -15117,7 +15209,7 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero) // do that for string variables. Use a single quote when comparing with // a non-string to do what the docs promise. if (tv1->v_type == VAR_STRING) { - if (tv2->v_type != VAR_STRING || item_compare_numeric) { + if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) { p1 = (char_u *)"'"; } else { p1 = tv1->vval.v_string; @@ -15126,7 +15218,7 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero) tofree1 = p1 = (char_u *) encode_tv2string(tv1, NULL); } if (tv2->v_type == VAR_STRING) { - if (tv1->v_type != VAR_STRING || item_compare_numeric) { + if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) { p2 = (char_u *)"'"; } else { p2 = tv2->vval.v_string; @@ -15134,12 +15226,14 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero) } else { tofree2 = p2 = (char_u *) encode_tv2string(tv2, NULL); } - if (p1 == NULL) + if (p1 == NULL) { p1 = (char_u *)""; - if (p2 == NULL) + } + if (p2 == NULL) { p2 = (char_u *)""; - if (!item_compare_numeric) { - if (item_compare_ic) { + } + if (!sortinfo->item_compare_numeric) { + if (sortinfo->item_compare_ic) { res = STRICMP(p1, p2); } else { res = STRCMP(p1, p2); @@ -15180,9 +15274,10 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero) typval_T argv[3]; int dummy; - /* shortcut after failure in previous call; compare all items equal */ - if (item_compare_func_err) + // shortcut after failure in previous call; compare all items equal + if (sortinfo->item_compare_func_err) { return 0; + } si1 = (sortItem_T *)s1; si2 = (sortItem_T *)s2; @@ -15192,19 +15287,22 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero) copy_tv(&si1->item->li_tv, &argv[0]); copy_tv(&si2->item->li_tv, &argv[1]); - rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */ - res = call_func(item_compare_func, (int)STRLEN(item_compare_func), - &rettv, 2, argv, 0L, 0L, &dummy, TRUE, - item_compare_selfdict); + rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this + res = call_func(sortinfo->item_compare_func, + (int)STRLEN(sortinfo->item_compare_func), + &rettv, 2, argv, 0L, 0L, &dummy, true, + sortinfo->item_compare_selfdict); clear_tv(&argv[0]); clear_tv(&argv[1]); - if (res == FAIL) + if (res == FAIL) { res = ITEM_COMPARE_FAIL; - else - res = get_tv_number_chk(&rettv, &item_compare_func_err); - if (item_compare_func_err) - res = ITEM_COMPARE_FAIL; /* return value has wrong type */ + } else { + res = get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err); + } + if (sortinfo->item_compare_func_err) { + res = ITEM_COMPARE_FAIL; // return value has wrong type + } clear_tv(&rettv); // When the result would be zero, compare the pointers themselves. Makes @@ -15237,6 +15335,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) long len; long i; + // Pointer to current info struct used in compare function. Save and restore + // the current one for nested calls. + sortinfo_T info; + sortinfo_T *old_sortinfo = sortinfo; + sortinfo = &info; + if (argvars[0].v_type != VAR_LIST) { EMSG2(_(e_listarg), sort ? "sort()" : "uniq()"); } else { @@ -15247,61 +15351,70 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) ? N_("sort() argument") : N_("uniq() argument")), true)) { - return; + goto theend; } rettv->vval.v_list = l; rettv->v_type = VAR_LIST; ++l->lv_refcount; len = list_len(l); - if (len <= 1) - return; /* short list sorts pretty quickly */ + if (len <= 1) { + goto theend; // short list sorts pretty quickly + } - item_compare_ic = FALSE; - item_compare_numeric = false; - item_compare_numbers = false; - item_compare_float = false; - item_compare_func = NULL; - item_compare_selfdict = NULL; + info.item_compare_ic = false; + info.item_compare_numeric = false; + info.item_compare_numbers = false; + info.item_compare_float = false; + info.item_compare_func = NULL; + info.item_compare_selfdict = NULL; if (argvars[1].v_type != VAR_UNKNOWN) { /* optional second argument: {func} */ if (argvars[1].v_type == VAR_FUNC) { - item_compare_func = argvars[1].vval.v_string; + info.item_compare_func = argvars[1].vval.v_string; } else { int error = FALSE; i = get_tv_number_chk(&argvars[1], &error); - if (error) - return; /* type error; errmsg already given */ - if (i == 1) - item_compare_ic = TRUE; - else - item_compare_func = get_tv_string(&argvars[1]); - if (item_compare_func != NULL) { - if (STRCMP(item_compare_func, "n") == 0) { - item_compare_func = NULL; - item_compare_numeric = true; - } else if (STRCMP(item_compare_func, "N") == 0) { - item_compare_func = NULL; - item_compare_numbers = true; - } else if (STRCMP(item_compare_func, "f") == 0) { - item_compare_func = NULL; - item_compare_float = true; - } else if (STRCMP(item_compare_func, "i") == 0) { - item_compare_func = NULL; - item_compare_ic = TRUE; + if (error) { + goto theend; // type error; errmsg already given + } + if (i == 1) { + info.item_compare_ic = true; + } else if (argvars[1].v_type != VAR_NUMBER) { + info.item_compare_func = get_tv_string(&argvars[1]); + } else if (i != 0) { + EMSG(_(e_invarg)); + goto theend; + } + if (info.item_compare_func != NULL) { + if (*info.item_compare_func == NUL) { + // empty string means default sort + info.item_compare_func = NULL; + } else if (STRCMP(info.item_compare_func, "n") == 0) { + info.item_compare_func = NULL; + info.item_compare_numeric = true; + } else if (STRCMP(info.item_compare_func, "N") == 0) { + info.item_compare_func = NULL; + info.item_compare_numbers = true; + } else if (STRCMP(info.item_compare_func, "f") == 0) { + info.item_compare_func = NULL; + info.item_compare_float = true; + } else if (STRCMP(info.item_compare_func, "i") == 0) { + info.item_compare_func = NULL; + info.item_compare_ic = true; } } } if (argvars[2].v_type != VAR_UNKNOWN) { - /* optional third argument: {dict} */ + // optional third argument: {dict} if (argvars[2].v_type != VAR_DICT) { EMSG(_(e_dictreq)); - return; + goto theend; } - item_compare_selfdict = argvars[2].vval.v_dict; + info.item_compare_selfdict = argvars[2].vval.v_dict; } } @@ -15317,19 +15430,20 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) i++; } - item_compare_func_err = FALSE; + info.item_compare_func_err = false; // Test the compare function. - if (item_compare_func != NULL + if (info.item_compare_func != NULL && item_compare2_not_keeping_zero(&ptrs[0], &ptrs[1]) == ITEM_COMPARE_FAIL) { EMSG(_("E702: Sort compare function failed")); } else { // Sort the array with item pointers. qsort(ptrs, (size_t)len, sizeof (sortItem_T), - item_compare_func == NULL ? item_compare_not_keeping_zero : - item_compare2_not_keeping_zero); + (info.item_compare_func == NULL ? + item_compare_not_keeping_zero : + item_compare2_not_keeping_zero)); - if (!item_compare_func_err) { + if (!info.item_compare_func_err) { // Clear the list and append the items in the sorted order. l->lv_first = NULL; l->lv_last = NULL; @@ -15345,21 +15459,24 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) int (*item_compare_func_ptr)(const void *, const void *); // f_uniq(): ptrs will be a stack of items to remove. - item_compare_func_err = FALSE; - item_compare_func_ptr = item_compare_func ? item_compare2_keeping_zero : - item_compare_keeping_zero; + info.item_compare_func_err = false; + if (info.item_compare_func != NULL) { + item_compare_func_ptr = item_compare2_keeping_zero; + } else { + item_compare_func_ptr = item_compare_keeping_zero; + } for (li = l->lv_first; li != NULL && li->li_next != NULL; li = li->li_next) { if (item_compare_func_ptr(&li, &li->li_next) == 0) { ptrs[i++].item = li; } - if (item_compare_func_err) { + if (info.item_compare_func_err) { EMSG(_("E882: Uniq compare function failed")); break; } } - if (!item_compare_func_err) { + if (!info.item_compare_func_err) { while (--i >= 0) { assert(ptrs[i].item->li_next); li = ptrs[i].item->li_next; @@ -15378,6 +15495,9 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) xfree(ptrs); } + +theend: + sortinfo = old_sortinfo; } /// "sort"({list})" function @@ -16414,8 +16534,21 @@ static void f_termopen(typval_T *argvars, typval_T *rettv) ufunc_T *on_stdout = NULL, *on_stderr = NULL, *on_exit = NULL; dict_T *job_opts = NULL; + char *cwd = "."; if (argvars[1].v_type == VAR_DICT) { job_opts = argvars[1].vval.v_dict; + + char *new_cwd = (char *)get_dict_string(job_opts, (char_u *)"cwd", false); + if (new_cwd && strlen(new_cwd) > 0) { + cwd = new_cwd; + // The new cwd must be a directory. + if (!os_isdir((char_u *)cwd)) { + EMSG2(_(e_invarg2), "expected valid directory"); + shell_free_argv(argv); + return; + } + } + if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) { shell_free_argv(argv); return; @@ -16423,7 +16556,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv) } TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit, - job_opts, true, false); + job_opts, true, false, cwd); data->proc.pty.width = curwin->w_width; data->proc.pty.height = curwin->w_height; data->proc.pty.term_name = xstrdup("xterm-256color"); @@ -16438,11 +16571,6 @@ static void f_termopen(typval_T *argvars, typval_T *rettv) topts.resize_cb = term_resize; topts.close_cb = term_close; - char *cwd = "."; - if (argvars[1].v_type == VAR_STRING - && os_isdir(argvars[1].vval.v_string)) { - cwd = (char *)argvars[1].vval.v_string; - } int pid = data->proc.pty.process.pid; char buf[1024]; @@ -16529,8 +16657,8 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv) timer->timer_id = last_timer_id++; timer->callback = func; - time_watcher_init(&loop, &timer->tw, timer); - timer->tw.events = queue_new_child(loop.events); + time_watcher_init(&main_loop, &timer->tw, timer); + timer->tw.events = queue_new_child(main_loop.events); // if main loop is blocked, don't queue up multiple events timer->tw.blockable = true; time_watcher_start(&timer->tw, timer_due_cb, timeout, @@ -16563,7 +16691,7 @@ static void timer_due_cb(TimeWatcher *tw, void *data) { timer_T *timer = (timer_T *)data; if (timer->stopped) { - return; + return; } // if repeat was negative repeat forever if (timer->repeat_count >= 0 && --timer->repeat_count == 0) { @@ -16603,6 +16731,14 @@ static void timer_free_cb(TimeWatcher *tw, void *data) xfree(timer); } +void timer_teardown(void) +{ + timer_T *timer; + map_foreach_value(timers, timer, { + timer_stop(timer); + }) +} + /* * "tolower(string)" function */ @@ -17702,7 +17838,8 @@ void set_vim_var_special(const VimVarIndex idx, const SpecialVarValue val) void set_vim_var_string(const VimVarIndex idx, const char *const val, const ptrdiff_t len) { - xfree(vimvars[idx].vv_str); + clear_tv(&vimvars[idx].vv_di.di_tv); + vimvars[idx].vv_type = VAR_STRING; if (val == NULL) { vimvars[idx].vv_str = NULL; } else if (len == -1) { @@ -17718,7 +17855,8 @@ void set_vim_var_string(const VimVarIndex idx, const char *const val, /// @param[in,out] val Value to set to. Reference count will be incremented. void set_vim_var_list(const VimVarIndex idx, list_T *const val) { - list_unref(vimvars[idx].vv_list); + clear_tv(&vimvars[idx].vv_di.di_tv); + vimvars[idx].vv_type = VAR_LIST; vimvars[idx].vv_list = val; if (val != NULL) { val->lv_refcount++; @@ -17732,7 +17870,8 @@ void set_vim_var_list(const VimVarIndex idx, list_T *const val) /// Also keys of the dictionary will be made read-only. void set_vim_var_dict(const VimVarIndex idx, dict_T *const val) { - dict_unref(vimvars[idx].vv_dict); + clear_tv(&vimvars[idx].vv_di.di_tv); + vimvars[idx].vv_type = VAR_DICT; vimvars[idx].vv_dict = val; if (val != NULL) { @@ -21699,7 +21838,8 @@ static inline TerminalJobData *common_job_init(char **argv, ufunc_T *on_exit, dict_T *self, bool pty, - bool detach) + bool detach, + char *cwd) { TerminalJobData *data = xcalloc(1, sizeof(TerminalJobData)); data->stopped = false; @@ -21707,11 +21847,11 @@ static inline TerminalJobData *common_job_init(char **argv, data->on_stderr = on_stderr; data->on_exit = on_exit; data->self = self; - data->events = queue_new_child(loop.events); + data->events = queue_new_child(main_loop.events); if (pty) { - data->proc.pty = pty_process_init(&loop, data); + data->proc.pty = pty_process_init(&main_loop, data); } else { - data->proc.uv = libuv_process_init(&loop, data); + data->proc.uv = libuv_process_init(&main_loop, data); } Process *proc = (Process *)&data->proc; proc->argv = argv; @@ -21723,6 +21863,7 @@ static inline TerminalJobData *common_job_init(char **argv, proc->cb = on_process_exit; proc->events = data->events; proc->detach = detach; + proc->cwd = cwd; return data; } @@ -21809,7 +21950,7 @@ static inline void free_term_job_data(TerminalJobData *data) { // data->queue may still be used after this function returns(process_wait), so // only free in the next event loop iteration - queue_put(loop.fast_events, free_term_job_data_event, 1, data); + queue_put(main_loop.fast_events, free_term_job_data_event, 1, data); } // vimscript job callbacks must be executed on Nvim main loop @@ -22013,6 +22154,7 @@ static void script_host_eval(char *name, typval_T *argvars, typval_T *rettv) if (argvars[0].v_type != VAR_STRING) { EMSG(_(e_invarg)); + return; } list_T *args = list_alloc(); @@ -22070,14 +22212,13 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments) bool eval_has_provider(char *name) { - -#define check_provider(name) \ - if (has_##name == -1) { \ - has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \ - if (!has_##name) { \ - script_autoload((uint8_t *)"provider#" #name "#Call", false); \ - has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \ - } \ +#define check_provider(name) \ + if (has_##name == -1) { \ + has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \ + if (!has_##name) { \ + script_autoload((uint8_t *)"provider#" #name "#Call", false); \ + has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \ + } \ } static int has_clipboard = -1, has_python = -1, has_python3 = -1; @@ -22096,9 +22237,8 @@ bool eval_has_provider(char *name) return false; } -// Compute the `DictWatcher` address from a QUEUE node. This only exists because -// ASAN doesn't handle `QUEUE_DATA` pointer arithmetic, and we blacklist this -// function on .asan-blacklist. +// Compute the `DictWatcher` address from a QUEUE node. This only exists for +// .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer arithmetic). static DictWatcher *dictwatcher_node_data(QUEUE *q) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index 0774ef515f..43e9f76c0f 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -101,7 +101,7 @@ static inline int json_decoder_pop(ValuesStackItem obj, FUNC_ATTR_NONNULL_ALL { if (kv_size(*container_stack) == 0) { - kv_push(ValuesStackItem, *stack, obj); + kv_push(*stack, obj); return OK; } ContainerStackItem last_container = kv_last(*container_stack); @@ -190,7 +190,7 @@ static inline int json_decoder_pop(ValuesStackItem obj, *next_map_special = true; return OK; } - kv_push(ValuesStackItem, *stack, obj); + kv_push(*stack, obj); } return OK; } @@ -628,10 +628,8 @@ int json_decode_string(const char *const buf, const size_t buf_len, convert_setup(&conv, (char_u *) "utf-8", p_enc); conv.vc_fail = true; int ret = OK; - ValuesStack stack; - kv_init(stack); - ContainerStack container_stack; - kv_init(container_stack); + ValuesStack stack = KV_INITIAL_VALUE; + ContainerStack container_stack = KV_INITIAL_VALUE; rettv->v_type = VAR_UNKNOWN; bool didcomma = false; bool didcolon = false; @@ -815,13 +813,13 @@ json_decode_string_cycle_start: .v_lock = VAR_UNLOCKED, .vval = { .v_list = list }, }; - kv_push(ContainerStackItem, container_stack, ((ContainerStackItem) { + kv_push(container_stack, ((ContainerStackItem) { .stack_index = kv_size(stack), .s = p, .container = tv, .special_val = NULL, })); - kv_push(ValuesStackItem, stack, OBJ(tv, false, didcomma, didcolon)); + kv_push(stack, OBJ(tv, false, didcomma, didcolon)); break; } case '{': { @@ -845,13 +843,13 @@ json_decode_string_cycle_start: .vval = { .v_dict = dict }, }; } - kv_push(ContainerStackItem, container_stack, ((ContainerStackItem) { + kv_push(container_stack, ((ContainerStackItem) { .stack_index = kv_size(stack), .s = p, .container = tv, .special_val = val_list, })); - kv_push(ValuesStackItem, stack, OBJ(tv, false, didcomma, didcolon)); + kv_push(stack, OBJ(tv, false, didcomma, didcolon)); break; } default: { diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index c651a50be9..54daf7557e 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -6,6 +6,7 @@ #include <msgpack.h> #include <inttypes.h> +#include <stddef.h> #include <assert.h> #include <math.h> @@ -22,6 +23,7 @@ #include "nvim/ascii.h" #include "nvim/vim.h" // For _() #include "nvim/lib/kvec.h" +#include "nvim/eval/typval_encode.h" #define ga_concat(a, b) ga_concat(a, (char_u *)b) #define utf_ptr2char(b) utf_ptr2char((char_u *)b) @@ -32,29 +34,6 @@ #define convert_setup(vcp, from, to) \ (convert_setup(vcp, (char_u *)from, (char_u *)to)) -/// Structure representing current VimL to messagepack conversion state -typedef struct { - enum { - kMPConvDict, ///< Convert dict_T *dictionary. - kMPConvList, ///< Convert list_T *list. - kMPConvPairs, ///< Convert mapping represented as a list_T* of pairs. - } type; - union { - struct { - dict_T *dict; ///< Currently converted dictionary. - hashitem_T *hi; ///< Currently converted dictionary item. - size_t todo; ///< Amount of items left to process. - } d; ///< State of dictionary conversion. - struct { - list_T *list; ///< Currently converted list. - listitem_T *li; ///< Currently converted list item. - } l; ///< State of list or generic mapping conversion. - } data; ///< Data to convert. -} MPConvStackVal; - -/// Stack used to convert VimL values to messagepack. -typedef kvec_t(MPConvStackVal) MPConvStack; - const char *const encode_special_var_names[] = { [kSpecialVarNull] = "null", [kSpecialVarTrue] = "true", @@ -275,368 +254,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, : OK); } -/// Code for checking whether container references itself -/// -/// @param[in,out] val Container to check. -/// @param copyID_attr Name of the container attribute that holds copyID. -/// After checking whether value of this attribute is -/// copyID (variable) it is set to copyID. -#define CHECK_SELF_REFERENCE(val, copyID_attr, conv_type) \ - do { \ - if ((val)->copyID_attr == copyID) { \ - CONV_RECURSE((val), conv_type); \ - } \ - (val)->copyID_attr = copyID; \ - } while (0) - -#define TV_STRLEN(tv) \ - (tv->vval.v_string == NULL ? 0 : STRLEN(tv->vval.v_string)) - -/// Define functions which convert VimL value to something else -/// -/// Creates function `vim_to_{name}(firstargtype firstargname, typval_T *const -/// tv)` which returns OK or FAIL and helper functions. -/// -/// @param firstargtype Type of the first argument. It will be used to return -/// the results. -/// @param firstargname Name of the first argument. -/// @param name Name of the target converter. -#define DEFINE_VIML_CONV_FUNCTIONS(scope, name, firstargtype, firstargname) \ -static int name##_convert_one_value(firstargtype firstargname, \ - MPConvStack *const mpstack, \ - typval_T *const tv, \ - const int copyID, \ - const char *const objname) \ - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \ -{ \ - switch (tv->v_type) { \ - case VAR_STRING: { \ - CONV_STRING(tv->vval.v_string, TV_STRLEN(tv)); \ - break; \ - } \ - case VAR_NUMBER: { \ - CONV_NUMBER(tv->vval.v_number); \ - break; \ - } \ - case VAR_FLOAT: { \ - CONV_FLOAT(tv->vval.v_float); \ - break; \ - } \ - case VAR_FUNC: { \ - CONV_FUNC(tv->vval.v_string); \ - break; \ - } \ - case VAR_LIST: { \ - if (tv->vval.v_list == NULL || tv->vval.v_list->lv_len == 0) { \ - CONV_EMPTY_LIST(); \ - break; \ - } \ - CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, kMPConvList); \ - CONV_LIST_START(tv->vval.v_list); \ - kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \ - .type = kMPConvList, \ - .data = { \ - .l = { \ - .list = tv->vval.v_list, \ - .li = tv->vval.v_list->lv_first, \ - }, \ - }, \ - })); \ - break; \ - } \ - case VAR_SPECIAL: { \ - switch (tv->vval.v_special) { \ - case kSpecialVarNull: { \ - CONV_NIL(); \ - break; \ - } \ - case kSpecialVarTrue: \ - case kSpecialVarFalse: { \ - CONV_BOOL(tv->vval.v_special == kSpecialVarTrue); \ - break; \ - } \ - } \ - break; \ - } \ - case VAR_DICT: { \ - if (tv->vval.v_dict == NULL \ - || tv->vval.v_dict->dv_hashtab.ht_used == 0) { \ - CONV_EMPTY_DICT(); \ - break; \ - } \ - const dictitem_T *type_di; \ - const dictitem_T *val_di; \ - if (CONV_ALLOW_SPECIAL \ - && tv->vval.v_dict->dv_hashtab.ht_used == 2 \ - && (type_di = dict_find((dict_T *) tv->vval.v_dict, \ - (char_u *) "_TYPE", -1)) != NULL \ - && type_di->di_tv.v_type == VAR_LIST \ - && (val_di = dict_find((dict_T *) tv->vval.v_dict, \ - (char_u *) "_VAL", -1)) != NULL) { \ - size_t i; \ - for (i = 0; i < ARRAY_SIZE(eval_msgpack_type_lists); i++) { \ - if (type_di->di_tv.vval.v_list == eval_msgpack_type_lists[i]) { \ - break; \ - } \ - } \ - if (i == ARRAY_SIZE(eval_msgpack_type_lists)) { \ - goto name##_convert_one_value_regular_dict; \ - } \ - switch ((MessagePackType) i) { \ - case kMPNil: { \ - CONV_NIL(); \ - break; \ - } \ - case kMPBoolean: { \ - if (val_di->di_tv.v_type != VAR_NUMBER) { \ - goto name##_convert_one_value_regular_dict; \ - } \ - CONV_BOOL(val_di->di_tv.vval.v_number); \ - break; \ - } \ - case kMPInteger: { \ - const list_T *val_list; \ - varnumber_T sign; \ - varnumber_T highest_bits; \ - varnumber_T high_bits; \ - varnumber_T low_bits; \ - /* List of 4 integers; first is signed (should be 1 or -1, but */ \ - /* this is not checked), second is unsigned and have at most */ \ - /* one (sign is -1) or two (sign is 1) non-zero bits (number of */ \ - /* bits is not checked), other unsigned and have at most 31 */ \ - /* non-zero bits (number of bits is not checked).*/ \ - if (val_di->di_tv.v_type != VAR_LIST \ - || (val_list = val_di->di_tv.vval.v_list) == NULL \ - || val_list->lv_len != 4 \ - || val_list->lv_first->li_tv.v_type != VAR_NUMBER \ - || (sign = val_list->lv_first->li_tv.vval.v_number) == 0 \ - || val_list->lv_first->li_next->li_tv.v_type != VAR_NUMBER \ - || (highest_bits = \ - val_list->lv_first->li_next->li_tv.vval.v_number) < 0 \ - || val_list->lv_last->li_prev->li_tv.v_type != VAR_NUMBER \ - || (high_bits = \ - val_list->lv_last->li_prev->li_tv.vval.v_number) < 0 \ - || val_list->lv_last->li_tv.v_type != VAR_NUMBER \ - || (low_bits = val_list->lv_last->li_tv.vval.v_number) < 0) { \ - goto name##_convert_one_value_regular_dict; \ - } \ - uint64_t number = ((uint64_t) (((uint64_t) highest_bits) << 62) \ - | (uint64_t) (((uint64_t) high_bits) << 31) \ - | (uint64_t) low_bits); \ - if (sign > 0) { \ - CONV_UNSIGNED_NUMBER(number); \ - } else { \ - CONV_NUMBER(-number); \ - } \ - break; \ - } \ - case kMPFloat: { \ - if (val_di->di_tv.v_type != VAR_FLOAT) { \ - goto name##_convert_one_value_regular_dict; \ - } \ - CONV_FLOAT(val_di->di_tv.vval.v_float); \ - break; \ - } \ - case kMPString: \ - case kMPBinary: { \ - const bool is_string = ((MessagePackType) i == kMPString); \ - if (val_di->di_tv.v_type != VAR_LIST) { \ - goto name##_convert_one_value_regular_dict; \ - } \ - size_t len; \ - char *buf; \ - if (!encode_vim_list_to_buf(val_di->di_tv.vval.v_list, &len, \ - &buf)) { \ - goto name##_convert_one_value_regular_dict; \ - } \ - if (is_string) { \ - CONV_STR_STRING(buf, len); \ - } else { \ - CONV_STRING(buf, len); \ - } \ - xfree(buf); \ - break; \ - } \ - case kMPArray: { \ - if (val_di->di_tv.v_type != VAR_LIST) { \ - goto name##_convert_one_value_regular_dict; \ - } \ - CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list, lv_copyID, \ - kMPConvList); \ - CONV_LIST_START(val_di->di_tv.vval.v_list); \ - kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \ - .type = kMPConvList, \ - .data = { \ - .l = { \ - .list = val_di->di_tv.vval.v_list, \ - .li = val_di->di_tv.vval.v_list->lv_first, \ - }, \ - }, \ - })); \ - break; \ - } \ - case kMPMap: { \ - if (val_di->di_tv.v_type != VAR_LIST) { \ - goto name##_convert_one_value_regular_dict; \ - } \ - list_T *const val_list = val_di->di_tv.vval.v_list; \ - if (val_list == NULL || val_list->lv_len == 0) { \ - CONV_EMPTY_DICT(); \ - break; \ - } \ - for (const listitem_T *li = val_list->lv_first; li != NULL; \ - li = li->li_next) { \ - if (li->li_tv.v_type != VAR_LIST \ - || li->li_tv.vval.v_list->lv_len != 2) { \ - goto name##_convert_one_value_regular_dict; \ - } \ - } \ - CHECK_SELF_REFERENCE(val_list, lv_copyID, kMPConvPairs); \ - CONV_DICT_START(val_list->lv_len); \ - kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \ - .type = kMPConvPairs, \ - .data = { \ - .l = { \ - .list = val_list, \ - .li = val_list->lv_first, \ - }, \ - }, \ - })); \ - break; \ - } \ - case kMPExt: { \ - const list_T *val_list; \ - varnumber_T type; \ - if (val_di->di_tv.v_type != VAR_LIST \ - || (val_list = val_di->di_tv.vval.v_list) == NULL \ - || val_list->lv_len != 2 \ - || (val_list->lv_first->li_tv.v_type != VAR_NUMBER) \ - || (type = val_list->lv_first->li_tv.vval.v_number) > INT8_MAX \ - || type < INT8_MIN \ - || (val_list->lv_last->li_tv.v_type != VAR_LIST)) { \ - goto name##_convert_one_value_regular_dict; \ - } \ - size_t len; \ - char *buf; \ - if (!encode_vim_list_to_buf(val_list->lv_last->li_tv.vval.v_list, \ - &len, &buf)) { \ - goto name##_convert_one_value_regular_dict; \ - } \ - CONV_EXT_STRING(buf, len, type); \ - xfree(buf); \ - break; \ - } \ - } \ - break; \ - } \ -name##_convert_one_value_regular_dict: \ - CHECK_SELF_REFERENCE(tv->vval.v_dict, dv_copyID, kMPConvDict); \ - CONV_DICT_START(tv->vval.v_dict->dv_hashtab.ht_used); \ - kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \ - .type = kMPConvDict, \ - .data = { \ - .d = { \ - .dict = tv->vval.v_dict, \ - .hi = tv->vval.v_dict->dv_hashtab.ht_array, \ - .todo = tv->vval.v_dict->dv_hashtab.ht_used, \ - }, \ - }, \ - })); \ - break; \ - } \ - case VAR_UNKNOWN: { \ - EMSG2(_(e_intern2), #name "_convert_one_value()"); \ - return FAIL; \ - } \ - } \ - return OK; \ -} \ -\ -scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \ - const char *const objname) \ - FUNC_ATTR_WARN_UNUSED_RESULT \ -{ \ - const int copyID = get_copyID(); \ - MPConvStack mpstack; \ - kv_init(mpstack); \ - if (name##_convert_one_value(firstargname, &mpstack, tv, copyID, objname) \ - == FAIL) { \ - goto encode_vim_to_##name##_error_ret; \ - } \ - while (kv_size(mpstack)) { \ - MPConvStackVal *cur_mpsv = &kv_A(mpstack, kv_size(mpstack) - 1); \ - typval_T *cur_tv = NULL; \ - switch (cur_mpsv->type) { \ - case kMPConvDict: { \ - if (!cur_mpsv->data.d.todo) { \ - (void) kv_pop(mpstack); \ - cur_mpsv->data.d.dict->dv_copyID = copyID - 1; \ - CONV_DICT_END(); \ - continue; \ - } else if (cur_mpsv->data.d.todo \ - != cur_mpsv->data.d.dict->dv_hashtab.ht_used) { \ - CONV_DICT_BETWEEN_ITEMS(); \ - } \ - while (HASHITEM_EMPTY(cur_mpsv->data.d.hi)) { \ - cur_mpsv->data.d.hi++; \ - } \ - dictitem_T *const di = HI2DI(cur_mpsv->data.d.hi); \ - cur_mpsv->data.d.todo--; \ - cur_mpsv->data.d.hi++; \ - CONV_STR_STRING(&di->di_key[0], STRLEN(&di->di_key[0])); \ - CONV_DICT_AFTER_KEY(); \ - cur_tv = &di->di_tv; \ - break; \ - } \ - case kMPConvList: { \ - if (cur_mpsv->data.l.li == NULL) { \ - (void) kv_pop(mpstack); \ - cur_mpsv->data.l.list->lv_copyID = copyID - 1; \ - CONV_LIST_END(cur_mpsv->data.l.list); \ - continue; \ - } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { \ - CONV_LIST_BETWEEN_ITEMS(); \ - } \ - cur_tv = &cur_mpsv->data.l.li->li_tv; \ - cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \ - break; \ - } \ - case kMPConvPairs: { \ - if (cur_mpsv->data.l.li == NULL) { \ - (void) kv_pop(mpstack); \ - cur_mpsv->data.l.list->lv_copyID = copyID - 1; \ - CONV_DICT_END(); \ - continue; \ - } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { \ - CONV_DICT_BETWEEN_ITEMS(); \ - } \ - const list_T *const kv_pair = cur_mpsv->data.l.li->li_tv.vval.v_list; \ - CONV_SPECIAL_DICT_KEY_CHECK(name, kv_pair); \ - if (name##_convert_one_value(firstargname, &mpstack, \ - &kv_pair->lv_first->li_tv, copyID, \ - objname) == FAIL) { \ - goto encode_vim_to_##name##_error_ret; \ - } \ - CONV_DICT_AFTER_KEY(); \ - cur_tv = &kv_pair->lv_last->li_tv; \ - cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \ - break; \ - } \ - } \ - assert(cur_tv != NULL); \ - if (name##_convert_one_value(firstargname, &mpstack, cur_tv, copyID, \ - objname) == FAIL) { \ - goto encode_vim_to_##name##_error_ret; \ - } \ - } \ - kv_destroy(mpstack); \ - return OK; \ -encode_vim_to_##name##_error_ret: \ - kv_destroy(mpstack); \ - return FAIL; \ -} - -#define CONV_STRING(buf, len) \ +#define TYPVAL_ENCODE_CONV_STRING(buf, len) \ do { \ const char *const buf_ = (const char *) buf; \ if (buf == NULL) { \ @@ -655,19 +273,19 @@ encode_vim_to_##name##_error_ret: \ } \ } while (0) -#define CONV_STR_STRING(buf, len) \ - CONV_STRING(buf, len) +#define TYPVAL_ENCODE_CONV_STR_STRING(buf, len) \ + TYPVAL_ENCODE_CONV_STRING(buf, len) -#define CONV_EXT_STRING(buf, len, type) +#define TYPVAL_ENCODE_CONV_EXT_STRING(buf, len, type) -#define CONV_NUMBER(num) \ +#define TYPVAL_ENCODE_CONV_NUMBER(num) \ do { \ char numbuf[NUMBUFLEN]; \ vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%" PRId64, (int64_t) (num)); \ ga_concat(gap, numbuf); \ } while (0) -#define CONV_FLOAT(flt) \ +#define TYPVAL_ENCODE_CONV_FLOAT(flt) \ do { \ const float_T flt_ = (flt); \ switch (fpclassify(flt_)) { \ @@ -690,51 +308,51 @@ encode_vim_to_##name##_error_ret: \ } \ } while (0) -#define CONV_FUNC(fun) \ +#define TYPVAL_ENCODE_CONV_FUNC(fun) \ do { \ ga_concat(gap, "function("); \ - CONV_STRING(fun, STRLEN(fun)); \ + TYPVAL_ENCODE_CONV_STRING(fun, STRLEN(fun)); \ ga_append(gap, ')'); \ } while (0) -#define CONV_EMPTY_LIST() \ +#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \ ga_concat(gap, "[]") -#define CONV_LIST_START(lst) \ +#define TYPVAL_ENCODE_CONV_LIST_START(len) \ ga_append(gap, '[') -#define CONV_EMPTY_DICT() \ +#define TYPVAL_ENCODE_CONV_EMPTY_DICT() \ ga_concat(gap, "{}") -#define CONV_NIL() \ +#define TYPVAL_ENCODE_CONV_NIL() \ ga_concat(gap, "v:null") -#define CONV_BOOL(num) \ +#define TYPVAL_ENCODE_CONV_BOOL(num) \ ga_concat(gap, ((num)? "v:true": "v:false")) -#define CONV_UNSIGNED_NUMBER(num) +#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(num) -#define CONV_DICT_START(len) \ +#define TYPVAL_ENCODE_CONV_DICT_START(len) \ ga_append(gap, '{') -#define CONV_DICT_END() \ +#define TYPVAL_ENCODE_CONV_DICT_END() \ ga_append(gap, '}') -#define CONV_DICT_AFTER_KEY() \ +#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY() \ ga_concat(gap, ": ") -#define CONV_DICT_BETWEEN_ITEMS() \ +#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS() \ ga_concat(gap, ", ") -#define CONV_SPECIAL_DICT_KEY_CHECK(name, kv_pair) +#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, kv_pair) -#define CONV_LIST_END(lst) \ +#define TYPVAL_ENCODE_CONV_LIST_END() \ ga_append(gap, ']') -#define CONV_LIST_BETWEEN_ITEMS() \ - CONV_DICT_BETWEEN_ITEMS() +#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS() \ + TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS() -#define CONV_RECURSE(val, conv_type) \ +#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ do { \ if (!did_echo_string_emsg) { \ /* Only give this message once for a recursive call to avoid */ \ @@ -764,12 +382,12 @@ encode_vim_to_##name##_error_ret: \ return OK; \ } while (0) -#define CONV_ALLOW_SPECIAL false +#define TYPVAL_ENCODE_ALLOW_SPECIALS false -DEFINE_VIML_CONV_FUNCTIONS(static, string, garray_T *const, gap) +TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, string, garray_T *const, gap) -#undef CONV_RECURSE -#define CONV_RECURSE(val, conv_type) \ +#undef TYPVAL_ENCODE_CONV_RECURSE +#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ do { \ char ebuf[NUMBUFLEN + 7]; \ size_t backref = 0; \ @@ -796,10 +414,10 @@ DEFINE_VIML_CONV_FUNCTIONS(static, string, garray_T *const, gap) return OK; \ } while (0) -DEFINE_VIML_CONV_FUNCTIONS(, echo, garray_T *const, gap) +TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(, echo, garray_T *const, gap) -#undef CONV_RECURSE -#define CONV_RECURSE(val, conv_type) \ +#undef TYPVAL_ENCODE_CONV_RECURSE +#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ do { \ if (!did_echo_string_emsg) { \ /* Only give this message once for a recursive call to avoid */ \ @@ -811,27 +429,27 @@ DEFINE_VIML_CONV_FUNCTIONS(, echo, garray_T *const, gap) return OK; \ } while (0) -#undef CONV_ALLOW_SPECIAL -#define CONV_ALLOW_SPECIAL true +#undef TYPVAL_ENCODE_ALLOW_SPECIALS +#define TYPVAL_ENCODE_ALLOW_SPECIALS true -#undef CONV_NIL -#define CONV_NIL() \ +#undef TYPVAL_ENCODE_CONV_NIL +#define TYPVAL_ENCODE_CONV_NIL() \ ga_concat(gap, "null") -#undef CONV_BOOL -#define CONV_BOOL(num) \ +#undef TYPVAL_ENCODE_CONV_BOOL +#define TYPVAL_ENCODE_CONV_BOOL(num) \ ga_concat(gap, ((num)? "true": "false")) -#undef CONV_UNSIGNED_NUMBER -#define CONV_UNSIGNED_NUMBER(num) \ +#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER +#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(num) \ do { \ char numbuf[NUMBUFLEN]; \ vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%" PRIu64, (num)); \ ga_concat(gap, numbuf); \ } while (0) -#undef CONV_FLOAT -#define CONV_FLOAT(flt) \ +#undef TYPVAL_ENCODE_CONV_FLOAT +#define TYPVAL_ENCODE_CONV_FLOAT(flt) \ do { \ const float_T flt_ = (flt); \ switch (fpclassify(flt_)) { \ @@ -1019,24 +637,24 @@ static inline int convert_to_json_string(garray_T *const gap, return OK; } -#undef CONV_STRING -#define CONV_STRING(buf, len) \ +#undef TYPVAL_ENCODE_CONV_STRING +#define TYPVAL_ENCODE_CONV_STRING(buf, len) \ do { \ if (convert_to_json_string(gap, (const char *) (buf), (len)) != OK) { \ return FAIL; \ } \ } while (0) -#undef CONV_EXT_STRING -#define CONV_EXT_STRING(buf, len, type) \ +#undef TYPVAL_ENCODE_CONV_EXT_STRING +#define TYPVAL_ENCODE_CONV_EXT_STRING(buf, len, type) \ do { \ xfree(buf); \ EMSG(_("E474: Unable to convert EXT string to JSON")); \ return FAIL; \ } while (0) -#undef CONV_FUNC -#define CONV_FUNC(fun) \ +#undef TYPVAL_ENCODE_CONV_FUNC +#define TYPVAL_ENCODE_CONV_FUNC(fun) \ return conv_error(_("E474: Error while dumping %s, %s: " \ "attempt to dump function reference"), \ mpstack, objname) @@ -1080,38 +698,38 @@ static inline bool check_json_key(const typval_T *const tv) return true; } -#undef CONV_SPECIAL_DICT_KEY_CHECK -#define CONV_SPECIAL_DICT_KEY_CHECK(name, kv_pair) \ +#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK +#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, kv_pair) \ do { \ if (!check_json_key(&kv_pair->lv_first->li_tv)) { \ EMSG(_("E474: Invalid key in special dictionary")); \ - goto encode_vim_to_##name##_error_ret; \ + goto label; \ } \ } while (0) -DEFINE_VIML_CONV_FUNCTIONS(static, json, garray_T *const, gap) - -#undef CONV_STRING -#undef CONV_STR_STRING -#undef CONV_EXT_STRING -#undef CONV_NUMBER -#undef CONV_FLOAT -#undef CONV_FUNC -#undef CONV_EMPTY_LIST -#undef CONV_LIST_START -#undef CONV_EMPTY_DICT -#undef CONV_NIL -#undef CONV_BOOL -#undef CONV_UNSIGNED_NUMBER -#undef CONV_DICT_START -#undef CONV_DICT_END -#undef CONV_DICT_AFTER_KEY -#undef CONV_DICT_BETWEEN_ITEMS -#undef CONV_SPECIAL_DICT_KEY_CHECK -#undef CONV_LIST_END -#undef CONV_LIST_BETWEEN_ITEMS -#undef CONV_RECURSE -#undef CONV_ALLOW_SPECIAL +TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, json, garray_T *const, gap) + +#undef TYPVAL_ENCODE_CONV_STRING +#undef TYPVAL_ENCODE_CONV_STR_STRING +#undef TYPVAL_ENCODE_CONV_EXT_STRING +#undef TYPVAL_ENCODE_CONV_NUMBER +#undef TYPVAL_ENCODE_CONV_FLOAT +#undef TYPVAL_ENCODE_CONV_FUNC +#undef TYPVAL_ENCODE_CONV_EMPTY_LIST +#undef TYPVAL_ENCODE_CONV_LIST_START +#undef TYPVAL_ENCODE_CONV_EMPTY_DICT +#undef TYPVAL_ENCODE_CONV_NIL +#undef TYPVAL_ENCODE_CONV_BOOL +#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER +#undef TYPVAL_ENCODE_CONV_DICT_START +#undef TYPVAL_ENCODE_CONV_DICT_END +#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY +#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS +#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK +#undef TYPVAL_ENCODE_CONV_LIST_END +#undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS +#undef TYPVAL_ENCODE_CONV_RECURSE +#undef TYPVAL_ENCODE_ALLOW_SPECIALS /// Return a string with the string representation of a variable. /// Puts quotes around strings, so that they can be parsed back by eval(). @@ -1181,7 +799,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) return (char *) ga.ga_data; } -#define CONV_STRING(buf, len) \ +#define TYPVAL_ENCODE_CONV_STRING(buf, len) \ do { \ if (buf == NULL) { \ msgpack_pack_bin(packer, 0); \ @@ -1192,7 +810,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) } \ } while (0) -#define CONV_STR_STRING(buf, len) \ +#define TYPVAL_ENCODE_CONV_STR_STRING(buf, len) \ do { \ if (buf == NULL) { \ msgpack_pack_str(packer, 0); \ @@ -1203,7 +821,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) } \ } while (0) -#define CONV_EXT_STRING(buf, len, type) \ +#define TYPVAL_ENCODE_CONV_EXT_STRING(buf, len, type) \ do { \ if (buf == NULL) { \ msgpack_pack_ext(packer, 0, (int8_t) type); \ @@ -1214,30 +832,30 @@ char *encode_tv2json(typval_T *tv, size_t *len) } \ } while (0) -#define CONV_NUMBER(num) \ +#define TYPVAL_ENCODE_CONV_NUMBER(num) \ msgpack_pack_int64(packer, (int64_t) (num)) -#define CONV_FLOAT(flt) \ +#define TYPVAL_ENCODE_CONV_FLOAT(flt) \ msgpack_pack_double(packer, (double) (flt)) -#define CONV_FUNC(fun) \ +#define TYPVAL_ENCODE_CONV_FUNC(fun) \ return conv_error(_("E951: Error while dumping %s, %s: " \ "attempt to dump function reference"), \ mpstack, objname) -#define CONV_EMPTY_LIST() \ +#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \ msgpack_pack_array(packer, 0) -#define CONV_LIST_START(lst) \ - msgpack_pack_array(packer, (size_t) (lst)->lv_len) +#define TYPVAL_ENCODE_CONV_LIST_START(len) \ + msgpack_pack_array(packer, (size_t) (len)) -#define CONV_EMPTY_DICT() \ +#define TYPVAL_ENCODE_CONV_EMPTY_DICT() \ msgpack_pack_map(packer, 0) -#define CONV_NIL() \ +#define TYPVAL_ENCODE_CONV_NIL() \ msgpack_pack_nil(packer) -#define CONV_BOOL(num) \ +#define TYPVAL_ENCODE_CONV_BOOL(num) \ do { \ if ((num)) { \ msgpack_pack_true(packer); \ @@ -1246,51 +864,51 @@ char *encode_tv2json(typval_T *tv, size_t *len) } \ } while (0) -#define CONV_UNSIGNED_NUMBER(num) \ +#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(num) \ msgpack_pack_uint64(packer, (num)) -#define CONV_DICT_START(len) \ +#define TYPVAL_ENCODE_CONV_DICT_START(len) \ msgpack_pack_map(packer, (size_t) (len)) -#define CONV_DICT_END() +#define TYPVAL_ENCODE_CONV_DICT_END() -#define CONV_DICT_AFTER_KEY() +#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY() -#define CONV_DICT_BETWEEN_ITEMS() +#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS() -#define CONV_SPECIAL_DICT_KEY_CHECK(name, kv_pair) +#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, kv_pair) -#define CONV_LIST_END(lst) +#define TYPVAL_ENCODE_CONV_LIST_END() -#define CONV_LIST_BETWEEN_ITEMS() +#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS() -#define CONV_RECURSE(val, conv_type) \ +#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ return conv_error(_("E952: Unable to dump %s: " \ "container references itself in %s"), \ mpstack, objname) -#define CONV_ALLOW_SPECIAL true - -DEFINE_VIML_CONV_FUNCTIONS(, msgpack, msgpack_packer *const, packer) - -#undef CONV_STRING -#undef CONV_STR_STRING -#undef CONV_EXT_STRING -#undef CONV_NUMBER -#undef CONV_FLOAT -#undef CONV_FUNC -#undef CONV_EMPTY_LIST -#undef CONV_LIST_START -#undef CONV_EMPTY_DICT -#undef CONV_NIL -#undef CONV_BOOL -#undef CONV_UNSIGNED_NUMBER -#undef CONV_DICT_START -#undef CONV_DICT_END -#undef CONV_DICT_AFTER_KEY -#undef CONV_DICT_BETWEEN_ITEMS -#undef CONV_SPECIAL_DICT_KEY_CHECK -#undef CONV_LIST_END -#undef CONV_LIST_BETWEEN_ITEMS -#undef CONV_RECURSE -#undef CONV_ALLOW_SPECIAL +#define TYPVAL_ENCODE_ALLOW_SPECIALS true + +TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(, msgpack, msgpack_packer *const, packer) + +#undef TYPVAL_ENCODE_CONV_STRING +#undef TYPVAL_ENCODE_CONV_STR_STRING +#undef TYPVAL_ENCODE_CONV_EXT_STRING +#undef TYPVAL_ENCODE_CONV_NUMBER +#undef TYPVAL_ENCODE_CONV_FLOAT +#undef TYPVAL_ENCODE_CONV_FUNC +#undef TYPVAL_ENCODE_CONV_EMPTY_LIST +#undef TYPVAL_ENCODE_CONV_LIST_START +#undef TYPVAL_ENCODE_CONV_EMPTY_DICT +#undef TYPVAL_ENCODE_CONV_NIL +#undef TYPVAL_ENCODE_CONV_BOOL +#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER +#undef TYPVAL_ENCODE_CONV_DICT_START +#undef TYPVAL_ENCODE_CONV_DICT_END +#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY +#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS +#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK +#undef TYPVAL_ENCODE_CONV_LIST_END +#undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS +#undef TYPVAL_ENCODE_CONV_RECURSE +#undef TYPVAL_ENCODE_ALLOW_SPECIALS diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h new file mode 100644 index 0000000000..f70a6c9e94 --- /dev/null +++ b/src/nvim/eval/typval_encode.h @@ -0,0 +1,563 @@ +/// @file eval/typval_convert.h +/// +/// Contains set of macros used to convert (possibly recursive) typval_T into +/// something else. For these macros to work the following macros must be +/// defined: + +/// @def TYPVAL_ENCODE_CONV_NIL +/// @brief Macros used to convert NIL value +/// +/// Is called both for special dictionary (unless #TYPVAL_ENCODE_ALLOW_SPECIALS +/// is false) and `v:null`. Accepts no arguments, but still must be +/// a function-like macros. + +/// @def TYPVAL_ENCODE_CONV_BOOL +/// @brief Macros used to convert boolean value +/// +/// Is called both for special dictionary (unless #TYPVAL_ENCODE_ALLOW_SPECIALS +/// is false) and `v:true`/`v:false`. +/// +/// @param num Boolean value to convert. Value is an expression which +/// evaluates to some integer. + +/// @def TYPVAL_ENCODE_CONV_NUMBER +/// @brief Macros used to convert integer +/// +/// @param num Integer to convert, must accept both varnumber_T and int64_t. + +/// @def TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER +/// @brief Macros used to convert unsigned integer +/// +/// Not used if #TYPVAL_ENCODE_ALLOW_SPECIALS is false, but still must be +/// defined. +/// +/// @param num Integer to convert, must accept uint64_t. + +/// @def TYPVAL_ENCODE_CONV_FLOAT +/// @brief Macros used to convert floating-point number +/// +/// @param flt Number to convert, must accept float_T. + +/// @def TYPVAL_ENCODE_CONV_STRING +/// @brief Macros used to convert plain string +/// +/// Is used to convert VAR_STRING objects as well as BIN strings represented as +/// special dictionary. +/// +/// @param buf String to convert. Is a char[] buffer, not NUL-terminated. +/// @param len String length. + +/// @def TYPVAL_ENCODE_CONV_STR_STRING +/// @brief Like #TYPVAL_ENCODE_CONV_STRING, but for STR strings +/// +/// Is used to convert dictionary keys and STR strings represented as special +/// dictionaries. + +/// @def TYPVAL_ENCODE_CONV_EXT_STRING +/// @brief Macros used to convert EXT string +/// +/// Is used to convert EXT strings represented as special dictionaries. Never +/// actually used if #TYPVAL_ENCODE_ALLOW_SPECIALS is false, but still must be +/// defined. +/// +/// @param buf String to convert. Is a char[] buffer, not NUL-terminated. +/// @param len String length. +/// @param type EXT type. + +/// @def TYPVAL_ENCODE_CONV_FUNC +/// @brief Macros used to convert a function reference +/// +/// @param fun Function name. + +/// @def TYPVAL_ENCODE_CONV_EMPTY_LIST +/// @brief Macros used to convert an empty list +/// +/// Accepts no arguments, but still must be a function-like macros. + +/// @def TYPVAL_ENCODE_CONV_EMPTY_DICT +/// @brief Macros used to convert an empty dictionary +/// +/// Accepts no arguments, but still must be a function-like macros. + +/// @def TYPVAL_ENCODE_CONV_LIST_START +/// @brief Macros used before starting to convert non-empty list +/// +/// @param len List length. Is an expression which evaluates to an integer. + +/// @def TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS +/// @brief Macros used after finishing converting non-last list item +/// +/// Accepts no arguments, but still must be a function-like macros. + +/// @def TYPVAL_ENCODE_CONV_LIST_END +/// @brief Macros used after converting non-empty list +/// +/// Accepts no arguments, but still must be a function-like macros. + +/// @def TYPVAL_ENCODE_CONV_DICT_START +/// @brief Macros used before starting to convert non-empty dictionary +/// +/// @param len Dictionary length. Is an expression which evaluates to an +/// integer. + +/// @def TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK +/// @brief Macros used to check special dictionary key +/// +/// @param label Label for goto in case check was not successfull. +/// @param kv_pair List with two elements: key and value. + +/// @def TYPVAL_ENCODE_CONV_DICT_AFTER_KEY +/// @brief Macros used after finishing converting dictionary key +/// +/// Accepts no arguments, but still must be a function-like macros. + +/// @def TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS +/// @brief Macros used after finishing converting non-last dictionary value +/// +/// Accepts no arguments, but still must be a function-like macros. + +/// @def TYPVAL_ENCODE_CONV_DICT_END +/// @brief Macros used after converting non-empty dictionary +/// +/// Accepts no arguments, but still must be a function-like macros. + +/// @def TYPVAL_ENCODE_CONV_RECURSE +/// @brief Macros used when self-containing container is detected +/// +/// @param val Container for which this situation was detected. +/// @param conv_type Type of the stack entry, @see MPConvStackValType. + +/// @def TYPVAL_ENCODE_ALLOW_SPECIALS +/// @brief Macros that specifies whether special dictionaries are special +/// +/// Must be something that evaluates to boolean, most likely `true` or `false`. +/// If it is false then special dictionaries are not treated specially. +#ifndef NVIM_EVAL_TYPVAL_ENCODE_H +#define NVIM_EVAL_TYPVAL_ENCODE_H + +#include <stddef.h> +#include <inttypes.h> +#include <assert.h> + +#include "nvim/lib/kvec.h" +#include "nvim/eval_defs.h" +#include "nvim/eval/encode.h" +#include "nvim/func_attr.h" + +/// Type of the stack entry +typedef enum { + kMPConvDict, ///< Convert dict_T *dictionary. + kMPConvList, ///< Convert list_T *list. + kMPConvPairs, ///< Convert mapping represented as a list_T* of pairs. +} MPConvStackValType; + +/// Structure representing current VimL to messagepack conversion state +typedef struct { + MPConvStackValType type; ///< Type of the stack entry. + union { + struct { + dict_T *dict; ///< Currently converted dictionary. + hashitem_T *hi; ///< Currently converted dictionary item. + size_t todo; ///< Amount of items left to process. + } d; ///< State of dictionary conversion. + struct { + list_T *list; ///< Currently converted list. + listitem_T *li; ///< Currently converted list item. + } l; ///< State of list or generic mapping conversion. + } data; ///< Data to convert. +} MPConvStackVal; + +/// Stack used to convert VimL values to messagepack. +typedef kvec_t(MPConvStackVal) MPConvStack; + +// Defines for MPConvStack +#define _mp_size kv_size +#define _mp_init kv_init +#define _mp_destroy kv_destroy +#define _mp_push kv_push +#define _mp_pop kv_pop +#define _mp_last kv_last + +/// Code for checking whether container references itself +/// +/// @param[in,out] val Container to check. +/// @param copyID_attr Name of the container attribute that holds copyID. +/// After checking whether value of this attribute is +/// copyID (variable) it is set to copyID. +#define _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val, copyID_attr, conv_type) \ + do { \ + if ((val)->copyID_attr == copyID) { \ + TYPVAL_ENCODE_CONV_RECURSE((val), conv_type); \ + } \ + (val)->copyID_attr = copyID; \ + } while (0) + +/// Length of the string stored in typval_T +/// +/// @param[in] tv String for which to compute length for. Must be typval_T +/// with VAR_STRING. +/// +/// @return Length of the string stored in typval_T, including 0 for NULL +/// string. +static inline size_t tv_strlen(const typval_T *const tv) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT + FUNC_ATTR_NONNULL_ALL +{ + assert(tv->v_type == VAR_STRING); + return (tv->vval.v_string == NULL + ? 0 + : strlen((char *) tv->vval.v_string)); +} + +/// Define functions which convert VimL value to something else +/// +/// Creates function `vim_to_{name}(firstargtype firstargname, typval_T *const +/// tv)` which returns OK or FAIL and helper functions. +/// +/// @param scope Scope of the main function: either nothing or `static`. +/// @param firstargtype Type of the first argument. It will be used to return +/// the results. +/// @param firstargname Name of the first argument. +/// @param name Name of the target converter. +#define TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(scope, name, firstargtype, \ + firstargname) \ +static int name##_convert_one_value(firstargtype firstargname, \ + MPConvStack *const mpstack, \ + typval_T *const tv, \ + const int copyID, \ + const char *const objname) \ + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \ +{ \ + switch (tv->v_type) { \ + case VAR_STRING: { \ + TYPVAL_ENCODE_CONV_STRING(tv->vval.v_string, tv_strlen(tv)); \ + break; \ + } \ + case VAR_NUMBER: { \ + TYPVAL_ENCODE_CONV_NUMBER(tv->vval.v_number); \ + break; \ + } \ + case VAR_FLOAT: { \ + TYPVAL_ENCODE_CONV_FLOAT(tv->vval.v_float); \ + break; \ + } \ + case VAR_FUNC: { \ + TYPVAL_ENCODE_CONV_FUNC(tv->vval.v_string); \ + break; \ + } \ + case VAR_LIST: { \ + if (tv->vval.v_list == NULL || tv->vval.v_list->lv_len == 0) { \ + TYPVAL_ENCODE_CONV_EMPTY_LIST(); \ + break; \ + } \ + _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, \ + kMPConvList); \ + TYPVAL_ENCODE_CONV_LIST_START(tv->vval.v_list->lv_len); \ + _mp_push(*mpstack, ((MPConvStackVal) { \ + .type = kMPConvList, \ + .data = { \ + .l = { \ + .list = tv->vval.v_list, \ + .li = tv->vval.v_list->lv_first, \ + }, \ + }, \ + })); \ + break; \ + } \ + case VAR_SPECIAL: { \ + switch (tv->vval.v_special) { \ + case kSpecialVarNull: { \ + TYPVAL_ENCODE_CONV_NIL(); \ + break; \ + } \ + case kSpecialVarTrue: \ + case kSpecialVarFalse: { \ + TYPVAL_ENCODE_CONV_BOOL(tv->vval.v_special == kSpecialVarTrue); \ + break; \ + } \ + } \ + break; \ + } \ + case VAR_DICT: { \ + if (tv->vval.v_dict == NULL \ + || tv->vval.v_dict->dv_hashtab.ht_used == 0) { \ + TYPVAL_ENCODE_CONV_EMPTY_DICT(); \ + break; \ + } \ + const dictitem_T *type_di; \ + const dictitem_T *val_di; \ + if (TYPVAL_ENCODE_ALLOW_SPECIALS \ + && tv->vval.v_dict->dv_hashtab.ht_used == 2 \ + && (type_di = dict_find((dict_T *) tv->vval.v_dict, \ + (char_u *) "_TYPE", -1)) != NULL \ + && type_di->di_tv.v_type == VAR_LIST \ + && (val_di = dict_find((dict_T *) tv->vval.v_dict, \ + (char_u *) "_VAL", -1)) != NULL) { \ + size_t i; \ + for (i = 0; i < ARRAY_SIZE(eval_msgpack_type_lists); i++) { \ + if (type_di->di_tv.vval.v_list == eval_msgpack_type_lists[i]) { \ + break; \ + } \ + } \ + if (i == ARRAY_SIZE(eval_msgpack_type_lists)) { \ + goto name##_convert_one_value_regular_dict; \ + } \ + switch ((MessagePackType) i) { \ + case kMPNil: { \ + TYPVAL_ENCODE_CONV_NIL(); \ + break; \ + } \ + case kMPBoolean: { \ + if (val_di->di_tv.v_type != VAR_NUMBER) { \ + goto name##_convert_one_value_regular_dict; \ + } \ + TYPVAL_ENCODE_CONV_BOOL(val_di->di_tv.vval.v_number); \ + break; \ + } \ + case kMPInteger: { \ + const list_T *val_list; \ + varnumber_T sign; \ + varnumber_T highest_bits; \ + varnumber_T high_bits; \ + varnumber_T low_bits; \ + /* List of 4 integers; first is signed (should be 1 or -1, but */ \ + /* this is not checked), second is unsigned and have at most */ \ + /* one (sign is -1) or two (sign is 1) non-zero bits (number of */ \ + /* bits is not checked), other unsigned and have at most 31 */ \ + /* non-zero bits (number of bits is not checked).*/ \ + if (val_di->di_tv.v_type != VAR_LIST \ + || (val_list = val_di->di_tv.vval.v_list) == NULL \ + || val_list->lv_len != 4 \ + || val_list->lv_first->li_tv.v_type != VAR_NUMBER \ + || (sign = val_list->lv_first->li_tv.vval.v_number) == 0 \ + || val_list->lv_first->li_next->li_tv.v_type != VAR_NUMBER \ + || (highest_bits = \ + val_list->lv_first->li_next->li_tv.vval.v_number) < 0 \ + || val_list->lv_last->li_prev->li_tv.v_type != VAR_NUMBER \ + || (high_bits = \ + val_list->lv_last->li_prev->li_tv.vval.v_number) < 0 \ + || val_list->lv_last->li_tv.v_type != VAR_NUMBER \ + || (low_bits = val_list->lv_last->li_tv.vval.v_number) < 0) { \ + goto name##_convert_one_value_regular_dict; \ + } \ + uint64_t number = ((uint64_t) (((uint64_t) highest_bits) << 62) \ + | (uint64_t) (((uint64_t) high_bits) << 31) \ + | (uint64_t) low_bits); \ + if (sign > 0) { \ + TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(number); \ + } else { \ + TYPVAL_ENCODE_CONV_NUMBER(-number); \ + } \ + break; \ + } \ + case kMPFloat: { \ + if (val_di->di_tv.v_type != VAR_FLOAT) { \ + goto name##_convert_one_value_regular_dict; \ + } \ + TYPVAL_ENCODE_CONV_FLOAT(val_di->di_tv.vval.v_float); \ + break; \ + } \ + case kMPString: \ + case kMPBinary: { \ + const bool is_string = ((MessagePackType) i == kMPString); \ + if (val_di->di_tv.v_type != VAR_LIST) { \ + goto name##_convert_one_value_regular_dict; \ + } \ + size_t len; \ + char *buf; \ + if (!encode_vim_list_to_buf(val_di->di_tv.vval.v_list, &len, \ + &buf)) { \ + goto name##_convert_one_value_regular_dict; \ + } \ + if (is_string) { \ + TYPVAL_ENCODE_CONV_STR_STRING(buf, len); \ + } else { \ + TYPVAL_ENCODE_CONV_STRING(buf, len); \ + } \ + xfree(buf); \ + break; \ + } \ + case kMPArray: { \ + if (val_di->di_tv.v_type != VAR_LIST) { \ + goto name##_convert_one_value_regular_dict; \ + } \ + _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list, \ + lv_copyID, kMPConvList); \ + TYPVAL_ENCODE_CONV_LIST_START(val_di->di_tv.vval.v_list->lv_len); \ + _mp_push(*mpstack, ((MPConvStackVal) { \ + .type = kMPConvList, \ + .data = { \ + .l = { \ + .list = val_di->di_tv.vval.v_list, \ + .li = val_di->di_tv.vval.v_list->lv_first, \ + }, \ + }, \ + })); \ + break; \ + } \ + case kMPMap: { \ + if (val_di->di_tv.v_type != VAR_LIST) { \ + goto name##_convert_one_value_regular_dict; \ + } \ + list_T *const val_list = val_di->di_tv.vval.v_list; \ + if (val_list == NULL || val_list->lv_len == 0) { \ + TYPVAL_ENCODE_CONV_EMPTY_DICT(); \ + break; \ + } \ + for (const listitem_T *li = val_list->lv_first; li != NULL; \ + li = li->li_next) { \ + if (li->li_tv.v_type != VAR_LIST \ + || li->li_tv.vval.v_list->lv_len != 2) { \ + goto name##_convert_one_value_regular_dict; \ + } \ + } \ + _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_list, lv_copyID, \ + kMPConvPairs); \ + TYPVAL_ENCODE_CONV_DICT_START(val_list->lv_len); \ + _mp_push(*mpstack, ((MPConvStackVal) { \ + .type = kMPConvPairs, \ + .data = { \ + .l = { \ + .list = val_list, \ + .li = val_list->lv_first, \ + }, \ + }, \ + })); \ + break; \ + } \ + case kMPExt: { \ + const list_T *val_list; \ + varnumber_T type; \ + if (val_di->di_tv.v_type != VAR_LIST \ + || (val_list = val_di->di_tv.vval.v_list) == NULL \ + || val_list->lv_len != 2 \ + || (val_list->lv_first->li_tv.v_type != VAR_NUMBER) \ + || (type = val_list->lv_first->li_tv.vval.v_number) > INT8_MAX \ + || type < INT8_MIN \ + || (val_list->lv_last->li_tv.v_type != VAR_LIST)) { \ + goto name##_convert_one_value_regular_dict; \ + } \ + size_t len; \ + char *buf; \ + if (!encode_vim_list_to_buf(val_list->lv_last->li_tv.vval.v_list, \ + &len, &buf)) { \ + goto name##_convert_one_value_regular_dict; \ + } \ + TYPVAL_ENCODE_CONV_EXT_STRING(buf, len, type); \ + xfree(buf); \ + break; \ + } \ + } \ + break; \ + } \ +name##_convert_one_value_regular_dict: \ + _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(tv->vval.v_dict, dv_copyID, \ + kMPConvDict); \ + TYPVAL_ENCODE_CONV_DICT_START(tv->vval.v_dict->dv_hashtab.ht_used); \ + _mp_push(*mpstack, ((MPConvStackVal) { \ + .type = kMPConvDict, \ + .data = { \ + .d = { \ + .dict = tv->vval.v_dict, \ + .hi = tv->vval.v_dict->dv_hashtab.ht_array, \ + .todo = tv->vval.v_dict->dv_hashtab.ht_used, \ + }, \ + }, \ + })); \ + break; \ + } \ + case VAR_UNKNOWN: { \ + EMSG2(_(e_intern2), #name "_convert_one_value()"); \ + return FAIL; \ + } \ + } \ + return OK; \ +} \ +\ +scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \ + const char *const objname) \ + FUNC_ATTR_WARN_UNUSED_RESULT \ +{ \ + const int copyID = get_copyID(); \ + MPConvStack mpstack; \ + _mp_init(mpstack); \ + if (name##_convert_one_value(firstargname, &mpstack, tv, copyID, objname) \ + == FAIL) { \ + goto encode_vim_to_##name##_error_ret; \ + } \ + while (_mp_size(mpstack)) { \ + MPConvStackVal *cur_mpsv = &_mp_last(mpstack); \ + typval_T *cur_tv = NULL; \ + switch (cur_mpsv->type) { \ + case kMPConvDict: { \ + if (!cur_mpsv->data.d.todo) { \ + (void) _mp_pop(mpstack); \ + cur_mpsv->data.d.dict->dv_copyID = copyID - 1; \ + TYPVAL_ENCODE_CONV_DICT_END(); \ + continue; \ + } else if (cur_mpsv->data.d.todo \ + != cur_mpsv->data.d.dict->dv_hashtab.ht_used) { \ + TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(); \ + } \ + while (HASHITEM_EMPTY(cur_mpsv->data.d.hi)) { \ + cur_mpsv->data.d.hi++; \ + } \ + dictitem_T *const di = HI2DI(cur_mpsv->data.d.hi); \ + cur_mpsv->data.d.todo--; \ + cur_mpsv->data.d.hi++; \ + TYPVAL_ENCODE_CONV_STR_STRING(&di->di_key[0], \ + strlen((char *) &di->di_key[0])); \ + TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(); \ + cur_tv = &di->di_tv; \ + break; \ + } \ + case kMPConvList: { \ + if (cur_mpsv->data.l.li == NULL) { \ + (void) _mp_pop(mpstack); \ + cur_mpsv->data.l.list->lv_copyID = copyID - 1; \ + TYPVAL_ENCODE_CONV_LIST_END(); \ + continue; \ + } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { \ + TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(); \ + } \ + cur_tv = &cur_mpsv->data.l.li->li_tv; \ + cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \ + break; \ + } \ + case kMPConvPairs: { \ + if (cur_mpsv->data.l.li == NULL) { \ + (void) _mp_pop(mpstack); \ + cur_mpsv->data.l.list->lv_copyID = copyID - 1; \ + TYPVAL_ENCODE_CONV_DICT_END(); \ + continue; \ + } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { \ + TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(); \ + } \ + const list_T *const kv_pair = cur_mpsv->data.l.li->li_tv.vval.v_list; \ + TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK( \ + encode_vim_to_##name##_error_ret, kv_pair); \ + if (name##_convert_one_value(firstargname, &mpstack, \ + &kv_pair->lv_first->li_tv, copyID, \ + objname) == FAIL) { \ + goto encode_vim_to_##name##_error_ret; \ + } \ + TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(); \ + cur_tv = &kv_pair->lv_last->li_tv; \ + cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \ + break; \ + } \ + } \ + assert(cur_tv != NULL); \ + if (name##_convert_one_value(firstargname, &mpstack, cur_tv, copyID, \ + objname) == FAIL) { \ + goto encode_vim_to_##name##_error_ret; \ + } \ + } \ + _mp_destroy(mpstack); \ + return OK; \ +encode_vim_to_##name##_error_ret: \ + _mp_destroy(mpstack); \ + return FAIL; \ +} + +#endif // NVIM_EVAL_TYPVAL_ENCODE_H diff --git a/src/nvim/event/defs.h b/src/nvim/event/defs.h index b802866a3d..e5335d9f25 100644 --- a/src/nvim/event/defs.h +++ b/src/nvim/event/defs.h @@ -14,19 +14,19 @@ typedef struct message { } Event; typedef void(*event_scheduler)(Event event, void *data); -#define VA_EVENT_INIT(event, p, h, a) \ - do { \ - assert(a <= EVENT_HANDLER_MAX_ARGC); \ - (event)->priority = p; \ - (event)->handler = h; \ - if (a) { \ - va_list args; \ - va_start(args, a); \ - for (int i = 0; i < a; i++) { \ - (event)->argv[i] = va_arg(args, void *); \ - } \ - va_end(args); \ - } \ +#define VA_EVENT_INIT(event, p, h, a) \ + do { \ + assert(a <= EVENT_HANDLER_MAX_ARGC); \ + (event)->priority = p; \ + (event)->handler = h; \ + if (a) { \ + va_list args; \ + va_start(args, a); \ + for (int i = 0; i < a; i++) { \ + (event)->argv[i] = va_arg(args, void *); \ + } \ + va_end(args); \ + } \ } while (0) static inline Event event_create(int priority, argv_callback cb, int argc, ...) diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c index 9ef3468284..a68badcc8f 100644 --- a/src/nvim/event/libuv_process.c +++ b/src/nvim/event/libuv_process.c @@ -25,7 +25,7 @@ bool libuv_process_spawn(LibuvProcess *uvproc) uvproc->uvopts.flags |= UV_PROCESS_DETACHED; } uvproc->uvopts.exit_cb = exit_cb; - uvproc->uvopts.cwd = NULL; + uvproc->uvopts.cwd = proc->cwd; uvproc->uvopts.env = NULL; uvproc->uvopts.stdio = uvproc->uvstdio; uvproc->uvopts.stdio_count = 3; diff --git a/src/nvim/event/loop.h b/src/nvim/event/loop.h index 0c1fcb5ed9..407aa4245f 100644 --- a/src/nvim/event/loop.h +++ b/src/nvim/event/loop.h @@ -26,43 +26,43 @@ typedef struct loop { int recursive; } Loop; -#define CREATE_EVENT(queue, handler, argc, ...) \ - do { \ - if (queue) { \ - queue_put((queue), (handler), argc, __VA_ARGS__); \ - } else { \ - void *argv[argc] = {__VA_ARGS__}; \ - (handler)(argv); \ - } \ +#define CREATE_EVENT(queue, handler, argc, ...) \ + do { \ + if (queue) { \ + queue_put((queue), (handler), argc, __VA_ARGS__); \ + } else { \ + void *argv[argc] = { __VA_ARGS__ }; \ + (handler)(argv); \ + } \ } while (0) // Poll for events until a condition or timeout -#define LOOP_PROCESS_EVENTS_UNTIL(loop, queue, timeout, condition) \ - do { \ - int remaining = timeout; \ - uint64_t before = (remaining > 0) ? os_hrtime() : 0; \ - while (!(condition)) { \ - LOOP_PROCESS_EVENTS(loop, queue, remaining); \ - if (remaining == 0) { \ - break; \ - } else if (remaining > 0) { \ - uint64_t now = os_hrtime(); \ - remaining -= (int) ((now - before) / 1000000); \ - before = now; \ - if (remaining <= 0) { \ - break; \ - } \ - } \ - } \ +#define LOOP_PROCESS_EVENTS_UNTIL(loop, queue, timeout, condition) \ + do { \ + int remaining = timeout; \ + uint64_t before = (remaining > 0) ? os_hrtime() : 0; \ + while (!(condition)) { \ + LOOP_PROCESS_EVENTS(loop, queue, remaining); \ + if (remaining == 0) { \ + break; \ + } else if (remaining > 0) { \ + uint64_t now = os_hrtime(); \ + remaining -= (int) ((now - before) / 1000000); \ + before = now; \ + if (remaining <= 0) { \ + break; \ + } \ + } \ + } \ } while (0) -#define LOOP_PROCESS_EVENTS(loop, queue, timeout) \ - do { \ - if (queue && !queue_empty(queue)) { \ - queue_process_events(queue); \ - } else { \ - loop_poll_events(loop, timeout); \ - } \ +#define LOOP_PROCESS_EVENTS(loop, queue, timeout) \ + do { \ + if (queue && !queue_empty(queue)) { \ + queue_process_events(queue); \ + } else { \ + loop_poll_events(loop, timeout); \ + } \ } while (0) diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 9bb62891c7..1fffdbf957 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -9,7 +9,7 @@ #include "nvim/event/wstream.h" #include "nvim/event/process.h" #include "nvim/event/libuv_process.h" -#include "nvim/event/pty_process.h" +#include "nvim/os/pty_process.h" #include "nvim/globals.h" #include "nvim/log.h" @@ -22,11 +22,11 @@ #define TERM_TIMEOUT 1000000000 #define KILL_TIMEOUT (TERM_TIMEOUT * 2) -#define CLOSE_PROC_STREAM(proc, stream) \ - do { \ - if (proc->stream && !proc->stream->closed) { \ - stream_close(proc->stream, NULL); \ - } \ +#define CLOSE_PROC_STREAM(proc, stream) \ + do { \ + if (proc->stream && !proc->stream->closed) { \ + stream_close(proc->stream, NULL); \ + } \ } while (0) static bool process_is_tearing_down = false; diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h index e23c8ea60f..a4c6e7eeb2 100644 --- a/src/nvim/event/process.h +++ b/src/nvim/event/process.h @@ -21,6 +21,7 @@ struct process { int pid, status, refcount; // set to the hrtime of when process_stop was called for the process. uint64_t stopped_time; + char *cwd; char **argv; Stream *in, *out, *err; process_exit_cb cb; @@ -40,6 +41,7 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data) .status = 0, .refcount = 0, .stopped_time = 0, + .cwd = NULL, .argv = NULL, .in = NULL, .out = NULL, diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 04fd88cc8d..6c58879d58 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -88,7 +88,7 @@ return { }, { command='argadd', - flags=bit.bor(BANG, NEEDARG, RANGE, NOTADR, ZEROR, FILES, TRLBAR), + flags=bit.bor(BANG, RANGE, NOTADR, ZEROR, FILES, TRLBAR), addr_type=ADDR_ARGUMENTS, func='ex_argadd', }, diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 5fe6209a0a..247f86679f 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -1616,9 +1616,15 @@ do_arglist ( char_u *p; int match; - /* - * Collect all file name arguments in "new_ga". - */ + // Set default argument for ":argadd" command. + if (what == AL_ADD && *str == NUL) { + if (curbuf->b_ffname == NULL) { + return FAIL; + } + str = curbuf->b_fname; + } + + // Collect all file name arguments in "new_ga". get_arglist(&new_ga, str); if (what == AL_DEL) { @@ -1990,17 +1996,21 @@ void ex_argdelete(exarg_T *eap) } else if (curwin->w_arg_idx > eap->line1) { curwin->w_arg_idx = (int)eap->line1; } + if (ARGCOUNT == 0) { + curwin->w_arg_idx = 0; + } else if (curwin->w_arg_idx >= ARGCOUNT) { + curwin->w_arg_idx = ARGCOUNT - 1; + } } - } else if (*eap->arg == NUL) + } else if (*eap->arg == NUL) { EMSG(_(e_argreq)); - else + } else { do_arglist(eap->arg, AL_DEL, 0); + } maketitle(); } -/* - * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo" - */ +/// ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo" void ex_listdo(exarg_T *eap) { int i; @@ -2048,9 +2058,9 @@ void ex_listdo(exarg_T *eap) buf_T *buf = curbuf; size_t qf_size = 0; - /* set pcmark now */ + // set pcmark now if (eap->cmdidx == CMD_bufdo) { - /* Advance to the first listed buffer after "eap->line1". */ + // Advance to the first listed buffer after "eap->line1". for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1 || !buf->b_p_bl); buf = buf->b_next) { @@ -2221,6 +2231,7 @@ alist_add_list ( int after /* where to add: 0 = before first one */ ) { + int old_argcount = ARGCOUNT; ga_grow(&ALIST(curwin)->al_ga, count); { if (after < 0) @@ -2235,8 +2246,9 @@ alist_add_list ( ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED); } ALIST(curwin)->al_ga.ga_len += count; - if (curwin->w_arg_idx >= after) - ++curwin->w_arg_idx; + if (old_argcount > 0 && curwin->w_arg_idx >= after) { + curwin->w_arg_idx += count; + } return after; } } @@ -2481,32 +2493,31 @@ int source_level(void *cookie) return ((struct source_cookie *)cookie)->level; } - -#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC) -# define USE_FOPEN_NOINH -/* - * Special function to open a file without handle inheritance. - * When possible the handle is closed on exec(). - */ +/// Special function to open a file without handle inheritance. +/// If possible the handle is closed on exec(). static FILE *fopen_noinh_readbin(char *filename) { +#ifdef WIN32 + int fd_tmp = os_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0); +#else int fd_tmp = os_open(filename, O_RDONLY, 0); +#endif - if (fd_tmp < 0) + if (fd_tmp < 0) { return NULL; + } -# ifdef HAVE_FD_CLOEXEC +#ifdef HAVE_FD_CLOEXEC { int fdflags = fcntl(fd_tmp, F_GETFD); if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) { (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC); } } -# endif +#endif return fdopen(fd_tmp, READBIN); } -#endif /* @@ -2560,11 +2571,7 @@ do_source ( /* Apply SourcePre autocommands, they may get the file. */ apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf); -#ifdef USE_FOPEN_NOINH cookie.fp = fopen_noinh_readbin((char *)fname_exp); -#else - cookie.fp = mch_fopen((char *)fname_exp, READBIN); -#endif if (cookie.fp == NULL && check_other) { /* * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa, @@ -2573,15 +2580,8 @@ do_source ( p = path_tail(fname_exp); if ((*p == '.' || *p == '_') && (STRICMP(p + 1, "nvimrc") == 0 || STRICMP(p + 1, "exrc") == 0)) { - if (*p == '_') - *p = '.'; - else - *p = '_'; -#ifdef USE_FOPEN_NOINH + *p = (*p == '_') ? '.' : '_'; cookie.fp = fopen_noinh_readbin((char *)fname_exp); -#else - cookie.fp = mch_fopen((char *)fname_exp, READBIN); -#endif } } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 59962c153b..6864e2b914 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1536,8 +1536,9 @@ static char_u * do_one_cmd(char_u **cmdlinep, } ea.cmd = skipwhite(ea.cmd); lnum = get_address(&ea, &ea.cmd, ea.addr_type, ea.skip, ea.addr_count == 0); - if (ea.cmd == NULL) /* error detected */ + if (ea.cmd == NULL) { // error detected goto doend; + } if (lnum == MAXLNUM) { if (*ea.cmd == '%') { /* '%' - all lines */ ++ea.cmd; @@ -4640,14 +4641,14 @@ static struct { char *name; } addr_type_complete[] = { - {ADDR_ARGUMENTS, "arguments"}, - {ADDR_LINES, "lines"}, - {ADDR_LOADED_BUFFERS, "loaded_buffers"}, - {ADDR_TABS, "tabs"}, - {ADDR_BUFFERS, "buffers"}, - {ADDR_WINDOWS, "windows"}, - {ADDR_QUICKFIX, "quickfix"}, - {-1, NULL} + { ADDR_ARGUMENTS, "arguments" }, + { ADDR_LINES, "lines" }, + { ADDR_LOADED_BUFFERS, "loaded_buffers" }, + { ADDR_TABS, "tabs" }, + { ADDR_BUFFERS, "buffers" }, + { ADDR_WINDOWS, "windows" }, + { ADDR_QUICKFIX, "quickfix" }, + { -1, NULL } }; /* @@ -6865,6 +6866,9 @@ void post_chdir(CdScope scope) curwin->w_localdir = vim_strsave(NameBuff); } break; + case kCdScopeInvalid: + // We should never get here + assert(false); } shorten_fnames(TRUE); @@ -6992,7 +6996,7 @@ void do_sleep(long msec) ui_flush(); // flush before waiting for (long left = msec; !got_int && left > 0; left -= 1000L) { int next = left > 1000l ? 1000 : (int)left; - LOOP_PROCESS_EVENTS_UNTIL(&loop, loop.events, (int)next, got_int); + LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, (int)next, got_int); os_breakcheck(); } } @@ -7122,8 +7126,8 @@ static void ex_put(exarg_T *eap) eap->forceit = TRUE; } curwin->w_cursor.lnum = eap->line2; - do_put(eap->regname, NULL, eap->forceit ? BACKWARD : FORWARD, 1L, - PUT_LINE|PUT_CURSLINE); + do_put(eap->regname, NULL, eap->forceit ? BACKWARD : FORWARD, 1, + PUT_LINE|PUT_CURSLINE); } /* @@ -7132,7 +7136,7 @@ static void ex_put(exarg_T *eap) static void ex_copymove(exarg_T *eap) { long n = get_address(eap, &eap->arg, eap->addr_type, false, false); - if (eap->arg == NULL) { /* error detected */ + if (eap->arg == NULL) { // error detected eap->nextcmd = NULL; return; } @@ -7351,10 +7355,11 @@ static void ex_redir(exarg_T *eap) /* Can use both "@a" and "@a>". */ if (*arg == '>') arg++; - /* Make register empty when not using @A-@Z and the - * command is valid. */ - if (*arg == NUL && !isupper(redir_reg)) - write_reg_contents(redir_reg, (char_u *)"", -1, FALSE); + // Make register empty when not using @A-@Z and the + // command is valid. + if (*arg == NUL && !isupper(redir_reg)) { + write_reg_contents(redir_reg, (char_u *)"", 0, false); + } } } if (*arg != NUL) { @@ -7855,19 +7860,26 @@ static void ex_stopinsert(exarg_T *eap) */ void exec_normal_cmd(char_u *cmd, int remap, bool silent) { + // Stuff the argument into the typeahead buffer. + ins_typebuf(cmd, remap, 0, true, silent); + exec_normal(false); +} + +/// Execute normal_cmd() until there is no typeahead left. +/// +/// @param was_typed whether or not something was typed +void exec_normal(bool was_typed) +{ oparg_T oa; - /* - * Stuff the argument into the typeahead buffer. - * Execute normal_cmd() until there is no typeahead left. - */ clear_oparg(&oa); - finish_op = FALSE; - ins_typebuf(cmd, remap, 0, TRUE, silent); - while ((!stuff_empty() || (!typebuf_typed() && typebuf.tb_len > 0)) + finish_op = false; + while ((!stuff_empty() + || ((was_typed || !typebuf_typed()) + && typebuf.tb_len > 0)) && !got_int) { update_topline_cursor(); - normal_cmd(&oa, TRUE); /* execute a Normal mode cmd */ + normal_cmd(&oa, true); // execute a Normal mode cmd } } diff --git a/src/nvim/ex_docmd.h b/src/nvim/ex_docmd.h index dbfc64e2f1..bafad20169 100644 --- a/src/nvim/ex_docmd.h +++ b/src/nvim/ex_docmd.h @@ -26,6 +26,7 @@ /// `getcwd()`. When using scopes as limits (e.g. in loops) don't use the scopes /// directly, use `MIN_CD_SCOPE` and `MAX_CD_SCOPE` instead. typedef enum { + kCdScopeInvalid = -1, kCdScopeWindow, ///< Affects one window. kCdScopeTab, ///< Affects one tab page. kCdScopeGlobal, ///< Affects the entire instance of Neovim. diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index db21fddedb..65144dace8 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -358,7 +358,7 @@ static int command_line_execute(VimState *state, int key) s->c = key; if (s->c == K_EVENT) { - queue_process_events(loop.events); + queue_process_events(main_loop.events); redrawcmdline(); return 1; } diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index beefc4238e..f7555c99fa 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -1378,7 +1378,7 @@ find_file_in_path_option ( /* copy file name into NameBuff, expanding environment variables */ save_char = ptr[len]; ptr[len] = NUL; - expand_env(ptr, NameBuff, MAXPATHL); + expand_env_esc(ptr, NameBuff, MAXPATHL, false, true, NULL); ptr[len] = save_char; xfree(ff_file_to_find); diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index db1469db97..4d9e10fb85 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -1749,8 +1749,9 @@ failed: #ifdef HAVE_FD_CLOEXEC else { int fdflags = fcntl(fd, F_GETFD); - if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) - fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC); + if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) { + (void)fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC); + } } #endif xfree(buffer); diff --git a/src/nvim/func_attr.h b/src/nvim/func_attr.h index c31d21ec6d..ea017ab0c8 100644 --- a/src/nvim/func_attr.h +++ b/src/nvim/func_attr.h @@ -41,168 +41,174 @@ // $ gcc -E -dM - </dev/null // $ echo | clang -dM -E - +#ifndef NVIM_FUNC_ATTR_H +#define NVIM_FUNC_ATTR_H +#undef NVIM_FUNC_ATTR_H + #ifdef FUNC_ATTR_MALLOC - #undef FUNC_ATTR_MALLOC +# undef FUNC_ATTR_MALLOC #endif #ifdef FUNC_ATTR_ALLOC_SIZE - #undef FUNC_ATTR_ALLOC_SIZE +# undef FUNC_ATTR_ALLOC_SIZE #endif #ifdef FUNC_ATTR_ALLOC_SIZE_PROD - #undef FUNC_ATTR_ALLOC_SIZE_PROD +# undef FUNC_ATTR_ALLOC_SIZE_PROD #endif #ifdef FUNC_ATTR_ALLOC_ALIGN - #undef FUNC_ATTR_ALLOC_ALIGN +# undef FUNC_ATTR_ALLOC_ALIGN #endif #ifdef FUNC_ATTR_PURE - #undef FUNC_ATTR_PURE +# undef FUNC_ATTR_PURE #endif #ifdef FUNC_ATTR_CONST - #undef FUNC_ATTR_CONST +# undef FUNC_ATTR_CONST #endif #ifdef FUNC_ATTR_WARN_UNUSED_RESULT - #undef FUNC_ATTR_WARN_UNUSED_RESULT +# undef FUNC_ATTR_WARN_UNUSED_RESULT #endif #ifdef FUNC_ATTR_ALWAYS_INLINE - #undef FUNC_ATTR_ALWAYS_INLINE +# undef FUNC_ATTR_ALWAYS_INLINE #endif #ifdef FUNC_ATTR_UNUSED - #undef FUNC_ATTR_UNUSED +# undef FUNC_ATTR_UNUSED #endif #ifdef FUNC_ATTR_NONNULL_ALL - #undef FUNC_ATTR_NONNULL_ALL +# undef FUNC_ATTR_NONNULL_ALL #endif #ifdef FUNC_ATTR_NONNULL_ARG - #undef FUNC_ATTR_NONNULL_ARG +# undef FUNC_ATTR_NONNULL_ARG #endif #ifdef FUNC_ATTR_NONNULL_RET - #undef FUNC_ATTR_NONNULL_RET +# undef FUNC_ATTR_NONNULL_RET #endif #ifndef DID_REAL_ATTR - #define DID_REAL_ATTR - #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) REAL_FATTR_ALWAYS_INLINE; - #define REAL_FATTR_MALLOC __attribute__((malloc)) - #define REAL_FATTR_ALLOC_ALIGN(x) __attribute__((alloc_align(x))) - #define REAL_FATTR_PURE __attribute__ ((pure)) - #define REAL_FATTR_CONST __attribute__((const)) - #define REAL_FATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) - #define REAL_FATTR_ALWAYS_INLINE __attribute__((always_inline)) - #define REAL_FATTR_UNUSED __attribute__((unused)) - #define REAL_FATTR_NONNULL_ALL __attribute__((nonnull)) - #define REAL_FATTR_NONNULL_ARG(...) __attribute__((nonnull(__VA_ARGS__))) - - #ifdef __clang__ - // clang only - #elif defined(__INTEL_COMPILER) - // intel only - #else - #define GCC_VERSION \ +# define DID_REAL_ATTR +# 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) REAL_FATTR_ALWAYS_INLINE; +# define REAL_FATTR_MALLOC __attribute__((malloc)) +# define REAL_FATTR_ALLOC_ALIGN(x) __attribute__((alloc_align(x))) +# define REAL_FATTR_PURE __attribute__ ((pure)) +# define REAL_FATTR_CONST __attribute__((const)) +# define REAL_FATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# define REAL_FATTR_ALWAYS_INLINE __attribute__((always_inline)) +# define REAL_FATTR_UNUSED __attribute__((unused)) +# define REAL_FATTR_NONNULL_ALL __attribute__((nonnull)) +# define REAL_FATTR_NONNULL_ARG(...) __attribute__((nonnull(__VA_ARGS__))) + +# ifdef __clang__ +// clang only +# elif defined(__INTEL_COMPILER) +// intel only +# else +# define GCC_VERSION \ (__GNUC__ * 10000 + \ - __GNUC_MINOR__ * 100 + \ - __GNUC_PATCHLEVEL__) - // gcc only - #define REAL_FATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x))) - #define REAL_FATTR_ALLOC_SIZE_PROD(x,y) __attribute__((alloc_size(x,y))) - #if GCC_VERSION >= 40900 - #define REAL_FATTR_NONNULL_RET __attribute__((returns_nonnull)) - #endif - #endif - #endif - - // define function attributes that haven't been defined for this specific - // compiler. - - #ifndef REAL_FATTR_MALLOC - #define REAL_FATTR_MALLOC - #endif - - #ifndef REAL_FATTR_ALLOC_SIZE - #define REAL_FATTR_ALLOC_SIZE(x) - #endif - - #ifndef REAL_FATTR_ALLOC_SIZE_PROD - #define REAL_FATTR_ALLOC_SIZE_PROD(x,y) - #endif - - #ifndef REAL_FATTR_ALLOC_ALIGN - #define REAL_FATTR_ALLOC_ALIGN(x) - #endif - - #ifndef REAL_FATTR_PURE - #define REAL_FATTR_PURE - #endif - - #ifndef REAL_FATTR_CONST - #define REAL_FATTR_CONST - #endif - - #ifndef REAL_FATTR_WARN_UNUSED_RESULT - #define REAL_FATTR_WARN_UNUSED_RESULT - #endif - - #ifndef REAL_FATTR_ALWAYS_INLINE - #define REAL_FATTR_ALWAYS_INLINE - #endif - - #ifndef REAL_FATTR_UNUSED - #define REAL_FATTR_UNUSED - #endif - - #ifndef REAL_FATTR_NONNULL_ALL - #define REAL_FATTR_NONNULL_ALL - #endif - - #ifndef REAL_FATTR_NONNULL_ARG - #define REAL_FATTR_NONNULL_ARG(...) - #endif - - #ifndef REAL_FATTR_NONNULL_RET - #define REAL_FATTR_NONNULL_RET - #endif + __GNUC_MINOR__ * 100 + \ + __GNUC_PATCHLEVEL__) +// gcc only +# define REAL_FATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x))) +# define REAL_FATTR_ALLOC_SIZE_PROD(x, y) __attribute__((alloc_size(x, y))) +# if GCC_VERSION >= 40900 +# define REAL_FATTR_NONNULL_RET __attribute__((returns_nonnull)) +# endif +# endif +# endif + +// define function attributes that haven't been defined for this specific +// compiler. + +# ifndef REAL_FATTR_MALLOC +# define REAL_FATTR_MALLOC +# endif + +# ifndef REAL_FATTR_ALLOC_SIZE +# define REAL_FATTR_ALLOC_SIZE(x) +# endif + +# ifndef REAL_FATTR_ALLOC_SIZE_PROD +# define REAL_FATTR_ALLOC_SIZE_PROD(x, y) +# endif + +# ifndef REAL_FATTR_ALLOC_ALIGN +# define REAL_FATTR_ALLOC_ALIGN(x) +# endif + +# ifndef REAL_FATTR_PURE +# define REAL_FATTR_PURE +# endif + +# ifndef REAL_FATTR_CONST +# define REAL_FATTR_CONST +# endif + +# ifndef REAL_FATTR_WARN_UNUSED_RESULT +# define REAL_FATTR_WARN_UNUSED_RESULT +# endif + +# ifndef REAL_FATTR_ALWAYS_INLINE +# define REAL_FATTR_ALWAYS_INLINE +# endif + +# ifndef REAL_FATTR_UNUSED +# define REAL_FATTR_UNUSED +# endif + +# ifndef REAL_FATTR_NONNULL_ALL +# define REAL_FATTR_NONNULL_ALL +# endif + +# ifndef REAL_FATTR_NONNULL_ARG +# define REAL_FATTR_NONNULL_ARG(...) +# endif + +# ifndef REAL_FATTR_NONNULL_RET +# define REAL_FATTR_NONNULL_RET +# endif #endif #ifdef DEFINE_FUNC_ATTRIBUTES - #define FUNC_ATTR_ASYNC - #define FUNC_ATTR_MALLOC REAL_FATTR_MALLOC - #define FUNC_ATTR_ALLOC_SIZE(x) REAL_FATTR_ALLOC_SIZE(x) - #define FUNC_ATTR_ALLOC_SIZE_PROD(x,y) REAL_FATTR_ALLOC_SIZE_PROD(x,y) - #define FUNC_ATTR_ALLOC_ALIGN(x) REAL_FATTR_ALLOC_ALIGN(x) - #define FUNC_ATTR_PURE REAL_FATTR_PURE - #define FUNC_ATTR_CONST REAL_FATTR_CONST - #define FUNC_ATTR_WARN_UNUSED_RESULT REAL_FATTR_WARN_UNUSED_RESULT - #define FUNC_ATTR_ALWAYS_INLINE REAL_FATTR_ALWAYS_INLINE - #define FUNC_ATTR_UNUSED REAL_FATTR_UNUSED - #define FUNC_ATTR_NONNULL_ALL REAL_FATTR_NONNULL_ALL - #define FUNC_ATTR_NONNULL_ARG(...) REAL_FATTR_NONNULL_ARG(__VA_ARGS__) - #define FUNC_ATTR_NONNULL_RET REAL_FATTR_NONNULL_RET +# define FUNC_API_ASYNC +# define FUNC_API_NOEXPORT +# define FUNC_ATTR_MALLOC REAL_FATTR_MALLOC +# define FUNC_ATTR_ALLOC_SIZE(x) REAL_FATTR_ALLOC_SIZE(x) +# define FUNC_ATTR_ALLOC_SIZE_PROD(x, y) REAL_FATTR_ALLOC_SIZE_PROD(x, y) +# define FUNC_ATTR_ALLOC_ALIGN(x) REAL_FATTR_ALLOC_ALIGN(x) +# define FUNC_ATTR_PURE REAL_FATTR_PURE +# define FUNC_ATTR_CONST REAL_FATTR_CONST +# define FUNC_ATTR_WARN_UNUSED_RESULT REAL_FATTR_WARN_UNUSED_RESULT +# define FUNC_ATTR_ALWAYS_INLINE REAL_FATTR_ALWAYS_INLINE +# define FUNC_ATTR_UNUSED REAL_FATTR_UNUSED +# define FUNC_ATTR_NONNULL_ALL REAL_FATTR_NONNULL_ALL +# define FUNC_ATTR_NONNULL_ARG(...) REAL_FATTR_NONNULL_ARG(__VA_ARGS__) +# define FUNC_ATTR_NONNULL_RET REAL_FATTR_NONNULL_RET #elif !defined(DO_NOT_DEFINE_EMPTY_ATTRIBUTES) - #define FUNC_ATTR_MALLOC - #define FUNC_ATTR_ALLOC_SIZE(x) - #define FUNC_ATTR_ALLOC_SIZE_PROD(x,y) - #define FUNC_ATTR_ALLOC_ALIGN(x) - #define FUNC_ATTR_PURE - #define FUNC_ATTR_CONST - #define FUNC_ATTR_WARN_UNUSED_RESULT - #define FUNC_ATTR_ALWAYS_INLINE - #define FUNC_ATTR_UNUSED - #define FUNC_ATTR_NONNULL_ALL - #define FUNC_ATTR_NONNULL_ARG(...) - #define FUNC_ATTR_NONNULL_RET +# define FUNC_ATTR_MALLOC +# define FUNC_ATTR_ALLOC_SIZE(x) +# define FUNC_ATTR_ALLOC_SIZE_PROD(x, y) +# define FUNC_ATTR_ALLOC_ALIGN(x) +# define FUNC_ATTR_PURE +# define FUNC_ATTR_CONST +# define FUNC_ATTR_WARN_UNUSED_RESULT +# define FUNC_ATTR_ALWAYS_INLINE +# define FUNC_ATTR_UNUSED +# define FUNC_ATTR_NONNULL_ALL +# define FUNC_ATTR_NONNULL_ARG(...) +# define FUNC_ATTR_NONNULL_RET #endif +#endif // NVIM_FUNC_ATTR_H diff --git a/src/nvim/garray.h b/src/nvim/garray.h index 642eaf54f0..5d7806bbfa 100644 --- a/src/nvim/garray.h +++ b/src/nvim/garray.h @@ -21,10 +21,10 @@ typedef struct growarray { #define GA_EMPTY(ga_ptr) ((ga_ptr)->ga_len <= 0) -#define GA_APPEND(item_type, gap, item) \ - do { \ - ga_grow(gap, 1); \ - ((item_type *)(gap)->ga_data)[(gap)->ga_len++] = (item); \ +#define GA_APPEND(item_type, gap, item) \ + do { \ + ga_grow(gap, 1); \ + ((item_type *)(gap)->ga_data)[(gap)->ga_len++] = (item); \ } while (0) #define GA_APPEND_VIA_PTR(item_type, gap) \ @@ -49,16 +49,16 @@ static inline void *ga_append_via_ptr(garray_T *gap, size_t item_size) /// @param gap the garray to be freed /// @param item_type type of the item in the garray /// @param free_item_fn free function that takes (*item_type) as parameter -#define GA_DEEP_CLEAR(gap, item_type, free_item_fn) \ - do { \ - garray_T *_gap = (gap); \ - if (_gap->ga_data != NULL) { \ - for (int i = 0; i < _gap->ga_len; i++) { \ - item_type *_item = &(((item_type *)_gap->ga_data)[i]); \ - free_item_fn(_item); \ - } \ - } \ - ga_clear(_gap); \ +#define GA_DEEP_CLEAR(gap, item_type, free_item_fn) \ + do { \ + garray_T *_gap = (gap); \ + if (_gap->ga_data != NULL) { \ + for (int i = 0; i < _gap->ga_len; i++) { \ + item_type *_item = &(((item_type *)_gap->ga_data)[i]); \ + free_item_fn(_item); \ + } \ + } \ + ga_clear(_gap); \ } while (false) #define FREE_PTR_PTR(ptr) xfree(*(ptr)) diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index dbf0322d78..ae1857f318 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1754,10 +1754,11 @@ static int vgetorpeek(int advance) || ((compl_cont_status & CONT_LOCAL) && (c1 == Ctrl_N || c1 == Ctrl_P))) ) { - if (c1 == K_SPECIAL) + if (c1 == K_SPECIAL) { nolmaplen = 2; - else { - LANGMAP_ADJUST(c1, (State & (CMDLINE | INSERT)) == 0); + } else { + LANGMAP_ADJUST(c1, (State & (CMDLINE | INSERT)) == 0 + && get_real_state() != SELECTMODE); nolmaplen = 0; } /* First try buffer-local mappings. */ diff --git a/src/nvim/globals.h b/src/nvim/globals.h index d399db1381..42fde50bee 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -836,8 +836,8 @@ EXTERN int* (*iconv_errno)(void); EXTERN int State INIT(= NORMAL); /* This is the current state of the * command interpreter. */ -EXTERN int finish_op INIT(= FALSE); /* TRUE while an operator is pending */ -EXTERN long opcount INIT(= 0); /* count for pending operator */ +EXTERN bool finish_op INIT(= false); // true while an operator is pending +EXTERN long opcount INIT(= 0); // count for pending operator /* * ex mode (Q) state @@ -1244,7 +1244,6 @@ EXTERN char *ignoredp; // If a msgpack-rpc channel should be started over stdin/stdout EXTERN bool embedded_mode INIT(= false); -EXTERN Loop loop; /// Used to track the status of external functions. /// Currently only used for iconv(). diff --git a/src/nvim/lib/klist.h b/src/nvim/lib/klist.h index 1280a927e8..7ee100ab8c 100644 --- a/src/nvim/lib/klist.h +++ b/src/nvim/lib/klist.h @@ -33,35 +33,37 @@ #include "nvim/func_attr.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(void) { \ - return xcalloc(1, sizeof(kmp_##name##_t)); \ - } \ - static inline void kmp_destroy_##name(kmp_##name##_t *mp) \ - REAL_FATTR_UNUSED; \ - 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]); xfree(mp->buf[k]); \ - } \ - xfree(mp->buf); xfree(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]; \ - } \ +#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(void) { \ + return xcalloc(1, sizeof(kmp_##name##_t)); \ + } \ + static inline void kmp_destroy_##name(kmp_##name##_t *mp) \ + REAL_FATTR_UNUSED; \ + 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]); xfree(mp->buf[k]); \ + } \ + xfree(mp->buf); xfree(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->cnt--; \ + if (mp->n == mp->max) { \ + mp->max = mp->max ? (mp->max << 1) : 16; \ mp->buf = xrealloc(mp->buf, sizeof(kmptype_t *) * mp->max); \ - } \ - mp->buf[mp->n++] = p; \ + } \ + mp->buf[mp->n++] = p; \ } #define kmempool_t(name) kmp_##name##_t @@ -70,54 +72,56 @@ #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(void) { \ - 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) \ - REAL_FATTR_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); \ - xfree(kl); \ - } \ - static inline void kl_push_##name(kl_##name##_t *kl, kltype_t d) { \ - kl1_##name *q, *p = kmp_alloc(name, kl->mp); \ - q = kl->tail; p->next = 0; kl->tail->next = p; kl->tail = p; \ - ++kl->size; \ - q->data = d; \ - } \ - static inline kltype_t kl_shift_at_##name(kl_##name##_t *kl, \ - kl1_##name **n) { \ - assert((*n)->next); \ - kl1_##name *p; \ - --kl->size; \ - p = *n; \ - *n = (*n)->next; \ - if (p == kl->head) kl->head = *n; \ - kltype_t d = p->data; \ - kmp_free(name, kl->mp, p); \ - return d; \ - } \ - +#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(void) { \ + 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) \ + REAL_FATTR_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); \ + xfree(kl); \ + } \ + static inline void kl_push_##name(kl_##name##_t *kl, kltype_t d) { \ + kl1_##name *q, *p = kmp_alloc(name, kl->mp); \ + q = kl->tail; p->next = 0; kl->tail->next = p; kl->tail = p; \ + kl->size++; \ + q->data = d; \ + } \ + static inline kltype_t kl_shift_at_##name(kl_##name##_t *kl, \ + kl1_##name **n) { \ + assert((*n)->next); \ + kl1_##name *p; \ + kl->size--; \ + p = *n; \ + *n = (*n)->next; \ + if (p == kl->head) { \ + kl->head = *n; \ + } \ + kltype_t d = p->data; \ + kmp_free(name, kl->mp, p); \ + return d; \ + } #define kliter_t(name) kl1_##name #define klist_t(name) kl_##name##_t diff --git a/src/nvim/lib/kvec.h b/src/nvim/lib/kvec.h index b41ef0cc9f..36c91c86b2 100644 --- a/src/nvim/lib/kvec.h +++ b/src/nvim/lib/kvec.h @@ -1,59 +1,61 @@ -/* The MIT License - - Copyright (c) 2008, 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 "kvec.h" -int main() { - kvec_t(int) array; - kv_init(array); - kv_push(int, array, 10); // append - kv_a(int, array, 20) = 5; // dynamic - kv_A(array, 20) = 4; // static - kv_destroy(array); - return 0; -} -*/ - -/* - 2008-09-22 (0.1.0): +// The MIT License +// +// Copyright (c) 2008, 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 "kvec.h" +// int main() { +// kvec_t(int) array = KV_INITIAL_VALUE; +// kv_push(array, 10); // append +// kv_a(array, 20) = 5; // dynamic +// kv_A(array, 20) = 4; // static +// kv_destroy(array); +// return 0; +// } + +#ifndef NVIM_LIB_KVEC_H +#define NVIM_LIB_KVEC_H - * The initial version. +#include <stdlib.h> +#include <string.h> -*/ +#include "nvim/memory.h" -#ifndef AC_KVEC_H -#define AC_KVEC_H +#define kv_roundup32(x) \ + ((--(x)), \ + ((x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16), \ + (++(x))) -#include <stdlib.h> -#include "nvim/memory.h" +#define KV_INITIAL_VALUE { .size = 0, .capacity = 0, .items = NULL } -#define kv_roundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x)) +#define kvec_t(type) \ + struct { \ + size_t size; \ + size_t capacity; \ + type *items; \ + } -#define kvec_t(type) struct { size_t size, capacity; type *items; } #define kv_init(v) ((v).size = (v).capacity = 0, (v).items = 0) #define kv_destroy(v) xfree((v).items) #define kv_A(v, i) ((v).items[(i)]) @@ -62,31 +64,130 @@ int main() { #define kv_max(v) ((v).capacity) #define kv_last(v) kv_A(v, kv_size(v) - 1) -#define kv_resize(type, v, s) ((v).capacity = (s), (v).items = (type*)xrealloc((v).items, sizeof(type) * (v).capacity)) - -#define kv_copy(type, v1, v0) do { \ - if ((v1).capacity < (v0).size) kv_resize(type, v1, (v0).size); \ - (v1).size = (v0).size; \ - memcpy((v1).items, (v0).items, sizeof(type) * (v0).size); \ - } while (0) \ - -#define kv_push(type, v, x) do { \ - if ((v).size == (v).capacity) { \ - (v).capacity = (v).capacity? (v).capacity<<1 : 8; \ - (v).items = (type*)xrealloc((v).items, sizeof(type) * (v).capacity); \ - } \ - (v).items[(v).size++] = (x); \ - } while (0) - -#define kv_pushp(type, v) ((((v).size == (v).capacity)? \ - ((v).capacity = ((v).capacity? (v).capacity<<1 : 8), \ - (v).items = (type*)xrealloc((v).items, sizeof(type) * (v).capacity), 0) \ - : 0), ((v).items + ((v).size++))) - -#define kv_a(type, v, i) (((v).capacity <= (size_t)(i)? \ - ((v).capacity = (v).size = (i) + 1, kv_roundup32((v).capacity), \ - (v).items = (type*)xrealloc((v).items, sizeof(type) * (v).capacity), 0) \ - : (v).size <= (size_t)(i)? (v).size = (i) + 1 \ - : 0), (v).items[(i)]) - -#endif +#define kv_resize(v, s) \ + ((v).capacity = (s), \ + (v).items = xrealloc((v).items, sizeof((v).items[0]) * (v).capacity)) + +#define kv_resize_full(v) \ + kv_resize(v, (v).capacity ? (v).capacity << 1 : 8) + +#define kv_copy(v1, v0) \ + do { \ + if ((v1).capacity < (v0).size) { \ + kv_resize(v1, (v0).size); \ + } \ + (v1).size = (v0).size; \ + memcpy((v1).items, (v0).items, sizeof((v1).items[0]) * (v0).size); \ + } while (0) \ + +#define kv_pushp(v) \ + ((((v).size == (v).capacity) ? (kv_resize_full(v), 0) : 0), \ + ((v).items + ((v).size++))) + +#define kv_push(v, x) \ + (*kv_pushp(v) = (x)) + +#define kv_a(v, i) \ + (((v).capacity <= (size_t) (i) \ + ? ((v).capacity = (v).size = (i) + 1, \ + kv_roundup32((v).capacity), \ + kv_resize((v), (v).capacity), 0) \ + : ((v).size <= (size_t) (i) \ + ? (v).size = (i) + 1 \ + : 0)), \ + (v).items[(i)]) + +/// Type of a vector with a few first members allocated on stack +/// +/// Is compatible with #kv_A, #kv_pop, #kv_size, #kv_max, #kv_last. +/// Is not compatible with #kv_resize, #kv_resize_full, #kv_copy, #kv_push, +/// #kv_pushp, #kv_a, #kv_destroy. +/// +/// @param[in] type Type of vector elements. +/// @param[in] init_size Number of the elements in the initial array. +#define kvec_withinit_t(type, INIT_SIZE) \ + struct { \ + size_t size; \ + size_t capacity; \ + type *items; \ + type init_array[INIT_SIZE]; \ + } + +/// Initialize vector with preallocated array +/// +/// @param[out] v Vector to initialize. +#define kvi_init(v) \ + ((v).capacity = ARRAY_SIZE((v).init_array), \ + (v).size = 0, \ + (v).items = (v).init_array) + +/// Move data to a new destination and free source +static inline void *_memcpy_free(void *const restrict dest, + void *const restrict src, + const size_t size) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_ALWAYS_INLINE +{ + memcpy(dest, src, size); + xfree(src); + return dest; +} + +/// Resize vector with preallocated array +/// +/// @param[out] v Vector to resize. +/// @param[in] s New size. +#define kvi_resize(v, s) \ + ((v).capacity = ((s) > ARRAY_SIZE((v).init_array) \ + ? (s) \ + : ARRAY_SIZE((v).init_array)), \ + (v).items = ((v).capacity == ARRAY_SIZE((v).init_array) \ + ? ((v).items == (v).init_array \ + ? (v).items \ + : _memcpy_free((v).init_array, (v).items, \ + (v).size * sizeof((v).items[0]))) \ + : ((v).items == (v).init_array \ + ? memcpy(xmalloc((v).capacity * sizeof((v).items[0])), \ + (v).items, \ + (v).size * sizeof((v).items[0])) \ + : xrealloc((v).items, \ + (v).capacity * sizeof((v).items[0]))))) + +/// Resize vector with preallocated array when it is full +/// +/// @param[out] v Vector to resize. +#define kvi_resize_full(v) \ + /* ARRAY_SIZE((v).init_array) is the minimal capacity of this vector. */ \ + /* Thus when vector is full capacity may not be zero and it is safe */ \ + /* not to bother with checking whether (v).capacity is 0. But now */ \ + /* capacity is not guaranteed to have size that is a power of 2. */ \ + kvi_resize(v, ((v).capacity == ARRAY_SIZE((v).init_array) \ + ? ((v).capacity++, kv_roundup32((v).capacity)) \ + : (v).capacity << 1)) + +/// Get location where to store new element to a vector with preallocated array +/// +/// @param[in,out] v Vector to push to. +/// +/// @return Pointer to the place where new value should be stored. +#define kvi_pushp(v) \ + ((((v).size == (v).capacity) ? (kvi_resize_full(v), 0) : 0), \ + ((v).items + ((v).size++))) + +/// Push value to a vector with preallocated array +/// +/// @param[out] v Vector to push to. +/// @param[in] x Value to push. +#define kvi_push(v, x) \ + (*kvi_pushp(v) = (x)) + +/// Free array of elements of a vector with preallocated array if needed +/// +/// @param[out] v Vector to free. +#define kvi_destroy(v) \ + do { \ + if ((v).items != (v).init_array) { \ + xfree((v).items); \ + } \ + } while (0) + +#endif // NVIM_LIB_KVEC_H diff --git a/src/nvim/lib/queue.h b/src/nvim/lib/queue.h index fe02b454ea..9fcedf298f 100644 --- a/src/nvim/lib/queue.h +++ b/src/nvim/lib/queue.h @@ -1,92 +1,94 @@ -/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ +// Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl> +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -#ifndef QUEUE_H_ -#define QUEUE_H_ +#ifndef NVIM_LIB_QUEUE_H +#define NVIM_LIB_QUEUE_H -typedef void *QUEUE[2]; +#include <stddef.h> -/* Private macros. */ -#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0])) -#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1])) -#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q))) -#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q))) +#include "nvim/func_attr.h" -/* Public macros. */ -#define QUEUE_DATA(ptr, type, field) \ - ((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field))) +typedef struct _queue { + struct _queue *next; + struct _queue *prev; +} QUEUE; -#define QUEUE_FOREACH(q, h) \ - for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q)) +// Public macros. +#define QUEUE_DATA(ptr, type, field) \ + ((type *)((char *)(ptr) - offsetof(type, field))) -#define QUEUE_EMPTY(q) \ - ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q)) +#define QUEUE_FOREACH(q, h) \ + for ( /* NOLINT(readability/braces) */ \ + (q) = (h)->next; (q) != (h); (q) = (q)->next) -#define QUEUE_HEAD(q) \ - (QUEUE_NEXT(q)) +// ffi.cdef is unable to swallow `bool` in place of `int` here. +static inline int QUEUE_EMPTY(const QUEUE *const q) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + return q == q->next; +} -#define QUEUE_INIT(q) \ - do { \ - QUEUE_NEXT(q) = (q); \ - QUEUE_PREV(q) = (q); \ - } \ - while (0) +#define QUEUE_HEAD(q) (q)->next -#define QUEUE_ADD(h, n) \ - do { \ - QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \ - QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \ - QUEUE_PREV(h) = QUEUE_PREV(n); \ - QUEUE_PREV_NEXT(h) = (h); \ - } \ - while (0) +static inline void QUEUE_INIT(QUEUE *const q) FUNC_ATTR_ALWAYS_INLINE +{ + q->next = q; + q->prev = q; +} -#define QUEUE_SPLIT(h, q, n) \ - do { \ - QUEUE_PREV(n) = QUEUE_PREV(h); \ - QUEUE_PREV_NEXT(n) = (n); \ - QUEUE_NEXT(n) = (q); \ - QUEUE_PREV(h) = QUEUE_PREV(q); \ - QUEUE_PREV_NEXT(h) = (h); \ - QUEUE_PREV(q) = (n); \ - } \ - while (0) +static inline void QUEUE_ADD(QUEUE *const h, QUEUE *const n) + FUNC_ATTR_ALWAYS_INLINE +{ + h->prev->next = n->next; + n->next->prev = h->prev; + h->prev = n->prev; + h->prev->next = h; +} -#define QUEUE_INSERT_HEAD(h, q) \ - do { \ - QUEUE_NEXT(q) = QUEUE_NEXT(h); \ - QUEUE_PREV(q) = (h); \ - QUEUE_NEXT_PREV(q) = (q); \ - QUEUE_NEXT(h) = (q); \ - } \ - while (0) +static inline void QUEUE_SPLIT(QUEUE *const h, QUEUE *const q, QUEUE *const n) + FUNC_ATTR_ALWAYS_INLINE +{ + n->prev = h->prev; + n->prev->next = n; + n->next = q; + h->prev = q->prev; + h->prev->next = h; + q->prev = n; +} -#define QUEUE_INSERT_TAIL(h, q) \ - do { \ - QUEUE_NEXT(q) = (h); \ - QUEUE_PREV(q) = QUEUE_PREV(h); \ - QUEUE_PREV_NEXT(q) = (q); \ - QUEUE_PREV(h) = (q); \ - } \ - while (0) +static inline void QUEUE_INSERT_HEAD(QUEUE *const h, QUEUE *const q) + FUNC_ATTR_ALWAYS_INLINE +{ + q->next = h->next; + q->prev = h; + q->next->prev = q; + h->next = q; +} -#define QUEUE_REMOVE(q) \ - do { \ - QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \ - QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \ - } \ - while (0) +static inline void QUEUE_INSERT_TAIL(QUEUE *const h, QUEUE *const q) + FUNC_ATTR_ALWAYS_INLINE +{ + q->next = h; + q->prev = h->prev; + q->prev->next = q; + h->prev = q; +} -#endif /* QUEUE_H_ */ +static inline void QUEUE_REMOVE(QUEUE *const q) FUNC_ATTR_ALWAYS_INLINE +{ + q->prev->next = q->next; + q->next->prev = q->prev; +} + +#endif // NVIM_LIB_QUEUE_H diff --git a/src/nvim/lib/ringbuf.h b/src/nvim/lib/ringbuf.h index cb71500bb7..12b75ec65a 100644 --- a/src/nvim/lib/ringbuf.h +++ b/src/nvim/lib/ringbuf.h @@ -65,12 +65,12 @@ /// @param TypeName Ring buffer type name. Actual type name will be /// `{TypeName}RingBuffer`. /// @param RBType Type of the single ring buffer element. -#define RINGBUF_TYPEDEF(TypeName, RBType) \ -typedef struct { \ - RBType *buf; \ - RBType *next; \ - RBType *first; \ - RBType *buf_end; \ +#define RINGBUF_TYPEDEF(TypeName, RBType) \ +typedef struct { \ + RBType *buf; \ + RBType *next; \ + RBType *first; \ + RBType *buf_end; \ } TypeName##RingBuffer; /// Initialize a new ring buffer @@ -84,198 +84,196 @@ typedef struct { \ /// a macros like `#define RBFREE(item)` (to skip freeing). /// /// Intended function signature: `void *rbfree(RBType *)`; -#define RINGBUF_INIT(TypeName, funcprefix, RBType, rbfree) \ - \ - \ -static inline TypeName##RingBuffer funcprefix##_rb_new(const size_t size) \ - REAL_FATTR_WARN_UNUSED_RESULT; \ -static inline TypeName##RingBuffer funcprefix##_rb_new(const size_t size) \ -{ \ - assert(size != 0); \ - RBType *buf = xmalloc(size * sizeof(RBType)); \ - return (TypeName##RingBuffer) { \ - .buf = buf, \ - .next = buf, \ - .first = NULL, \ - .buf_end = buf + size - 1, \ - }; \ -} \ - \ -static inline void funcprefix##_rb_free(TypeName##RingBuffer *const rb) \ - REAL_FATTR_UNUSED; \ -static inline void funcprefix##_rb_free(TypeName##RingBuffer *const rb) \ -{ \ - if (rb == NULL) { \ - return; \ - } \ - RINGBUF_FORALL(rb, RBType, rbitem) { \ - rbfree(rbitem); \ - } \ - xfree(rb->buf); \ -} \ - \ -static inline void funcprefix##_rb_dealloc(TypeName##RingBuffer *const rb) \ - REAL_FATTR_UNUSED; \ -static inline void funcprefix##_rb_dealloc(TypeName##RingBuffer *const rb) \ -{ \ - xfree(rb->buf); \ -} \ - \ -static inline void funcprefix##_rb_push(TypeName##RingBuffer *const rb, \ - RBType item) \ - REAL_FATTR_NONNULL_ARG(1); \ -static inline void funcprefix##_rb_push(TypeName##RingBuffer *const rb, \ - RBType item) \ -{ \ - if (rb->next == rb->first) { \ - rbfree(rb->first); \ - rb->first = _RINGBUF_NEXT(rb, rb->first); \ - } else if (rb->first == NULL) { \ - rb->first = rb->next; \ - } \ - *rb->next = item; \ - rb->next = _RINGBUF_NEXT(rb, rb->next); \ -} \ - \ -static inline ptrdiff_t funcprefix##_rb_find_idx( \ - const TypeName##RingBuffer *const rb, const RBType *const item_p) \ - REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE REAL_FATTR_UNUSED; \ -static inline ptrdiff_t funcprefix##_rb_find_idx( \ - const TypeName##RingBuffer *const rb, const RBType *const item_p) \ -{ \ - assert(rb->buf <= item_p); \ - assert(rb->buf_end >= item_p); \ - if (rb->first == NULL) { \ - return -1; \ - } else if (item_p >= rb->first) { \ - return item_p - rb->first; \ - } else { \ - return item_p - rb->buf + rb->buf_end - rb->first + 1; \ - } \ -} \ - \ -static inline size_t funcprefix##_rb_size( \ - const TypeName##RingBuffer *const rb) \ - REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE; \ -static inline size_t funcprefix##_rb_size( \ - const TypeName##RingBuffer *const rb) \ -{ \ - return (size_t) (rb->buf_end - rb->buf) + 1; \ -} \ - \ -static inline size_t funcprefix##_rb_length( \ - const TypeName##RingBuffer *const rb) \ - REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE; \ -static inline size_t funcprefix##_rb_length( \ - const TypeName##RingBuffer *const rb) \ -{ \ - return _RINGBUF_LENGTH(rb); \ -} \ - \ -static inline RBType *funcprefix##_rb_idx_p( \ - const TypeName##RingBuffer *const rb, const size_t idx) \ - REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE; \ -static inline RBType *funcprefix##_rb_idx_p( \ - const TypeName##RingBuffer *const rb, const size_t idx) \ -{ \ - assert(idx <= funcprefix##_rb_size(rb)); \ - assert(idx <= funcprefix##_rb_length(rb)); \ - if (rb->first + idx > rb->buf_end) { \ - return rb->buf + ((rb->first + idx) - (rb->buf_end + 1)); \ - } else { \ - return rb->first + idx; \ - } \ -} \ - \ +#define RINGBUF_INIT(TypeName, funcprefix, RBType, rbfree) \ +static inline TypeName##RingBuffer funcprefix##_rb_new(const size_t size) \ + REAL_FATTR_WARN_UNUSED_RESULT; \ +static inline TypeName##RingBuffer funcprefix##_rb_new(const size_t size) \ +{ \ + assert(size != 0); \ + RBType *buf = xmalloc(size * sizeof(RBType)); \ + return (TypeName##RingBuffer) { \ + .buf = buf, \ + .next = buf, \ + .first = NULL, \ + .buf_end = buf + size - 1, \ + }; \ +} \ +\ +static inline void funcprefix##_rb_free(TypeName##RingBuffer *const rb) \ + REAL_FATTR_UNUSED; \ +static inline void funcprefix##_rb_free(TypeName##RingBuffer *const rb) \ +{ \ + if (rb == NULL) { \ + return; \ + } \ + RINGBUF_FORALL(rb, RBType, rbitem) { \ + rbfree(rbitem); \ + } \ + xfree(rb->buf); \ +} \ +\ +static inline void funcprefix##_rb_dealloc(TypeName##RingBuffer *const rb) \ + REAL_FATTR_UNUSED; \ +static inline void funcprefix##_rb_dealloc(TypeName##RingBuffer *const rb) \ +{ \ + xfree(rb->buf); \ +} \ +\ +static inline void funcprefix##_rb_push(TypeName##RingBuffer *const rb, \ + RBType item) \ + REAL_FATTR_NONNULL_ARG(1); \ +static inline void funcprefix##_rb_push(TypeName##RingBuffer *const rb, \ + RBType item) \ +{ \ + if (rb->next == rb->first) { \ + rbfree(rb->first); \ + rb->first = _RINGBUF_NEXT(rb, rb->first); \ + } else if (rb->first == NULL) { \ + rb->first = rb->next; \ + } \ + *rb->next = item; \ + rb->next = _RINGBUF_NEXT(rb, rb->next); \ +} \ +\ +static inline ptrdiff_t funcprefix##_rb_find_idx( \ + const TypeName##RingBuffer *const rb, const RBType *const item_p) \ + REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE REAL_FATTR_UNUSED; \ +static inline ptrdiff_t funcprefix##_rb_find_idx( \ + const TypeName##RingBuffer *const rb, const RBType *const item_p) \ +{ \ + assert(rb->buf <= item_p); \ + assert(rb->buf_end >= item_p); \ + if (rb->first == NULL) { \ + return -1; \ + } else if (item_p >= rb->first) { \ + return item_p - rb->first; \ + } else { \ + return item_p - rb->buf + rb->buf_end - rb->first + 1; \ + } \ +} \ +\ +static inline size_t funcprefix##_rb_size( \ + const TypeName##RingBuffer *const rb) \ + REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE; \ +static inline size_t funcprefix##_rb_size( \ + const TypeName##RingBuffer *const rb) \ +{ \ + return (size_t) (rb->buf_end - rb->buf) + 1; \ +} \ +\ +static inline size_t funcprefix##_rb_length( \ + const TypeName##RingBuffer *const rb) \ + REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE; \ +static inline size_t funcprefix##_rb_length( \ + const TypeName##RingBuffer *const rb) \ +{ \ + return _RINGBUF_LENGTH(rb); \ +} \ +\ +static inline RBType *funcprefix##_rb_idx_p( \ + const TypeName##RingBuffer *const rb, const size_t idx) \ + REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE; \ +static inline RBType *funcprefix##_rb_idx_p( \ + const TypeName##RingBuffer *const rb, const size_t idx) \ +{ \ + assert(idx <= funcprefix##_rb_size(rb)); \ + assert(idx <= funcprefix##_rb_length(rb)); \ + if (rb->first + idx > rb->buf_end) { \ + return rb->buf + ((rb->first + idx) - (rb->buf_end + 1)); \ + } else { \ + return rb->first + idx; \ + } \ +} \ +\ static inline RBType funcprefix##_rb_idx(const TypeName##RingBuffer *const rb, \ - const size_t idx) \ - REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE REAL_FATTR_UNUSED; \ + const size_t idx) \ + REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE REAL_FATTR_UNUSED; \ static inline RBType funcprefix##_rb_idx(const TypeName##RingBuffer *const rb, \ - const size_t idx) \ -{ \ - return *funcprefix##_rb_idx_p(rb, idx); \ -} \ - \ -static inline void funcprefix##_rb_insert(TypeName##RingBuffer *const rb, \ - const size_t idx, \ - RBType item) \ - REAL_FATTR_NONNULL_ARG(1) REAL_FATTR_UNUSED; \ -static inline void funcprefix##_rb_insert(TypeName##RingBuffer *const rb, \ - const size_t idx, \ - RBType item) \ -{ \ - assert(idx <= funcprefix##_rb_size(rb)); \ - assert(idx <= funcprefix##_rb_length(rb)); \ - const size_t length = funcprefix##_rb_length(rb); \ - if (idx == length) { \ - funcprefix##_rb_push(rb, item); \ - return; \ - } \ - RBType *const insertpos = funcprefix##_rb_idx_p(rb, idx); \ - if (insertpos == rb->next) { \ - funcprefix##_rb_push(rb, item); \ - return; \ - } \ - if (length == funcprefix##_rb_size(rb)) { \ - rbfree(rb->first); \ - } \ - if (insertpos < rb->next) { \ - memmove(insertpos + 1, insertpos, \ - (size_t) ((uintptr_t) rb->next - (uintptr_t) insertpos)); \ - } else { \ - assert(insertpos > rb->first); \ - assert(rb->next <= rb->first); \ - memmove(rb->buf + 1, rb->buf, \ - (size_t) ((uintptr_t) rb->next - (uintptr_t) rb->buf)); \ - *rb->buf = *rb->buf_end; \ - memmove(insertpos + 1, insertpos, \ + const size_t idx) \ +{ \ + return *funcprefix##_rb_idx_p(rb, idx); \ +} \ +\ +static inline void funcprefix##_rb_insert(TypeName##RingBuffer *const rb, \ + const size_t idx, \ + RBType item) \ + REAL_FATTR_NONNULL_ARG(1) REAL_FATTR_UNUSED; \ +static inline void funcprefix##_rb_insert(TypeName##RingBuffer *const rb, \ + const size_t idx, \ + RBType item) \ +{ \ + assert(idx <= funcprefix##_rb_size(rb)); \ + assert(idx <= funcprefix##_rb_length(rb)); \ + const size_t length = funcprefix##_rb_length(rb); \ + if (idx == length) { \ + funcprefix##_rb_push(rb, item); \ + return; \ + } \ + RBType *const insertpos = funcprefix##_rb_idx_p(rb, idx); \ + if (insertpos == rb->next) { \ + funcprefix##_rb_push(rb, item); \ + return; \ + } \ + if (length == funcprefix##_rb_size(rb)) { \ + rbfree(rb->first); \ + } \ + if (insertpos < rb->next) { \ + memmove(insertpos + 1, insertpos, \ + (size_t) ((uintptr_t) rb->next - (uintptr_t) insertpos)); \ + } else { \ + assert(insertpos > rb->first); \ + assert(rb->next <= rb->first); \ + memmove(rb->buf + 1, rb->buf, \ + (size_t) ((uintptr_t) rb->next - (uintptr_t) rb->buf)); \ + *rb->buf = *rb->buf_end; \ + memmove(insertpos + 1, insertpos, \ (size_t) ((uintptr_t) (rb->buf_end + 1) - (uintptr_t) insertpos)); \ - } \ - *insertpos = item; \ - if (length == funcprefix##_rb_size(rb)) { \ - rb->first = _RINGBUF_NEXT(rb, rb->first); \ - } \ - rb->next = _RINGBUF_NEXT(rb, rb->next); \ -} \ - \ -static inline void funcprefix##_rb_remove(TypeName##RingBuffer *const rb, \ - const size_t idx) \ - REAL_FATTR_NONNULL_ARG(1) REAL_FATTR_UNUSED; \ -static inline void funcprefix##_rb_remove(TypeName##RingBuffer *const rb, \ - const size_t idx) \ -{ \ - assert(idx < funcprefix##_rb_size(rb)); \ - assert(idx < funcprefix##_rb_length(rb)); \ - RBType *const rmpos = funcprefix##_rb_idx_p(rb, idx); \ - rbfree(rmpos); \ - if (rmpos == rb->next - 1) { \ - rb->next--; \ - if (rb->first == rb->next) { \ - rb->first = NULL; \ - rb->next = rb->buf; \ - } \ - } else if (rmpos == rb->first) { \ - rb->first = _RINGBUF_NEXT(rb, rb->first); \ - if (rb->first == rb->next) { \ - rb->first = NULL; \ - rb->next = rb->buf; \ - } \ - } else if (rb->first < rb->next || rb->next == rb->buf) { \ - assert(rmpos > rb->first); \ - assert(rmpos <= _RINGBUF_PREV(rb, rb->next)); \ - memmove(rb->first + 1, rb->first, \ - (size_t) ((uintptr_t) rmpos - (uintptr_t) rb->first)); \ - rb->first = _RINGBUF_NEXT(rb, rb->first); \ - } else if (rmpos < rb->next) { \ - memmove(rmpos, rmpos + 1, \ - (size_t) ((uintptr_t) rb->next - (uintptr_t) rmpos)); \ - rb->next = _RINGBUF_PREV(rb, rb->next); \ - } else { \ - assert(rb->first < rb->buf_end); \ - memmove(rb->first + 1, rb->first, \ - (size_t) ((uintptr_t) rmpos - (uintptr_t) rb->first)); \ - rb->first = _RINGBUF_NEXT(rb, rb->first); \ - } \ + } \ + *insertpos = item; \ + if (length == funcprefix##_rb_size(rb)) { \ + rb->first = _RINGBUF_NEXT(rb, rb->first); \ + } \ + rb->next = _RINGBUF_NEXT(rb, rb->next); \ +} \ +\ +static inline void funcprefix##_rb_remove(TypeName##RingBuffer *const rb, \ + const size_t idx) \ + REAL_FATTR_NONNULL_ARG(1) REAL_FATTR_UNUSED; \ +static inline void funcprefix##_rb_remove(TypeName##RingBuffer *const rb, \ + const size_t idx) \ +{ \ + assert(idx < funcprefix##_rb_size(rb)); \ + assert(idx < funcprefix##_rb_length(rb)); \ + RBType *const rmpos = funcprefix##_rb_idx_p(rb, idx); \ + rbfree(rmpos); \ + if (rmpos == rb->next - 1) { \ + rb->next--; \ + if (rb->first == rb->next) { \ + rb->first = NULL; \ + rb->next = rb->buf; \ + } \ + } else if (rmpos == rb->first) { \ + rb->first = _RINGBUF_NEXT(rb, rb->first); \ + if (rb->first == rb->next) { \ + rb->first = NULL; \ + rb->next = rb->buf; \ + } \ + } else if (rb->first < rb->next || rb->next == rb->buf) { \ + assert(rmpos > rb->first); \ + assert(rmpos <= _RINGBUF_PREV(rb, rb->next)); \ + memmove(rb->first + 1, rb->first, \ + (size_t) ((uintptr_t) rmpos - (uintptr_t) rb->first)); \ + rb->first = _RINGBUF_NEXT(rb, rb->first); \ + } else if (rmpos < rb->next) { \ + memmove(rmpos, rmpos + 1, \ + (size_t) ((uintptr_t) rb->next - (uintptr_t) rmpos)); \ + rb->next = _RINGBUF_PREV(rb, rb->next); \ + } else { \ + assert(rb->first < rb->buf_end); \ + memmove(rb->first + 1, rb->first, \ + (size_t) ((uintptr_t) rmpos - (uintptr_t) rb->first)); \ + rb->first = _RINGBUF_NEXT(rb, rb->first); \ + } \ } #endif // NVIM_LIB_RINGBUF_H diff --git a/src/nvim/log.c b/src/nvim/log.c index 773d497881..c31af6b287 100644 --- a/src/nvim/log.c +++ b/src/nvim/log.c @@ -10,7 +10,14 @@ #include "nvim/os/os.h" #include "nvim/os/time.h" -#define USR_LOG_FILE "$HOME" _PATHSEPSTR ".nvimlog" +/// First location of the log file used by log_path_init() +#define USR_LOG_FILE "$NVIM_LOG_FILE" + +/// Fall back location of the log file used by log_path_init() +#define USR_LOG_FILE_2 "$HOME" _PATHSEPSTR ".nvimlog" + +/// Cached location of the log file set by log_path_init() +static char expanded_log_file_path[MAXPATHL + 1] = { 0 }; static uv_mutex_t mutex; @@ -18,6 +25,35 @@ static uv_mutex_t mutex; # include "log.c.generated.h" #endif +/// Initialize path to log file +/// +/// Tries to use #USR_LOG_FILE, then falls back #USR_LOG_FILE_2. Path to log +/// file is cached, so only the first call has effect, unless first call was not +/// successful. To make initialization not succeed either a bug in expand_env() +/// is needed or both `$NVIM_LOG_FILE` and `$HOME` environment variables +/// undefined. +/// +/// @return true if path was initialized, false otherwise. +static bool log_path_init(void) +{ + if (expanded_log_file_path[0]) { + return true; + } + expand_env((char_u *)USR_LOG_FILE, (char_u *)expanded_log_file_path, + sizeof(expanded_log_file_path) - 1); + // if the log file path expansion failed then fall back to stderr + if (strcmp(USR_LOG_FILE, expanded_log_file_path) == 0) { + memset(expanded_log_file_path, 0, sizeof(expanded_log_file_path)); + expand_env((char_u *)USR_LOG_FILE_2, (char_u *)expanded_log_file_path, + sizeof(expanded_log_file_path) - 1); + if (strcmp(USR_LOG_FILE_2, expanded_log_file_path) == 0) { + memset(expanded_log_file_path, 0, sizeof(expanded_log_file_path)); + return false; + } + } + return true; +} + void log_init(void) { uv_mutex_init(&mutex); @@ -73,30 +109,17 @@ FILE *open_log_file(void) return stderr; } - // expand USR_LOG_FILE and open the file - FILE *log_file; + // expand USR_LOG_FILE if needed and open the file + FILE *log_file = NULL; 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; - } - + if (log_path_init()) { 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; + if (log_file != NULL) { + return log_file; + } do_log_to_file(stderr, ERROR_LOG_LEVEL, __func__, __LINE__, true, "Couldn't open USR_LOG_FILE, logging to stderr! This may be " diff --git a/src/nvim/main.c b/src/nvim/main.c index 71a972e8f6..ba545c0815 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -120,6 +120,8 @@ typedef struct { # include "main.c.generated.h" #endif +Loop main_loop; + static char *argv0; // Error messages @@ -133,7 +135,7 @@ static const char *err_extra_cmd = void event_init(void) { - loop_init(&loop, NULL); + loop_init(&main_loop, NULL); // early msgpack-rpc initialization msgpack_rpc_init_method_table(); msgpack_rpc_helpers_init(); @@ -151,19 +153,20 @@ void event_init(void) void event_teardown(void) { - if (!loop.events) { + if (!main_loop.events) { return; } - queue_process_events(loop.events); + queue_process_events(main_loop.events); input_stop(); channel_teardown(); - process_teardown(&loop); + process_teardown(&main_loop); + timer_teardown(); server_teardown(); signal_teardown(); terminal_teardown(); - loop_close(&loop); + loop_close(&main_loop); } /// Performs early initialization. diff --git a/src/nvim/main.h b/src/nvim/main.h index 084e247b7e..86d25fe657 100644 --- a/src/nvim/main.h +++ b/src/nvim/main.h @@ -2,6 +2,9 @@ #define NVIM_MAIN_H #include "nvim/normal.h" +#include "nvim/event/loop.h" + +extern Loop main_loop; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "main.h.generated.h" diff --git a/src/nvim/map.c b/src/nvim/map.c index d4262ae9a8..03439e7a9c 100644 --- a/src/nvim/map.c +++ b/src/nvim/map.c @@ -34,88 +34,88 @@ #define INITIALIZER_DECLARE(T, U, ...) const U INITIALIZER(T, U) = __VA_ARGS__ #define DEFAULT_INITIALIZER {0} -#define MAP_IMPL(T, U, ...) \ - INITIALIZER_DECLARE(T, U, __VA_ARGS__); \ - __KHASH_IMPL(T##_##U##_map,, T, U, 1, T##_hash, T##_eq) \ - \ - Map(T, U) *map_##T##_##U##_new() \ - { \ - Map(T, U) *rv = xmalloc(sizeof(Map(T, U))); \ - rv->table = kh_init(T##_##U##_map); \ - return rv; \ - } \ - \ - void map_##T##_##U##_free(Map(T, U) *map) \ - { \ - kh_destroy(T##_##U##_map, map->table); \ - xfree(map); \ - } \ - \ - U map_##T##_##U##_get(Map(T, U) *map, T key) \ - { \ - khiter_t k; \ - \ +#define MAP_IMPL(T, U, ...) \ + INITIALIZER_DECLARE(T, U, __VA_ARGS__); \ + __KHASH_IMPL(T##_##U##_map,, T, U, 1, T##_hash, T##_eq) \ + \ + Map(T, U) *map_##T##_##U##_new() \ + { \ + Map(T, U) *rv = xmalloc(sizeof(Map(T, U))); \ + rv->table = kh_init(T##_##U##_map); \ + return rv; \ + } \ + \ + void map_##T##_##U##_free(Map(T, U) *map) \ + { \ + kh_destroy(T##_##U##_map, map->table); \ + xfree(map); \ + } \ + \ + U map_##T##_##U##_get(Map(T, U) *map, T key) \ + { \ + khiter_t k; \ + \ if ((k = kh_get(T##_##U##_map, map->table, key)) == kh_end(map->table)) { \ - return INITIALIZER(T, U); \ - } \ - \ - return kh_val(map->table, k); \ - } \ - \ - bool map_##T##_##U##_has(Map(T, U) *map, T key) \ - { \ - return kh_get(T##_##U##_map, map->table, key) != kh_end(map->table); \ - } \ - \ - U map_##T##_##U##_put(Map(T, U) *map, T key, U value) \ - { \ - int ret; \ - U rv = INITIALIZER(T, U); \ - khiter_t k = kh_put(T##_##U##_map, map->table, key, &ret); \ - \ - if (!ret) { \ - rv = kh_val(map->table, k); \ - } \ - \ - kh_val(map->table, k) = value; \ - return rv; \ - } \ - \ - U *map_##T##_##U##_ref(Map(T, U) *map, T key, bool put) \ - { \ - int ret; \ - khiter_t k; \ - if (put) { \ - k = kh_put(T##_##U##_map, map->table, key, &ret); \ - if (ret) { \ - kh_val(map->table, k) = INITIALIZER(T, U); \ - } \ - } else { \ - k = kh_get(T##_##U##_map, map->table, key); \ - if (k == kh_end(map->table)) { \ - return NULL; \ - } \ - } \ - \ - return &kh_val(map->table, k); \ - } \ - \ - U map_##T##_##U##_del(Map(T, U) *map, T key) \ - { \ - U rv = INITIALIZER(T, U); \ - khiter_t k; \ - \ + return INITIALIZER(T, U); \ + } \ + \ + return kh_val(map->table, k); \ + } \ + \ + bool map_##T##_##U##_has(Map(T, U) *map, T key) \ + { \ + return kh_get(T##_##U##_map, map->table, key) != kh_end(map->table); \ + } \ + \ + U map_##T##_##U##_put(Map(T, U) *map, T key, U value) \ + { \ + int ret; \ + U rv = INITIALIZER(T, U); \ + khiter_t k = kh_put(T##_##U##_map, map->table, key, &ret); \ + \ + if (!ret) { \ + rv = kh_val(map->table, k); \ + } \ + \ + kh_val(map->table, k) = value; \ + return rv; \ + } \ + \ + U *map_##T##_##U##_ref(Map(T, U) *map, T key, bool put) \ + { \ + int ret; \ + khiter_t k; \ + if (put) { \ + k = kh_put(T##_##U##_map, map->table, key, &ret); \ + if (ret) { \ + kh_val(map->table, k) = INITIALIZER(T, U); \ + } \ + } else { \ + k = kh_get(T##_##U##_map, map->table, key); \ + if (k == kh_end(map->table)) { \ + return NULL; \ + } \ + } \ + \ + return &kh_val(map->table, k); \ + } \ + \ + U map_##T##_##U##_del(Map(T, U) *map, T key) \ + { \ + U rv = INITIALIZER(T, U); \ + khiter_t k; \ + \ if ((k = kh_get(T##_##U##_map, map->table, key)) != kh_end(map->table)) { \ - rv = kh_val(map->table, k); \ - kh_del(T##_##U##_map, map->table, k); \ - } \ - \ - return rv; \ - } \ - \ - void map_##T##_##U##_clear(Map(T, U) *map) \ - { \ - kh_clear(T##_##U##_map, map->table); \ + rv = kh_val(map->table, k); \ + kh_del(T##_##U##_map, map->table, k); \ + } \ + \ + return rv; \ + } \ + \ + void map_##T##_##U##_clear(Map(T, U) *map) \ + { \ + kh_clear(T##_##U##_map, map->table); \ } static inline khint_t String_hash(String s) diff --git a/src/nvim/map.h b/src/nvim/map.h index e90cc360ce..c7d9894bd1 100644 --- a/src/nvim/map.h +++ b/src/nvim/map.h @@ -8,20 +8,20 @@ #include "nvim/msgpack_rpc/defs.h" #include "nvim/bufhl_defs.h" -#define MAP_DECLS(T, U) \ - KHASH_DECLARE(T##_##U##_map, T, U) \ - \ - typedef struct { \ - khash_t(T##_##U##_map) *table; \ - } Map(T, U); \ - \ - Map(T, U) *map_##T##_##U##_new(void); \ - void map_##T##_##U##_free(Map(T, U) *map); \ - U map_##T##_##U##_get(Map(T, U) *map, T key); \ - bool map_##T##_##U##_has(Map(T, U) *map, T key); \ - U map_##T##_##U##_put(Map(T, U) *map, T key, U value); \ - U *map_##T##_##U##_ref(Map(T, U) *map, T key, bool put); \ - U map_##T##_##U##_del(Map(T, U) *map, T key); \ +#define MAP_DECLS(T, U) \ + KHASH_DECLARE(T##_##U##_map, T, U) \ + \ + typedef struct { \ + khash_t(T##_##U##_map) *table; \ + } Map(T, U); \ + \ + Map(T, U) *map_##T##_##U##_new(void); \ + void map_##T##_##U##_free(Map(T, U) *map); \ + U map_##T##_##U##_get(Map(T, U) *map, T key); \ + bool map_##T##_##U##_has(Map(T, U) *map, T key); \ + U map_##T##_##U##_put(Map(T, U) *map, T key, U value); \ + U *map_##T##_##U##_ref(Map(T, U) *map, T key, bool put); \ + U map_##T##_##U##_del(Map(T, U) *map, T key); \ void map_##T##_##U##_clear(Map(T, U) *map); MAP_DECLS(int, int) diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 3495203c43..0ba9f8b076 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -1304,7 +1304,7 @@ int utfc_ptr2char(const char_u *p, int *pcc) */ int utfc_ptr2char_len(const char_u *p, int *pcc, int maxlen) { -#define IS_COMPOSING(s1, s2, s3) \ +#define IS_COMPOSING(s1, s2, s3) \ (i == 0 ? UTF_COMPOSINGLIKE((s1), (s2)) : utf_iscomposing((s3))) assert(maxlen > 0); diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index 6599db787f..9fb03c4ac7 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -913,7 +913,7 @@ static bool mf_do_open(memfile_T *mfp, char_u *fname, int flags) #ifdef HAVE_FD_CLOEXEC int fdflags = fcntl(mfp->mf_fd, F_GETFD); if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) { - fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC); + (void)fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC); } #endif #ifdef HAVE_SELINUX diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 4e35dd481f..9c20f15727 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -443,8 +443,9 @@ void ml_setname(buf_T *buf) #ifdef HAVE_FD_CLOEXEC { int fdflags = fcntl(mfp->mf_fd, F_GETFD); - if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) - fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC); + if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) { + (void)fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC); + } } #endif } diff --git a/src/nvim/message.c b/src/nvim/message.c index 02201107db..77e8f0e4f2 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -493,10 +493,11 @@ int emsg(char_u *s) * when the message should be ignored completely (used for the * interrupt message). */ - if (cause_errthrow(s, severe, &ignore) == TRUE) { - if (!ignore) - did_emsg = TRUE; - return TRUE; + if (cause_errthrow(s, severe, &ignore) == true) { + if (!ignore) { + did_emsg = true; + } + return true; } // set "v:errmsg", also when using ":silent! cmd" @@ -511,41 +512,43 @@ int emsg(char_u *s) p = get_emsg_source(); if (p != NULL) { STRCAT(p, "\n"); - redir_write(p, -1); + redir_write(p, STRLEN(p)); xfree(p); } p = get_emsg_lnum(); if (p != NULL) { STRCAT(p, "\n"); - redir_write(p, -1); + redir_write(p, STRLEN(p)); xfree(p); } - redir_write(s, -1); - return TRUE; + redir_write(s, STRLEN(s)); + return true; } - /* Reset msg_silent, an error causes messages to be switched back on. */ + // Reset msg_silent, an error causes messages to be switched back on. msg_silent = 0; cmd_silent = FALSE; - if (global_busy) /* break :global command */ - ++global_busy; + if (global_busy) { // break :global command + global_busy++; + } - if (p_eb) - beep_flush(); /* also includes flush_buffers() */ - else - flush_buffers(FALSE); /* flush internal buffers */ - did_emsg = TRUE; /* flag for DoOneCmd() */ + if (p_eb) { + beep_flush(); // also includes flush_buffers() + } else { + flush_buffers(false); // flush internal buffers + } + did_emsg = true; // flag for DoOneCmd() } - emsg_on_display = TRUE; /* remember there is an error message */ - ++msg_scroll; /* don't overwrite a previous message */ - attr = hl_attr(HLF_E); /* set highlight mode for error messages */ - if (msg_scrolled != 0) - need_wait_return = TRUE; /* needed in case emsg() is called after - * wait_return has reset need_wait_return - * and a redraw is expected because - * msg_scrolled is non-zero */ + emsg_on_display = true; // remember there is an error message + msg_scroll++; // don't overwrite a previous message + attr = hl_attr(HLF_E); // set highlight mode for error messages + if (msg_scrolled != 0) { + need_wait_return = true; // needed in case emsg() is called after + } // wait_return has reset need_wait_return + // and a redraw is expected because + // msg_scrolled is non-zero /* * Display name and line number for the source of the error. @@ -2414,22 +2417,27 @@ static void redir_write(char_u *str, int maxlen) /* If the string doesn't start with CR or NL, go to msg_col */ if (*s != '\n' && *s != '\r') { while (cur_col < msg_col) { - if (redir_reg) - write_reg_contents(redir_reg, (char_u *)" ", -1, TRUE); - else if (redir_vname) + if (redir_reg) { + write_reg_contents(redir_reg, (char_u *)" ", 1, true); + } else if (redir_vname) { var_redir_str((char_u *)" ", -1); - else if (redir_fd != NULL) + } else if (redir_fd != NULL) { fputs(" ", redir_fd); - if (verbose_fd != NULL) + } + if (verbose_fd != NULL) { fputs(" ", verbose_fd); - ++cur_col; + } + cur_col++; } } - if (redir_reg) - write_reg_contents(redir_reg, s, maxlen, TRUE); - if (redir_vname) + if (redir_reg) { + size_t len = maxlen == -1 ? STRLEN(s) : (size_t)maxlen; + write_reg_contents(redir_reg, s, len, true); + } + if (redir_vname) { var_redir_str(s, maxlen); + } /* Write and adjust the current column. */ while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen)) { diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 48791384a6..d72d8e8513 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -178,12 +178,11 @@ open_line ( if (curbuf->b_p_ai || do_si ) { - /* - * count white space on current line - */ - newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts, FALSE); - if (newindent == 0 && !(flags & OPENLINE_COM_LIST)) - newindent = second_line_indent; /* for ^^D command in insert mode */ + // count white space on current line + newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts, false); + if (newindent == 0 && !(flags & OPENLINE_COM_LIST)) { + newindent = second_line_indent; // for ^^D command in insert mode + } /* * Do smart indenting. @@ -612,7 +611,7 @@ open_line ( if (curbuf->b_p_ai || do_si ) - newindent = get_indent_str(leader, (int)curbuf->b_p_ts, FALSE); + newindent = get_indent_str(leader, (int)curbuf->b_p_ts, false); /* Add the indent offset */ if (newindent + off < 0) { diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 34ff7c6374..0d7d5a247e 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -7,8 +7,8 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" +#include "nvim/api/ui.h" #include "nvim/msgpack_rpc/channel.h" -#include "nvim/msgpack_rpc/remote_ui.h" #include "nvim/event/loop.h" #include "nvim/event/libuv_process.h" #include "nvim/event/rstream.h" @@ -16,6 +16,7 @@ #include "nvim/event/socket.h" #include "nvim/msgpack_rpc/helpers.h" #include "nvim/vim.h" +#include "nvim/main.h" #include "nvim/ascii.h" #include "nvim/memory.h" #include "nvim/os_unix.h" @@ -119,7 +120,7 @@ void channel_teardown(void) uint64_t channel_from_process(char **argv) { Channel *channel = register_channel(kChannelTypeProc); - channel->data.process.uvproc = libuv_process_init(&loop, channel); + channel->data.process.uvproc = libuv_process_init(&main_loop, channel); Process *proc = &channel->data.process.uvproc.process; proc->argv = argv; proc->in = &channel->data.process.in; @@ -127,7 +128,7 @@ uint64_t channel_from_process(char **argv) proc->err = &channel->data.process.err; proc->cb = process_exit; if (!process_spawn(proc)) { - loop_poll_events(&loop, 0); + loop_poll_events(&main_loop, 0); decref(channel); return 0; } @@ -179,7 +180,7 @@ bool channel_send_event(uint64_t id, char *name, Array args) // Pending request, queue the notification for later sending. String method = cstr_as_string(name); WBuffer *buffer = serialize_request(id, 0, method, args, &out_buffer, 1); - kv_push(WBuffer *, channel->delayed_notifications, buffer); + kv_push(channel->delayed_notifications, buffer); } else { send_event(channel, name, args); } @@ -217,10 +218,10 @@ Object channel_send_call(uint64_t id, send_request(channel, request_id, method_name, args); // Push the frame - ChannelCallFrame frame = {request_id, false, false, NIL}; - kv_push(ChannelCallFrame *, channel->call_stack, &frame); + ChannelCallFrame frame = { request_id, false, false, NIL }; + kv_push(channel->call_stack, &frame); channel->pending_requests++; - LOOP_PROCESS_EVENTS_UNTIL(&loop, channel->events, -1, frame.returned); + LOOP_PROCESS_EVENTS_UNTIL(&main_loop, channel->events, -1, frame.returned); (void)kv_pop(channel->call_stack); channel->pending_requests--; @@ -316,11 +317,11 @@ void channel_from_stdio(void) Channel *channel = register_channel(kChannelTypeStdio); incref(channel); // stdio channels are only closed on exit // read stream - rstream_init_fd(&loop, &channel->data.std.in, 0, CHANNEL_BUFFER_SIZE, - channel); + rstream_init_fd(&main_loop, &channel->data.std.in, 0, CHANNEL_BUFFER_SIZE, + channel); rstream_start(&channel->data.std.in, parse_msgpack); // write stream - wstream_init_fd(&loop, &channel->data.std.out, 1, 0, NULL); + wstream_init_fd(&main_loop, &channel->data.std.out, 1, 0, NULL); } static void forward_stderr(Stream *stream, RBuffer *rbuf, size_t count, @@ -574,13 +575,12 @@ static void send_event(Channel *channel, static void broadcast_event(char *name, Array args) { - kvec_t(Channel *) subscribed; - kv_init(subscribed); + kvec_t(Channel *) subscribed = KV_INITIAL_VALUE; Channel *channel; map_foreach_value(channels, channel, { if (pmap_has(cstr_t)(channel->subscribed_events, name)) { - kv_push(Channel *, subscribed, channel); + kv_push(subscribed, channel); } }); @@ -600,7 +600,7 @@ static void broadcast_event(char *name, Array args) for (size_t i = 0; i < kv_size(subscribed); i++) { Channel *channel = kv_A(subscribed, i); if (channel->pending_requests) { - kv_push(WBuffer *, channel->delayed_notifications, buffer); + kv_push(channel->delayed_notifications, buffer); } else { channel_write(channel, buffer); } @@ -647,7 +647,7 @@ static void close_channel(Channel *channel) case kChannelTypeStdio: stream_close(&channel->data.std.in, NULL); stream_close(&channel->data.std.out, NULL); - queue_put(loop.fast_events, exit_event, 1, channel); + queue_put(main_loop.fast_events, exit_event, 1, channel); return; default: abort(); @@ -692,7 +692,7 @@ static void close_cb(Stream *stream, void *data) static Channel *register_channel(ChannelType type) { Channel *rv = xmalloc(sizeof(Channel)); - rv->events = queue_new_child(loop.events); + rv->events = queue_new_child(main_loop.events); rv->type = type; rv->refcount = 1; rv->closed = false; diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c index 0049ae6b95..c643bae0e8 100644 --- a/src/nvim/msgpack_rpc/helpers.c +++ b/src/nvim/msgpack_rpc/helpers.c @@ -18,39 +18,39 @@ static msgpack_zone zone; static msgpack_sbuffer sbuffer; -#define HANDLE_TYPE_CONVERSION_IMPL(t, lt) \ - bool msgpack_rpc_to_##lt(msgpack_object *obj, t *arg) \ - FUNC_ATTR_NONNULL_ALL \ - { \ - if (obj->type != MSGPACK_OBJECT_EXT \ - || obj->via.ext.type != kObjectType##t) { \ - return false; \ - } \ - \ - msgpack_object data; \ - msgpack_unpack_return ret = msgpack_unpack(obj->via.ext.ptr, \ - obj->via.ext.size, \ - NULL, \ - &zone, \ - &data); \ - \ - if (ret != MSGPACK_UNPACK_SUCCESS) { \ - return false; \ - } \ - \ - *arg = data.via.u64; \ - return true; \ - } \ - \ - void msgpack_rpc_from_##lt(t o, msgpack_packer *res) \ - FUNC_ATTR_NONNULL_ARG(2) \ - { \ - msgpack_packer pac; \ - msgpack_packer_init(&pac, &sbuffer, msgpack_sbuffer_write); \ - msgpack_pack_uint64(&pac, o); \ - msgpack_pack_ext(res, sbuffer.size, kObjectType##t); \ - msgpack_pack_ext_body(res, sbuffer.data, sbuffer.size); \ - msgpack_sbuffer_clear(&sbuffer); \ +#define HANDLE_TYPE_CONVERSION_IMPL(t, lt) \ + bool msgpack_rpc_to_##lt(msgpack_object *obj, t *arg) \ + FUNC_ATTR_NONNULL_ALL \ + { \ + if (obj->type != MSGPACK_OBJECT_EXT \ + || obj->via.ext.type != kObjectType##t) { \ + return false; \ + } \ + \ + msgpack_object data; \ + msgpack_unpack_return ret = msgpack_unpack(obj->via.ext.ptr, \ + obj->via.ext.size, \ + NULL, \ + &zone, \ + &data); \ + \ + if (ret != MSGPACK_UNPACK_SUCCESS) { \ + return false; \ + } \ + \ + *arg = data.via.u64; \ + return true; \ + } \ + \ + void msgpack_rpc_from_##lt(t o, msgpack_packer *res) \ + FUNC_ATTR_NONNULL_ARG(2) \ + { \ + msgpack_packer pac; \ + msgpack_packer_init(&pac, &sbuffer, msgpack_sbuffer_write); \ + msgpack_pack_uint64(&pac, o); \ + msgpack_pack_ext(res, sbuffer.size, kObjectType##t); \ + msgpack_pack_ext_body(res, sbuffer.data, sbuffer.size); \ + msgpack_sbuffer_clear(&sbuffer); \ } void msgpack_rpc_helpers_init(void) diff --git a/src/nvim/msgpack_rpc/remote_ui.h b/src/nvim/msgpack_rpc/remote_ui.h deleted file mode 100644 index 8af86dc1b8..0000000000 --- a/src/nvim/msgpack_rpc/remote_ui.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef NVIM_MSGPACK_RPC_REMOTE_UI_H -#define NVIM_MSGPACK_RPC_REMOTE_UI_H - -#include "nvim/ui.h" - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "msgpack_rpc/remote_ui.h.generated.h" -#endif -#endif // NVIM_MSGPACK_RPC_REMOTE_UI_H diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c index 6cc56ba3dd..abbd3e8aff 100644 --- a/src/nvim/msgpack_rpc/server.c +++ b/src/nvim/msgpack_rpc/server.c @@ -12,6 +12,7 @@ #include "nvim/eval.h" #include "nvim/garray.h" #include "nvim/vim.h" +#include "nvim/main.h" #include "nvim/memory.h" #include "nvim/log.h" #include "nvim/fileio.h" @@ -108,7 +109,7 @@ int server_start(const char *endpoint) } SocketWatcher *watcher = xmalloc(sizeof(SocketWatcher)); - socket_watcher_init(&loop, watcher, endpoint, NULL); + socket_watcher_init(&main_loop, watcher, endpoint, NULL); // Check if a watcher for the endpoint already exists for (int i = 0; i < watchers.ga_len; i++) { diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 382c4943ff..c95e5e1a15 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -974,7 +974,7 @@ static int normal_execute(VimState *state, int key) s->old_col = curwin->w_curswant; s->c = key; - LANGMAP_ADJUST(s->c, true); + LANGMAP_ADJUST(s->c, get_real_state() != SELECTMODE); // If a mapping was started in Visual or Select mode, remember the length // of the mapping. This is used below to not return to Insert mode for as @@ -1795,10 +1795,11 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) if (oap->line_count < 2) oap->line_count = 2; if (curwin->w_cursor.lnum + oap->line_count - 1 > - curbuf->b_ml.ml_line_count) + curbuf->b_ml.ml_line_count) { beep_flush(); - else { - do_join(oap->line_count, oap->op_type == OP_JOIN, true, true, true); + } else { + do_join((size_t)oap->line_count, oap->op_type == OP_JOIN, + true, true, true); auto_format(false, true); } break; @@ -7666,7 +7667,7 @@ static void nv_join(cmdarg_T *cap) prep_redo(cap->oap->regname, cap->count0, NUL, cap->cmdchar, NUL, NUL, cap->nchar); - do_join(cap->count0, cap->nchar == NUL, true, true, true); + do_join((size_t)cap->count0, cap->nchar == NUL, true, true, true); } } @@ -7879,7 +7880,7 @@ static void nv_event(cmdarg_T *cap) // not safe to perform garbage collection because there could be unreferenced // lists or dicts being used. may_garbage_collect = false; - queue_process_events(loop.events); + queue_process_events(main_loop.events); cap->retval |= CA_COMMAND_BUSY; // don't call edit() now } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index adfd0424f0..cb068aa37f 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -1,6 +1,6 @@ /* * ops.c: implementation of various operators: op_shift, op_delete, op_tilde, - * op_change, op_yank, do_put, do_join + * op_change, op_yank, do_put, do_join */ #include <assert.h> @@ -257,8 +257,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount) * shift the current line one shiftwidth left (if left != 0) or right * leaves cursor on first blank in the line */ -void -shift_line ( +void shift_line( int left, int round, int amount, @@ -369,18 +368,18 @@ static void shift_block(oparg_T *oap, int amount) memset(newp + bd.textcol + i, ' ', (size_t)j); /* the end */ memmove(newp + bd.textcol + i + j, bd.textstart, (size_t)len); - } else { /* left */ - colnr_T destination_col; /* column to which text in block will - be shifted */ - char_u *verbatim_copy_end; /* end of the part of the line which is - copied verbatim */ - colnr_T verbatim_copy_width; /* the (displayed) width of this part - of line */ - unsigned fill; /* nr of spaces that replace a TAB */ - unsigned new_line_len; /* the length of the line after the - block shift */ - size_t block_space_width; - size_t shift_amount; + } else { // left + colnr_T destination_col; // column to which text in block will + // be shifted + char_u *verbatim_copy_end; // end of the part of the line which is + // copied verbatim + colnr_T verbatim_copy_width; // the (displayed) width of this part + // of line + size_t fill; // nr of spaces that replace a TAB + size_t new_line_len; // the length of the line after the + // block shift + colnr_T block_space_width; + colnr_T shift_amount; char_u *non_white = bd.textstart; colnr_T non_white_col; @@ -409,11 +408,10 @@ static void shift_block(oparg_T *oap, int amount) block_space_width = non_white_col - oap->start_vcol; /* We will shift by "total" or "block_space_width", whichever is less. */ - shift_amount = (block_space_width < (size_t)total - ? block_space_width : (size_t)total); + shift_amount = (block_space_width < total ? block_space_width : total); - /* The column to which we will shift the text. */ - destination_col = (colnr_T)(non_white_col - shift_amount); + // The column to which we will shift the text. + destination_col = non_white_col - shift_amount; /* Now let's find out how much of the beginning of the line we can * reuse without modification. */ @@ -439,20 +437,21 @@ static void shift_block(oparg_T *oap, int amount) /* If "destination_col" is different from the width of the initial * part of the line that will be copied, it means we encountered a tab * character, which we will have to partly replace with spaces. */ - fill = destination_col - verbatim_copy_width; - - /* The replacement line will consist of: - * - the beginning of the original line up to "verbatim_copy_end", - * - "fill" number of spaces, - * - the rest of the line, pointed to by non_white. */ - new_line_len = (unsigned)(verbatim_copy_end - oldp) - + fill - + (unsigned)STRLEN(non_white) + 1; - - newp = (char_u *) xmalloc((size_t)(new_line_len)); - memmove(newp, oldp, (size_t)(verbatim_copy_end - oldp)); - memset(newp + (verbatim_copy_end - oldp), ' ', (size_t)fill); - STRMOVE(newp + (verbatim_copy_end - oldp) + fill, non_white); + assert(destination_col - verbatim_copy_width >= 0); + fill = (size_t)(destination_col - verbatim_copy_width); + + assert(verbatim_copy_end - oldp >= 0); + size_t verbatim_diff = (size_t)(verbatim_copy_end - oldp); + // The replacement line will consist of: + // - the beginning of the original line up to "verbatim_copy_end", + // - "fill" number of spaces, + // - the rest of the line, pointed to by non_white. + new_line_len = verbatim_diff + fill + STRLEN(non_white) + 1; + + newp = (char_u *) xmalloc(new_line_len); + memmove(newp, oldp, verbatim_diff); + memset(newp + verbatim_diff, ' ', fill); + STRMOVE(newp + verbatim_diff + fill, non_white); } /* replace the line */ ml_replace(curwin->w_cursor.lnum, newp, FALSE); @@ -469,21 +468,20 @@ static void shift_block(oparg_T *oap, int amount) static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def *bdp) { int p_ts; - int count = 0; /* extra spaces to replace a cut TAB */ - int spaces = 0; /* non-zero if cutting a TAB */ - colnr_T offset; /* pointer along new line */ - unsigned s_len; /* STRLEN(s) */ - char_u *newp, *oldp; /* new, old lines */ - linenr_T lnum; /* loop var */ + int count = 0; // extra spaces to replace a cut TAB + int spaces = 0; // non-zero if cutting a TAB + colnr_T offset; // pointer along new line + size_t s_len = STRLEN(s); + char_u *newp, *oldp; // new, old lines + linenr_T lnum; // loop var int oldstate = State; - - State = INSERT; /* don't want REPLACE for State */ - s_len = (unsigned)STRLEN(s); + State = INSERT; // don't want REPLACE for State for (lnum = oap->start.lnum + 1; lnum <= oap->end.lnum; lnum++) { - block_prep(oap, bdp, lnum, TRUE); - if (bdp->is_short && b_insert) - continue; /* OP_INSERT, line ends before block start */ + block_prep(oap, bdp, lnum, true); + if (bdp->is_short && b_insert) { + continue; // OP_INSERT, line ends before block start + } oldp = ml_get(lnum); @@ -523,25 +521,26 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def count -= off; } - newp = (char_u *) xmalloc((size_t)(STRLEN(oldp) + s_len + count + 1)); + assert(count >= 0); + newp = (char_u *)xmalloc(STRLEN(oldp) + s_len + (size_t)count + 1); - /* copy up to shifted part */ - memmove(newp, oldp, (size_t)(offset)); + // copy up to shifted part + memmove(newp, oldp, (size_t)offset); oldp += offset; - /* insert pre-padding */ + // insert pre-padding memset(newp + offset, ' ', (size_t)spaces); - /* copy the new text */ - memmove(newp + offset + spaces, s, (size_t)s_len); - offset += s_len; + // copy the new text + memmove(newp + offset + spaces, s, s_len); + offset += (int)s_len; if (spaces && !bdp->is_short) { - /* insert post-padding */ + // insert post-padding memset(newp + offset + spaces, ' ', (size_t)(p_ts - spaces)); - /* We're splitting a TAB, don't copy it. */ + // We're splitting a TAB, don't copy it. oldp++; - /* We allowed for that TAB, remember this now */ + // We allowed for that TAB, remember this now count++; } @@ -804,7 +803,7 @@ yankreg_T *copy_register(int name) copy->y_array = NULL; } else { copy->y_array = xcalloc(copy->y_size, sizeof(char_u *)); - for (linenr_T i = 0; i < copy->y_size; i++) { + for (size_t i = 0; i < copy->y_size; i++) { copy->y_array[i] = vim_strsave(reg->y_array[i]); } } @@ -888,7 +887,7 @@ static void set_yreg_additional_data(yankreg_T *reg, dict_T *additional_data) /* * Stuff string "p" into yank register "regname" as a single line (append if - * uppercase). "p" must have been alloced. + * uppercase). "p" must have been alloced. * * return FAIL for failure, OK otherwise */ @@ -940,10 +939,8 @@ do_execreg ( int silent /* set "silent" flag in typeahead buffer */ ) { - long i; - char_u *p; + char_u *p; int retval = OK; - int remap; if (regname == '@') { /* repeat previous one */ if (execreg_lastc == NUL) { @@ -1001,21 +998,20 @@ do_execreg ( if (reg->y_array == NULL) return FAIL; - /* Disallow remaping for ":@r". */ - remap = colon ? REMAP_NONE : REMAP_YES; + // Disallow remaping for ":@r". + int remap = colon ? REMAP_NONE : REMAP_YES; /* * Insert lines into typeahead buffer, from last one to first one. */ put_reedit_in_typebuf(silent); - for (i = reg->y_size - 1; i >= 0; i--) { - char_u *escaped; - + char_u *escaped; + for (size_t i = reg->y_size; i-- > 0;) { // from y_size - 1 to 0 included // insert NL between lines and after last line if type is kMTLineWise - if (reg->y_type == kMTLineWise || i < reg->y_size - 1 - || addcr) { - if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL) + if (reg->y_type == kMTLineWise || i < reg->y_size - 1 || addcr) { + if (ins_typebuf((char_u *)"\n", remap, 0, true, silent) == FAIL) { return FAIL; + } } escaped = vim_strsave_escape_csi(reg->y_array[i]); retval = ins_typebuf(escaped, remap, 0, TRUE, silent); @@ -1045,7 +1041,7 @@ static void put_reedit_in_typebuf(int silent) buf[1] = 'R'; buf[2] = NUL; } else { - buf[0] = restart_edit == 'I' ? 'i' : restart_edit; + buf[0] = (char_u)(restart_edit == 'I' ? 'i' : restart_edit); buf[1] = NUL; } if (ins_typebuf(buf, REMAP_NONE, 0, TRUE, silent) == OK) @@ -1059,8 +1055,7 @@ static void put_reedit_in_typebuf(int silent) * When "esc" is TRUE it is to be taken literally: Escape CSI characters and * no remapping. */ -static int -put_in_typebuf ( +static int put_in_typebuf( char_u *s, int esc, int colon, /* add ':' before the line */ @@ -1098,13 +1093,11 @@ put_in_typebuf ( * * return FAIL for failure, OK otherwise */ -int -insert_reg ( +int insert_reg( int regname, int literally /* insert literally, not as if typed */ ) { - long i; int retval = OK; char_u *arg; int allocated; @@ -1132,10 +1125,10 @@ insert_reg ( xfree(arg); } else { /* name or number register */ yankreg_T *reg = get_yank_register(regname, YREG_PASTE); - if (reg->y_array == NULL) + if (reg->y_array == NULL) { retval = FAIL; - else { - for (i = 0; i < reg->y_size; i++) { + } else { + for (size_t i = 0; i < reg->y_size; i++) { stuffescaped(reg->y_array[i], literally); // Insert a newline between lines and after last line if // y_type is kMTLineWise. @@ -1185,8 +1178,7 @@ static void stuffescaped(char_u *arg, int literally) * If "regname" is a special register, return TRUE and store a pointer to its * value in "argp". */ -int -get_spec_reg ( +int get_spec_reg( int regname, char_u **argp, int *allocated, /* return: TRUE when value was allocated */ @@ -1273,13 +1265,11 @@ get_spec_reg ( /// @returns FAIL for failure, OK otherwise bool cmdline_paste_reg(int regname, bool literally, bool remcr) { - long i; - yankreg_T *reg = get_yank_register(regname, YREG_PASTE); if (reg->y_array == NULL) return FAIL; - for (i = 0; i < reg->y_size; i++) { + for (size_t i = 0; i < reg->y_size; i++) { cmdline_paste_str(reg->y_array[i], literally); // Insert ^M between lines and after last line if type is kMTLineWise. @@ -1311,12 +1301,14 @@ int op_delete(oparg_T *oap) struct block_def bd; linenr_T old_lcount = curbuf->b_ml.ml_line_count; - if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to do */ + if (curbuf->b_ml.ml_flags & ML_EMPTY) { // nothing to do return OK; + } - /* Nothing to delete, return here. Do prepare undo, for op_change(). */ - if (oap->empty) + // Nothing to delete, return here. Do prepare undo, for op_change(). + if (oap->empty) { return u_save_cursor(); + } if (!MODIFIABLE(curbuf)) { EMSG(_(e_modifiable)); @@ -1431,23 +1423,21 @@ int op_delete(oparg_T *oap) curwin->w_cursor.coladd = 0; } - /* n == number of chars deleted - * If we delete a TAB, it may be replaced by several characters. - * Thus the number of characters may increase! - */ + // n == number of chars deleted + // If we delete a TAB, it may be replaced by several characters. + // Thus the number of characters may increase! n = bd.textlen - bd.startspaces - bd.endspaces; oldp = ml_get(lnum); - newp = (char_u *) xmalloc((size_t)(STRLEN(oldp) + 1 - n)); - /* copy up to deleted part */ + newp = (char_u *)xmalloc(STRLEN(oldp) - (size_t)n + 1); + // copy up to deleted part memmove(newp, oldp, (size_t)bd.textcol); - /* insert spaces */ - memset(newp + bd.textcol, ' ', - (size_t)(bd.startspaces + bd.endspaces)); - /* copy the part after the deleted part */ + // insert spaces + memset(newp + bd.textcol, ' ', (size_t)(bd.startspaces + bd.endspaces)); + // copy the part after the deleted part oldp += bd.textcol + bd.textlen; STRMOVE(newp + bd.textcol + bd.startspaces + bd.endspaces, oldp); - /* replace the line */ - ml_replace(lnum, newp, FALSE); + // replace the line + ml_replace(lnum, newp, false); } check_cursor_col(); @@ -1552,7 +1542,7 @@ int op_delete(oparg_T *oap) curwin->w_cursor.coladd = 0; } - (void)del_bytes((long)n, !virtual_op, + (void)del_bytes((colnr_T)n, !virtual_op, oap->op_type == OP_DELETE && !oap->is_VIsual); } else { // delete characters between lines @@ -1572,7 +1562,7 @@ int op_delete(oparg_T *oap) // delete from start of line until op_end n = (oap->end.col + 1 - !oap->inclusive); curwin->w_cursor.col = 0; - (void)del_bytes((long)n, !virtual_op, + (void)del_bytes((colnr_T)n, !virtual_op, oap->op_type == OP_DELETE && !oap->is_VIsual); curwin->w_cursor = curpos; // restore curwin->w_cursor (void)do_join(2, false, false, false, false); @@ -1611,7 +1601,8 @@ static void mb_adjust_opend(oparg_T *oap) */ static inline void pchar(pos_T lp, int c) { - *(ml_get_buf(curbuf, lp.lnum, TRUE) + lp.col) = c;; + assert(c <= UCHAR_MAX); + *(ml_get_buf(curbuf, lp.lnum, true) + lp.col) = (char_u)c; } /* @@ -1695,15 +1686,16 @@ int op_replace(oparg_T *oap, int c) oldp = get_cursor_line_ptr(); oldlen = STRLEN(oldp); - newp = (char_u *) xmalloc((size_t)(oldlen + 1 + n)); - memset(newp, NUL, (size_t)(oldlen + 1 + n)); - /* copy up to deleted part */ + assert(n >= 0); + newp = (char_u *)xmalloc(oldlen + 1 + (size_t)n); + memset(newp, NUL, oldlen + 1 + (size_t)n); + // copy up to deleted part memmove(newp, oldp, (size_t)bd.textcol); oldp += bd.textcol + bd.textlen; - /* insert pre-spaces */ + // insert pre-spaces memset(newp + bd.textcol, ' ', (size_t)bd.startspaces); - /* insert replacement chars CHECK FOR ALLOCATED SPACE */ - /* -1/-2 is used for entering CR literally. */ + // insert replacement chars CHECK FOR ALLOCATED SPACE + // -1/-2 is used for entering CR literally. if (had_ctrl_v_cr || (c != '\r' && c != '\n')) { if (has_mbyte) { n = (int)STRLEN(newp); @@ -1718,8 +1710,8 @@ int op_replace(oparg_T *oap, int c) STRMOVE(newp + STRLEN(newp), oldp); } } else { - /* Replacing with \r or \n means splitting the line. */ - after_p = (char_u *) xmalloc((size_t)(oldlen + 1 + n - STRLEN(newp))); + // Replacing with \r or \n means splitting the line. + after_p = (char_u *)xmalloc(oldlen + 1 + (size_t)n - STRLEN(newp)); STRMOVE(after_p, oldp); } /* replace the line */ @@ -1992,7 +1984,7 @@ void op_insert(oparg_T *oap, long count1) // already disabled, but still need it when calling // coladvance_force(). if (curwin->w_cursor.coladd > 0) { - int old_ve_flags = ve_flags; + unsigned old_ve_flags = ve_flags; ve_flags = VE_ALL; if (u_save_cursor() == FAIL) @@ -2066,8 +2058,8 @@ void op_insert(oparg_T *oap, long count1) if (oap->op_type == OP_INSERT && oap->start.col + oap->start.coladd != curbuf->b_op_start_orig.col + curbuf->b_op_start_orig.coladd) { - size_t t = getviscol2(curbuf->b_op_start_orig.col, - curbuf->b_op_start_orig.coladd); + int t = getviscol2(curbuf->b_op_start_orig.col, + curbuf->b_op_start_orig.coladd); oap->start.col = curbuf->b_op_start_orig.col; pre_textlen -= t - oap->start_vcol; oap->start_vcol = t; @@ -2075,8 +2067,8 @@ void op_insert(oparg_T *oap, long count1) && oap->end.col + oap->end.coladd >= curbuf->b_op_start_orig.col + curbuf->b_op_start_orig.coladd) { - size_t t = getviscol2(curbuf->b_op_start_orig.col, - curbuf->b_op_start_orig.coladd); + int t = getviscol2(curbuf->b_op_start_orig.col, + curbuf->b_op_start_orig.coladd); oap->start.col = curbuf->b_op_start_orig.col; /* reset pre_textlen to the value of OP_INSERT */ pre_textlen += bd.textlen; @@ -2109,14 +2101,13 @@ void op_insert(oparg_T *oap, long count1) firstline = ml_get(oap->start.lnum) + bd.textcol; if (oap->op_type == OP_APPEND) firstline += bd.textlen; - if (pre_textlen >= 0 - && (ins_len = (long)STRLEN(firstline) - pre_textlen) > 0) { - ins_text = vim_strnsave(firstline, (int)ins_len); - /* block handled here */ - if (u_save(oap->start.lnum, - (linenr_T)(oap->end.lnum + 1)) == OK) - block_insert(oap, ins_text, (oap->op_type == OP_INSERT), - &bd); + ins_len = (long)STRLEN(firstline) - pre_textlen; + if (pre_textlen >= 0 && ins_len > 0) { + ins_text = vim_strnsave(firstline, (size_t)ins_len); + // block handled here + if (u_save(oap->start.lnum, (linenr_T)(oap->end.lnum + 1)) == OK) { + block_insert(oap, ins_text, (oap->op_type == OP_INSERT), &bd); + } curwin->w_cursor.col = oap->start.col; check_cursor(); @@ -2139,8 +2130,10 @@ int op_change(oparg_T *oap) long ins_len; long pre_textlen = 0; long pre_indent = 0; - char_u *firstline; - char_u *ins_text, *newp, *oldp; + char_u *newp; + char_u *firstline; + char_u *ins_text; + char_u *oldp; struct block_def bd; l = oap->start.col; @@ -2198,14 +2191,14 @@ int op_change(oparg_T *oap) long new_indent = (long)(skipwhite(firstline) - firstline); pre_textlen += new_indent - pre_indent; - bd.textcol += new_indent - pre_indent; + bd.textcol += (colnr_T)(new_indent - pre_indent); } ins_len = (long)STRLEN(firstline) - pre_textlen; if (ins_len > 0) { /* Subsequent calls to ml_get() flush the firstline data - take a * copy of the inserted text. */ - ins_text = (char_u *) xmalloc((size_t)(ins_len + 1)); + ins_text = (char_u *)xmalloc((size_t)(ins_len + 1)); STRLCPY(ins_text, firstline + bd.textcol, ins_len + 1); for (linenr = oap->start.lnum + 1; linenr <= oap->end.lnum; linenr++) { @@ -2218,11 +2211,13 @@ int op_change(oparg_T *oap) if (bd.is_short) { vpos.lnum = linenr; (void)getvpos(&vpos, oap->start_vcol); - } else + } else { vpos.coladd = 0; + } oldp = ml_get(linenr); - newp = (char_u *) xmalloc((size_t)(STRLEN(oldp) + vpos.coladd + ins_len + 1)); - /* copy up to block start */ + newp = xmalloc(STRLEN(oldp) + (size_t)vpos.coladd + + (size_t)ins_len + 1); + // copy up to block start memmove(newp, oldp, (size_t)bd.textcol); offset = bd.textcol; memset(newp + offset, ' ', (size_t)vpos.coladd); @@ -2272,9 +2267,7 @@ void free_register(yankreg_T *reg) { set_yreg_additional_data(reg, NULL); if (reg->y_array != NULL) { - long i; - - for (i = reg->y_size - 1; i >= 0; i--) { + for (size_t i = reg->y_size; i-- > 0;) { // from y_size - 1 to 0 included xfree(reg->y_array[i]); } xfree(reg->y_array); @@ -2311,30 +2304,27 @@ bool op_yank(oparg_T *oap, bool message) static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) { - long y_idx; /* index in y_array[] */ - yankreg_T *curr; /* copy of current register */ - yankreg_T newreg; /* new yank register when appending */ - char_u **new_ptr; - linenr_T lnum; /* current line number */ - long j; + yankreg_T newreg; // new yank register when appending + char_u **new_ptr; + linenr_T lnum; // current line number + size_t j; MotionType yank_type = oap->motion_type; - long yanklines = oap->line_count; + size_t yanklines = (size_t)oap->line_count; linenr_T yankendlnum = oap->end.lnum; - char_u *p; - char_u *pnew; + char_u *p; + char_u *pnew; struct block_def bd; - curr = reg; - /* append to existing contents */ - if (append && reg->y_array != NULL) + yankreg_T *curr = reg; // copy of current register + // append to existing contents + if (append && reg->y_array != NULL) { reg = &newreg; - else - free_register(reg); /* free previously yanked lines */ + } else { + free_register(reg); // free previously yanked lines + } - /* - * If the cursor was in column 1 before and after the movement, and the - * operator is not inclusive, the yank is always linewise. - */ + // If the cursor was in column 1 before and after the movement, and the + // operator is not inclusive, the yank is always linewise. if (oap->motion_type == kMTCharWise && oap->start.col == 0 && !oap->inclusive @@ -2353,7 +2343,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) reg->additional_data = NULL; reg->timestamp = os_time(); - y_idx = 0; + size_t y_idx = 0; // index in y_array[] lnum = oap->start.lnum; if (yank_type == kMTBlockWise) { @@ -2481,7 +2471,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) yanklines = 0; } // Some versions of Vi use ">=" here, some don't... - if (yanklines > p_report) { + if (yanklines > (size_t)p_report) { // redisplay now, so message is not deleted update_topline_redraw(); if (yanklines == 1) { @@ -2512,10 +2502,10 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) return; } -static void yank_copy_line(yankreg_T *reg, struct block_def *bd, long y_idx) +static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx) { - char_u *pnew = xmallocz(bd->startspaces + bd->endspaces + bd->textlen); - + char_u *pnew = xmallocz((size_t)(bd->startspaces + bd->endspaces + + bd->textlen)); reg->y_array[y_idx] = pnew; memset(pnew, ' ', (size_t)bd->startspaces); pnew += bd->startspaces; @@ -2548,7 +2538,7 @@ static void yank_do_autocmd(oparg_T *oap, yankreg_T *reg) // the yanked text list_T *list = list_alloc(); - for (linenr_T i = 0; i < reg->y_size; i++) { + for (size_t i = 0; i < reg->y_size; i++) { list_append_string(list, reg->y_array[i], -1); } list->lv_lock = VAR_FIXED; @@ -2565,7 +2555,7 @@ static void yank_do_autocmd(oparg_T *oap, yankreg_T *reg) dict_add_nr_str(dict, "regname", 0, (char_u *)buf); // kind of operation (yank/delete/change) - buf[0] = get_op_char(oap->op_type); + buf[0] = (char)get_op_char(oap->op_type); buf[1] = NUL; dict_add_nr_str(dict, "operator", 0, (char_u *)buf); @@ -2582,23 +2572,24 @@ static void yank_do_autocmd(oparg_T *oap, yankreg_T *reg) /* * Put contents of register "regname" into the text. * Caller must check "regname" to be valid! - * "flags": PUT_FIXINDENT make indent look nice - * PUT_CURSEND leave cursor after end of new text - * PUT_LINE force linewise put (":put") + * "flags": PUT_FIXINDENT make indent look nice + * PUT_CURSEND leave cursor after end of new text + * PUT_LINE force linewise put (":put") dir: BACKWARD for 'P', FORWARD for 'p' */ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) { - char_u *ptr; - char_u *newp, *oldp; + char_u *ptr; + char_u *newp; + char_u *oldp; int yanklen; - int totlen = 0; /* init for gcc */ + size_t totlen = 0; // init for gcc linenr_T lnum; colnr_T col; - long i; // index in y_array[] + size_t i; // index in y_array[] MotionType y_type; - long y_size; - int oldlen; - long y_width = 0; + size_t y_size; + size_t oldlen; + int y_width = 0; colnr_T vcol; int delcount; int incr = 0; @@ -2705,7 +2696,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) if (curbuf->terminal) { for (int i = 0; i < count; i++) { // feed the lines to the terminal - for (int j = 0; j < y_size; j++) { + for (size_t j = 0; j < y_size; j++) { if (j) { // terminate the previous line terminal_send(curbuf->terminal, "\n", 1); @@ -2736,7 +2727,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) if (dir == FORWARD && *p != NUL) { mb_ptr_adv(p); } - ptr = vim_strnsave(oldp, p - oldp); + ptr = vim_strnsave(oldp, (size_t)(p - oldp)); ml_replace(curwin->w_cursor.lnum, ptr, false); nr_lines++; dir = FORWARD; @@ -2761,11 +2752,13 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) } if (y_type == kMTBlockWise) { - lnum = curwin->w_cursor.lnum + y_size + 1; - if (lnum > curbuf->b_ml.ml_line_count) + lnum = curwin->w_cursor.lnum + (linenr_T)y_size + 1; + if (lnum > curbuf->b_ml.ml_line_count) { lnum = curbuf->b_ml.ml_line_count + 1; - if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL) + } + if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL) { goto end; + } } else if (y_type == kMTLineWise) { lnum = curwin->w_cursor.lnum; /* Correct line number for closed fold. Don't move the cursor yet, @@ -2811,7 +2804,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) * Block mode */ if (y_type == kMTBlockWise) { - char c = gchar_cursor(); + int c = gchar_cursor(); colnr_T endcol2 = 0; if (dir == FORWARD && c != NUL) { @@ -2864,7 +2857,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) } /* get the old line and advance to the position to insert at */ oldp = get_cursor_line_ptr(); - oldlen = (int)STRLEN(oldp); + oldlen = STRLEN(oldp); for (ptr = oldp; vcol < col && *ptr; ) { /* Count a tab for what it's worth (if list mode not on) */ incr = lbr_chartabsize_adv(oldp, &ptr, (colnr_T)vcol); @@ -2901,10 +2894,11 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) if (spaces < 0) spaces = 0; - /* insert the new text */ - totlen = count * (yanklen + spaces) + bd.startspaces + bd.endspaces; - newp = (char_u *) xmalloc((size_t)(totlen + oldlen + 1)); - /* copy part up to cursor to new line */ + // insert the new text + totlen = (size_t)(count * (yanklen + spaces) + + bd.startspaces + bd.endspaces); + newp = (char_u *) xmalloc(totlen + oldlen + 1); + // copy part up to cursor to new line ptr = newp; memmove(ptr, oldp, (size_t)bd.textcol); ptr += bd.textcol; @@ -2925,10 +2919,10 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) /* may insert some spaces after the new text */ memset(ptr, ' ', (size_t)bd.endspaces); ptr += bd.endspaces; - /* move the text after the cursor to the end of the line. */ + // move the text after the cursor to the end of the line. memmove(ptr, oldp + bd.textcol + delcount, - (size_t)(oldlen - bd.textcol - delcount + 1)); - ml_replace(curwin->w_cursor.lnum, newp, FALSE); + (size_t)((int)oldlen - bd.textcol - delcount + 1)); + ml_replace(curwin->w_cursor.lnum, newp, false); ++curwin->w_cursor.lnum; if (i == 0) @@ -2943,7 +2937,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) /* adjust '] mark */ curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1; - curbuf->b_op_end.col = bd.textcol + totlen - 1; + curbuf->b_op_end.col = bd.textcol + (colnr_T)totlen - 1; curbuf->b_op_end.coladd = 0; if (flags & PUT_CURSEND) { colnr_T len; @@ -2994,13 +2988,13 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) */ if (y_type == kMTCharWise && y_size == 1) { do { - totlen = count * yanklen; + totlen = (size_t)(count * yanklen); if (totlen > 0) { oldp = ml_get(lnum); newp = (char_u *) xmalloc((size_t)(STRLEN(oldp) + totlen + 1)); memmove(newp, oldp, (size_t)col); ptr = newp + col; - for (i = 0; i < count; i++) { + for (i = 0; i < (size_t)count; i++) { memmove(ptr, y_array[0], (size_t)yanklen); ptr += yanklen; } @@ -3037,7 +3031,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) // Then append y_array[0] to first line. lnum = new_cursor.lnum; ptr = ml_get(lnum) + col; - totlen = (int)STRLEN(y_array[y_size - 1]); + totlen = STRLEN(y_array[y_size - 1]); newp = (char_u *) xmalloc((size_t)(STRLEN(ptr) + totlen + 1)); STRCPY(newp, y_array[y_size - 1]); STRCAT(newp, ptr); @@ -3217,22 +3211,19 @@ int get_register_name(int num) */ void ex_display(exarg_T *eap) { - int i, n; - long j; - char_u *p; - yankreg_T *yb; + char_u *p; + yankreg_T *yb; int name; - int attr; - char_u *arg = eap->arg; + char_u *arg = eap->arg; int clen; if (arg != NULL && *arg == NUL) arg = NULL; - attr = hl_attr(HLF_8); + int attr = hl_attr(HLF_8); /* Highlight title */ MSG_PUTS_TITLE(_("\n--- Registers ---")); - for (i = -1; i < NUM_REGISTERS && !got_int; i++) { + for (int i = -1; i < NUM_REGISTERS && !got_int; i++) { name = get_register_name(i); if (arg != NULL && vim_strchr(arg, name) == NULL) { @@ -3261,8 +3252,8 @@ void ex_display(exarg_T *eap) msg_putchar(name); MSG_PUTS(" "); - n = (int)Columns - 6; - for (j = 0; j < yb->y_size && n > 1; ++j) { + int n = (int)Columns - 6; + for (size_t j = 0; j < yb->y_size && n > 1; j++) { if (j) { MSG_PUTS_ATTR("^J", attr); n -= 2; @@ -3438,7 +3429,7 @@ static char_u *skip_comment(char_u *line, int process, int include_space, int *i // to set those marks. // // return FAIL for failure, OK otherwise -int do_join(long count, +int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions, @@ -3461,24 +3452,21 @@ int do_join(long count, && has_format_option(FO_REMOVE_COMS); int prev_was_comment; - assert(count > 1); - if (save_undo && u_save((linenr_T)(curwin->w_cursor.lnum - 1), - (linenr_T)(curwin->w_cursor.lnum + count)) == FAIL) + if (save_undo && u_save(curwin->w_cursor.lnum - 1, + curwin->w_cursor.lnum + (linenr_T)count) == FAIL) { return FAIL; - - /* Allocate an array to store the number of spaces inserted before each - * line. We will use it to pre-compute the length of the new line and the - * proper placement of each original line in the new one. */ + } + // Allocate an array to store the number of spaces inserted before each + // line. We will use it to pre-compute the length of the new line and the + // proper placement of each original line in the new one. spaces = xcalloc(count, 1); if (remove_comments) { comments = xcalloc(count, sizeof(*comments)); } - /* - * Don't move anything, just compute the final line length - * and setup the array of space strings lengths - */ - for (t = 0; t < count; ++t) { + // Don't move anything, just compute the final line length + // and setup the array of space strings lengths + for (t = 0; t < (linenr_T)count; t++) { curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t)); if (t == 0 && setmark) { // Set the '[ mark. @@ -3558,7 +3546,7 @@ int do_join(long count, * column. This is not Vi compatible, but Vi deletes the marks, thus that * should not really be a problem. */ - for (t = count - 1;; --t) { + for (t = (linenr_T)count - 1;; t--) { cend -= currsize; memmove(cend, curr, (size_t)currsize); if (spaces[t] > 0) { @@ -3595,8 +3583,8 @@ int do_join(long count, * have moved up (last line deleted), so the current lnum is kept in t. */ t = curwin->w_cursor.lnum; - ++curwin->w_cursor.lnum; - del_lines(count - 1, FALSE); + curwin->w_cursor.lnum++; + del_lines((long)count - 1, false); curwin->w_cursor.lnum = t; /* @@ -3778,8 +3766,8 @@ fex_format ( * Set v:lnum to the first line number and v:count to the number of lines. * Set v:char to the character to be inserted (can be NUL). */ - set_vim_var_nr(VV_LNUM, lnum); - set_vim_var_nr(VV_COUNT, count); + set_vim_var_nr(VV_LNUM, (varnumber_T)lnum); + set_vim_var_nr(VV_COUNT, (varnumber_T)count); set_vim_var_char(c); /* @@ -4473,7 +4461,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) firstdigit = 'a'; } } else { - firstdigit -= Prenum1; + firstdigit -= (int)Prenum1; } } else { if (26 - CharOrd(firstdigit) - 1 < Prenum1) { @@ -4483,7 +4471,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) firstdigit = 'z'; } } else { - firstdigit += Prenum1; + firstdigit += (int)Prenum1; } } curwin->w_cursor.col = col; @@ -4591,7 +4579,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) // Prepare the leading characters in buf1[]. // When there are many leading zeros it could be very long. // Allocate a bit too much. - buf1 = xmalloc(length + NUMBUFLEN); + buf1 = xmalloc((size_t)length + NUMBUFLEN); if (buf1 == NULL) { goto theend; } @@ -4604,7 +4592,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) length--; } if (pre == 'b' || pre == 'B' || pre == 'x' || pre == 'X') { - *ptr++ = pre; + *ptr++ = (char_u)pre; length--; } @@ -4767,8 +4755,6 @@ static void *get_reg_wrap_one_line(char_u *s, int flags) /// @returns NULL for error. void *get_reg_contents(int regname, int flags) { - long i; - // Don't allow using an expression register inside an expression. if (regname == '=') { if (flags & kGRegNoExpr) { @@ -4804,7 +4790,7 @@ void *get_reg_contents(int regname, int flags) if (flags & kGRegList) { list_T *list = list_alloc(); - for (int i = 0; i < reg->y_size; i++) { + for (size_t i = 0; i < reg->y_size; i++) { list_append_string(list, reg->y_array[i], -1); } @@ -4815,7 +4801,7 @@ void *get_reg_contents(int regname, int flags) * Compute length of resulting string. */ size_t len = 0; - for (i = 0; i < reg->y_size; i++) { + for (size_t i = 0; i < reg->y_size; i++) { len += STRLEN(reg->y_array[i]); /* * Insert a newline between lines and after last line if @@ -4832,7 +4818,7 @@ void *get_reg_contents(int regname, int flags) * Copy the lines of the yank register into the string. */ len = 0; - for (i = 0; i < reg->y_size; i++) { + for (size_t i = 0; i < reg->y_size; i++) { STRCPY(retval + len, reg->y_array[i]); len += STRLEN(retval + len); @@ -4888,7 +4874,7 @@ void write_reg_contents(int name, const char_u *str, ssize_t len, void write_reg_contents_lst(int name, char_u **strings, int maxlen, bool must_append, MotionType yank_type, - long block_len) + colnr_T block_len) { if (name == '/' || name == '=') { char_u *s = strings[0]; @@ -4913,7 +4899,8 @@ void write_reg_contents_lst(int name, char_u **strings, int maxlen, return; } - str_to_reg(reg, yank_type, (char_u *) strings, -1, block_len, true); + str_to_reg(reg, yank_type, (char_u *)strings, STRLEN((char_u *)strings), + block_len, true); finish_write_reg(name, reg, old_y_previous); } @@ -4941,7 +4928,7 @@ void write_reg_contents_ex(int name, ssize_t len, bool must_append, MotionType yank_type, - long block_len) + colnr_T block_len) { if (len < 0) { len = (ssize_t) STRLEN(str); @@ -4991,7 +4978,7 @@ void write_reg_contents_ex(int name, // Copy the input string into the adjusted memory at the specified // offset. expr_line = xrealloc(expr_line, totlen + 1); - memcpy(expr_line + offset, str, (size_t) len); + memcpy(expr_line + offset, str, (size_t)len); expr_line[totlen] = NUL; return; @@ -5005,7 +4992,7 @@ void write_reg_contents_ex(int name, if (!(reg = init_write_reg(name, &old_y_previous, must_append))) { return; } - str_to_reg(reg, yank_type, str, len, block_len, false); + str_to_reg(reg, yank_type, str, (size_t)len, block_len, false); finish_write_reg(name, reg, old_y_previous); } @@ -5061,7 +5048,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, (y_ptr->y_size + newlines) * sizeof(char_u *)); y_ptr->y_array = pp; - linenr_T lnum = y_ptr->y_size; // The current line number. + size_t lnum = y_ptr->y_size; // The current line number. // If called with `blocklen < 0`, we have to update the yank reg's width. size_t maxlen = 0; @@ -5080,7 +5067,9 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, for (const char_u *start = str, *end = str + len; start < end + extraline; start += line_len + 1, lnum++) { - line_len = (const char_u *) xmemscan(start, '\n', end - start) - start; + assert(end - start >= 0); + line_len = (size_t)((char_u *)xmemscan(start, '\n', + (size_t)(end - start)) - start); if (line_len > maxlen) { maxlen = line_len; } @@ -5090,7 +5079,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, char_u *s = xmallocz(line_len + extra); memcpy(s, pp[lnum], extra); memcpy(s + extra, start, line_len); - ssize_t s_len = extra + line_len; + size_t s_len = extra + line_len; if (append) { xfree(pp[lnum]); @@ -5474,7 +5463,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) free_register(reg); list_T *args = list_alloc(); - char_u regname = name; + char_u regname = (char_u)name; list_append_string(args, ®name, 1); typval_T result = eval_call_provider("clipboard", "get", args); @@ -5519,8 +5508,8 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) reg->y_type = kMTUnknown; } - reg->y_array = xcalloc(lines->lv_len, sizeof(uint8_t *)); - reg->y_size = lines->lv_len; + reg->y_array = xcalloc((size_t)lines->lv_len, sizeof(uint8_t *)); + reg->y_size = (size_t)lines->lv_len; reg->additional_data = NULL; reg->timestamp = 0; // Timestamp is not saved for clipboard registers because clipboard registers @@ -5551,14 +5540,15 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) } if (reg->y_type == kMTBlockWise) { - int maxlen = 0; - for (int i = 0; i < reg->y_size; i++) { - int rowlen = STRLEN(reg->y_array[i]); + size_t maxlen = 0; + for (size_t i = 0; i < reg->y_size; i++) { + size_t rowlen = STRLEN(reg->y_array[i]); if (rowlen > maxlen) { maxlen = rowlen; } } - reg->y_width = maxlen-1; + assert(maxlen <= INT_MAX); + reg->y_width = (int)maxlen - 1; } *target = reg; @@ -5566,7 +5556,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) err: if (reg->y_array) { - for (int i = 0; i < reg->y_size; i++) { + for (size_t i = 0; i < reg->y_size; i++) { xfree(reg->y_array[i]); } xfree(reg->y_array); @@ -5590,7 +5580,7 @@ static void set_clipboard(int name, yankreg_T *reg) list_T *lines = list_alloc(); - for (int i = 0; i < reg->y_size; i++) { + for (size_t i = 0; i < reg->y_size; i++) { list_append_string(lines, reg->y_array[i], -1); } @@ -5615,7 +5605,7 @@ static void set_clipboard(int name, yankreg_T *reg) } list_append_string(args, ®type, 1); - char_u regname = name; + char_u regname = (char_u)name; list_append_string(args, ®name, 1); (void)eval_call_provider("clipboard", "set", args); @@ -5678,8 +5668,8 @@ const void *op_register_iter(const void *const iter, char *const name, if (iter_reg - &(y_regs[0]) == NUM_SAVED_REGISTERS || reg_empty(iter_reg)) { return NULL; } - size_t iter_off = iter_reg - &(y_regs[0]); - *name = (char) get_register_name(iter_off); + int iter_off = (int)(iter_reg - &(y_regs[0])); + *name = (char)get_register_name(iter_off); *reg = *iter_reg; while (++iter_reg - &(y_regs[0]) < NUM_SAVED_REGISTERS) { if (!reg_empty(iter_reg)) { diff --git a/src/nvim/ops.h b/src/nvim/ops.h index 8c8a586957..44df2e9e0c 100644 --- a/src/nvim/ops.h +++ b/src/nvim/ops.h @@ -79,7 +79,7 @@ enum GRegFlags { /// Definition of one register typedef struct yankreg { char_u **y_array; ///< Pointer to an array of line pointers. - linenr_T y_size; ///< Number of lines in y_array. + size_t y_size; ///< Number of lines in y_array. MotionType y_type; ///< Register type colnr_T y_width; ///< Register width (only valid for y_type == kBlockWise). Timestamp timestamp; ///< Time when register was last modified. diff --git a/src/nvim/option.c b/src/nvim/option.c index 45ebb4fa4c..52a1fd8558 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2129,6 +2129,7 @@ void check_buf_options(buf_T *buf) check_string_option(&buf->b_p_nf); check_string_option(&buf->b_p_qe); check_string_option(&buf->b_p_syn); + check_string_option(&buf->b_s.b_syn_isk); check_string_option(&buf->b_s.b_p_spc); check_string_option(&buf->b_s.b_p_spf); check_string_option(&buf->b_s.b_p_spl); @@ -3402,9 +3403,10 @@ char_u *check_stl_option(char_u *s) if (!*s) break; s++; - if (*s != '%' && *s != ')') - ++itemcnt; - if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_MIDDLEMARK) { + if (*s != '%' && *s != ')') { + itemcnt++; + } + if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_SEPARATE) { s++; continue; } @@ -4029,15 +4031,16 @@ set_num_option ( errmsg = e_invarg; curwin->w_p_fdc = 12; } - } - /* 'shiftwidth' or 'tabstop' */ - else if (pp == &curbuf->b_p_sw || pp == &curbuf->b_p_ts) { - if (foldmethodIsIndent(curwin)) + // 'shiftwidth' or 'tabstop' + } else if (pp == &curbuf->b_p_sw || pp == (long *)&curbuf->b_p_ts) { + if (foldmethodIsIndent(curwin)) { foldUpdateAll(curwin); - /* When 'shiftwidth' changes, or it's zero and 'tabstop' changes: - * parse 'cinoptions'. */ - if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0) + } + // When 'shiftwidth' changes, or it's zero and 'tabstop' changes: + // parse 'cinoptions'. + if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0) { parse_cino(curbuf); + } } /* 'maxcombine' */ else if (pp == &p_mco) { @@ -5606,6 +5609,7 @@ void buf_copy_options(buf_T *buf, int flags) /* Don't copy 'syntax', it must be set */ buf->b_p_syn = empty_option; buf->b_p_smc = p_smc; + buf->b_s.b_syn_isk = empty_option; buf->b_s.b_p_spc = vim_strsave(p_spc); (void)compile_cap_prog(&buf->b_s); buf->b_s.b_p_spf = vim_strsave(p_spf); @@ -5655,7 +5659,7 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_isk = save_p_isk; else { buf->b_p_isk = vim_strsave(p_isk); - did_isk = TRUE; + did_isk = true; buf->b_p_ts = p_ts; buf->b_help = false; if (buf->b_p_bt[0] == 'h') diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 904e97f8ca..b1a2b00bdb 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -258,7 +258,7 @@ enum { STL_ARGLISTSTAT = 'a', ///< Argument list status as (x of y). STL_PAGENUM = 'N', ///< Page number (when printing). STL_VIM_EXPR = '{', ///< Start of expression to substitute. - STL_MIDDLEMARK = '=', ///< Separation between left and right. + STL_SEPARATE = '=', ///< Separation between alignment sections. STL_TRUNCMARK = '<', ///< Truncation mark if line is too long. STL_USER_HL = '*', ///< Highlight from (User)1..9 or 0. STL_HIGHLIGHT = '#', ///< Highlight name. @@ -274,7 +274,7 @@ enum { STL_HELPFLAG, STL_HELPFLAG_ALT, STL_FILETYPE, STL_FILETYPE_ALT, \ STL_PREVIEWFLAG, STL_PREVIEWFLAG_ALT, STL_MODIFIED, STL_MODIFIED_ALT, \ STL_QUICKFIX, STL_PERCENTAGE, STL_ALTPERCENT, STL_ARGLISTSTAT, STL_PAGENUM, \ - STL_VIM_EXPR, STL_MIDDLEMARK, STL_TRUNCMARK, STL_USER_HL, STL_HIGHLIGHT, \ + STL_VIM_EXPR, STL_SEPARATE, STL_TRUNCMARK, STL_USER_HL, STL_HIGHLIGHT, \ STL_TABPAGENR, STL_TABCLOSENR, STL_CLICK_FUNC, \ 0, \ }) diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 143a7160b0..08122828bd 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -398,7 +398,6 @@ int os_setperm(const char_u *name, int perm) /// @note If the `owner` or `group` is specified as `-1`, then that ID is not /// changed. int os_fchown(int file_descriptor, uv_uid_t owner, uv_gid_t group) - FUNC_ATTR_NONNULL_ALL { uv_fs_t request; int result = uv_fs_fchown(&fs_loop, &request, file_descriptor, diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 7687b14f02..0c46dc96ee 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -60,7 +60,7 @@ void input_start(int fd) } global_fd = fd; - rstream_init_fd(&loop, &read_stream, fd, READ_BUFFER_SIZE, NULL); + rstream_init_fd(&main_loop, &read_stream, fd, READ_BUFFER_SIZE, NULL); rstream_start(&read_stream, read_cb); } @@ -87,8 +87,8 @@ static void create_cursorhold_event(void) // have been called(inbuf_poll would return kInputAvail) // TODO(tarruda): Cursorhold should be implemented as a timer set during the // `state_check` callback for the states where it can be triggered. - assert(!events_enabled || queue_empty(loop.events)); - queue_put(loop.events, cursorhold_event, 0); + assert(!events_enabled || queue_empty(main_loop.events)); + queue_put(main_loop.events, cursorhold_event, 0); } // Low level input function @@ -147,7 +147,7 @@ bool os_char_avail(void) void os_breakcheck(void) { if (!got_int) { - loop_poll_events(&loop, 0); + loop_poll_events(&main_loop, 0); } } @@ -322,7 +322,7 @@ static bool input_poll(int ms) prof_inchar_enter(); } - LOOP_PROCESS_EVENTS_UNTIL(&loop, NULL, ms, input_ready() || input_eof); + LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms, input_ready() || input_eof); if (do_profiling == PROF_YES && ms) { prof_inchar_exit(); @@ -419,5 +419,5 @@ static void read_error_exit(void) static bool pending_events(void) { - return events_enabled && !queue_empty(loop.events); + return events_enabled && !queue_empty(main_loop.events); } diff --git a/src/nvim/os/pty_process.h b/src/nvim/os/pty_process.h new file mode 100644 index 0000000000..94923499ca --- /dev/null +++ b/src/nvim/os/pty_process.h @@ -0,0 +1,9 @@ +#ifndef NVIM_OS_PTY_PROCESS_H +#define NVIM_OS_PTY_PROCESS_H + +#ifdef WIN32 +# include "nvim/os/pty_process_win.h" +#else +# include "nvim/os/pty_process_unix.h" +#endif +#endif // NVIM_OS_PTY_PROCESS_H diff --git a/src/nvim/event/pty_process.c b/src/nvim/os/pty_process_unix.c index 8eef72f12f..436de030ba 100644 --- a/src/nvim/event/pty_process.c +++ b/src/nvim/os/pty_process_unix.c @@ -26,11 +26,12 @@ #include "nvim/event/rstream.h" #include "nvim/event/wstream.h" #include "nvim/event/process.h" -#include "nvim/event/pty_process.h" +#include "nvim/os/pty_process_unix.h" #include "nvim/log.h" +#include "nvim/os/os.h" #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "event/pty_process.c.generated.h" +# include "os/pty_process_unix.c.generated.h" #endif bool pty_process_spawn(PtyProcess *ptyproc) @@ -44,7 +45,7 @@ bool pty_process_spawn(PtyProcess *ptyproc) Process *proc = (Process *)ptyproc; assert(!proc->err); uv_signal_start(&proc->loop->children_watcher, chld_handler, SIGCHLD); - ptyproc->winsize = (struct winsize){ptyproc->height, ptyproc->width, 0, 0}; + ptyproc->winsize = (struct winsize){ ptyproc->height, ptyproc->width, 0, 0 }; uv_disable_stdio_inheritance(); int master; int pid = forkpty(&master, NULL, &termios, &ptyproc->winsize); @@ -86,11 +87,10 @@ error: return false; } -void pty_process_resize(PtyProcess *ptyproc, uint16_t width, - uint16_t height) +void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height) FUNC_ATTR_NONNULL_ALL { - ptyproc->winsize = (struct winsize){height, width, 0, 0}; + ptyproc->winsize = (struct winsize){ height, width, 0, 0 }; ioctl(ptyproc->tty_fd, TIOCSWINSZ, &ptyproc->winsize); } @@ -132,6 +132,12 @@ static void init_child(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL signal(SIGTERM, SIG_DFL); signal(SIGALRM, SIG_DFL); + Process *proc = (Process *)ptyproc; + if (proc->cwd && os_chdir(proc->cwd) != 0) { + fprintf(stderr, "chdir failed: %s\n", strerror(errno)); + return; + } + setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1); execvp(ptyproc->process.argv[0], ptyproc->process.argv); fprintf(stderr, "execvp failed: %s\n", strerror(errno)); diff --git a/src/nvim/event/pty_process.h b/src/nvim/os/pty_process_unix.h index 446d7fd3c8..f7c57b3839 100644 --- a/src/nvim/event/pty_process.h +++ b/src/nvim/os/pty_process_unix.h @@ -1,5 +1,5 @@ -#ifndef NVIM_EVENT_PTY_PROCESS_H -#define NVIM_EVENT_PTY_PROCESS_H +#ifndef NVIM_OS_PTY_PROCESS_UNIX_H +#define NVIM_OS_PTY_PROCESS_UNIX_H #include <sys/ioctl.h> @@ -25,6 +25,7 @@ static inline PtyProcess pty_process_init(Loop *loop, void *data) } #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "event/pty_process.h.generated.h" +# include "os/pty_process_unix.h.generated.h" #endif -#endif // NVIM_EVENT_PTY_PROCESS_H + +#endif // NVIM_OS_PTY_PROCESS_UNIX_H diff --git a/src/nvim/os/pty_process_win.h b/src/nvim/os/pty_process_win.h new file mode 100644 index 0000000000..20cc589925 --- /dev/null +++ b/src/nvim/os/pty_process_win.h @@ -0,0 +1,28 @@ +#ifndef NVIM_OS_PTY_PROCESS_WIN_H +#define NVIM_OS_PTY_PROCESS_WIN_H + +#include "nvim/event/libuv_process.h" + +typedef struct pty_process { + Process process; + char *term_name; + uint16_t width, height; +} PtyProcess; + +#define pty_process_spawn(job) libuv_process_spawn((LibuvProcess *)job) +#define pty_process_close(job) libuv_process_close((LibuvProcess *)job) +#define pty_process_close_master(job) libuv_process_close((LibuvProcess *)job) +#define pty_process_resize(job, width, height) +#define pty_process_teardown(loop) + +static inline PtyProcess pty_process_init(Loop *loop, void *data) +{ + PtyProcess rv; + rv.process = process_init(loop, kProcessTypePty, data); + rv.term_name = NULL; + rv.width = 80; + rv.height = 24; + return rv; +} + +#endif // NVIM_OS_PTY_PROCESS_WIN_H diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index f5a1637c94..988620b145 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -14,6 +14,7 @@ #include "nvim/os/shell.h" #include "nvim/os/signal.h" #include "nvim/types.h" +#include "nvim/main.h" #include "nvim/vim.h" #include "nvim/message.h" #include "nvim/memory.h" @@ -205,16 +206,16 @@ static int do_os_system(char **argv, xstrlcpy(prog, argv[0], MAXPATHL); Stream in, out, err; - LibuvProcess uvproc = libuv_process_init(&loop, &buf); + LibuvProcess uvproc = libuv_process_init(&main_loop, &buf); Process *proc = &uvproc.process; - Queue *events = queue_new_child(loop.events); + Queue *events = queue_new_child(main_loop.events); proc->events = events; proc->argv = argv; proc->in = input != NULL ? &in : NULL; proc->out = &out; proc->err = &err; if (!process_spawn(proc)) { - loop_poll_events(&loop, 0); + loop_poll_events(&main_loop, 0); // Failed, probably due to `sh` not being executable if (!silent) { MSG_PUTS(_("\nCannot execute ")); diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c index 0ff6016e32..4abc9cfc36 100644 --- a/src/nvim/os/signal.c +++ b/src/nvim/os/signal.c @@ -8,6 +8,7 @@ #include "nvim/globals.h" #include "nvim/memline.h" #include "nvim/eval.h" +#include "nvim/main.h" #include "nvim/memory.h" #include "nvim/misc1.h" #include "nvim/misc2.h" @@ -28,10 +29,10 @@ static bool rejecting_deadly; void signal_init(void) { - signal_watcher_init(&loop, &spipe, NULL); - signal_watcher_init(&loop, &shup, NULL); - signal_watcher_init(&loop, &squit, NULL); - signal_watcher_init(&loop, &sterm, NULL); + signal_watcher_init(&main_loop, &spipe, NULL); + signal_watcher_init(&main_loop, &shup, NULL); + signal_watcher_init(&main_loop, &squit, NULL); + signal_watcher_init(&main_loop, &sterm, NULL); #ifdef SIGPIPE signal_watcher_start(&spipe, on_signal, SIGPIPE); #endif @@ -41,7 +42,7 @@ void signal_init(void) #endif signal_watcher_start(&sterm, on_signal, SIGTERM); #ifdef SIGPWR - signal_watcher_init(&loop, &spwr, NULL); + signal_watcher_init(&main_loop, &spwr, NULL); signal_watcher_start(&spwr, on_signal, SIGPWR); #endif } diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c index 188f0802c9..2205ad0958 100644 --- a/src/nvim/os/time.c +++ b/src/nvim/os/time.c @@ -9,6 +9,7 @@ #include "nvim/os/time.h" #include "nvim/event/loop.h" #include "nvim/vim.h" +#include "nvim/main.h" static uv_mutex_t delay_mutex; static uv_cond_t delay_cond; @@ -43,7 +44,7 @@ void os_delay(uint64_t milliseconds, bool ignoreinput) if (milliseconds > INT_MAX) { milliseconds = INT_MAX; } - LOOP_PROCESS_EVENTS_UNTIL(&loop, NULL, (int)milliseconds, got_int); + LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, (int)milliseconds, got_int); } else { os_microdelay(milliseconds * 1000); } diff --git a/src/nvim/po/eo.po b/src/nvim/po/eo.po index 5b0cb2260b..6bc76506ae 100644 --- a/src/nvim/po/eo.po +++ b/src/nvim/po/eo.po @@ -23,8 +23,8 @@ msgid "" msgstr "" "Project-Id-Version: Vim(Esperanto)\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-07-30 17:54+0200\n" -"PO-Revision-Date: 2015-07-30 18:00+0200\n" +"POT-Creation-Date: 2016-02-13 23:42+0100\n" +"PO-Revision-Date: 2016-02-13 23:45+0100\n" "Last-Translator: Dominique PELLÉ <dominique.pelle@gmail.com>\n" "Language-Team: \n" "Language: eo\n" @@ -504,10 +504,6 @@ msgstr "E686: Argumento de %s devas esti Listo" msgid "E712: Argument of %s must be a List or Dictionary" msgstr "E712: Argumento de %s devas esti Listo aÅ Vortaro" -#: ../eval.c:144 -msgid "E713: Cannot use empty key for Dictionary" -msgstr "E713: Ne eblas uzi malplenan Ålosilon de Vortaro" - #: ../eval.c:145 msgid "E714: List required" msgstr "E714: Listo bezonata" @@ -657,6 +653,9 @@ msgstr "E110: Mankas ')'" msgid "E695: Cannot index a Funcref" msgstr "E695: Ne eblas indeksi Funcref" +msgid "E909: Cannot index a special variable" +msgstr "E909: Ne eblas indeksi specialan variablon" + #: ../eval.c:4839 #, c-format msgid "E112: Option name missing: %s" @@ -689,7 +688,7 @@ msgstr "E697: Mankas fino de Listo ']': %s" #: ../eval.c:5750 msgid "Not enough memory to set references, garbage collection aborted!" -msgstr "Ne sufiĉa memory por valorigi referencojn, senrubigado ĉesigita!" +msgstr "Ne sufiĉa memoro por valorigi referencojn, senrubigado ĉesigita!" #: ../eval.c:6475 #, c-format @@ -874,6 +873,18 @@ msgstr "E745: Uzo de Listo kiel Nombro" msgid "E728: Using a Dictionary as a Number" msgstr "E728: Uzo de Vortaro kiel Nombro" +msgid "E891: Using a Funcref as a Float" +msgstr "E891: Uzo de Funcref kiel Glitpunktnombro" + +msgid "E892: Using a String as a Float" +msgstr "E892: Uzo de Ĉeno kiel Glitpunktnombro" + +msgid "E893: Using a List as a Float" +msgstr "E893: Uzo de Listo kiel Glitpunktnombro" + +msgid "E894: Using a Dictionary as a Float" +msgstr "E894: Uzo de Vortaro kiel Glitpunktnombro" + #: ../eval.c:16259 msgid "E729: using Funcref as a String" msgstr "E729: uzo de Funcref kiel Ĉeno" @@ -886,6 +897,9 @@ msgstr "E730: uzo de Listo kiel Ĉeno" msgid "E731: using Dictionary as a String" msgstr "E731: uzo de Vortaro kiel Ĉeno" +msgid "E908: using an invalid value as a String" +msgstr "E908: uzo de nevalida valoro kiel Ĉeno" + #: ../eval.c:16619 #, c-format msgid "E706: Variable type mismatch for: %s" @@ -1391,6 +1405,13 @@ msgstr "linio %<PRId64>: %s" msgid "cmd: %s" msgstr "kmd: %s" +msgid "frame is zero" +msgstr "kadro estas nul" + +#, c-format +msgid "frame at highest level: %d" +msgstr "kadro je la plej alta nivelo: %d" + #: ../ex_cmds2.c:322 #, c-format msgid "Breakpoint in \"%s%s\" line %<PRId64>" @@ -2861,6 +2882,9 @@ msgstr "E46: Ne eblas ÅanÄi nurlegeblan variablon \"%s\"" msgid "E794: Cannot set variable in the sandbox: \"%s\"" msgstr "E794: Ne eblas agordi variablon en la sabloludejo: \"%s\"" +msgid "E713: Cannot use empty key for Dictionary" +msgstr "E713: Ne eblas uzi malplenan Ålosilon de Vortaro" + #: ../globals.h:1076 msgid "E47: Error while reading errorfile" msgstr "E47: Eraro dum legado de erardosiero" @@ -4090,12 +4114,12 @@ msgid "" "\n" "(1) Another program may be editing the same file. If this is the case,\n" " be careful not to end up with two different instances of the same\n" -" file when making changes." +" file when making changes. Quit, or continue with caution.\n" msgstr "" "\n" -"(1) Alia programo eble redaktas la saman dosieron.\n" -" Se jes, estu singarda por ne havi du malsamajn\n" -" aperojn de la sama dosiero, kiam vi faros ÅanÄojn." +"(1) Alia programo eble redaktas la saman dosieron. Se jes, estu singarda\n" +" por ne havi du malsamajn aperojn de la sama dosiero, kiam vi faros\n" +" ÅanÄojn. Eliru aÅ daÅrigu singarde.\n" #: ../memline.c:3245 msgid " Quit, or continue with caution.\n" @@ -4792,6 +4816,15 @@ msgstr "" "\n" "Ne povis Åalti kuntekston de sekureco por " +#, c-format +msgid "Could not set security context %s for %s" +msgstr "Ne povis Åalti kuntekston de sekureco %s por %s" + +#, c-format +msgid "Could not get security context %s for %s. Removing it!" +msgstr "" +"Ne povis akiri kuntekston de sekureco %s por %s. Gi nun estas forigata!" + #: ../os_unix.c:1558 ../os_unix.c:1647 #, c-format msgid "dlerror = \"%s\"" @@ -5717,6 +5750,9 @@ msgstr "Neniu sintaksa elemento difinita por tiu bufro" msgid "E390: Illegal argument: %s" msgstr "E390: Nevalida argumento: %s" +msgid "syntax iskeyword " +msgstr "sintakso iskeyword " + #: ../syntax.c:3299 #, c-format msgid "E391: No such syntax cluster: %s" @@ -5813,6 +5849,10 @@ msgstr "E847: Tro da sintaksaj inkluzivoj" msgid "E789: Missing ']': %s" msgstr "E789: Mankas ']': %s" +#, c-format +msgid "E890: trailing char after ']': %s]%s" +msgstr "E890: vosta signo post ']': %s]%s" + #: ../syntax.c:4531 #, c-format msgid "E398: Missing '=': %s" diff --git a/src/nvim/po/it.po b/src/nvim/po/it.po index 171e155689..084102da60 100644 --- a/src/nvim/po/it.po +++ b/src/nvim/po/it.po @@ -13,13 +13,13 @@ msgid "" msgstr "" "Project-Id-Version: vim 7.4\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-08-11 20:58+0200\n" -"PO-Revision-Date: 2015-08-11 22:02+0200\n" -"Last-Translator: Vlad Sandrini <vlad.gently@gmail.com>\n" -"Language-Team: Italian Antonio Colombo <azc100@gmail." -"com> Vlad Sandrini <vlad.gently@gmail." -"com> Luciano Montanaro <mikelima@cirulla.net>\n" -"Language: \n" +"POT-Creation-Date: 2016-02-11 12:10+0100\n" +"PO-Revision-Date: 2016-02-11 14:42+0200\n" +"Last-Translator: Antonio Colombo <azc100@gmail.com>\n" +"Language-Team: Antonio Colombo <azc100@gmail.com>" +" Vlad Sandrini <vlad.gently@gmail.com" +" Luciano Montanaro <mikelima@cirulla.net>\n" +"Language: Italian\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO_8859-1\n" "Content-Transfer-Encoding: 8-bit\n" @@ -491,10 +491,6 @@ msgstr "E686: L'argomento di %s deve essere una Lista" msgid "E712: Argument of %s must be a List or Dictionary" msgstr "E712: L'argomento di %s deve essere una Lista o un Dizionario" -#: ../eval.c:144 -msgid "E713: Cannot use empty key for Dictionary" -msgstr "E713: Non posso usare una chiave nulla per il Dizionario" - #: ../eval.c:145 msgid "E714: List required" msgstr "E714: È necessaria una Lista" @@ -548,7 +544,7 @@ msgstr "E461: Nome di variabile non ammesso: %s" # nuovo #: ../eval.c:157 msgid "E806: using Float as a String" -msgstr "E806: uso di un numero con virgola come stringa" +msgstr "E806: uso di un Numero-a-virgola-mobile come Stringa" #: ../eval.c:1830 msgid "E687: Less targets than List items" @@ -635,7 +631,7 @@ msgstr "E694: Operazione non valida per Funcref" #: ../eval.c:4277 msgid "E804: Cannot use '%' with Float" -msgstr "E804: Non si può usare '%' con un numero con virgola" +msgstr "E804: Non si può usare '%' con un Numero-a-virgola-mobile" #: ../eval.c:4478 msgid "E110: Missing ')'" @@ -645,6 +641,9 @@ msgstr "E110: Manca ')'" msgid "E695: Cannot index a Funcref" msgstr "E695: Non posso indicizzare un Funcref" +msgid "E909: Cannot index a special variable" +msgstr "E909: Non posso indicizzare una variabile speciale" + #: ../eval.c:4839 #, c-format msgid "E112: Option name missing: %s" @@ -736,7 +735,7 @@ msgstr "E725: Chiamata di funzione dict in assenza di Dizionario: %s" #: ../eval.c:7453 msgid "E808: Number or Float required" -msgstr "E808: Ci vuole un numero intero o con virgola" +msgstr "E808: Ci vuole un Numero o un Numero-a-virgola-mobile" #: ../eval.c:7503 msgid "add() argument" @@ -847,7 +846,7 @@ msgstr "E677: Errore in scrittura su file temporaneo" #: ../eval.c:16159 msgid "E805: Using a Float as a Number" -msgstr "E805: Uso di un numero con virgola come intero" +msgstr "E805: Uso di un Numero-a-virgola-mobile come Numero" #: ../eval.c:16162 msgid "E703: Using a Funcref as a Number" @@ -861,6 +860,18 @@ msgstr "E745: Uso di Lista come Numero" msgid "E728: Using a Dictionary as a Number" msgstr "E728: Uso di Dizionario come Numero" +msgid "E891: Using a Funcref as a Float" +msgstr "E891: Uso di Funcref come Numero-a-virgola-mobile" + +msgid "E892: Using a String as a Float" +msgstr "E892: Uso di Stringa come Numero-a-virgola-mobile" + +msgid "E893: Using a List as a Float" +msgstr "E893: Uso di Lista come Numero-a-virgola-mobile" + +msgid "E894: Using a Dictionary as a Float" +msgstr "E894: Uso di Dizionario come Numero-a-virgola-mobile" + #: ../eval.c:16259 msgid "E729: using Funcref as a String" msgstr "E729: uso di Funcref come Stringa" @@ -873,6 +884,10 @@ msgstr "E730: uso di Lista come Stringa" msgid "E731: using Dictionary as a String" msgstr "E731: uso di Dizionario come Stringa" +# nuovo +msgid "E908: using an invalid value as a String" +msgstr "E908: uso di un valore non valido come Stringa" + #: ../eval.c:16619 #, c-format msgid "E706: Variable type mismatch for: %s" @@ -960,12 +975,14 @@ msgid "E129: Function name required" msgstr "E129: Nome funzione necessario" #: ../eval.c:17824 +#, c-format msgid "E128: Function name must start with a capital or \"s:\": %s" -msgstr "E128: Il nome funzione deve iniziare con una maiuscola o \"s:\": %s" +msgstr "E128: Il nome funzione deve iniziare con maiuscola o \"s:\": %s" #: ../eval.c:17833 +#, c-format msgid "E884: Function name cannot contain a colon: %s" -msgstr "E884: Il nome funzione non può contenere una virgola: %s" +msgstr "E884: Il nome della funzione non può contenere un due punti: %s" #: ../eval.c:18336 #, c-format @@ -1382,6 +1399,13 @@ msgstr "riga %<PRId64>: %s" msgid "cmd: %s" msgstr "com: %s" +msgid "frame is zero" +msgstr "al livello zero" + +#, c-format +msgid "frame at highest level: %d" +msgstr "al livello più alto: %d" + #: ../ex_cmds2.c:322 #, c-format msgid "Breakpoint in \"%s%s\" line %<PRId64>" @@ -1422,8 +1446,7 @@ msgstr "E162: Buffer \"%s\" non salvato dopo modifica" #: ../ex_cmds2.c:1480 msgid "Warning: Entered other buffer unexpectedly (check autocommands)" msgstr "" -"Avviso: Entrato in altro buffer inaspettatamente (controllare " -"autocomandi)" +"Avviso: Entrato in altro buffer inaspettatamente (controllare autocomandi)" #: ../ex_cmds2.c:1826 msgid "E163: There is only one file to edit" @@ -2301,19 +2324,19 @@ msgstr "[in formato DOS]" #: ../fileio.c:3801 msgid "[mac]" -msgstr "[MAC]" +msgstr "[Mac]" #: ../fileio.c:3801 msgid "[mac format]" -msgstr "[in formato MAC]" +msgstr "[in formato Mac]" #: ../fileio.c:3807 msgid "[unix]" -msgstr "[UNIX]" +msgstr "[Unix]" #: ../fileio.c:3807 msgid "[unix format]" -msgstr "[in formato UNIX]" +msgstr "[in formato Unix]" #: ../fileio.c:3831 msgid "1 line, " @@ -2864,6 +2887,9 @@ msgstr "E46: Non posso cambiare la variabile read-only \"%s\"" msgid "E794: Cannot set variable in the sandbox: \"%s\"" msgstr "E794: Non posso impostare la variabile read-only in ambiente protetto: \"%s\"" +msgid "E713: Cannot use empty key for Dictionary" +msgstr "E713: Non posso usare una chiave nulla per il Dizionario" + #: ../globals.h:1076 msgid "E47: Error while reading errorfile" msgstr "E47: Errore leggendo il file errori" @@ -4087,12 +4113,12 @@ msgid "" "\n" "(1) Another program may be editing the same file. If this is the case,\n" " be careful not to end up with two different instances of the same\n" -" file when making changes." +" file when making changes. Quit, or continue with caution.\n" msgstr "" "\n" -"(1) Un altro programma può essere in edit sullo stesso file.\n" -" Se è così, attenzione a non trovarti con due versioni\n" -" differenti dello stesso file a cui vengono apportate modifiche." +"(1) Un altro programma può essere in edit sullo stesso file. Se è così,\n" +" attenzione a non finire con due sessioni differenti che modificano lo\n" +" stesso file. Uscire da Vim, o continuare con cautela.\n" #: ../memline.c:3245 msgid " Quit, or continue with caution.\n" @@ -4335,7 +4361,7 @@ msgstr "E766: Argomenti non sufficienti per printf()" #: ../message.c:3119 msgid "E807: Expected Float argument for printf()" -msgstr "E807: Numero con virgola atteso come argomento per printf()" +msgstr "E807: Numero-a-virgola-mobile atteso come argomento per printf()" #: ../message.c:3873 msgid "E767: Too many arguments to printf()" @@ -4526,7 +4552,8 @@ msgstr "E574: Tipo di registro sconosciuto: %d" msgid "" "E883: search pattern and expression register may not contain two or more " "lines" -msgstr "E883: espressione di ricerca e registro dell'espressione non possono " +msgstr "" +"E883: espressione di ricerca e registro dell'espressione non possono " "contenere due o più righe" #: ../ops.c:5089 @@ -4794,6 +4821,14 @@ msgstr "" "\n" "Non posso impostare il contesto di sicurezza per " +#, c-format +msgid "Could not set security context %s for %s" +msgstr "Non posso impostare il contesto di sicurezza %s per %s" + +#, c-format +msgid "Could not get security context %s for %s. Removing it!" +msgstr "Non posso ottenere il contesto di sicurezza %s per %s. Lo rimuovo!" + #: ../os_unix.c:1558 ../os_unix.c:1647 #, c-format msgid "dlerror = \"%s\"" @@ -4890,6 +4925,7 @@ msgid "E777: String or List expected" msgstr "E777: aspettavo Stringa o Lista" #: ../regexp.c:359 +#, c-format msgid "E369: invalid item in %s%%[]" msgstr "E369: elemento non valido in %s%%[]" @@ -5005,6 +5041,7 @@ msgid "External submatches:\n" msgstr "Sotto-corrispondenze esterne:\n" #: ../regexp.c:2470 +#, c-format msgid "E888: (NFA regexp) cannot repeat %s" msgstr "E888: (NFA regexp) non riesco a ripetere %s" @@ -5399,8 +5436,7 @@ msgstr "Valore errato per CHECKCOMPOUNDPATTERN in %s riga %d: %s" #: ../spell.c:4847 #, c-format msgid "Different combining flag in continued affix block in %s line %d: %s" -msgstr "" -"Flag combinazione diverso in blocco affissi continuo in %s riga %d: %s" +msgstr "Flag combinazione diverso in blocco affissi continuo in %s riga %d: %s" #: ../spell.c:4850 #, c-format @@ -5639,10 +5675,12 @@ msgid "E765: 'spellfile' does not have %<PRId64> entries" msgstr "E765: 'spellfile' non ha %<PRId64> elementi" #: ../spell.c:8074 +#, c-format msgid "Word '%.*s' removed from %s" msgstr "Parola '%.*s' rimossa da %s" #: ../spell.c:8117 +#, c-format msgid "Word '%.*s' added to %s" msgstr "Parola '%.*s' aggiunta a %s" @@ -5720,6 +5758,9 @@ msgstr "Nessun elemento sintattico definito per questo buffer" msgid "E390: Illegal argument: %s" msgstr "E390: Argomento non ammesso: %s" +msgid "syntax iskeyword " +msgstr "syntax iskeyword " + #: ../syntax.c:3299 #, c-format msgid "E391: No such syntax cluster: %s" @@ -5816,6 +5857,9 @@ msgstr "E847: Troppe inclusioni di sintassi" msgid "E789: Missing ']': %s" msgstr "E789: Manca ']': %s" +msgid "E890: trailing char after ']': %s]%s" +msgstr "E890: Caratteri in più dopo ']': %s]%s" + #: ../syntax.c:4531 #, c-format msgid "E398: Missing '=': %s" diff --git a/src/nvim/po/ja.euc-jp.po b/src/nvim/po/ja.euc-jp.po index d3061d3c5a..85042e3506 100644 --- a/src/nvim/po/ja.euc-jp.po +++ b/src/nvim/po/ja.euc-jp.po @@ -1,11 +1,11 @@ -# Japanese translation for Vim vim:set foldmethod=marker: +# Japanese translation for Vim # # Do ":help uganda" in Vim to read copying and usage conditions. # Do ":help credits" in Vim to see a list of people who contributed. # -# Last Change: 2013 Jul 06 +# Copyright (C) 2001-2016 MURAOKA Taro <koron.kaoriya@gmail.com>, +# vim-jp (http://vim-jp.org/) # -# Copyright (C) 2001-13 MURAOKA Taro <koron.kaoriya@gmail.com> # THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE. # # Generated from ja.po, DO NOT EDIT. @@ -14,10 +14,10 @@ msgid "" msgstr "" "Project-Id-Version: Vim 7.4\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-05-26 14:21+0200\n" -"PO-Revision-Date: 2013-07-06 15:00+0900\n" +"POT-Creation-Date: 2016-02-01 09:02+0900\n" +"PO-Revision-Date: 2016-02-01 09:08+0900\n" "Last-Translator: MURAOKA Taro <koron.kaoriya@gmail.com>\n" -"Language-Team: MURAOKA Taro <koron.kaoriya@gmail.com>\n" +"Language-Team: vim-jp (https://github.com/vim-jp/lang-ja)\n" "Language: Japanese\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=euc-jp\n" @@ -34,7 +34,7 @@ msgstr "ÆâÉô¥¨¥é¡¼: ̤ÃΤΥª¥×¥·¥ç¥ó·¿¤Ç¤¹" #: ../buffer.c:92 msgid "[Location List]" -msgstr "[¾ì½ê¥ê¥¹¥È]" +msgstr "[¥í¥±¡¼¥·¥ç¥ó¥ê¥¹¥È]" #: ../buffer.c:93 msgid "[Quickfix List]" @@ -277,7 +277,7 @@ msgstr "E810: °ì»þ¥Õ¥¡¥¤¥ë¤ÎÆÉ¹þ¤â¤·¤¯¤Ï½ñ¹þ¤¬¤Ç¤¤Þ¤»¤ó" #: ../diff.c:755 msgid "E97: Cannot create diffs" -msgstr "E97: º¹Ê¬¤òºîÀ®¤Ç¤¤Þ¤»¤ó " +msgstr "E97: º¹Ê¬¤òºîÀ®¤Ç¤¤Þ¤»¤ó" #: ../diff.c:966 msgid "E816: Cannot read patch output" @@ -293,7 +293,7 @@ msgstr "E99: ¸½ºß¤Î¥Ð¥Ã¥Õ¥¡¤Ïº¹Ê¬¥â¡¼¥É¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó" #: ../diff.c:2100 msgid "E793: No other buffer in diff mode is modifiable" -msgstr "E793: º¹Ê¬¥â¡¼¥É¤Ç¤¢¤ë¾¤Î¥Ð¥Ã¥Õ¥¡¤ÏÊѹ¹²Äǽ¤Ç¤¹" +msgstr "E793: º¹Ê¬¥â¡¼¥É¤Ç¤¢¤ë¾¤Î¥Ð¥Ã¥Õ¥¡¤ÏÊѹ¹¤Ç¤¤Þ¤»¤ó" #: ../diff.c:2102 msgid "E100: No other buffer in diff mode" @@ -349,7 +349,7 @@ msgstr " ¹Ô(Á´ÂÎ)Êä´° (^L^N^P)" #: ../edit.c:86 msgid " File name completion (^F^N^P)" -msgstr "¥Õ¥¡¥¤¥ë̾Êä´° (^F^N^P)" +msgstr " ¥Õ¥¡¥¤¥ë̾Êä´° (^F^N^P)" #: ../edit.c:87 msgid " Tag completion (^]^N^P)" @@ -377,7 +377,7 @@ msgstr " ¥³¥Þ¥ó¥É¥é¥¤¥óÊä´° (^V^N^P)" #: ../edit.c:94 msgid " User defined completion (^U^N^P)" -msgstr " ¥æ¡¼¥¶ÄêµÁÊä´° (^U^N^P)" +msgstr " ¥æ¡¼¥¶¡¼ÄêµÁÊä´° (^U^N^P)" #: ../edit.c:95 msgid " Omni completion (^O^N^P)" @@ -679,6 +679,11 @@ msgstr "E696: ¥ê¥¹¥È·¿¤Ë¥«¥ó¥Þ¤¬¤¢¤ê¤Þ¤»¤ó: %s" msgid "E697: Missing end of List ']': %s" msgstr "E697: ¥ê¥¹¥È·¿¤ÎºÇ¸å¤Ë ']' ¤¬¤¢¤ê¤Þ¤»¤ó: %s" +#: ../eval.c:5807 +msgid "Not enough memory to set references, garbage collection aborted!" +msgstr "" +"¥¬¡¼¥Ù¥Ã¥¸¥³¥ì¥¯¥·¥ç¥ó¤òÃæ»ß¤·¤Þ¤·¤¿! »²¾È¤òºîÀ®¤¹¤ë¤Î¤Ë¥á¥â¥ê¤¬ÉÔ¤·¤Þ¤·¤¿" + #: ../eval.c:6475 #, c-format msgid "E720: Missing colon in Dictionary: %s" @@ -721,7 +726,7 @@ msgstr "E117: ̤ÃΤδؿô¤Ç¤¹: %s" #: ../eval.c:7383 #, c-format msgid "E119: Not enough arguments for function: %s" -msgstr "E119: ´Ø¿ô¤Î°ú¿ô¤¬¾¯¤Ê²á¤®¤Þ¤¹: %s" +msgstr "E119: ´Ø¿ô¤Î°ú¿ô¤¬Â¤ê¤Þ¤»¤ó: %s" #: ../eval.c:7387 #, c-format @@ -826,18 +831,16 @@ msgid "sort() argument" msgstr "sort() ¤Î°ú¿ô" #: ../eval.c:13721 -#, fuzzy msgid "uniq() argument" -msgstr "add() ¤Î°ú¿ô" +msgstr "uniq() ¤Î°ú¿ô" #: ../eval.c:13776 msgid "E702: Sort compare function failed" msgstr "E702: ¥½¡¼¥È¤ÎÈæ³Ó´Ø¿ô¤¬¼ºÇÔ¤·¤Þ¤·¤¿" #: ../eval.c:13806 -#, fuzzy msgid "E882: Uniq compare function failed" -msgstr "E702: ¥½¡¼¥È¤ÎÈæ³Ó´Ø¿ô¤¬¼ºÇÔ¤·¤Þ¤·¤¿" +msgstr "E882: Uniq ¤ÎÈæ³Ó´Ø¿ô¤¬¼ºÇÔ¤·¤Þ¤·¤¿" #: ../eval.c:14085 msgid "(Invalid)" @@ -863,6 +866,18 @@ msgstr "E745: ¥ê¥¹¥È·¿¤ò¿ôÃͤȤ·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹" msgid "E728: Using a Dictionary as a Number" msgstr "E728: ¼½ñ·¿¤ò¿ôÃͤȤ·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹" +msgid "E891: Using a Funcref as a Float" +msgstr "E891: ´Ø¿ô»²¾È·¿¤òÉâÆ°¾®¿ôÅÀ¿ô¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹¡£" + +msgid "E892: Using a String as a Float" +msgstr "E892: ʸ»úÎó¤òÉâÆ°¾®¿ôÅÀ¿ô¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹" + +msgid "E893: Using a List as a Float" +msgstr "E893: ¥ê¥¹¥È·¿¤òÉâÆ°¾®¿ôÅÀ¿ô¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹" + +msgid "E894: Using a Dictionary as a Float" +msgstr "E894: ¼½ñ·¿¤òÉâÆ°¾®¿ôÅÀ¿ô¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹" + #: ../eval.c:16259 msgid "E729: using Funcref as a String" msgstr "E729: ´Ø¿ô»²¾È·¿¤òʸ»úÎó¤È¤·¤Æ°·¤Ã¤Æ¤¤¤Þ¤¹" @@ -961,14 +976,14 @@ msgid "E129: Function name required" msgstr "E129: ´Ø¿ô̾¤¬Í׵ᤵ¤ì¤Þ¤¹" #: ../eval.c:17824 -#, fuzzy, c-format +#, c-format msgid "E128: Function name must start with a capital or \"s:\": %s" -msgstr "E128: ´Ø¿ô̾¤ÏÂçʸ»ú¤Ç»Ï¤Þ¤ë¤«¥³¥í¥ó¤ò´Þ¤Þ¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó: %s" +msgstr "E128: ´Ø¿ô̾¤ÏÂçʸ»ú¤« \"s:\" ¤Ç»Ï¤Þ¤é¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó: %s" #: ../eval.c:17833 -#, fuzzy, c-format +#, c-format msgid "E884: Function name cannot contain a colon: %s" -msgstr "E128: ´Ø¿ô̾¤ÏÂçʸ»ú¤Ç»Ï¤Þ¤ë¤«¥³¥í¥ó¤ò´Þ¤Þ¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó: %s" +msgstr "E884: ´Ø¿ô̾¤Ë¤Ï¥³¥í¥ó¤Ï´Þ¤á¤é¤ì¤Þ¤»¤ó: %s" #: ../eval.c:18336 #, c-format @@ -1081,7 +1096,7 @@ msgstr "E136: viminfo: ¥¨¥é¡¼¤¬Â¿²á¤®¤ë¤Î¤Ç, °Ê¹ß¤Ï¥¹¥¥Ã¥×¤·¤Þ¤¹" #: ../ex_cmds.c:1458 #, c-format msgid "Reading viminfo file \"%s\"%s%s%s" -msgstr "viminfo¥Õ¥¡¥¤¥ë \"%s\"%s%s%s ¤òÆÉ¹þ¤ßÃæ " +msgstr "viminfo¥Õ¥¡¥¤¥ë \"%s\"%s%s%s ¤òÆÉ¹þ¤ßÃæ" #: ../ex_cmds.c:1460 msgid " info" @@ -1357,6 +1372,10 @@ msgstr "E158: ̵¸ú¤Ê¥Ð¥Ã¥Õ¥¡Ì¾¤Ç¤¹: %s" msgid "E157: Invalid sign ID: %<PRId64>" msgstr "E157: ̵¸ú¤Êsign¼±Ê̻ҤǤ¹: %<PRId64>" +#, c-format +msgid "E885: Not possible to change sign %s" +msgstr "E885: Êѹ¹¤Ç¤¤Ê¤¤ sign ¤Ç¤¹: %s" + #: ../ex_cmds.c:6066 msgid " (not supported)" msgstr " (È󥵥ݡ¼¥È)" @@ -1379,6 +1398,13 @@ msgstr "¹Ô %<PRId64>: %s" msgid "cmd: %s" msgstr "¥³¥Þ¥ó¥É: %s" +msgid "frame is zero" +msgstr "¥Õ¥ì¡¼¥à¤¬ 0 ¤Ç¤¹" + +#, c-format +msgid "frame at highest level: %d" +msgstr "ºÇ¹â¥ì¥Ù¥ë¤Î¥Õ¥ì¡¼¥à: %d" + #: ../ex_cmds2.c:322 #, c-format msgid "Breakpoint in \"%s%s\" line %<PRId64>" @@ -1528,7 +1554,8 @@ msgstr "E197: ¸À¸ì¤ò \"%s\" ¤ËÀßÄê¤Ç¤¤Þ¤»¤ó" #. don't wait for return #: ../ex_docmd.c:387 msgid "Entering Ex mode. Type \"visual\" to go to Normal mode." -msgstr "Ex¥â¡¼¥É¤ËÆþ¤ê¤Þ¤¹. ¥Î¡¼¥Þ¥ë¤ËÌá¤ë¤Ë¤Ï\"visual\"¤ÈÆþÎϤ·¤Æ¤¯¤À¤µ¤¤." +msgstr "" +"Ex¥â¡¼¥É¤ËÆþ¤ê¤Þ¤¹. ¥Î¡¼¥Þ¥ë¥â¡¼¥É¤ËÌá¤ë¤Ë¤Ï\"visual\"¤ÈÆþÎϤ·¤Æ¤¯¤À¤µ¤¤." #: ../ex_docmd.c:428 msgid "E501: At end-of-file" @@ -1553,7 +1580,7 @@ msgstr "´Ø¿ô¤ÎºÇ¸å¤Ç¤¹" #: ../ex_docmd.c:1628 msgid "E464: Ambiguous use of user-defined command" -msgstr "E464: ¥æ¡¼¥¶ÄêµÁ¥³¥Þ¥ó¥É¤Î¤¢¤¤¤Þ¤¤¤Ê»ÈÍѤǤ¹" +msgstr "E464: ¥æ¡¼¥¶¡¼ÄêµÁ¥³¥Þ¥ó¥É¤Î¤¢¤¤¤Þ¤¤¤Ê»ÈÍѤǤ¹" #: ../ex_docmd.c:1638 msgid "E492: Not an editor command" @@ -1606,14 +1633,14 @@ msgstr "E174: ¥³¥Þ¥ó¥É¤¬´û¤Ë¤¢¤ê¤Þ¤¹: ºÆÄêµÁ¤¹¤ë¤Ë¤Ï ! ¤òÄɲ䷤Ƥ¯¤À¤µ¤¤" #: ../ex_docmd.c:4432 msgid "" "\n" -" Name Args Range Complete Definition" +" Name Args Address Complete Definition" msgstr "" "\n" -" ̾Á° °ú¿ô ÈÏ°Ï Êä´° ÄêµÁ" +" ̾Á° °ú¿ô ¥¢¥É¥ì¥¹ Êä´° ÄêµÁ" #: ../ex_docmd.c:4516 msgid "No user-defined commands found" -msgstr "¥æ¡¼¥¶ÄêµÁ¥³¥Þ¥ó¥É¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¤Ç¤·¤¿" +msgstr "¥æ¡¼¥¶¡¼ÄêµÁ¥³¥Þ¥ó¥É¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¤Ç¤·¤¿" #: ../ex_docmd.c:4538 msgid "E175: No attribute specified" @@ -1633,7 +1660,10 @@ msgstr "E178: ¥«¥¦¥ó¥È¤Î¾ÊάÃͤ¬Ìµ¸ú¤Ç¤¹" #: ../ex_docmd.c:4625 msgid "E179: argument required for -complete" -msgstr "E179: -Êä´°¤Î¤¿¤á¤Î°ú¿ô¤¬É¬ÍפǤ¹" +msgstr "E179: -complete ¤Ë¤Ï°ú¿ô¤¬É¬ÍפǤ¹" + +msgid "E179: argument required for -addr" +msgstr "E179: -addr ¤Ë¤Ï°ú¿ô¤¬É¬ÍפǤ¹" #: ../ex_docmd.c:4635 #, c-format @@ -1650,12 +1680,16 @@ msgstr "E183: ¥æ¡¼¥¶ÄêµÁ¥³¥Þ¥ó¥É¤Ï±ÑÂçʸ»ú¤Ç»Ï¤Þ¤é¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó" #: ../ex_docmd.c:4696 msgid "E841: Reserved name, cannot be used for user defined command" -msgstr "E841: ͽÌó̾¤Ê¤Î¤Ç, ¥æ¡¼¥¶ÄêµÁ¥³¥Þ¥ó¥É¤ËÍøÍѤǤ¤Þ¤»¤ó" +msgstr "E841: ͽÌó̾¤Ê¤Î¤Ç, ¥æ¡¼¥¶¡¼ÄêµÁ¥³¥Þ¥ó¥É¤ËÍøÍѤǤ¤Þ¤»¤ó" #: ../ex_docmd.c:4751 #, c-format msgid "E184: No such user-defined command: %s" -msgstr "E184: ¤½¤Î¥æ¡¼¥¶ÄêµÁ¥³¥Þ¥ó¥É¤Ï¤¢¤ê¤Þ¤»¤ó: %s" +msgstr "E184: ¤½¤Î¥æ¡¼¥¶¡¼ÄêµÁ¥³¥Þ¥ó¥É¤Ï¤¢¤ê¤Þ¤»¤ó: %s" + +#, c-format +msgid "E180: Invalid address type value: %s" +msgstr "E180: ̵¸ú¤Ê¥¢¥É¥ì¥¹¥¿¥¤¥×ÃͤǤ¹: %s" #: ../ex_docmd.c:5219 #, c-format @@ -2019,11 +2053,11 @@ msgstr "ÉÔÀµ¤Ê¥Õ¥¡¥¤¥ë̾" #: ../fileio.c:395 ../fileio.c:476 ../fileio.c:2543 ../fileio.c:2578 msgid "is a directory" -msgstr " ¤Ï¥Ç¥£¥ì¥¯¥È¥ê¤Ç¤¹" +msgstr "¤Ï¥Ç¥£¥ì¥¯¥È¥ê¤Ç¤¹" #: ../fileio.c:397 msgid "is not a file" -msgstr " ¤Ï¥Õ¥¡¥¤¥ë¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó" +msgstr "¤Ï¥Õ¥¡¥¤¥ë¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó" #: ../fileio.c:508 ../fileio.c:3522 msgid "[New File]" @@ -2039,7 +2073,7 @@ msgstr "[¥Õ¥¡¥¤¥ë²áÂç]" #: ../fileio.c:534 msgid "[Permission Denied]" -msgstr "[ǧ²Ä¤¬¤¢¤ê¤Þ¤»¤ó]" +msgstr "[¸¢¸Â¤¬¤¢¤ê¤Þ¤»¤ó]" #: ../fileio.c:653 msgid "E200: *ReadPre autocommands made the file unreadable" @@ -2210,7 +2244,7 @@ msgstr " ÊÑ´¹¥¨¥é¡¼" #: ../fileio.c:3509 #, c-format msgid " in line %<PRId64>;" -msgstr "¹Ô %<PRId64>;" +msgstr " ¹Ô %<PRId64>;" #: ../fileio.c:3519 msgid "[Device]" @@ -2766,9 +2800,8 @@ msgid "E37: No write since last change (add ! to override)" msgstr "E37: ºÇ¸å¤ÎÊѹ¹¤¬Êݸ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó (! ¤òÄɲäÇÊѹ¹¤òÇË´þ)" #: ../globals.h:1055 -#, fuzzy msgid "E37: No write since last change" -msgstr "[ºÇ¸å¤ÎÊѹ¹¤¬Êݸ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó]\n" +msgstr "E37: ºÇ¸å¤ÎÊѹ¹¤¬Êݸ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó" #: ../globals.h:1056 msgid "E38: Null argument" @@ -2810,7 +2843,7 @@ msgstr "E42: ¥¨¥é¡¼¤Ï¤¢¤ê¤Þ¤»¤ó" #: ../globals.h:1067 msgid "E776: No location list" -msgstr "E776: ¾ì½ê¥ê¥¹¥È¤Ï¤¢¤ê¤Þ¤»¤ó" +msgstr "E776: ¥í¥±¡¼¥·¥ç¥ó¥ê¥¹¥È¤Ï¤¢¤ê¤Þ¤»¤ó" #: ../globals.h:1068 msgid "E43: Damaged match string" @@ -3831,7 +3864,7 @@ msgid "" "\n" msgstr "" "\n" -"¤½¤ì¤«¤é.swp¥Õ¥¡¥¤¥ë¤òºï½ü¤·¤Æ¤¯¤À¤µ¤¤\n" +"¸µ¤Î.swp¥Õ¥¡¥¤¥ë¤Ïºï½ü¤·¤Æ¤â¹½¤¤¤Þ¤»¤ó\n" "\n" #. use msg() to start the scrolling properly @@ -3845,7 +3878,7 @@ msgstr " ¸½ºß¤Î¥Ç¥£¥ì¥¯¥È¥ê:\n" #: ../memline.c:1448 msgid " Using specified name:\n" -msgstr " ¤¢¤ë̾Á°¤ò»ÈÍÑÃæ:\n" +msgstr " °Ê²¼¤Î̾Á°¤ò»ÈÍÑÃæ:\n" #: ../memline.c:1450 msgid " In directory " @@ -3901,7 +3934,7 @@ msgid "" " user name: " msgstr "" "\n" -" ¥æ¡¼¥¶Ì¾: " +" ¥æ¡¼¥¶¡¼Ì¾: " #: ../memline.c:1568 msgid " host name: " @@ -4050,12 +4083,12 @@ msgid "" msgstr "" "\n" "(1) ÊÌ¤Î¥×¥í¥°¥é¥à¤¬Æ±¤¸¥Õ¥¡¥¤¥ë¤òÊÔ½¸¤·¤Æ¤¤¤ë¤«¤â¤·¤ì¤Þ¤»¤ó.\n" -" ¤³¤Î¾ì¹ç¤Ë¤Ï, Êѹ¹¤ò¤·¤¿ºÝ¤ËºÇ½ªÅª¤Ë, Ʊ¤¸¥Õ¥¡¥¤¥ë¤Î°Û¤Ê¤ë\n" -" 2¤Ä¤Î¥¤¥ó¥¹¥¿¥ó¥¹¤¬¤Ç¤¤Æ¤·¤Þ¤¦¤³¤È¤ËÃí°Õ¤·¤Æ¤¯¤À¤µ¤¤." +" ¤³¤Î¾ì¹ç¤Ë¤Ï, Êѹ¹¤ò¤·¤Æ¤·¤Þ¤¦¤È1¤Ä¤Î¥Õ¥¡¥¤¥ë¤ËÂФ·¤Æ°Û¤Ê¤ë2¤Ä¤Î\n" +" ¥¤¥ó¥¹¥¿¥ó¥¹¤¬¤Ç¤¤Æ¤·¤Þ¤¦¤Î¤Ç, ¤½¤¦¤·¤Ê¤¤¤è¤¦¤Ëµ¤¤ò¤Ä¤±¤Æ¤¯¤À¤µ¤¤." #: ../memline.c:3245 msgid " Quit, or continue with caution.\n" -msgstr " ½ªÎ»¤¹¤ë¤«, Ãí°Õ¤·¤Ê¤¬¤é³¤±¤Æ¤¯¤À¤µ¤¤.\n" +msgstr " ½ªÎ»¤¹¤ë¤«, Ãí°Õ¤·¤Ê¤¬¤é³¤±¤Æ¤¯¤À¤µ¤¤.\n" #: ../memline.c:3246 msgid "(2) An edit session for this file crashed.\n" @@ -4479,6 +4512,11 @@ msgstr "" msgid "E574: Unknown register type %d" msgstr "E574: ̤ÃΤΥ쥸¥¹¥¿·¿ %d ¤Ç¤¹" +msgid "" +"E883: search pattern and expression register may not contain two or more " +"lines" +msgstr "E883: ¸¡º÷¥Ñ¥¿¡¼¥ó¤È¼°¥ì¥¸¥¹¥¿¤Ë¤Ï2¹Ô°Ê¾å¤ò´Þ¤á¤é¤ì¤Þ¤»¤ó" + #: ../ops.c:5089 #, c-format msgid "%<PRId64> Cols; " @@ -4563,6 +4601,10 @@ msgstr "E522: termcap Æâ¤Ë¸«¤Ä¤«¤ê¤Þ¤»¤ó" msgid "E539: Illegal character <%s>" msgstr "E539: ÉÔÀµ¤Êʸ»ú¤Ç¤¹ <%s>" +#, c-format +msgid "For option %s" +msgstr "¥ª¥×¥·¥ç¥ó: %s" + #: ../option.c:3862 msgid "E529: Cannot set 'term' to empty string" msgstr "E529: 'term' ¤Ë¤Ï¶õʸ»úÎó¤òÀßÄê¤Ç¤¤Þ¤»¤ó" @@ -4740,6 +4782,14 @@ msgstr "" "\n" "¥»¥¥å¥ê¥Æ¥£¥³¥ó¥Æ¥¥¹¥È¤òÀßÄê¤Ç¤¤Þ¤»¤ó " +#, c-format +msgid "Could not set security context %s for %s" +msgstr "¥»¥¥å¥ê¥Æ¥£¥³¥ó¥Æ¥¥¹¥È %s ¤ò %s ¤ËÀßÄê¤Ç¤¤Þ¤»¤ó" + +#, c-format +msgid "Could not get security context %s for %s. Removing it!" +msgstr "¥»¥¥å¥ê¥Æ¥£¥³¥ó¥Æ¥¥¹¥È %s ¤ò %s ¤«¤é¼èÆÀ¤Ç¤¤Þ¤»¤ó. ºï½ü¤·¤Þ¤¹!" + #: ../os_unix.c:1558 ../os_unix.c:1647 #, c-format msgid "dlerror = \"%s\"" @@ -4960,6 +5010,10 @@ msgstr "E554: %s{...} Æâ¤Ëʸˡ¥¨¥é¡¼¤¬¤¢¤ê¤Þ¤¹" msgid "External submatches:\n" msgstr "³°Éô¤ÎÉôʬ³ºÅö:\n" +#, c-format +msgid "E888: (NFA regexp) cannot repeat %s" +msgstr "E888: (NFA Àµµ¬É½¸½) ·«¤êÊÖ¤»¤Þ¤»¤ó %s" + #: ../regexp.c:7022 msgid "" "E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be " @@ -4968,6 +5022,9 @@ msgstr "" "E864: \\%#= ¤Ë¤Ï 0, 1 ¤â¤·¤¯¤Ï 2 ¤Î¤ß¤¬Â³¤±¤é¤ì¤Þ¤¹¡£Àµµ¬É½¸½¥¨¥ó¥¸¥ó¤Ï¼«Æ°Áª" "Âò¤µ¤ì¤Þ¤¹¡£" +msgid "Switching to backtracking RE engine for pattern: " +msgstr "¼¡¤Î¥Ñ¥¿¡¼¥ó¤Ë¥Ð¥Ã¥¯¥È¥é¥Ã¥¥ó¥° RE ¥¨¥ó¥¸¥ó¤òŬÍѤ·¤Þ¤¹: " + #: ../regexp_nfa.c:239 msgid "E865: (NFA) Regexp end encountered prematurely" msgstr "E865: (NFA) ´üÂÔ¤è¤êÁ᤯Àµµ¬É½¸½¤Î½ªÃ¼¤ËÅþ㤷¤Þ¤·¤¿" @@ -4980,7 +5037,7 @@ msgstr "E866: (NFA Àµµ¬É½¸½) °ÌÃÖ¤¬¸í¤Ã¤Æ¤¤¤Þ¤¹: %c" #: ../regexp_nfa.c:242 #, c-format msgid "E877: (NFA regexp) Invalid character class: %<PRId64>" -msgstr "" +msgstr "E877: (NFA Àµµ¬É½¸½) ̵¸ú¤Êʸ»ú¥¯¥é¥¹: %<PRId64>" #: ../regexp_nfa.c:1261 #, c-format @@ -5590,14 +5647,14 @@ msgid "E765: 'spellfile' does not have %<PRId64> entries" msgstr "E765: 'spellfile' ¤Ë¤Ï %<PRId64> ¸Ä¤Î¥¨¥ó¥È¥ê¤Ï¤¢¤ê¤Þ¤»¤ó" #: ../spell.c:8074 -#, fuzzy, c-format +#, c-format msgid "Word '%.*s' removed from %s" -msgstr "%s ¤«¤éñ¸ì¤¬ºï½ü¤µ¤ì¤Þ¤·¤¿" +msgstr "ñ¸ì '%.*s' ¤¬ %s ¤«¤éºï½ü¤µ¤ì¤Þ¤·¤¿" #: ../spell.c:8117 -#, fuzzy, c-format +#, c-format msgid "Word '%.*s' added to %s" -msgstr "%s ¤Ëñ¸ì¤¬Äɲ䵤ì¤Þ¤·¤¿" +msgstr "ñ¸ì '%.*s' ¤¬ %s ¤ØÄɲ䵤ì¤Þ¤·¤¿" #: ../spell.c:8381 msgid "E763: Word characters differ between spell files" @@ -5673,6 +5730,9 @@ msgstr "¤³¤Î¥Ð¥Ã¥Õ¥¡¤ËÄêµÁ¤µ¤ì¤¿¹½Ê¸Í×ÁǤϤ¢¤ê¤Þ¤»¤ó" msgid "E390: Illegal argument: %s" msgstr "E390: ÉÔÀµ¤Ê°ú¿ô¤Ç¤¹: %s" +msgid "syntax iskeyword " +msgstr "¥·¥ó¥¿¥Ã¥¯¥¹ÍÑ iskeyword " + #: ../syntax.c:3299 #, c-format msgid "E391: No such syntax cluster: %s" @@ -5769,6 +5829,10 @@ msgstr "E847: ¹½Ê¸¤Î¼è¤ê¹þ¤ß(include)¤¬Â¿²á¤®¤Þ¤¹" msgid "E789: Missing ']': %s" msgstr "E789: ']' ¤¬¤¢¤ê¤Þ¤»¤ó: %s" +#, c-format +msgid "E890: trailing char after ']': %s]%s" +msgstr "E890: ']' ¤Î¸å¤í¤Ë;ʬ¤Êʸ»ú¤¬¤¢¤ê¤Þ¤¹: %s]%s" + #: ../syntax.c:4531 #, c-format msgid "E398: Missing '=': %s" @@ -5874,7 +5938,7 @@ msgstr "E415: ͽ´ü¤»¤ÌÅù¹æ¤Ç¤¹: %s" #: ../syntax.c:6395 #, c-format msgid "E416: missing equal sign: %s" -msgstr "E416: Åù¹æ¤¬¤¬¤¢¤ê¤Þ¤»¤ó: %s" +msgstr "E416: Åù¹æ¤¬¤¢¤ê¤Þ¤»¤ó: %s" #: ../syntax.c:6418 #, c-format @@ -6078,9 +6142,8 @@ msgstr "Vim: ÆþÎϤòÆÉ¹þ¤ßÃæ¤Î¥¨¥é¡¼¤Ë¤è¤ê½ªÎ»¤·¤Þ¤¹...\n" #. This happens when the FileChangedRO autocommand changes the #. * file in a way it becomes shorter. #: ../undo.c:379 -#, fuzzy msgid "E881: Line count changed unexpectedly" -msgstr "E834: ͽ´ü¤»¤º¹Ô¥«¥¦¥ó¥È¤¬ÊѤï¤ê¤Þ¤·¤¿" +msgstr "E881: ͽ´ü¤»¤º¹Ô¥«¥¦¥ó¥È¤¬ÊѤï¤ê¤Þ¤·¤¿" #: ../undo.c:627 #, c-format @@ -6287,23 +6350,23 @@ msgstr " ¥·¥¹¥Æ¥à vimrc: \"" #: ../version.c:672 msgid " user vimrc file: \"" -msgstr " ¥æ¡¼¥¶ vimrc: \"" +msgstr " ¥æ¡¼¥¶¡¼ vimrc: \"" #: ../version.c:677 msgid " 2nd user vimrc file: \"" -msgstr " Âè2¥æ¡¼¥¶ vimrc: \"" +msgstr " Âè2¥æ¡¼¥¶¡¼ vimrc: \"" #: ../version.c:682 msgid " 3rd user vimrc file: \"" -msgstr " Âè3¥æ¡¼¥¶ vimrc: \"" +msgstr " Âè3¥æ¡¼¥¶¡¼ vimrc: \"" #: ../version.c:687 msgid " user exrc file: \"" -msgstr " ¥æ¡¼¥¶ exrc: \"" +msgstr " ¥æ¡¼¥¶¡¼ exrc: \"" #: ../version.c:692 msgid " 2nd user exrc file: \"" -msgstr " Âè2¥æ¡¼¥¶ exrc: \"" +msgstr " Âè2¥æ¡¼¥¶¡¼ exrc: \"" #: ../version.c:699 msgid " fall-back for $VIM: \"" @@ -6379,7 +6442,7 @@ msgstr "Vim¤Î³«È¯¤ò±þ±ç¤·¤Æ¤¯¤À¤µ¤¤!" #: ../version.c:828 msgid "Become a registered Vim user!" -msgstr "Vim¤ÎÅÐÏ¿¥æ¡¼¥¶¤Ë¤Ê¤Ã¤Æ¤¯¤À¤µ¤¤!" +msgstr "Vim¤ÎÅÐÏ¿¥æ¡¼¥¶¡¼¤Ë¤Ê¤Ã¤Æ¤¯¤À¤µ¤¤!" #: ../version.c:831 msgid "type :help sponsor<Enter> for information " @@ -6391,7 +6454,7 @@ msgstr "¾ÜºÙ¤Ê¾ðÊó¤Ï :help register<Enter> " #: ../version.c:834 msgid "menu Help->Sponsor/Register for information " -msgstr "¾ÜºÙ¤Ï¥á¥Ë¥å¡¼¤Î ¥Ø¥ë¥×¢ª¥¹¥Ý¥ó¥µ¡¼/ÅÐÏ¿ ¤ò»²¾È¤·¤Æ²¼¤µ¤¤ " +msgstr "¾ÜºÙ¤Ï¥á¥Ë¥å¡¼¤Î ¥Ø¥ë¥×->¥¹¥Ý¥ó¥µ¡¼/ÅÐÏ¿ ¤ò»²¾È¤·¤Æ²¼¤µ¤¤" #: ../window.c:119 msgid "Already only one window" @@ -6429,6 +6492,9 @@ msgstr "E445: ¾¤Î¥¦¥£¥ó¥É¥¦¤Ë¤ÏÊѹ¹¤¬¤¢¤ê¤Þ¤¹" msgid "E446: No file name under cursor" msgstr "E446: ¥«¡¼¥½¥ë¤Î²¼¤Ë¥Õ¥¡¥¤¥ë̾¤¬¤¢¤ê¤Þ¤»¤ó" +msgid "List or number required" +msgstr "¥ê¥¹¥È¤«¿ôÃͤ¬É¬ÍפǤ¹" + #~ msgid "E831: bf_key_init() called with empty password" #~ msgstr "E831: bf_key_init() ¤¬¶õ¥Ñ¥¹¥ï¡¼¥É¤Ç¸Æ¤Ó½Ð¤µ¤ì¤Þ¤·¤¿" diff --git a/src/nvim/po/ja.po b/src/nvim/po/ja.po index 6bdfcb426f..8a3fcb8f78 100644 --- a/src/nvim/po/ja.po +++ b/src/nvim/po/ja.po @@ -1,11 +1,11 @@ -# Japanese translation for Vim vim:set foldmethod=marker: +# Japanese translation for Vim # # Do ":help uganda" in Vim to read copying and usage conditions. # Do ":help credits" in Vim to see a list of people who contributed. # -# Last Change: 2013 Jul 06 +# Copyright (C) 2001-2016 MURAOKA Taro <koron.kaoriya@gmail.com>, +# vim-jp (http://vim-jp.org/) # -# Copyright (C) 2001-13 MURAOKA Taro <koron.kaoriya@gmail.com> # THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE. # # Original translations. @@ -14,10 +14,10 @@ msgid "" msgstr "" "Project-Id-Version: Vim 7.4\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-05-26 14:21+0200\n" -"PO-Revision-Date: 2013-07-06 15:00+0900\n" +"POT-Creation-Date: 2016-02-01 09:02+0900\n" +"PO-Revision-Date: 2013-06-02-01 09:08+09n" "Last-Translator: MURAOKA Taro <koron.kaoriya@gmail.com>\n" -"Language-Team: MURAOKA Taro <koron.kaoriya@gmail.com>\n" +"Language-Team: vim-jp (https://github.com/vim-jp/lang-ja)\n" "Language: Japanese\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" @@ -34,7 +34,7 @@ msgstr "内部エラー: 未知ã®ã‚ªãƒ—ション型ã§ã™" #: ../buffer.c:92 msgid "[Location List]" -msgstr "[å ´æ‰€ãƒªã‚¹ãƒˆ]" +msgstr "[ãƒã‚±ãƒ¼ã‚·ãƒ§ãƒ³ãƒªã‚¹ãƒˆ]" #: ../buffer.c:93 msgid "[Quickfix List]" @@ -277,7 +277,7 @@ msgstr "E810: 一時ファイルã®èªè¾¼ã‚‚ã—ãã¯æ›¸è¾¼ãŒã§ãã¾ã›ã‚“" #: ../diff.c:755 msgid "E97: Cannot create diffs" -msgstr "E97: 差分を作æˆã§ãã¾ã›ã‚“ " +msgstr "E97: 差分を作æˆã§ãã¾ã›ã‚“" #: ../diff.c:966 msgid "E816: Cannot read patch output" @@ -293,7 +293,7 @@ msgstr "E99: ç¾åœ¨ã®ãƒãƒƒãƒ•ã‚¡ã¯å·®åˆ†ãƒ¢ãƒ¼ãƒ‰ã§ã¯ã‚りã¾ã›ã‚“" #: ../diff.c:2100 msgid "E793: No other buffer in diff mode is modifiable" -msgstr "E793: 差分モードã§ã‚ã‚‹ä»–ã®ãƒãƒƒãƒ•ã‚¡ã¯å¤‰æ›´å¯èƒ½ã§ã™" +msgstr "E793: 差分モードã§ã‚ã‚‹ä»–ã®ãƒãƒƒãƒ•ã‚¡ã¯å¤‰æ›´ã§ãã¾ã›ã‚“" #: ../diff.c:2102 msgid "E100: No other buffer in diff mode" @@ -349,7 +349,7 @@ msgstr " 行(全体)補完 (^L^N^P)" #: ../edit.c:86 msgid " File name completion (^F^N^P)" -msgstr "ファイルå補完 (^F^N^P)" +msgstr " ファイルå補完 (^F^N^P)" #: ../edit.c:87 msgid " Tag completion (^]^N^P)" @@ -377,7 +377,7 @@ msgstr " コマンドライン補完 (^V^N^P)" #: ../edit.c:94 msgid " User defined completion (^U^N^P)" -msgstr " ユーザ定義補完 (^U^N^P)" +msgstr " ユーザー定義補完 (^U^N^P)" #: ../edit.c:95 msgid " Omni completion (^O^N^P)" @@ -679,6 +679,10 @@ msgstr "E696: リスト型ã«ã‚«ãƒ³ãƒžãŒã‚りã¾ã›ã‚“: %s" msgid "E697: Missing end of List ']': %s" msgstr "E697: ãƒªã‚¹ãƒˆåž‹ã®æœ€å¾Œã« ']' ãŒã‚りã¾ã›ã‚“: %s" +msgid "Not enough memory to set references, garbage collection aborted!" +msgstr "" +"ã‚¬ãƒ¼ãƒ™ãƒƒã‚¸ã‚³ãƒ¬ã‚¯ã‚·ãƒ§ãƒ³ã‚’ä¸æ¢ã—ã¾ã—ãŸ! å‚照を作æˆã™ã‚‹ã®ã«ãƒ¡ãƒ¢ãƒªãŒä¸è¶³ã—ã¾ã—ãŸ" + #: ../eval.c:6475 #, c-format msgid "E720: Missing colon in Dictionary: %s" @@ -721,7 +725,7 @@ msgstr "E117: 未知ã®é–¢æ•°ã§ã™: %s" #: ../eval.c:7383 #, c-format msgid "E119: Not enough arguments for function: %s" -msgstr "E119: 関数ã®å¼•æ•°ãŒå°‘ãªéŽãŽã¾ã™: %s" +msgstr "E119: 関数ã®å¼•æ•°ãŒè¶³ã‚Šã¾ã›ã‚“: %s" #: ../eval.c:7387 #, c-format @@ -826,18 +830,16 @@ msgid "sort() argument" msgstr "sort() ã®å¼•æ•°" #: ../eval.c:13721 -#, fuzzy msgid "uniq() argument" -msgstr "add() ã®å¼•æ•°" +msgstr "uniq() ã®å¼•æ•°" #: ../eval.c:13776 msgid "E702: Sort compare function failed" msgstr "E702: ã‚½ãƒ¼ãƒˆã®æ¯”較関数ãŒå¤±æ•—ã—ã¾ã—ãŸ" #: ../eval.c:13806 -#, fuzzy msgid "E882: Uniq compare function failed" -msgstr "E702: ã‚½ãƒ¼ãƒˆã®æ¯”較関数ãŒå¤±æ•—ã—ã¾ã—ãŸ" +msgstr "E882: Uniq ã®æ¯”較関数ãŒå¤±æ•—ã—ã¾ã—ãŸ" #: ../eval.c:14085 msgid "(Invalid)" @@ -863,6 +865,18 @@ msgstr "E745: リスト型を数値ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™" msgid "E728: Using a Dictionary as a Number" msgstr "E728: 辞書型を数値ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™" +msgid "E891: Using a Funcref as a Float" +msgstr "E891: 関数å‚ç…§åž‹ã‚’æµ®å‹•å°æ•°ç‚¹æ•°ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™ã€‚" + +msgid "E892: Using a String as a Float" +msgstr "E892: æ–‡å—åˆ—ã‚’æµ®å‹•å°æ•°ç‚¹æ•°ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™" + +msgid "E893: Using a List as a Float" +msgstr "E893: ãƒªã‚¹ãƒˆåž‹ã‚’æµ®å‹•å°æ•°ç‚¹æ•°ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™" + +msgid "E894: Using a Dictionary as a Float" +msgstr "E894: è¾žæ›¸åž‹ã‚’æµ®å‹•å°æ•°ç‚¹æ•°ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™" + #: ../eval.c:16259 msgid "E729: using Funcref as a String" msgstr "E729: 関数å‚照型を文å—列ã¨ã—ã¦æ‰±ã£ã¦ã„ã¾ã™" @@ -961,14 +975,14 @@ msgid "E129: Function name required" msgstr "E129: 関数åãŒè¦æ±‚ã•れã¾ã™" #: ../eval.c:17824 -#, fuzzy, c-format +#, c-format msgid "E128: Function name must start with a capital or \"s:\": %s" -msgstr "E128: 関数åã¯å¤§æ–‡å—ã§å§‹ã¾ã‚‹ã‹ã‚³ãƒãƒ³ã‚’å«ã¾ãªã‘れã°ãªã‚Šã¾ã›ã‚“: %s" +msgstr "E128: 関数åã¯å¤§æ–‡å—ã‹ \"s:\" ã§å§‹ã¾ã‚‰ãªã‘れã°ãªã‚Šã¾ã›ã‚“: %s" #: ../eval.c:17833 -#, fuzzy, c-format +#, c-format msgid "E884: Function name cannot contain a colon: %s" -msgstr "E128: 関数åã¯å¤§æ–‡å—ã§å§‹ã¾ã‚‹ã‹ã‚³ãƒãƒ³ã‚’å«ã¾ãªã‘れã°ãªã‚Šã¾ã›ã‚“: %s" +msgstr "E884: 関数åã«ã¯ã‚³ãƒãƒ³ã¯å«ã‚られã¾ã›ã‚“: %s" #: ../eval.c:18336 #, c-format @@ -1081,7 +1095,7 @@ msgstr "E136: viminfo: エラーãŒå¤šéŽãŽã‚‹ã®ã§, 以é™ã¯ã‚¹ã‚ップã—ã #: ../ex_cmds.c:1458 #, c-format msgid "Reading viminfo file \"%s\"%s%s%s" -msgstr "viminfoファイル \"%s\"%s%s%s ã‚’èªè¾¼ã¿ä¸ " +msgstr "viminfoファイル \"%s\"%s%s%s ã‚’èªè¾¼ã¿ä¸" #: ../ex_cmds.c:1460 msgid " info" @@ -1357,6 +1371,10 @@ msgstr "E158: 無効ãªãƒãƒƒãƒ•ã‚¡åã§ã™: %s" msgid "E157: Invalid sign ID: %<PRId64>" msgstr "E157: 無効ãªsignè˜åˆ¥åã§ã™: %<PRId64>" +#, c-format +msgid "E885: Not possible to change sign %s" +msgstr "E885: 変更ã§ããªã„ sign ã§ã™: %s" + #: ../ex_cmds.c:6066 msgid " (not supported)" msgstr " (éžã‚µãƒãƒ¼ãƒˆ)" @@ -1379,6 +1397,13 @@ msgstr "行 %<PRId64>: %s" msgid "cmd: %s" msgstr "コマンド: %s" +msgid "frame is zero" +msgstr "フレーム㌠0 ã§ã™" + +#, c-format +msgid "frame at highest level: %d" +msgstr "最高レベルã®ãƒ•レーム: %d" + #: ../ex_cmds2.c:322 #, c-format msgid "Breakpoint in \"%s%s\" line %<PRId64>" @@ -1528,7 +1553,8 @@ msgstr "E197: 言語を \"%s\" ã«è¨å®šã§ãã¾ã›ã‚“" #. don't wait for return #: ../ex_docmd.c:387 msgid "Entering Ex mode. Type \"visual\" to go to Normal mode." -msgstr "Exモードã«å…¥ã‚Šã¾ã™. ãƒŽãƒ¼ãƒžãƒ«ã«æˆ»ã‚‹ã«ã¯\"visual\"ã¨å…¥åŠ›ã—ã¦ãã ã•ã„." +msgstr "" +"Exモードã«å…¥ã‚Šã¾ã™. ãƒŽãƒ¼ãƒžãƒ«ãƒ¢ãƒ¼ãƒ‰ã«æˆ»ã‚‹ã«ã¯\"visual\"ã¨å…¥åŠ›ã—ã¦ãã ã•ã„." #: ../ex_docmd.c:428 msgid "E501: At end-of-file" @@ -1553,7 +1579,7 @@ msgstr "é–¢æ•°ã®æœ€å¾Œã§ã™" #: ../ex_docmd.c:1628 msgid "E464: Ambiguous use of user-defined command" -msgstr "E464: ユーザ定義コマンドã®ã‚ã„ã¾ã„ãªä½¿ç”¨ã§ã™" +msgstr "E464: ユーザー定義コマンドã®ã‚ã„ã¾ã„ãªä½¿ç”¨ã§ã™" #: ../ex_docmd.c:1638 msgid "E492: Not an editor command" @@ -1606,14 +1632,14 @@ msgstr "E174: ã‚³ãƒžãƒ³ãƒ‰ãŒæ—¢ã«ã‚りã¾ã™: å†å®šç¾©ã™ã‚‹ã«ã¯ ! を追å #: ../ex_docmd.c:4432 msgid "" "\n" -" Name Args Range Complete Definition" +" Name Args Address Complete Definition" msgstr "" "\n" -" åå‰ å¼•æ•° 範囲 補完 定義" +" åå‰ å¼•æ•° アドレス 補完 定義" #: ../ex_docmd.c:4516 msgid "No user-defined commands found" -msgstr "ユーザ定義コマンドãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ" +msgstr "ユーザー定義コマンドãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ" #: ../ex_docmd.c:4538 msgid "E175: No attribute specified" @@ -1633,7 +1659,10 @@ msgstr "E178: カウントã®çœç•¥å€¤ãŒç„¡åйã§ã™" #: ../ex_docmd.c:4625 msgid "E179: argument required for -complete" -msgstr "E179: -補完ã®ãŸã‚ã®å¼•æ•°ãŒå¿…è¦ã§ã™" +msgstr "E179: -complete ã«ã¯å¼•æ•°ãŒå¿…è¦ã§ã™" + +msgid "E179: argument required for -addr" +msgstr "E179: -addr ã«ã¯å¼•æ•°ãŒå¿…è¦ã§ã™" #: ../ex_docmd.c:4635 #, c-format @@ -1646,16 +1675,20 @@ msgstr "E182: 無効ãªã‚³ãƒžãƒ³ãƒ‰åã§ã™" #: ../ex_docmd.c:4691 msgid "E183: User defined commands must start with an uppercase letter" -msgstr "E183: ユーザ定義コマンドã¯è‹±å¤§æ–‡å—ã§å§‹ã¾ã‚‰ãªã‘れã°ãªã‚Šã¾ã›ã‚“" +msgstr "E183: ユーザー定義コマンドã¯è‹±å¤§æ–‡å—ã§å§‹ã¾ã‚‰ãªã‘れã°ãªã‚Šã¾ã›ã‚“" #: ../ex_docmd.c:4696 msgid "E841: Reserved name, cannot be used for user defined command" -msgstr "E841: 予約åãªã®ã§, ユーザ定義コマンドã«åˆ©ç”¨ã§ãã¾ã›ã‚“" +msgstr "E841: 予約åãªã®ã§, ユーザー定義コマンドã«åˆ©ç”¨ã§ãã¾ã›ã‚“" #: ../ex_docmd.c:4751 #, c-format msgid "E184: No such user-defined command: %s" -msgstr "E184: ãã®ãƒ¦ãƒ¼ã‚¶å®šç¾©ã‚³ãƒžãƒ³ãƒ‰ã¯ã‚りã¾ã›ã‚“: %s" +msgstr "E184: ãã®ãƒ¦ãƒ¼ã‚¶ãƒ¼å®šç¾©ã‚³ãƒžãƒ³ãƒ‰ã¯ã‚りã¾ã›ã‚“: %s" + +#, c-format +msgid "E180: Invalid address type value: %s" +msgstr "E180: 無効ãªã‚¢ãƒ‰ãƒ¬ã‚¹ã‚¿ã‚¤ãƒ—値ã§ã™: %s" #: ../ex_docmd.c:5219 #, c-format @@ -2019,11 +2052,11 @@ msgstr "䏿£ãªãƒ•ァイルå" #: ../fileio.c:395 ../fileio.c:476 ../fileio.c:2543 ../fileio.c:2578 msgid "is a directory" -msgstr " ã¯ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ã™" +msgstr "ã¯ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ã™" #: ../fileio.c:397 msgid "is not a file" -msgstr " ã¯ãƒ•ァイルã§ã¯ã‚りã¾ã›ã‚“" +msgstr "ã¯ãƒ•ァイルã§ã¯ã‚りã¾ã›ã‚“" #: ../fileio.c:508 ../fileio.c:3522 msgid "[New File]" @@ -2039,7 +2072,7 @@ msgstr "[ファイルéŽå¤§]" #: ../fileio.c:534 msgid "[Permission Denied]" -msgstr "[èªå¯ãŒã‚りã¾ã›ã‚“]" +msgstr "[権é™ãŒã‚りã¾ã›ã‚“]" #: ../fileio.c:653 msgid "E200: *ReadPre autocommands made the file unreadable" @@ -2210,7 +2243,7 @@ msgstr " 変æ›ã‚¨ãƒ©ãƒ¼" #: ../fileio.c:3509 #, c-format msgid " in line %<PRId64>;" -msgstr "行 %<PRId64>;" +msgstr " 行 %<PRId64>;" #: ../fileio.c:3519 msgid "[Device]" @@ -2766,9 +2799,8 @@ msgid "E37: No write since last change (add ! to override)" msgstr "E37: 最後ã®å¤‰æ›´ãŒä¿å˜ã•れã¦ã„ã¾ã›ã‚“ (! ã‚’è¿½åŠ ã§å¤‰æ›´ã‚’ç ´æ£„)" #: ../globals.h:1055 -#, fuzzy msgid "E37: No write since last change" -msgstr "[最後ã®å¤‰æ›´ãŒä¿å˜ã•れã¦ã„ã¾ã›ã‚“]\n" +msgstr "E37: 最後ã®å¤‰æ›´ãŒä¿å˜ã•れã¦ã„ã¾ã›ã‚“" #: ../globals.h:1056 msgid "E38: Null argument" @@ -2810,7 +2842,7 @@ msgstr "E42: エラーã¯ã‚りã¾ã›ã‚“" #: ../globals.h:1067 msgid "E776: No location list" -msgstr "E776: å ´æ‰€ãƒªã‚¹ãƒˆã¯ã‚りã¾ã›ã‚“" +msgstr "E776: ãƒã‚±ãƒ¼ã‚·ãƒ§ãƒ³ãƒªã‚¹ãƒˆã¯ã‚りã¾ã›ã‚“" #: ../globals.h:1068 msgid "E43: Damaged match string" @@ -3831,7 +3863,7 @@ msgid "" "\n" msgstr "" "\n" -"ãれã‹ã‚‰.swpファイルを削除ã—ã¦ãã ã•ã„\n" +"å…ƒã®.swpファイルã¯å‰Šé™¤ã—ã¦ã‚‚æ§‹ã„ã¾ã›ã‚“\n" "\n" #. use msg() to start the scrolling properly @@ -3845,7 +3877,7 @@ msgstr " ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª:\n" #: ../memline.c:1448 msgid " Using specified name:\n" -msgstr " ã‚ã‚‹åå‰ã‚’使用ä¸:\n" +msgstr " 以下ã®åå‰ã‚’使用ä¸:\n" #: ../memline.c:1450 msgid " In directory " @@ -3901,7 +3933,7 @@ msgid "" " user name: " msgstr "" "\n" -" ユーザå: " +" ユーザーå: " #: ../memline.c:1568 msgid " host name: " @@ -4050,12 +4082,12 @@ msgid "" msgstr "" "\n" "(1) 別ã®ãƒ—ãƒã‚°ãƒ©ãƒ ãŒåŒã˜ãƒ•ァイルを編集ã—ã¦ã„ã‚‹ã‹ã‚‚ã—れã¾ã›ã‚“.\n" -" ã“ã®å ´åˆã«ã¯, 変更をã—ãŸéš›ã«æœ€çµ‚çš„ã«, åŒã˜ãƒ•ァイルã®ç•°ãªã‚‹\n" -" 2ã¤ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒã§ãã¦ã—ã¾ã†ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„." +" ã“ã®å ´åˆã«ã¯, 変更をã—ã¦ã—ã¾ã†ã¨1ã¤ã®ãƒ•ァイルã«å¯¾ã—ã¦ç•°ãªã‚‹2ã¤ã®\n" +" インスタンスãŒã§ãã¦ã—ã¾ã†ã®ã§, ãã†ã—ãªã„よã†ã«æ°—ã‚’ã¤ã‘ã¦ãã ã•ã„." #: ../memline.c:3245 msgid " Quit, or continue with caution.\n" -msgstr " 終了ã™ã‚‹ã‹, 注æ„ã—ãªãŒã‚‰ç¶šã‘ã¦ãã ã•ã„.\n" +msgstr " 終了ã™ã‚‹ã‹, 注æ„ã—ãªãŒã‚‰ç¶šã‘ã¦ãã ã•ã„.\n" #: ../memline.c:3246 msgid "(2) An edit session for this file crashed.\n" @@ -4479,6 +4511,11 @@ msgstr "" msgid "E574: Unknown register type %d" msgstr "E574: 未知ã®ãƒ¬ã‚¸ã‚¹ã‚¿åž‹ %d ã§ã™" +msgid "" +"E883: search pattern and expression register may not contain two or more " +"lines" +msgstr "E883: 検索パターンã¨å¼ãƒ¬ã‚¸ã‚¹ã‚¿ã«ã¯2行以上をå«ã‚られã¾ã›ã‚“" + #: ../ops.c:5089 #, c-format msgid "%<PRId64> Cols; " @@ -4563,6 +4600,10 @@ msgstr "E522: termcap 内ã«è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“" msgid "E539: Illegal character <%s>" msgstr "E539: 䏿£ãªæ–‡å—ã§ã™ <%s>" +#, c-format +msgid "For option %s" +msgstr "オプション: %s" + #: ../option.c:3862 msgid "E529: Cannot set 'term' to empty string" msgstr "E529: 'term' ã«ã¯ç©ºæ–‡å—列をè¨å®šã§ãã¾ã›ã‚“" @@ -4740,6 +4781,14 @@ msgstr "" "\n" "ã‚»ã‚ュリティコンテã‚ストをè¨å®šã§ãã¾ã›ã‚“ " +#, c-format +msgid "Could not set security context %s for %s" +msgstr "ã‚»ã‚ュリティコンテã‚スト %s ã‚’ %s ã«è¨å®šã§ãã¾ã›ã‚“" + +#, c-format +msgid "Could not get security context %s for %s. Removing it!" +msgstr "ã‚»ã‚ュリティコンテã‚スト %s ã‚’ %s ã‹ã‚‰å–å¾—ã§ãã¾ã›ã‚“. 削除ã—ã¾ã™!" + #: ../os_unix.c:1558 ../os_unix.c:1647 #, c-format msgid "dlerror = \"%s\"" @@ -4960,6 +5009,10 @@ msgstr "E554: %s{...} å†…ã«æ–‡æ³•エラーãŒã‚りã¾ã™" msgid "External submatches:\n" msgstr "外部ã®éƒ¨åˆ†è©²å½“:\n" +#, c-format +msgid "E888: (NFA regexp) cannot repeat %s" +msgstr "E888: (NFA æ£è¦è¡¨ç¾) 繰り返ã›ã¾ã›ã‚“ %s" + #: ../regexp.c:7022 msgid "" "E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be " @@ -4968,6 +5021,9 @@ msgstr "" "E864: \\%#= ã«ã¯ 0, 1 ã‚‚ã—ã㯠2 ã®ã¿ãŒç¶šã‘られã¾ã™ã€‚æ£è¦è¡¨ç¾ã‚¨ãƒ³ã‚¸ãƒ³ã¯è‡ªå‹•é¸" "択ã•れã¾ã™ã€‚" +msgid "Switching to backtracking RE engine for pattern: " +msgstr "次ã®ãƒ‘ターンã«ãƒãƒƒã‚¯ãƒˆãƒ©ãƒƒã‚ング RE エンジンをé©ç”¨ã—ã¾ã™: " + #: ../regexp_nfa.c:239 msgid "E865: (NFA) Regexp end encountered prematurely" msgstr "E865: (NFA) æœŸå¾…ã‚ˆã‚Šæ—©ãæ£è¦è¡¨ç¾ã®çµ‚端ã«åˆ°é”ã—ã¾ã—ãŸ" @@ -4980,7 +5036,7 @@ msgstr "E866: (NFA æ£è¦è¡¨ç¾) ä½ç½®ãŒèª¤ã£ã¦ã„ã¾ã™: %c" #: ../regexp_nfa.c:242 #, c-format msgid "E877: (NFA regexp) Invalid character class: %<PRId64>" -msgstr "" +msgstr "E877: (NFA æ£è¦è¡¨ç¾) ç„¡åŠ¹ãªæ–‡å—クラス: %<PRId64>" #: ../regexp_nfa.c:1261 #, c-format @@ -5590,12 +5646,12 @@ msgid "E765: 'spellfile' does not have %<PRId64> entries" msgstr "E765: 'spellfile' ã«ã¯ %<PRId64> 個ã®ã‚¨ãƒ³ãƒˆãƒªã¯ã‚りã¾ã›ã‚“" #: ../spell.c:8074 -#, fuzzy, c-format +#, c-format msgid "Word '%.*s' removed from %s" -msgstr "%s ã‹ã‚‰å˜èªžãŒå‰Šé™¤ã•れã¾ã—ãŸ" +msgstr "å˜èªž '%.*s' ㌠%s ã‹ã‚‰å‰Šé™¤ã•れã¾ã—ãŸ" #: ../spell.c:8117 -#, fuzzy, c-format +#, c-format msgid "Word '%.*s' added to %s" msgstr "%s ã«å˜èªžãŒè¿½åŠ ã•れã¾ã—ãŸ" @@ -5673,6 +5729,9 @@ msgstr "ã“ã®ãƒãƒƒãƒ•ã‚¡ã«å®šç¾©ã•ã‚ŒãŸæ§‹æ–‡è¦ç´ ã¯ã‚りã¾ã›ã‚“" msgid "E390: Illegal argument: %s" msgstr "E390: 䏿£ãªå¼•æ•°ã§ã™: %s" +msgid "syntax iskeyword " +msgstr "シンタックス用 iskeyword " + #: ../syntax.c:3299 #, c-format msgid "E391: No such syntax cluster: %s" @@ -5769,6 +5828,10 @@ msgstr "E847: æ§‹æ–‡ã®å–り込ã¿(include)ãŒå¤šéŽãŽã¾ã™" msgid "E789: Missing ']': %s" msgstr "E789: ']' ãŒã‚りã¾ã›ã‚“: %s" +#, c-format +msgid "E890: trailing char after ']': %s]%s" +msgstr "E890: ']' ã®å¾Œã‚ã«ä½™åˆ†ãªæ–‡å—ãŒã‚りã¾ã™: %s]%s" + #: ../syntax.c:4531 #, c-format msgid "E398: Missing '=': %s" @@ -5874,7 +5937,7 @@ msgstr "E415: 予期ã›ã¬ç‰å·ã§ã™: %s" #: ../syntax.c:6395 #, c-format msgid "E416: missing equal sign: %s" -msgstr "E416: ç‰å·ãŒãŒã‚りã¾ã›ã‚“: %s" +msgstr "E416: ç‰å·ãŒã‚りã¾ã›ã‚“: %s" #: ../syntax.c:6418 #, c-format @@ -6078,9 +6141,8 @@ msgstr "Vim: 入力をèªè¾¼ã¿ä¸ã®ã‚¨ãƒ©ãƒ¼ã«ã‚ˆã‚Šçµ‚了ã—ã¾ã™...\n" #. This happens when the FileChangedRO autocommand changes the #. * file in a way it becomes shorter. #: ../undo.c:379 -#, fuzzy msgid "E881: Line count changed unexpectedly" -msgstr "E834: 予期ã›ãšè¡Œã‚«ã‚¦ãƒ³ãƒˆãŒå¤‰ã‚りã¾ã—ãŸ" +msgstr "E881: 予期ã›ãšè¡Œã‚«ã‚¦ãƒ³ãƒˆãŒå¤‰ã‚りã¾ã—ãŸ" #: ../undo.c:627 #, c-format @@ -6287,23 +6349,23 @@ msgstr " システムvimrc: \"" #: ../version.c:672 msgid " user vimrc file: \"" -msgstr " ユーザ vimrc: \"" +msgstr " ユーザー vimrc: \"" #: ../version.c:677 msgid " 2nd user vimrc file: \"" -msgstr " 第2ユーザ vimrc: \"" +msgstr " 第2ユーザー vimrc: \"" #: ../version.c:682 msgid " 3rd user vimrc file: \"" -msgstr " 第3ユーザ vimrc: \"" +msgstr " 第3ユーザー vimrc: \"" #: ../version.c:687 msgid " user exrc file: \"" -msgstr " ユーザ exrc: \"" +msgstr " ユーザー exrc: \"" #: ../version.c:692 msgid " 2nd user exrc file: \"" -msgstr " 第2ユーザ exrc: \"" +msgstr " 第2ユーザー exrc: \"" #: ../version.c:699 msgid " fall-back for $VIM: \"" @@ -6379,7 +6441,7 @@ msgstr "Vimã®é–‹ç™ºã‚’応æ´ã—ã¦ãã ã•ã„!" #: ../version.c:828 msgid "Become a registered Vim user!" -msgstr "Vimã®ç™»éŒ²ãƒ¦ãƒ¼ã‚¶ã«ãªã£ã¦ãã ã•ã„!" +msgstr "Vimã®ç™»éŒ²ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ãªã£ã¦ãã ã•ã„!" #: ../version.c:831 msgid "type :help sponsor<Enter> for information " @@ -6391,7 +6453,7 @@ msgstr "è©³ç´°ãªæƒ…å ±ã¯ :help register<Enter> " #: ../version.c:834 msgid "menu Help->Sponsor/Register for information " -msgstr "詳細ã¯ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã® ヘルプ→スãƒãƒ³ã‚µãƒ¼/登録 ã‚’å‚ç…§ã—ã¦ä¸‹ã•ã„ " +msgstr "詳細ã¯ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã® ヘルプ->スãƒãƒ³ã‚µãƒ¼/登録 ã‚’å‚ç…§ã—ã¦ä¸‹ã•ã„" #: ../window.c:119 msgid "Already only one window" @@ -6429,6 +6491,9 @@ msgstr "E445: ä»–ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã«ã¯å¤‰æ›´ãŒã‚りã¾ã™" msgid "E446: No file name under cursor" msgstr "E446: カーソルã®ä¸‹ã«ãƒ•ァイルåãŒã‚りã¾ã›ã‚“" +msgid "List or number required" +msgstr "ãƒªã‚¹ãƒˆã‹æ•°å€¤ãŒå¿…è¦ã§ã™" + #~ msgid "E831: bf_key_init() called with empty password" #~ msgstr "E831: bf_key_init() ãŒç©ºãƒ‘スワードã§å‘¼ã³å‡ºã•れã¾ã—ãŸ" diff --git a/src/nvim/po/ja.sjis.po b/src/nvim/po/ja.sjis.po index 7dac89e172..16a5d2ce36 100644 --- a/src/nvim/po/ja.sjis.po +++ b/src/nvim/po/ja.sjis.po @@ -1,11 +1,11 @@ -# Japanese translation for Vim vim:set foldmethod=marker: +# Japanese translation for Vim # # Do ":help uganda" in Vim to read copying and usage conditions. # Do ":help credits" in Vim to see a list of people who contributed. # -# Last Change: 2013 Jul 06 +# Copyright (C) 2001-2016 MURAOKA Taro <koron.kaoriya@gmail.com>, +# vim-jp (http://vim-jp.org/) # -# Copyright (C) 2001-13 MURAOKA Taro <koron.kaoriya@gmail.com> # THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE. # # Original translations. @@ -14,10 +14,10 @@ msgid "" msgstr "" "Project-Id-Version: Vim 7.4\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-05-26 14:21+0200\n" -"PO-Revision-Date: 2013-07-06 15:00+0900\n" +"POT-Creation-Date: 2016-02-01 09:02+0900\n" +"PO-Revision-Date: 2016-02-01 09:08+0900\n" "Last-Translator: MURAOKA Taro <koron.kaoriya@gmail.com>\n" -"Language-Team: MURAOKA Taro <koron.kaoriya@gmail.com>\n" +"Language-Team: vim-jpj (https://github.com/vim-jp/lang-ja)\n" "Language: Japanese\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=cp932\n" @@ -34,7 +34,7 @@ msgstr "“à•”ƒGƒ‰[: –¢’m‚̃IƒvƒVƒ‡ƒ“Œ^‚Å‚·" #: ../buffer.c:92 msgid "[Location List]" -msgstr "[êŠƒŠƒXƒg]" +msgstr "[ƒƒP[ƒVƒ‡ƒ“ƒŠƒXƒg]" #: ../buffer.c:93 msgid "[Quickfix List]" @@ -277,7 +277,7 @@ msgstr "E810: ˆêŽžƒtƒ@ƒCƒ‹‚̓Ǟ‚à‚µ‚‚Í‘ž‚ª‚Å‚«‚Ü‚¹‚ñ" #: ../diff.c:755 msgid "E97: Cannot create diffs" -msgstr "E97: ·•ª‚ð쬂ł«‚Ü‚¹‚ñ " +msgstr "E97: ·•ª‚ð쬂ł«‚Ü‚¹‚ñ" #: ../diff.c:966 msgid "E816: Cannot read patch output" @@ -293,7 +293,7 @@ msgstr "E99: Œ»Ý‚̃oƒbƒtƒ@‚Í·•ªƒ‚[ƒh‚ł͂ ‚è‚Ü‚¹‚ñ" #: ../diff.c:2100 msgid "E793: No other buffer in diff mode is modifiable" -msgstr "E793: ·•ªƒ‚[ƒh‚Å‚ ‚鑼‚̃oƒbƒtƒ@‚Í•ÏX‰Â”\\‚Å‚·" +msgstr "E793: ·•ªƒ‚[ƒh‚Å‚ ‚鑼‚̃oƒbƒtƒ@‚Í•ÏX‚Å‚«‚Ü‚¹‚ñ" #: ../diff.c:2102 msgid "E100: No other buffer in diff mode" @@ -349,7 +349,7 @@ msgstr " s(‘S‘Ì)•⊮ (^L^N^P)" #: ../edit.c:86 msgid " File name completion (^F^N^P)" -msgstr "ƒtƒ@ƒCƒ‹–¼•⊮ (^F^N^P)" +msgstr " ƒtƒ@ƒCƒ‹–¼•⊮ (^F^N^P)" #: ../edit.c:87 msgid " Tag completion (^]^N^P)" @@ -377,7 +377,7 @@ msgstr " ƒRƒ}ƒ“ƒhƒ‰ƒCƒ“•⊮ (^V^N^P)" #: ../edit.c:94 msgid " User defined completion (^U^N^P)" -msgstr " ƒ†[ƒU’è‹`•⊮ (^U^N^P)" +msgstr " ƒ†[ƒU[’è‹`•⊮ (^U^N^P)" #: ../edit.c:95 msgid " Omni completion (^O^N^P)" @@ -679,6 +679,10 @@ msgstr "E696: ƒŠƒXƒgŒ^‚ɃJƒ“ƒ}‚ª‚ ‚è‚Ü‚¹‚ñ: %s" msgid "E697: Missing end of List ']': %s" msgstr "E697: ƒŠƒXƒgŒ^‚ÌÅŒã‚É ']' ‚ª‚ ‚è‚Ü‚¹‚ñ: %s" +msgid "Not enough memory to set references, garbage collection aborted!" +msgstr "" +"ƒK[ƒxƒbƒWƒRƒŒƒNƒVƒ‡ƒ“‚𒆎~‚µ‚Ü‚µ‚½! ŽQÆ‚ð쬂·‚é‚̂Ƀƒ‚ƒŠ‚ª•s‘«‚µ‚Ü‚µ‚½" + #: ../eval.c:6475 #, c-format msgid "E720: Missing colon in Dictionary: %s" @@ -721,7 +725,7 @@ msgstr "E117: –¢’m‚ÌŠÖ”‚Å‚·: %s" #: ../eval.c:7383 #, c-format msgid "E119: Not enough arguments for function: %s" -msgstr "E119: ŠÖ”‚̈ø”‚ª‚ȉ߂¬‚Ü‚·: %s" +msgstr "E119: ŠÖ”‚̈ø”‚ª‘«‚è‚Ü‚¹‚ñ: %s" #: ../eval.c:7387 #, c-format @@ -826,18 +830,16 @@ msgid "sort() argument" msgstr "sort() ‚̈ø”" #: ../eval.c:13721 -#, fuzzy msgid "uniq() argument" -msgstr "add() ‚̈ø”" +msgstr "uniq() ‚̈ø”" #: ../eval.c:13776 msgid "E702: Sort compare function failed" msgstr "E702: ƒ\\[ƒg‚Ì”äŠrŠÖ”‚ªŽ¸”s‚µ‚Ü‚µ‚½" #: ../eval.c:13806 -#, fuzzy msgid "E882: Uniq compare function failed" -msgstr "E702: ƒ\\[ƒg‚Ì”äŠrŠÖ”‚ªŽ¸”s‚µ‚Ü‚µ‚½" +msgstr "E882: Uniq ‚Ì”äŠrŠÖ”‚ªŽ¸”s‚µ‚Ü‚µ‚½" #: ../eval.c:14085 msgid "(Invalid)" @@ -863,6 +865,18 @@ msgstr "E745: ƒŠƒXƒgŒ^‚ð”’l‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·" msgid "E728: Using a Dictionary as a Number" msgstr "E728: Ž«‘Œ^‚ð”’l‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·" +msgid "E891: Using a Funcref as a Float" +msgstr "E891: ŠÖ”ŽQÆŒ^‚ð•‚“®¬”“_”‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·B" + +msgid "E892: Using a String as a Float" +msgstr "E892: •¶Žš—ñ‚ð•‚“®¬”“_”‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·" + +msgid "E893: Using a List as a Float" +msgstr "E893: ƒŠƒXƒgŒ^‚ð•‚“®¬”“_”‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·" + +msgid "E894: Using a Dictionary as a Float" +msgstr "E894: Ž«‘Œ^‚ð•‚“®¬”“_”‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·" + #: ../eval.c:16259 msgid "E729: using Funcref as a String" msgstr "E729: ŠÖ”ŽQÆŒ^‚ð•¶Žš—ñ‚Æ‚µ‚Ĉµ‚Á‚Ä‚¢‚Ü‚·" @@ -961,14 +975,14 @@ msgid "E129: Function name required" msgstr "E129: ŠÖ”–¼‚ª—v‹‚³‚ê‚Ü‚·" #: ../eval.c:17824 -#, fuzzy, c-format +#, c-format msgid "E128: Function name must start with a capital or \"s:\": %s" -msgstr "E128: ŠÖ”–¼‚Í‘å•¶Žš‚ÅŽn‚܂邩ƒRƒƒ“‚ðŠÜ‚܂Ȃ¯‚ê‚΂Ȃè‚Ü‚¹‚ñ: %s" +msgstr "E128: ŠÖ”–¼‚Í‘å•¶Žš‚© \"s:\" ‚ÅŽn‚Ü‚ç‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ: %s" #: ../eval.c:17833 -#, fuzzy, c-format +#, c-format msgid "E884: Function name cannot contain a colon: %s" -msgstr "E128: ŠÖ”–¼‚Í‘å•¶Žš‚ÅŽn‚܂邩ƒRƒƒ“‚ðŠÜ‚܂Ȃ¯‚ê‚΂Ȃè‚Ü‚¹‚ñ: %s" +msgstr "E884: ŠÖ”–¼‚ɂ̓Rƒƒ“‚͊܂߂ç‚ê‚Ü‚¹‚ñ: %s" #: ../eval.c:18336 #, c-format @@ -1081,7 +1095,7 @@ msgstr "E136: viminfo: ƒGƒ‰[‚ª‘½‰ß‚¬‚é‚Ì‚Å, ˆÈ~‚̓XƒLƒbƒv‚µ‚Ü‚·" #: ../ex_cmds.c:1458 #, c-format msgid "Reading viminfo file \"%s\"%s%s%s" -msgstr "viminfoƒtƒ@ƒCƒ‹ \"%s\"%s%s%s ‚ð“Çž‚Ý’† " +msgstr "viminfoƒtƒ@ƒCƒ‹ \"%s\"%s%s%s ‚ð“Çž‚Ý’†" #: ../ex_cmds.c:1460 msgid " info" @@ -1357,6 +1371,10 @@ msgstr "E158: –³Œø‚ȃoƒbƒtƒ@–¼‚Å‚·: %s" msgid "E157: Invalid sign ID: %<PRId64>" msgstr "E157: –³Œø‚Èsignޝ•ÊŽq‚Å‚·: %<PRId64>" +#, c-format +msgid "E885: Not possible to change sign %s" +msgstr "E885: •ÏX‚Å‚«‚È‚¢ sign ‚Å‚·: %s" + #: ../ex_cmds.c:6066 msgid " (not supported)" msgstr " (”ñƒTƒ|[ƒg)" @@ -1379,6 +1397,13 @@ msgstr "s %<PRId64>: %s" msgid "cmd: %s" msgstr "ƒRƒ}ƒ“ƒh: %s" +msgid "frame is zero" +msgstr "ƒtƒŒ[ƒ€‚ª 0 ‚Å‚·" + +#, c-format +msgid "frame at highest level: %d" +msgstr "Å‚ƒŒƒxƒ‹‚̃tƒŒ[ƒ€: %d" + #: ../ex_cmds2.c:322 #, c-format msgid "Breakpoint in \"%s%s\" line %<PRId64>" @@ -1528,7 +1553,8 @@ msgstr "E197: Œ¾Œê‚ð \"%s\" ‚ÉÝ’è‚Å‚«‚Ü‚¹‚ñ" #. don't wait for return #: ../ex_docmd.c:387 msgid "Entering Ex mode. Type \"visual\" to go to Normal mode." -msgstr "Exƒ‚[ƒh‚É“ü‚è‚Ü‚·. ƒm[ƒ}ƒ‹‚É–ß‚é‚É‚Í\"visual\"‚Æ“ü—Í‚µ‚Ä‚‚¾‚³‚¢." +msgstr "" +"Exƒ‚[ƒh‚É“ü‚è‚Ü‚·. ƒm[ƒ}ƒ‹ƒ‚[ƒh‚É–ß‚é‚É‚Í\"visual\"‚Æ“ü—Í‚µ‚Ä‚‚¾‚³‚¢." #: ../ex_docmd.c:428 msgid "E501: At end-of-file" @@ -1553,7 +1579,7 @@ msgstr "ŠÖ”‚ÌÅŒã‚Å‚·" #: ../ex_docmd.c:1628 msgid "E464: Ambiguous use of user-defined command" -msgstr "E464: ƒ†[ƒU’è‹`ƒRƒ}ƒ“ƒh‚Ì‚ ‚¢‚Ü‚¢‚ÈŽg—p‚Å‚·" +msgstr "E464: ƒ†[ƒU[’è‹`ƒRƒ}ƒ“ƒh‚Ì‚ ‚¢‚Ü‚¢‚ÈŽg—p‚Å‚·" #: ../ex_docmd.c:1638 msgid "E492: Not an editor command" @@ -1606,14 +1632,14 @@ msgstr "E174: ƒRƒ}ƒ“ƒh‚ªŠù‚É‚ ‚è‚Ü‚·: Ä’è‹`‚·‚é‚É‚Í ! ‚ð’ljÁ‚µ‚Ä‚‚¾‚³‚¢" #: ../ex_docmd.c:4432 msgid "" "\n" -" Name Args Range Complete Definition" +" Name Args Address Complete Definition" msgstr "" "\n" -" –¼‘O ˆø” ”ÍˆÍ •⊮ ’è‹`" +" –¼‘O ˆø” ƒAƒhƒŒƒX •⊮ ’è‹`" #: ../ex_docmd.c:4516 msgid "No user-defined commands found" -msgstr "ƒ†[ƒU’è‹`ƒRƒ}ƒ“ƒh‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ‚Å‚µ‚½" +msgstr "ƒ†[ƒU[’è‹`ƒRƒ}ƒ“ƒh‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ‚Å‚µ‚½" #: ../ex_docmd.c:4538 msgid "E175: No attribute specified" @@ -1633,7 +1659,10 @@ msgstr "E178: ƒJƒEƒ“ƒg‚ÌÈ—ª’l‚ª–³Œø‚Å‚·" #: ../ex_docmd.c:4625 msgid "E179: argument required for -complete" -msgstr "E179: -•⊮‚Ì‚½‚߂̈ø”‚ª•K—v‚Å‚·" +msgstr "E179: -complete ‚ɂ͈ø”‚ª•K—v‚Å‚·" + +msgid "E179: argument required for -addr" +msgstr "E179: -addr ‚ɂ͈ø”‚ª•K—v‚Å‚·" #: ../ex_docmd.c:4635 #, c-format @@ -1646,16 +1675,20 @@ msgstr "E182: –³Œø‚ȃRƒ}ƒ“ƒh–¼‚Å‚·" #: ../ex_docmd.c:4691 msgid "E183: User defined commands must start with an uppercase letter" -msgstr "E183: ƒ†[ƒU’è‹`ƒRƒ}ƒ“ƒh‚͉p‘å•¶Žš‚ÅŽn‚Ü‚ç‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ" +msgstr "E183: ƒ†[ƒU[’è‹`ƒRƒ}ƒ“ƒh‚͉p‘å•¶Žš‚ÅŽn‚Ü‚ç‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ" #: ../ex_docmd.c:4696 msgid "E841: Reserved name, cannot be used for user defined command" -msgstr "E841: —\\–ñ–¼‚Ȃ̂Å, ƒ†[ƒU’è‹`ƒRƒ}ƒ“ƒh‚É—˜—p‚Å‚«‚Ü‚¹‚ñ" +msgstr "E841: —\\–ñ–¼‚Ȃ̂Å, ƒ†[ƒU[’è‹`ƒRƒ}ƒ“ƒh‚É—˜—p‚Å‚«‚Ü‚¹‚ñ" #: ../ex_docmd.c:4751 #, c-format msgid "E184: No such user-defined command: %s" -msgstr "E184: ‚»‚̃†[ƒU’è‹`ƒRƒ}ƒ“ƒh‚Í‚ ‚è‚Ü‚¹‚ñ: %s" +msgstr "E184: ‚»‚̃†[ƒU[’è‹`ƒRƒ}ƒ“ƒh‚Í‚ ‚è‚Ü‚¹‚ñ: %s" + +#, c-format +msgid "E180: Invalid address type value: %s" +msgstr "E180: –³Œø‚ȃAƒhƒŒƒXƒ^ƒCƒv’l‚Å‚·: %s" #: ../ex_docmd.c:5219 #, c-format @@ -2019,11 +2052,11 @@ msgstr "•s³‚ȃtƒ@ƒCƒ‹–¼" #: ../fileio.c:395 ../fileio.c:476 ../fileio.c:2543 ../fileio.c:2578 msgid "is a directory" -msgstr " ‚̓fƒBƒŒƒNƒgƒŠ‚Å‚·" +msgstr "‚̓fƒBƒŒƒNƒgƒŠ‚Å‚·" #: ../fileio.c:397 msgid "is not a file" -msgstr " ‚̓tƒ@ƒCƒ‹‚ł͂ ‚è‚Ü‚¹‚ñ" +msgstr "‚̓tƒ@ƒCƒ‹‚ł͂ ‚è‚Ü‚¹‚ñ" #: ../fileio.c:508 ../fileio.c:3522 msgid "[New File]" @@ -2039,7 +2072,7 @@ msgstr "[ƒtƒ@ƒCƒ‹‰ß‘å]" #: ../fileio.c:534 msgid "[Permission Denied]" -msgstr "[”F‰Â‚ª‚ ‚è‚Ü‚¹‚ñ]" +msgstr "[Œ ŒÀ‚ª‚ ‚è‚Ü‚¹‚ñ]" #: ../fileio.c:653 msgid "E200: *ReadPre autocommands made the file unreadable" @@ -2210,7 +2243,7 @@ msgstr " •ÏŠ·ƒGƒ‰[" #: ../fileio.c:3509 #, c-format msgid " in line %<PRId64>;" -msgstr "s %<PRId64>;" +msgstr " s %<PRId64>;" #: ../fileio.c:3519 msgid "[Device]" @@ -2766,9 +2799,8 @@ msgid "E37: No write since last change (add ! to override)" msgstr "E37: ÅŒã‚Ì•ÏX‚ª•Û‘¶‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ (! ‚ð’ljÁ‚Å•ÏX‚ð”jŠü)" #: ../globals.h:1055 -#, fuzzy msgid "E37: No write since last change" -msgstr "[ÅŒã‚Ì•ÏX‚ª•Û‘¶‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ]\n" +msgstr "E37: ÅŒã‚Ì•ÏX‚ª•Û‘¶‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ" #: ../globals.h:1056 msgid "E38: Null argument" @@ -2810,7 +2842,7 @@ msgstr "E42: ƒGƒ‰[‚Í‚ ‚è‚Ü‚¹‚ñ" #: ../globals.h:1067 msgid "E776: No location list" -msgstr "E776: êŠƒŠƒXƒg‚Í‚ ‚è‚Ü‚¹‚ñ" +msgstr "E776: ƒƒP[ƒVƒ‡ƒ“ƒŠƒXƒg‚Í‚ ‚è‚Ü‚¹‚ñ" #: ../globals.h:1068 msgid "E43: Damaged match string" @@ -2931,6 +2963,10 @@ msgstr "E363: ƒpƒ^[ƒ“‚ª 'maxmempattern' ˆÈã‚̃ƒ‚ƒŠ‚ðŽg—p‚µ‚Ü‚·" msgid "E749: empty buffer" msgstr "E749: ƒoƒbƒtƒ@‚ª‹ó‚Å‚·" +#, c-format +msgid "E86: Buffer %ld does not exist" +msgstr "E86: ƒoƒbƒtƒ@ %ld ‚Í‚ ‚è‚Ü‚¹‚ñ" + #: ../globals.h:1108 msgid "E682: Invalid search pattern or delimiter" msgstr "E682: ŒŸõƒpƒ^[ƒ“‚©‹æØ‚è‹L†‚ª•s³‚Å‚·" @@ -3831,7 +3867,7 @@ msgid "" "\n" msgstr "" "\n" -"‚»‚ê‚©‚ç.swpƒtƒ@ƒCƒ‹‚ð휂µ‚Ä‚‚¾‚³‚¢\n" +"Œ³‚Ì.swpƒtƒ@ƒCƒ‹‚Í휂µ‚Ä‚à\\‚¢‚Ü‚¹‚ñ\n" "\n" #. use msg() to start the scrolling properly @@ -3845,7 +3881,7 @@ msgstr " Œ»Ý‚̃fƒBƒŒƒNƒgƒŠ:\n" #: ../memline.c:1448 msgid " Using specified name:\n" -msgstr " ‚ ‚é–¼‘O‚ðŽg—p’†:\n" +msgstr " ˆÈ‰º‚Ì–¼‘O‚ðŽg—p’†:\n" #: ../memline.c:1450 msgid " In directory " @@ -3901,7 +3937,7 @@ msgid "" " user name: " msgstr "" "\n" -" ƒ†[ƒU–¼: " +" ƒ†[ƒU[–¼: " #: ../memline.c:1568 msgid " host name: " @@ -4050,12 +4086,12 @@ msgid "" msgstr "" "\n" "(1) •ʂ̃vƒƒOƒ‰ƒ€‚ª“¯‚¶ƒtƒ@ƒCƒ‹‚ð•ÒW‚µ‚Ä‚¢‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñ.\n" -" ‚±‚ÌꇂɂÍ, •ÏX‚ð‚µ‚½Û‚ÉÅI“I‚É, “¯‚¶ƒtƒ@ƒCƒ‹‚̈قȂé\n" -" 2‚‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ª‚Å‚«‚Ä‚µ‚Ü‚¤‚±‚ƂɒˆÓ‚µ‚Ä‚‚¾‚³‚¢." +" ‚±‚ÌꇂɂÍ, •ÏX‚ð‚µ‚Ä‚µ‚Ü‚¤‚Æ1‚‚̃tƒ@ƒCƒ‹‚ɑ΂µ‚ĈقȂé2‚‚Ì\n" +" ƒCƒ“ƒXƒ^ƒ“ƒX‚ª‚Å‚«‚Ä‚µ‚Ü‚¤‚Ì‚Å, ‚»‚¤‚µ‚È‚¢‚悤‚É‹C‚ð‚‚¯‚Ä‚‚¾‚³‚¢." #: ../memline.c:3245 msgid " Quit, or continue with caution.\n" -msgstr " I—¹‚·‚é‚©, ’ˆÓ‚µ‚È‚ª‚瑱‚¯‚Ä‚‚¾‚³‚¢.\n" +msgstr " I—¹‚·‚é‚©, ’ˆÓ‚µ‚È‚ª‚瑱‚¯‚Ä‚‚¾‚³‚¢.\n" #: ../memline.c:3246 msgid "(2) An edit session for this file crashed.\n" @@ -4479,6 +4515,11 @@ msgstr "" msgid "E574: Unknown register type %d" msgstr "E574: –¢’m‚̃ŒƒWƒXƒ^Œ^ %d ‚Å‚·" +msgid "" +"E883: search pattern and expression register may not contain two or more " +"lines" +msgstr "E883: ŒŸõƒpƒ^[ƒ“‚ÆŽ®ƒŒƒWƒXƒ^‚É‚Í2sˆÈã‚ðŠÜ‚ß‚ç‚ê‚Ü‚¹‚ñ" + #: ../ops.c:5089 #, c-format msgid "%<PRId64> Cols; " @@ -4563,6 +4604,10 @@ msgstr "E522: termcap “à‚ÉŒ©‚‚©‚è‚Ü‚¹‚ñ" msgid "E539: Illegal character <%s>" msgstr "E539: •s³‚È•¶Žš‚Å‚· <%s>" +#, c-format +msgid "For option %s" +msgstr "ƒIƒvƒVƒ‡ƒ“: %s" + #: ../option.c:3862 msgid "E529: Cannot set 'term' to empty string" msgstr "E529: 'term' ‚ɂ͋󕶎š—ñ‚ðÝ’è‚Å‚«‚Ü‚¹‚ñ" @@ -4740,6 +4785,14 @@ msgstr "" "\n" "ƒZƒLƒ…ƒŠƒeƒBƒRƒ“ƒeƒLƒXƒg‚ðÝ’è‚Å‚«‚Ü‚¹‚ñ " +#, c-format +msgid "Could not set security context %s for %s" +msgstr "ƒZƒLƒ…ƒŠƒeƒBƒRƒ“ƒeƒLƒXƒg %s ‚ð %s ‚ÉÝ’è‚Å‚«‚Ü‚¹‚ñ" + +#, c-format +msgid "Could not get security context %s for %s. Removing it!" +msgstr "ƒZƒLƒ…ƒŠƒeƒBƒRƒ“ƒeƒLƒXƒg %s ‚ð %s ‚©‚çŽæ“¾‚Å‚«‚Ü‚¹‚ñ. 휂µ‚Ü‚·!" + #: ../os_unix.c:1558 ../os_unix.c:1647 #, c-format msgid "dlerror = \"%s\"" @@ -4960,6 +5013,10 @@ msgstr "E554: %s{...} “à‚É•¶–@ƒGƒ‰[‚ª‚ ‚è‚Ü‚·" msgid "External submatches:\n" msgstr "ŠO•”‚Ì•”•ªŠY“–:\n" +#, c-format +msgid "E888: (NFA regexp) cannot repeat %s" +msgstr "E888: (NFA ³‹K•\\Œ») ŒJ‚è•Ô‚¹‚Ü‚¹‚ñ %s" + #: ../regexp.c:7022 msgid "" "E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be " @@ -4968,7 +5025,9 @@ msgstr "" "E864: \\%#= ‚É‚Í 0, 1 ‚à‚µ‚‚Í 2 ‚݂̂ª‘±‚¯‚ç‚ê‚Ü‚·B³‹K•\\Œ»ƒGƒ“ƒWƒ“‚ÍŽ©“®‘I" "‘ð‚³‚ê‚Ü‚·B" -#: ../regexp_nfa.c:239 +msgid "Switching to backtracking RE engine for pattern: " +msgstr "ŽŸ‚̃pƒ^[ƒ“‚ɃoƒbƒNƒgƒ‰ƒbƒLƒ“ƒO RE ƒGƒ“ƒWƒ“‚ð“K—p‚µ‚Ü‚·: " + msgid "E865: (NFA) Regexp end encountered prematurely" msgstr "E865: (NFA) Šú‘Ò‚æ‚è‘‚³‹K•\\Œ»‚ÌI’[‚É“ž’B‚µ‚Ü‚µ‚½" @@ -4980,7 +5039,7 @@ msgstr "E866: (NFA ³‹K•\\Œ») ˆÊ’u‚ªŒë‚Á‚Ä‚¢‚Ü‚·: %c" #: ../regexp_nfa.c:242 #, c-format msgid "E877: (NFA regexp) Invalid character class: %<PRId64>" -msgstr "" +msgstr "E877: (NFA ³‹K•\\Œ») –³Œø‚È•¶ŽšƒNƒ‰ƒX: %<PRId64>" #: ../regexp_nfa.c:1261 #, c-format @@ -5590,14 +5649,14 @@ msgid "E765: 'spellfile' does not have %<PRId64> entries" msgstr "E765: 'spellfile' ‚É‚Í %<PRId64> ŒÂ‚̃Gƒ“ƒgƒŠ‚Í‚ ‚è‚Ü‚¹‚ñ" #: ../spell.c:8074 -#, fuzzy, c-format +#, c-format msgid "Word '%.*s' removed from %s" -msgstr "%s ‚©‚ç’PŒê‚ªíœ‚³‚ê‚Ü‚µ‚½" +msgstr "’PŒê '%.*s' ‚ª %s ‚©‚ç휂³‚ê‚Ü‚µ‚½" #: ../spell.c:8117 -#, fuzzy, c-format +#, c-format msgid "Word '%.*s' added to %s" -msgstr "%s ‚É’PŒê‚ª’ljÁ‚³‚ê‚Ü‚µ‚½" +msgstr "’PŒê '%.*s' ‚ª %s ‚֒ljÁ‚³‚ê‚Ü‚µ‚½" #: ../spell.c:8381 msgid "E763: Word characters differ between spell files" @@ -5673,6 +5732,9 @@ msgstr "‚±‚̃oƒbƒtƒ@‚É’è‹`‚³‚ꂽ\\•¶—v‘f‚Í‚ ‚è‚Ü‚¹‚ñ" msgid "E390: Illegal argument: %s" msgstr "E390: •s³‚Ȉø”‚Å‚·: %s" +msgid "syntax iskeyword " +msgstr "ƒVƒ“ƒ^ƒbƒNƒX—p iskeyword " + #: ../syntax.c:3299 #, c-format msgid "E391: No such syntax cluster: %s" @@ -5769,6 +5831,10 @@ msgstr "E847: \\•¶‚ÌŽæ‚èž‚Ý(include)‚ª‘½‰ß‚¬‚Ü‚·" msgid "E789: Missing ']': %s" msgstr "E789: ']' ‚ª‚ ‚è‚Ü‚¹‚ñ: %s" +#, c-format +msgid "E890: trailing char after ']': %s]%s" +msgstr "E890: ']' ‚ÌŒã‚ë‚É—]•ª‚È•¶Žš‚ª‚ ‚è‚Ü‚·: %s]%s" + #: ../syntax.c:4531 #, c-format msgid "E398: Missing '=': %s" @@ -5874,7 +5940,7 @@ msgstr "E415: —\\Šú‚¹‚Ê“™†‚Å‚·: %s" #: ../syntax.c:6395 #, c-format msgid "E416: missing equal sign: %s" -msgstr "E416: “™†‚ª‚ª‚ ‚è‚Ü‚¹‚ñ: %s" +msgstr "E416: “™†‚ª‚ ‚è‚Ü‚¹‚ñ: %s" #: ../syntax.c:6418 #, c-format @@ -6078,9 +6144,8 @@ msgstr "Vim: “ü—Í‚ð“Çž‚Ý’†‚̃Gƒ‰[‚É‚æ‚èI—¹‚µ‚Ü‚·...\n" #. This happens when the FileChangedRO autocommand changes the #. * file in a way it becomes shorter. #: ../undo.c:379 -#, fuzzy msgid "E881: Line count changed unexpectedly" -msgstr "E834: —\\Šú‚¹‚¸sƒJƒEƒ“ƒg‚ª•Ï‚í‚è‚Ü‚µ‚½" +msgstr "E881: —\\Šú‚¹‚¸sƒJƒEƒ“ƒg‚ª•Ï‚í‚è‚Ü‚µ‚½" #: ../undo.c:627 #, c-format @@ -6287,23 +6352,23 @@ msgstr " ƒVƒXƒeƒ€ vimrc: \"" #: ../version.c:672 msgid " user vimrc file: \"" -msgstr " ƒ†[ƒU vimrc: \"" +msgstr " ƒ†[ƒU[ vimrc: \"" #: ../version.c:677 msgid " 2nd user vimrc file: \"" -msgstr " ‘æ2ƒ†[ƒU vimrc: \"" +msgstr " ‘æ2ƒ†[ƒU[ vimrc: \"" #: ../version.c:682 msgid " 3rd user vimrc file: \"" -msgstr " ‘æ3ƒ†[ƒU vimrc: \"" +msgstr " ‘æ3ƒ†[ƒU[ vimrc: \"" #: ../version.c:687 msgid " user exrc file: \"" -msgstr " ƒ†[ƒU exrc: \"" +msgstr " ƒ†[ƒU[ exrc: \"" #: ../version.c:692 msgid " 2nd user exrc file: \"" -msgstr " ‘æ2ƒ†[ƒU exrc: \"" +msgstr " ‘æ2ƒ†[ƒU[ exrc: \"" #: ../version.c:699 msgid " fall-back for $VIM: \"" @@ -6379,7 +6444,7 @@ msgstr "Vim‚ÌŠJ”‚ð‰ž‰‡‚µ‚Ä‚‚¾‚³‚¢!" #: ../version.c:828 msgid "Become a registered Vim user!" -msgstr "Vim‚Ì“o˜^ƒ†[ƒU‚ɂȂÁ‚Ä‚‚¾‚³‚¢!" +msgstr "Vim‚Ì“o˜^ƒ†[ƒU[‚ɂȂÁ‚Ä‚‚¾‚³‚¢!" #: ../version.c:831 msgid "type :help sponsor<Enter> for information " @@ -6391,7 +6456,7 @@ msgstr "ÚׂÈî•ñ‚Í :help register<Enter> " #: ../version.c:834 msgid "menu Help->Sponsor/Register for information " -msgstr "Úׂ̓ƒjƒ…[‚Ì ƒwƒ‹ƒv¨ƒXƒ|ƒ“ƒT[/“o˜^ ‚ðŽQÆ‚µ‚ĉº‚³‚¢ " +msgstr "Úׂ̓ƒjƒ…[‚Ì ƒwƒ‹ƒv->ƒXƒ|ƒ“ƒT[/“o˜^ ‚ðŽQÆ‚µ‚ĉº‚³‚¢" #: ../window.c:119 msgid "Already only one window" @@ -6429,6 +6494,9 @@ msgstr "E445: ‘¼‚̃EƒBƒ“ƒhƒE‚ɂ͕ÏX‚ª‚ ‚è‚Ü‚·" msgid "E446: No file name under cursor" msgstr "E446: ƒJ[ƒ\\ƒ‹‚̉º‚Ƀtƒ@ƒCƒ‹–¼‚ª‚ ‚è‚Ü‚¹‚ñ" +msgid "List or number required" +msgstr "ƒŠƒXƒg‚©”’l‚ª•K—v‚Å‚·" + #~ msgid "E831: bf_key_init() called with empty password" #~ msgstr "E831: bf_key_init() ‚ª‹óƒpƒXƒ[ƒh‚ŌĂÑo‚³‚ê‚Ü‚µ‚½" diff --git a/src/nvim/rbuffer.h b/src/nvim/rbuffer.h index 35fb16508e..454972c69d 100644 --- a/src/nvim/rbuffer.h +++ b/src/nvim/rbuffer.h @@ -36,30 +36,36 @@ // // Note that the rbuffer_{produced,consumed} calls are necessary or these macros // create infinite loops -#define RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) \ - for (size_t rcnt = 0, _r = 1; _r; _r = 0) \ - for (char *rptr = rbuffer_read_ptr(buf, &rcnt); \ - buf->size; \ - rptr = rbuffer_read_ptr(buf, &rcnt)) +#define RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) \ + for (size_t rcnt = 0, _r = 1; _r; _r = 0) /* NOLINT(readability/braces) */ \ + for ( /* NOLINT(readability/braces) */ \ + char *rptr = rbuffer_read_ptr(buf, &rcnt); \ + buf->size; \ + rptr = rbuffer_read_ptr(buf, &rcnt)) -#define RBUFFER_UNTIL_FULL(buf, wptr, wcnt) \ - for (size_t wcnt = 0, _r = 1; _r; _r = 0) \ - for (char *wptr = rbuffer_write_ptr(buf, &wcnt); \ - rbuffer_space(buf); \ - wptr = rbuffer_write_ptr(buf, &wcnt)) +#define RBUFFER_UNTIL_FULL(buf, wptr, wcnt) \ + for (size_t wcnt = 0, _r = 1; _r; _r = 0) /* NOLINT(readability/braces) */ \ + for ( /* NOLINT(readability/braces) */ \ + char *wptr = rbuffer_write_ptr(buf, &wcnt); \ + rbuffer_space(buf); \ + wptr = rbuffer_write_ptr(buf, &wcnt)) // Iteration -#define RBUFFER_EACH(buf, c, i) \ - for (size_t i = 0; i < buf->size; i = buf->size) \ - for (char c = 0; \ - i < buf->size ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \ +#define RBUFFER_EACH(buf, c, i) \ + for (size_t i = 0; /* NOLINT(readability/braces) */ \ + i < buf->size; \ + i = buf->size) \ + for (char c = 0; /* NOLINT(readability/braces) */ \ + i < buf->size ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \ i++) -#define RBUFFER_EACH_REVERSE(buf, c, i) \ - for (size_t i = buf->size; i != SIZE_MAX; i = SIZE_MAX) \ - for (char c = 0; \ - i-- > 0 ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \ +#define RBUFFER_EACH_REVERSE(buf, c, i) \ + for (size_t i = buf->size; /* NOLINT(readability/braces) */ \ + i != SIZE_MAX; \ + i = SIZE_MAX) \ + for (char c = 0; /* NOLINT(readability/braces) */ \ + i-- > 0 ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \ ) typedef struct rbuffer RBuffer; diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index 7e53b2ccd1..f97dce9e0d 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -357,13 +357,14 @@ static int nfa_ll_index = 0; # include "regexp_nfa.c.generated.h" #endif -/* helper functions used when doing re2post() ... regatom() parsing */ -#define EMIT(c) do { \ - if (post_ptr >= post_end) { \ - realloc_post_list(); \ - } \ - *post_ptr++ = c; \ -} while (0) +// Helper functions used when doing re2post() ... regatom() parsing +#define EMIT(c) \ + do { \ + if (post_ptr >= post_end) { \ + realloc_post_list(); \ + } \ + *post_ptr++ = c; \ + } while (0) /* * Initialize internal variables before NFA compilation. @@ -2892,12 +2893,11 @@ static nfa_state_T *post2nfa(int *postfix, int *end, int nfa_calc_size) return NULL; #define PUSH(s) st_push((s), &stackp, stack_end) -#define POP() st_pop(&stackp, stack); \ - if (stackp < stack) \ - { \ - st_error(postfix, end, p); \ - xfree(stack); \ - return NULL; \ +#define POP() st_pop(&stackp, stack); \ + if (stackp < stack) { \ + st_error(postfix, end, p); \ + xfree(stack); \ + return NULL; \ } if (nfa_calc_size == FALSE) { @@ -4904,10 +4904,10 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, } else addstate(thislist, start, m, NULL, 0); -#define ADD_STATE_IF_MATCH(state) \ - if (result) { \ - add_state = state->out; \ - add_off = clen; \ +#define ADD_STATE_IF_MATCH(state) \ + if (result) { \ + add_state = state->out; \ + add_off = clen; \ } /* diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 51c8597d53..380d955f63 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -1422,7 +1422,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) } if (!op_register_set(cur_entry.data.reg.name, (yankreg_T) { .y_array = (char_u **) cur_entry.data.reg.contents, - .y_size = (linenr_T) cur_entry.data.reg.contents_size, + .y_size = cur_entry.data.reg.contents_size, .y_type = cur_entry.data.reg.type, .y_width = (colnr_T) cur_entry.data.reg.width, .timestamp = cur_entry.timestamp, @@ -2745,7 +2745,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, if (name == NUL) { break; } - if (limit_reg_lines && reg.y_size > max_reg_lines) { + if (limit_reg_lines && reg.y_size > (size_t)max_reg_lines) { continue; } wms->registers[op_reg_index(name)] = (PossiblyFreedShadaEntry) { diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 84906a3548..d2401b6776 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -9319,7 +9319,56 @@ static void suggest_try_special(suginfo_T *su) } } +// Measure how much time is spent in each state. +// Output is dumped in "suggestprof". + +#ifdef SUGGEST_PROFILE +proftime_T current; +proftime_T total; +proftime_T times[STATE_FINAL + 1]; +long counts[STATE_FINAL + 1]; + + static void +prof_init(void) +{ + for (int i = 0; i <= STATE_FINAL; i++) { + profile_zero(×[i]); + counts[i] = 0; + } + profile_start(¤t); + profile_start(&total); +} + +// call before changing state + static void +prof_store(state_T state) +{ + profile_end(¤t); + profile_add(×[state], ¤t); + counts[state]++; + profile_start(¤t); +} +# define PROF_STORE(state) prof_store(state); + + static void +prof_report(char *name) +{ + FILE *fd = fopen("suggestprof", "a"); + + profile_end(&total); + fprintf(fd, "-----------------------\n"); + fprintf(fd, "%s: %s\n", name, profile_msg(&total)); + for (int i = 0; i <= STATE_FINAL; i++) { + fprintf(fd, "%d: %s ("%" PRId64)\n", i, profile_msg(×[i]), counts[i]); + } + fclose(fd); +} +#else +# define PROF_STORE(state) +#endif + // Try finding suggestions by adding/removing/swapping letters. + static void suggest_try_change(suginfo_T *su) { char_u fword[MAXWLEN]; // copy of the bad word, case-folded @@ -9344,7 +9393,14 @@ static void suggest_try_change(suginfo_T *su) continue; // Try it for this language. Will add possible suggestions. + // +#ifdef SUGGEST_PROFILE + prof_init(); +#endif suggest_trie_walk(su, lp, fword, false); +#ifdef SUGGEST_PROFILE + prof_report("try_change"); +#endif } } @@ -9478,6 +9534,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // Always past NUL bytes now. n = (int)sp->ts_state; + PROF_STORE(sp->ts_state) sp->ts_state = STATE_ENDNUL; sp->ts_save_badflags = su->su_badflags; @@ -9517,6 +9574,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so if (sp->ts_curi > len || byts[arridx] != 0) { // Past bytes in node and/or past NUL bytes. + PROF_STORE(sp->ts_state) sp->ts_state = STATE_ENDNUL; sp->ts_save_badflags = su->su_badflags; break; @@ -9870,6 +9928,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so #endif // Save things to be restored at STATE_SPLITUNDO. sp->ts_save_badflags = su->su_badflags; + PROF_STORE(sp->ts_state) sp->ts_state = STATE_SPLITUNDO; ++depth; @@ -9936,6 +9995,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so byts = pbyts; idxs = pidxs; sp->ts_prefixdepth = PFD_PREFIXTREE; + PROF_STORE(sp->ts_state) sp->ts_state = STATE_NOPREFIX; } } @@ -9948,6 +10008,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so su->su_badflags = sp->ts_save_badflags; // Continue looking for NUL bytes. + PROF_STORE(sp->ts_state) sp->ts_state = STATE_START; // In case we went into the prefix tree. @@ -9962,9 +10023,11 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so && sp->ts_tcharlen == 0 ) { // The badword ends, can't use STATE_PLAIN. + PROF_STORE(sp->ts_state) sp->ts_state = STATE_DEL; break; } + PROF_STORE(sp->ts_state) sp->ts_state = STATE_PLAIN; // FALLTHROUGH @@ -9975,10 +10038,12 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so if (sp->ts_curi > byts[arridx]) { // Done all bytes at this node, do next state. When still at // already changed bytes skip the other tricks. - if (sp->ts_fidx >= sp->ts_fidxtry) + PROF_STORE(sp->ts_state) + if (sp->ts_fidx >= sp->ts_fidxtry) { sp->ts_state = STATE_DEL; - else + } else { sp->ts_state = STATE_FINAL; + } } else { arridx += sp->ts_curi++; c = byts[arridx]; @@ -10110,10 +10175,12 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // When past the first byte of a multi-byte char don't try // delete/insert/swap a character. if (has_mbyte && sp->ts_tcharlen > 0) { + PROF_STORE(sp->ts_state) sp->ts_state = STATE_FINAL; break; } // Try skipping one character in the bad word (delete it). + PROF_STORE(sp->ts_state) sp->ts_state = STATE_INS_PREP; sp->ts_curi = 1; if (soundfold && sp->ts_fidx == 0 && fword[sp->ts_fidx] == '*') @@ -10161,6 +10228,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so if (sp->ts_flags & TSF_DIDDEL) { // If we just deleted a byte then inserting won't make sense, // a substitute is always cheaper. + PROF_STORE(sp->ts_state) sp->ts_state = STATE_SWAP; break; } @@ -10170,11 +10238,13 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so for (;; ) { if (sp->ts_curi > byts[n]) { // Only NUL bytes at this node, go to next state. + PROF_STORE(sp->ts_state) sp->ts_state = STATE_SWAP; break; } if (byts[n + sp->ts_curi] != NUL) { // Found a byte to insert. + PROF_STORE(sp->ts_state) sp->ts_state = STATE_INS; break; } @@ -10190,6 +10260,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so n = sp->ts_arridx; if (sp->ts_curi > byts[n]) { // Done all bytes at this node, go to next state. + PROF_STORE(sp->ts_state) sp->ts_state = STATE_SWAP; break; } @@ -10250,6 +10321,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so c = *p; if (c == NUL) { // End of word, can't swap or replace. + PROF_STORE(sp->ts_state) sp->ts_state = STATE_FINAL; break; } @@ -10257,6 +10329,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // Don't swap if the first character is not a word character. // SWAP3 etc. also don't make sense then. if (!soundfold && !spell_iswordp(p, curwin)) { + PROF_STORE(sp->ts_state) sp->ts_state = STATE_REP_INI; break; } @@ -10281,6 +10354,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // When the second character is NUL we can't swap. if (c2 == NUL) { + PROF_STORE(sp->ts_state) sp->ts_state = STATE_REP_INI; break; } @@ -10288,6 +10362,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // When characters are identical, swap won't do anything. // Also get here if the second char is not a word character. if (c == c2) { + PROF_STORE(sp->ts_state) sp->ts_state = STATE_SWAP3; break; } @@ -10298,6 +10373,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so sp->ts_twordlen, tword, fword + sp->ts_fidx, c, c2); #endif + PROF_STORE(sp->ts_state) sp->ts_state = STATE_UNSWAP; ++depth; if (has_mbyte) { @@ -10312,6 +10388,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so } } else // If this swap doesn't work then SWAP3 won't either. + PROF_STORE(sp->ts_state) sp->ts_state = STATE_REP_INI; break; @@ -10359,6 +10436,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // Also get here when the third character is not a word character. // Second character may any char: "a.b" -> "b.a" if (c == c3 || c3 == NUL) { + PROF_STORE(sp->ts_state) sp->ts_state = STATE_REP_INI; break; } @@ -10369,6 +10447,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so sp->ts_twordlen, tword, fword + sp->ts_fidx, c, c3); #endif + PROF_STORE(sp->ts_state) sp->ts_state = STATE_UNSWAP3; ++depth; if (has_mbyte) { @@ -10382,8 +10461,10 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so p[2] = c; stack[depth].ts_fidxtry = sp->ts_fidx + 3; } - } else + } else { + PROF_STORE(sp->ts_state) sp->ts_state = STATE_REP_INI; + } break; case STATE_UNSWAP3: @@ -10409,6 +10490,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so if (!soundfold && !spell_iswordp(p, curwin)) { // Middle char is not a word char, skip the rotate. First and // third char were already checked at swap and swap3. + PROF_STORE(sp->ts_state) sp->ts_state = STATE_REP_INI; break; } @@ -10423,6 +10505,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so sp->ts_twordlen, tword, fword + sp->ts_fidx, p[0], p[1], p[2]); #endif + PROF_STORE(sp->ts_state) sp->ts_state = STATE_UNROT3L; ++depth; p = fword + sp->ts_fidx; @@ -10441,8 +10524,10 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so p[2] = c; stack[depth].ts_fidxtry = sp->ts_fidx + 3; } - } else + } else { + PROF_STORE(sp->ts_state) sp->ts_state = STATE_REP_INI; + } break; case STATE_UNROT3L: @@ -10472,6 +10557,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so sp->ts_twordlen, tword, fword + sp->ts_fidx, p[0], p[1], p[2]); #endif + PROF_STORE(sp->ts_state) sp->ts_state = STATE_UNROT3R; ++depth; p = fword + sp->ts_fidx; @@ -10490,8 +10576,10 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so *p = c; stack[depth].ts_fidxtry = sp->ts_fidx + 3; } - } else + } else { + PROF_STORE(sp->ts_state) sp->ts_state = STATE_REP_INI; + } break; case STATE_UNROT3R: @@ -10521,6 +10609,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so if ((lp->lp_replang == NULL && !soundfold) || sp->ts_score + SCORE_REP >= su->su_maxscore || sp->ts_fidx < sp->ts_fidxtry) { + PROF_STORE(sp->ts_state) sp->ts_state = STATE_FINAL; break; } @@ -10533,10 +10622,12 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so sp->ts_curi = lp->lp_replang->sl_rep_first[fword[sp->ts_fidx]]; if (sp->ts_curi < 0) { + PROF_STORE(sp->ts_state) sp->ts_state = STATE_FINAL; break; } + PROF_STORE(sp->ts_state) sp->ts_state = STATE_REP; // FALLTHROUGH @@ -10566,6 +10657,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so ftp->ft_from, ftp->ft_to); #endif // Need to undo this afterwards. + PROF_STORE(sp->ts_state) sp->ts_state = STATE_REP_UNDO; // Change the "from" to the "to" string. @@ -10585,6 +10677,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so if (sp->ts_curi >= gap->ga_len && sp->ts_state == STATE_REP) // No (more) matches. + PROF_STORE(sp->ts_state) sp->ts_state = STATE_FINAL; break; @@ -10604,6 +10697,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so repextra -= tl - fl; } memmove(p, ftp->ft_from, fl); + PROF_STORE(sp->ts_state) sp->ts_state = STATE_REP; break; @@ -11014,7 +11108,13 @@ static void suggest_try_soundalike(suginfo_T *su) // try all kinds of inserts/deletes/swaps/etc. // TODO: also soundfold the next words, so that we can try joining // and splitting +#ifdef SUGGEST_PROFILE + prof_init(); +#endif suggest_trie_walk(su, lp, salword, true); +#ifdef SUGGEST_PROFILE + prof_report("soundalike"); +#endif } } } @@ -13364,3 +13464,4 @@ int expand_spelling(linenr_T lnum, char_u *pat, char_u ***matchp) return ga.ga_len; } + diff --git a/src/nvim/state.c b/src/nvim/state.c index b2f3f0bebe..30133e2201 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -4,6 +4,7 @@ #include "nvim/state.h" #include "nvim/vim.h" +#include "nvim/main.h" #include "nvim/getchar.h" #include "nvim/ui.h" #include "nvim/os/input.h" @@ -32,7 +33,7 @@ getkey: // processing. Characters can come from mappings, scripts and other // sources, so this scenario is very common. key = safe_vgetc(); - } else if (!queue_empty(loop.events)) { + } else if (!queue_empty(main_loop.events)) { // Event was made available after the last queue_process_events call key = K_EVENT; } else { @@ -45,7 +46,7 @@ getkey: // directly. (void)os_inchar(NULL, 0, -1, 0); input_disable_events(); - key = !queue_empty(loop.events) ? K_EVENT : safe_vgetc(); + key = !queue_empty(main_loop.events) ? K_EVENT : safe_vgetc(); } if (key == K_EVENT) { diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 1f9dbd8228..05141eaf1e 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -812,19 +812,39 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) validate_current_state(); } +static void save_chartab(char_u *chartab) +{ + if (syn_block->b_syn_isk != empty_option) { + memmove(chartab, syn_buf->b_chartab, (size_t)32); + memmove(syn_buf->b_chartab, syn_win->w_s->b_syn_chartab, (size_t)32); + } +} + +static void restore_chartab(char_u *chartab) +{ + if (syn_win->w_s->b_syn_isk != empty_option) { + memmove(syn_buf->b_chartab, chartab, (size_t)32); + } +} + /* * Return TRUE if the line-continuation pattern matches in line "lnum". */ static int syn_match_linecont(linenr_T lnum) { - regmmatch_T regmatch; - if (syn_block->b_syn_linecont_prog != NULL) { + regmmatch_T regmatch; + // chartab array for syn iskeyword + char_u buf_chartab[32]; + save_chartab(buf_chartab); + regmatch.rmm_ic = syn_block->b_syn_linecont_ic; regmatch.regprog = syn_block->b_syn_linecont_prog; int r = syn_regexec(®match, lnum, (colnr_T)0, IF_SYN_TIME(&syn_block->b_syn_linecont_time)); syn_block->b_syn_linecont_prog = regmatch.regprog; + + restore_chartab(buf_chartab); return r; } return FALSE; @@ -1617,8 +1637,9 @@ syn_current_attr ( lpos_T pos; int lc_col; reg_extmatch_T *cur_extmatch = NULL; - char_u *line; /* current line. NOTE: becomes invalid after - looking for a pattern match! */ + char_u buf_chartab[32]; // chartab array for syn iskeyword + char_u *line; // current line. NOTE: becomes invalid after + // looking for a pattern match! /* variables for zero-width matches that have a "nextgroup" argument */ int keep_next_list; @@ -1668,6 +1689,9 @@ syn_current_attr ( * avoid matching the same item in the same position twice. */ ga_init(&zero_width_next_ga, (int)sizeof(int), 10); + // use syntax iskeyword option + save_chartab(buf_chartab); + /* * Repeat matching keywords and patterns, to find contained items at the * same column. This stops when there are no extra matches at the current @@ -1992,6 +2016,8 @@ syn_current_attr ( } while (found_match); + restore_chartab(buf_chartab); + /* * Use attributes from the current state, if within its highlighting. * If not, use attributes from the current-but-one state, etc. @@ -2522,7 +2548,8 @@ find_endpos ( regmmatch_T best_regmatch; /* startpos/endpos of best match */ lpos_T pos; char_u *line; - int had_match = FALSE; + int had_match = false; + char_u buf_chartab[32]; // chartab array for syn option iskeyword /* just in case we are invoked for a keyword */ if (idx < 0) @@ -2562,9 +2589,13 @@ find_endpos ( unref_extmatch(re_extmatch_in); re_extmatch_in = ref_extmatch(start_ext); - matchcol = startpos->col; /* start looking for a match at sstart */ - start_idx = idx; /* remember the first END pattern. */ - best_regmatch.startpos[0].col = 0; /* avoid compiler warning */ + matchcol = startpos->col; // start looking for a match at sstart + start_idx = idx; // remember the first END pattern. + best_regmatch.startpos[0].col = 0; // avoid compiler warning + + // use syntax iskeyword option + save_chartab(buf_chartab); + for (;; ) { /* * Find end pattern that matches first after "matchcol". @@ -2707,6 +2738,8 @@ find_endpos ( if (!had_match) m_endpos->lnum = 0; + restore_chartab(buf_chartab); + /* Remove external matches. */ unref_extmatch(re_extmatch_in); re_extmatch_in = NULL; @@ -3027,6 +3060,46 @@ static void syn_cmd_spell(exarg_T *eap, int syncing) redraw_win_later(curwin, NOT_VALID); } +/// Handle ":syntax iskeyword" command. +static void syn_cmd_iskeyword(exarg_T *eap, int syncing) +{ + char_u *arg = eap->arg; + char_u save_chartab[32]; + char_u *save_isk; + + if (eap->skip) { + return; + } + + arg = skipwhite(arg); + if (*arg == NUL) { + MSG_PUTS("\n"); + MSG_PUTS(_("syntax iskeyword ")); + if (curwin->w_s->b_syn_isk != empty_option) { + msg_outtrans(curwin->w_s->b_syn_isk); + } else { + msg_outtrans((char_u *)"not set"); + } + } else { + if (STRNICMP(arg, "clear", 5) == 0) { + memmove(curwin->w_s->b_syn_chartab, curbuf->b_chartab, (size_t)32); + clear_string_option(&curwin->w_s->b_syn_isk); + } else { + memmove(save_chartab, curbuf->b_chartab, (size_t)32); + save_isk = curbuf->b_p_isk; + curbuf->b_p_isk = vim_strsave(arg); + + buf_init_chartab(curbuf, false); + memmove(curwin->w_s->b_syn_chartab, curbuf->b_chartab, (size_t)32); + memmove(curbuf->b_chartab, save_chartab, (size_t)32); + clear_string_option(&curwin->w_s->b_syn_isk); + curwin->w_s->b_syn_isk = curbuf->b_p_isk; + curbuf->b_p_isk = save_isk; + } + } + redraw_win_later(curwin, NOT_VALID); +} + /* * Clear all syntax info for one buffer. */ @@ -3065,6 +3138,7 @@ void syntax_clear(synblock_T *block) xfree(block->b_syn_linecont_pat); block->b_syn_linecont_pat = NULL; block->b_syn_folditems = 0; + clear_string_option(&block->b_syn_isk); /* free the stored states */ syn_stack_free_all(block); @@ -3107,6 +3181,7 @@ static void syntax_sync_clear(void) curwin->w_s->b_syn_linecont_prog = NULL; xfree(curwin->w_s->b_syn_linecont_pat); curwin->w_s->b_syn_linecont_pat = NULL; + clear_string_option(&curwin->w_s->b_syn_isk); syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */ } @@ -3266,6 +3341,7 @@ static void syn_cmd_enable(exarg_T *eap, int syncing) /* * Handle ":syntax reset" command. + * It actually resets highlighting, not syntax. */ static void syn_cmd_reset(exarg_T *eap, int syncing) { @@ -5363,24 +5439,25 @@ struct subcommand { static struct subcommand subcommands[] = { - {"case", syn_cmd_case}, - {"clear", syn_cmd_clear}, - {"cluster", syn_cmd_cluster}, - {"conceal", syn_cmd_conceal}, - {"enable", syn_cmd_enable}, - {"include", syn_cmd_include}, - {"keyword", syn_cmd_keyword}, - {"list", syn_cmd_list}, - {"manual", syn_cmd_manual}, - {"match", syn_cmd_match}, - {"on", syn_cmd_on}, - {"off", syn_cmd_off}, - {"region", syn_cmd_region}, - {"reset", syn_cmd_reset}, - {"spell", syn_cmd_spell}, - {"sync", syn_cmd_sync}, - {"", syn_cmd_list}, - {NULL, NULL} + { "case", syn_cmd_case }, + { "clear", syn_cmd_clear }, + { "cluster", syn_cmd_cluster }, + { "conceal", syn_cmd_conceal }, + { "enable", syn_cmd_enable }, + { "include", syn_cmd_include }, + { "iskeyword", syn_cmd_iskeyword }, + { "keyword", syn_cmd_keyword }, + { "list", syn_cmd_list }, + { "manual", syn_cmd_manual }, + { "match", syn_cmd_match }, + { "on", syn_cmd_on }, + { "off", syn_cmd_off }, + { "region", syn_cmd_region }, + { "reset", syn_cmd_reset }, + { "spell", syn_cmd_spell }, + { "sync", syn_cmd_sync }, + { "", syn_cmd_list }, + { NULL, NULL } }; /* @@ -5434,6 +5511,7 @@ void ex_ownsyntax(exarg_T *eap) clear_string_option(&curwin->w_s->b_p_spc); clear_string_option(&curwin->w_s->b_p_spf); clear_string_option(&curwin->w_s->b_p_spl); + clear_string_option(&curwin->w_s->b_syn_isk); } /* save value of b:current_syntax */ @@ -6874,8 +6952,23 @@ highlight_color ( else if (!(TOLOWER_ASC(what[0]) == 'b' && TOLOWER_ASC(what[1]) == 'g')) return NULL; if (modec == 'g') { - if (fg) + if (what[2] == '#' && ui_rgb_attached()) { + if (fg) { + n = HL_TABLE()[id - 1].sg_rgb_fg; + } else if (sp) { + n = HL_TABLE()[id - 1].sg_rgb_sp; + } else { + n = HL_TABLE()[id - 1].sg_rgb_bg; + } + if (n < 0 || n > 0xffffff) { + return NULL; + } + snprintf((char *)name, sizeof(name), "#%06x", n); + return name; + } + if (fg) { return HL_TABLE()[id - 1].sg_rgb_fg_name; + } if (sp) { return HL_TABLE()[id - 1].sg_rgb_sp_name; } diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 104cc47cda..3e41926b70 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -63,6 +63,7 @@ #include "nvim/map.h" #include "nvim/misc1.h" #include "nvim/move.h" +#include "nvim/main.h" #include "nvim/state.h" #include "nvim/ex_docmd.h" #include "nvim/ex_cmds.h" @@ -163,9 +164,9 @@ static VTermColor default_vt_bg_rgb; void terminal_init(void) { invalidated_terminals = pmap_new(ptr_t)(); - time_watcher_init(&loop, &refresh_timer, NULL); + time_watcher_init(&main_loop, &refresh_timer, NULL); // refresh_timer_cb will redraw the screen which can call vimscript - refresh_timer.events = queue_new_child(loop.events); + refresh_timer.events = queue_new_child(main_loop.events); // initialize a rgb->color index map for cterm attributes(VTermScreenCell // only has RGB information and we need color indexes for terminal UIs) @@ -452,7 +453,7 @@ static int terminal_execute(VimState *state, int key) case K_EVENT: // We cannot let an event free the terminal yet. It is still needed. s->term->refcount++; - queue_process_events(loop.events); + queue_process_events(main_loop.events); s->term->refcount--; if (s->term->buf_handle == 0) { s->close = true; @@ -1158,15 +1159,15 @@ static bool is_focused(Terminal *term) return State & TERM_FOCUS && curbuf->terminal == term; } -#define GET_CONFIG_VALUE(k, o) \ - do { \ - Error err; \ - /* Only called from terminal_open where curbuf->terminal is the */ \ - /* context */ \ - o = dict_get_value(curbuf->b_vars, cstr_as_string(k), &err); \ - if (o.type == kObjectTypeNil) { \ - o = dict_get_value(&globvardict, cstr_as_string(k), &err); \ - } \ +#define GET_CONFIG_VALUE(k, o) \ + do { \ + Error err; \ + /* Only called from terminal_open where curbuf->terminal is the */ \ + /* context */ \ + o = dict_get_value(curbuf->b_vars, cstr_as_string(k), &err); \ + if (o.type == kObjectTypeNil) { \ + o = dict_get_value(&globvardict, cstr_as_string(k), &err); \ + } \ } while (0) static char *get_config_string(char *key) diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 3e17117db0..4b0b5e8d26 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -9,7 +9,6 @@ SCRIPTSOURCE := ../../../runtime SCRIPTS := \ test8.out \ - test10.out \ test12.out \ test13.out \ test14.out \ @@ -17,7 +16,6 @@ SCRIPTS := \ test24.out \ test30.out \ test32.out \ - test34.out \ test37.out \ test40.out \ test42.out \ @@ -26,21 +24,23 @@ SCRIPTS := \ test49.out \ test52.out \ test53.out \ - test55.out \ test64.out \ test69.out \ test73.out \ test79.out \ - test_listlbr.out \ test_marks.out \ # Tests using runtest.vim.vim. # Keep test_alot*.res as the last one, sort the others. NEW_TESTS = \ test_cursor_func.res \ + test_hardcopy.res \ test_help_tagjump.res \ + test_langmap.res \ test_menu.res \ + test_syntax.res \ test_timers.res \ + test_unlet.res \ test_viml.res \ test_alot.res @@ -60,7 +60,7 @@ ifdef USE_VALGRIND TOOL := valgrind -q \ -q \ $(VALGRIND_TOOL) \ - --suppressions=../../../.valgrind.supp \ + --suppressions=../../.valgrind.supp \ --error-exitcode=123 \ --log-file=valgrind.\%p.$* \ $(VGDB) \ diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim index 2712fb9371..578d64efde 100644 --- a/src/nvim/testdir/runtest.vim +++ b/src/nvim/testdir/runtest.vim @@ -61,12 +61,13 @@ endif " Locate Test_ functions and execute them. set nomore redir @q -function /^Test_ +silent function /^Test_ redir END let tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g')) " Execute the tests in alphabetical order. for test in sort(tests) + echo 'Executing ' . test if exists("*SetUp") call SetUp() endif diff --git a/src/nvim/testdir/test10.in b/src/nvim/testdir/test10.in deleted file mode 100644 index 2178cf41ce..0000000000 --- a/src/nvim/testdir/test10.in +++ /dev/null @@ -1,110 +0,0 @@ -Test for 'errorformat'. This will fail if the quickfix feature was disabled. - -STARTTEST -:7/start of errorfile/,/end of errorfile/w! Xerrorfile1 -:7/start of errorfile/,/end of errorfile/-1w! Xerrorfile2 -:/start of testfile/,/end of testfile/w! Xtestfile -:set efm+==%f=\\,\ line\ %l%*\\D%v%*[^\ ]\ %m -:set efm^=%AError\ in\ \"%f\"\ at\ line\ %l:,%Z%p^,%C%m -:cf Xerrorfile2 -:clast -:copen -:let a=w:quickfix_title -:wincmd p -lgR=a
-:cf Xerrorfile1 -grA -:cn -gRLINE 6, COL 19 -:cn -gRNO COLUMN SPECIFIED -:cn -gRAGAIN NO COLUMN -:cn -gRCOL 1 -:cn -gRCOL 2 -:cn -gRCOL 10 -:cn -gRVCOL 10 -:cn -grI -:cn -gR. SPACE POINTER -:cn -gR. DOT POINTER -:cn -gR. DASH POINTER -:cn -gR. TAB-SPACE POINTER -:clast -:cprev -:cprev -:wincmd w -:let a=w:quickfix_title -:wincmd p -lgR=a
-:w! test.out " Write contents of this file -:qa! -ENDTEST - -start of errorfile -"Xtestfile", line 4.12: 1506-045 (S) Undeclared identifier fd_set. -"Xtestfile", line 6 col 19; this is an error -gcc -c -DHAVE_CONFIsing-prototypes -I/usr/X11R6/include version.c -Xtestfile:9: parse error before `asd' -make: *** [vim] Error 1 -in file "Xtestfile" linenr 10: there is an error - -2 returned -"Xtestfile", line 11 col 1; this is an error -"Xtestfile", line 12 col 2; this is another error -"Xtestfile", line 14:10; this is an error in column 10 -=Xtestfile=, line 15:10; this is another error, but in vcol 10 this time -"Xtestfile", linenr 16: yet another problem -Error in "Xtestfile" at line 17: -x should be a dot - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17 - ^ -Error in "Xtestfile" at line 18: -x should be a dot - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18 -.............^ -Error in "Xtestfile" at line 19: -x should be a dot - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19 ---------------^ -Error in "Xtestfile" at line 20: -x should be a dot - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20 - ^ - -Does anyone know what is the problem and how to correction it? -"Xtestfile", line 21 col 9: What is the title of the quickfix window? -"Xtestfile", line 22 col 9: What is the title of the quickfix window? -end of errorfile - -start of testfile - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 2 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 3 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 4 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 5 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 6 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 7 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 8 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 9 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 10 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 11 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 12 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 13 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 14 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 15 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 16 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 21 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 22 -end of testfile diff --git a/src/nvim/testdir/test10.ok b/src/nvim/testdir/test10.ok deleted file mode 100644 index 76a02f40b4..0000000000 --- a/src/nvim/testdir/test10.ok +++ /dev/null @@ -1,23 +0,0 @@ -start of testfile - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 2 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 3 - xxxxxxxxxxAxxxxxxxxxxxxxxxxxxx line 4 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 5 - xxxxxxxxxxxxxxxxxLINE 6, COL 19 line 6 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 7 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 8 - NO COLUMN SPECIFIEDxxxxxxxxxxx line 9 - AGAIN NO COLUMNxxxxxxxxxxxxxxx line 10 -COL 1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 11 - COL 2xxxxxxxxxxxxxxxxxxxxxxxxx line 12 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 13 - xxxxxxxxCOL 10xxxxxxxxxxxxxxxx line 14 - xVCOL 10xxxxxxxxxxxxxxxxxxxxxx line 15 - Ixxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 16 - xxxx. SPACE POINTERxxxxxxxxxxx line 17 - xxxxx. DOT POINTERxxxxxxxxxxxx line 18 - xxxxxx. DASH POINTERxxxxxxxxxx line 19 - xxxxxxx. TAB-SPACE POINTERxxxx line 20 - xxxxxxxx:cf Xerrorfile1xxxxxxx line 21 - xxxxxxxx:cf Xerrorfile2xxxxxxx line 22 -end of testfile diff --git a/src/nvim/testdir/test10a.in b/src/nvim/testdir/test10a.in deleted file mode 100644 index 99a5a03db8..0000000000 --- a/src/nvim/testdir/test10a.in +++ /dev/null @@ -1,72 +0,0 @@ -Test for 'errorformat'. - -STARTTEST -:/start of errorfile/,/end of errorfile/w! Xerrorfile -:/start of testfile/,/end of testfile/w! Xtestfile -:cf Xerrorfile -rA -:cn -rB -:cn -rC -:cn -rD -:cn -rE -:w! test.out " Write contents of this file -:qa! -ENDTEST - -start of errorfile - - printf(" %d \n", (number/other)%10 ); -..................^ -%CC-E-NOSEMI, Missing ";". -at line number 4 in file SYS$DISK:XTESTFILE - - other=10000000; -.............^ -%CC-E-UNDECLARED, In this statement, "oszt" is not declared. -at line number 7 in file SYS$DISK:XTESTFILE - - for (i = 0; i<7 ; i++ ){ -..................^ -%CC-E-UNDECLARED, In this statement, "i" is not declared. -at line number 16 in file SYS$DISK:XTESTFILE - -some other error somewhere here. -...........................^ -%CC-W-WARRING, Sorry, but no expalnation for such an warring. -at line number 19 in file SYS$DISK:XTESTFILE - -and finally some other error exactly here. -.....................................^ -%CC-I-INFORMATIONAL, It should be some informational message. -at line number 20 in file SYS$DISK:XTESTFILE - -Does anyone know what is the problem and how to correct ?? :) -end of errorfile - -start of testfile -01234567890123456789012345678901234567 -line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 4 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 8 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 10 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 11 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 12 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 13 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 14 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 15 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 16 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 17 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 18 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 19 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 20 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 21 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 22 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -end of testfile diff --git a/src/nvim/testdir/test10a.ok b/src/nvim/testdir/test10a.ok deleted file mode 100644 index 10e78c9239..0000000000 --- a/src/nvim/testdir/test10a.ok +++ /dev/null @@ -1,23 +0,0 @@ -start of testfile -01234567890123456789012345678901234567 -line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 4 xxxxxxxxxxAxxxxxxxxxxxxxxxxxxx -line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 7 xxxxxBxxxxxxxxxxxxxxxxxxxxxxxx -line 8 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 10 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 11 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 12 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 13 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 14 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 15 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 16 xxxxxxxxxxCxxxxxxxxxxxxxxxxxxx -line 17 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 18 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 19 xxxxxxxxxxxxxxxxxxxDxxxxxxxxxx -line 20 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxE -line 21 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 22 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -end of testfile diff --git a/src/nvim/testdir/test34.in b/src/nvim/testdir/test34.in deleted file mode 100644 index 4cb7e9494a..0000000000 --- a/src/nvim/testdir/test34.in +++ /dev/null @@ -1,86 +0,0 @@ -Test for user functions. -Also test an <expr> mapping calling a function. -Also test that a builtin function cannot be replaced. -Also test for regression when calling arbitrary expression. - -STARTTEST -:function Table(title, ...) -: let ret = a:title -: let idx = 1 -: while idx <= a:0 -: exe "let ret = ret . a:" . idx -: let idx = idx + 1 -: endwhile -: return ret -:endfunction -:function Compute(n1, n2, divname) -: if a:n2 == 0 -: return "fail" -: endif -: exe "let g:" . a:divname . " = ". a:n1 / a:n2 -: return "ok" -:endfunction -:func Expr1() -: normal! v -: return "111" -:endfunc -:func Expr2() -: call search('XX', 'b') -: return "222" -:endfunc -:func ListItem() -: let g:counter += 1 -: return g:counter . '. ' -:endfunc -:func ListReset() -: let g:counter = 0 -: return '' -:endfunc -:func FuncWithRef(a) -: unlet g:FuncRef -: return a:a -:endfunc -:let g:FuncRef=function("FuncWithRef") -:let counter = 0 -:inoremap <expr> ( ListItem() -:inoremap <expr> [ ListReset() -:imap <expr> + Expr1() -:imap <expr> * Expr2() -:let retval = "nop" -/^here -C=Table("xxx", 4, "asdf") - =Compute(45, 0, "retval") - =retval - =Compute(45, 5, "retval") - =retval - =g:FuncRef(333) - -XX+-XX ----*--- -(one -(two -[(one again:call append(line('$'), max([1, 2, 3])) -:call extend(g:, {'max': function('min')}) -:call append(line('$'), max([1, 2, 3])) -:try -: " Regression: the first line below used to throw ?E110: Missing ')'? -: " Second is here just to prove that this line is correct when not skipping -: " rhs of &&. -: $put =(0&&(function('tr'))(1, 2, 3)) -: $put =(1&&(function('tr'))(1, 2, 3)) -:catch -: $put ='!!! Unexpected exception:' -: $put =v:exception -:endtry -:$-9,$w! test.out -:delfunc Table -:delfunc Compute -:delfunc Expr1 -:delfunc Expr2 -:delfunc ListItem -:delfunc ListReset -:unlet retval counter -:q! -ENDTEST - -here diff --git a/src/nvim/testdir/test34.ok b/src/nvim/testdir/test34.ok deleted file mode 100644 index 97995de80e..0000000000 --- a/src/nvim/testdir/test34.ok +++ /dev/null @@ -1,10 +0,0 @@ -xxx4asdf fail nop ok 9 333 -XX111-XX ----222--- -1. one -2. two -1. one again -3 -3 -0 -1 diff --git a/src/nvim/testdir/test55.in b/src/nvim/testdir/test55.in deleted file mode 100644 index 9a55eac6f6..0000000000 --- a/src/nvim/testdir/test55.in +++ /dev/null @@ -1,600 +0,0 @@ -Tests for List and Dictionary types. vim: set ft=vim : - -STARTTEST -:fun Test(...) -:lang C -:" Creating List directly with different types -:let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},] -:$put =string(l) -:$put =string(l[-1]) -:$put =string(l[-4]) -:try -: $put =string(l[-5]) -:catch -: $put =v:exception[:14] -:endtry -:" List slices -:$put =string(l[:]) -:$put =string(l[1:]) -:$put =string(l[:-2]) -:$put =string(l[0:8]) -:$put =string(l[8:-1]) -:" -:" List identity -:let ll = l -:let lx = copy(l) -:try -: $put =(l == ll) . (l isnot ll) . (l is ll) . (l == lx) . (l is lx) . (l isnot lx) -:catch -: $put =v:exception -:endtry -:" -:" Creating Dictionary directly with different types -:let d = {001: 'asd', 'b': [1, 2, function('strlen')], -1: {'a': 1},} -:$put =string(d) . d.1 -:$put =string(sort(keys(d))) -:$put =string (values(d)) -:for [key, val] in items(d) -: $put =key . ':' . string(val) -: unlet key val -:endfor -:call extend (d, {3:33, 1:99}) -:call extend(d, {'b':'bbb', 'c':'ccc'}, "keep") -:try -: call extend(d, {3:333,4:444}, "error") -:catch -: $put =v:exception[:15] . v:exception[-1:-1] -:endtry -:$put =string(d) -:call filter(d, 'v:key =~ ''[ac391]''') -:$put =string(d) -:" -:" Dictionary identity -:let dd = d -:let dx = copy(d) -:try -: $put =(d == dd) . (d isnot dd) . (d is dd) . (d == dx) . (d is dx) . (d isnot dx) -:catch -: $put =v:exception -:endtry -:" -:" Changing var type should fail -:try -: let d = [] -:catch -: $put =v:exception[:14] . v:exception[-1:-1] -:endtry -:try -: let l = {} -:catch -: $put =v:exception[:14] . v:exception[-1:-1] -:endtry -:" -:" removing items with :unlet -:unlet l[2] -:$put =string(l) -:let l = range(8) -:try -:unlet l[:3] -:unlet l[1:] -:catch -:$put =v:exception -:endtry -:$put =string(l) -:" -:unlet d.c -:unlet d[-1] -:$put =string(d) -:" -:" removing items out of range: silently skip items that don't exist -let l = [0, 1, 2, 3] -:unlet l[2:1] -:$put =string(l) -let l = [0, 1, 2, 3] -:unlet l[2:2] -:$put =string(l) -let l = [0, 1, 2, 3] -:unlet l[2:3] -:$put =string(l) -let l = [0, 1, 2, 3] -:unlet l[2:4] -:$put =string(l) -let l = [0, 1, 2, 3] -:unlet l[2:5] -:$put =string(l) -let l = [0, 1, 2, 3] -:unlet l[-1:2] -:$put =string(l) -let l = [0, 1, 2, 3] -:unlet l[-2:2] -:$put =string(l) -let l = [0, 1, 2, 3] -:unlet l[-3:2] -:$put =string(l) -let l = [0, 1, 2, 3] -:unlet l[-4:2] -:$put =string(l) -let l = [0, 1, 2, 3] -:unlet l[-5:2] -:$put =string(l) -let l = [0, 1, 2, 3] -:unlet l[-6:2] -:$put =string(l) -:" -:" assignment to a list -:let l = [0, 1, 2, 3] -:let [va, vb] = l[2:3] -:$put =va -:$put =vb -:try -: let [va, vb] = l -:catch -: $put =v:exception[:14] -:endtry -:try -: let [va, vb] = l[1:1] -:catch -: $put =v:exception[:14] -:endtry -:" -:" manipulating a big Dictionary (hashtable.c has a border of 1000 entries) -:let d = {} -:for i in range(1500) -: let d[i] = 3000 - i -:endfor -:$put =d[0] . ' ' . d[100] . ' ' . d[999] . ' ' . d[1400] . ' ' . d[1499] -:try -: let n = d[1500] -:catch -: $put =substitute(v:exception, '\v(.{14}).*( \d{4}).*', '\1\2', '') -:endtry -:" lookup each items -:for i in range(1500) -: if d[i] != 3000 - i -: $put =d[i] -: endif -:endfor -: let i += 1 -:" delete even items -:while i >= 2 -: let i -= 2 -: unlet d[i] -:endwhile -:$put =get(d, 1500 - 100, 'NONE') . ' ' . d[1] -:" delete odd items, checking value, one intentionally wrong -:let d[33] = 999 -:let i = 1 -:while i < 1500 -: if d[i] != 3000 - i -: $put =i . '=' . d[i] -: else -: unlet d[i] -: endif -: let i += 2 -:endwhile -:$put =string(d) " must be almost empty now -:unlet d -:" -:" Dictionary function -:let dict = {} -:func dict.func(a) dict -: $put =a:a . len(self.data) -:endfunc -:let dict.data = [1,2,3] -:call dict.func("len: ") -:let x = dict.func("again: ") -:try -: let Fn = dict.func -: call Fn('xxx') -:catch -: $put =v:exception[:15] -:endtry -:" -:" Function in script-local List or Dict -:let g:dict = {} -:function g:dict.func() dict -: $put ='g:dict.func'.self.foo[1].self.foo[0]('asdf') -:endfunc -:let g:dict.foo = ['-', 2, 3] -:call insert(g:dict.foo, function('strlen')) -:call g:dict.func() -:" -:" Nasty: remove func from Dict that's being called (works) -:let d = {1:1} -:func d.func(a) -: return "a:". a:a -:endfunc -:$put =d.func(string(remove(d, 'func'))) -:" -:" Nasty: deepcopy() dict that refers to itself (fails when noref used) -:let d = {1:1, 2:2} -:let l = [4, d, 6] -:let d[3] = l -:let dc = deepcopy(d) -:try -: let dc = deepcopy(d, 1) -:catch -: $put =v:exception[:14] -:endtry -:let l2 = [0, l, l, 3] -:let l[1] = l2 -:let l3 = deepcopy(l2) -:$put ='same list: ' . (l3[1] is l3[2]) -:" -:" Locked variables -:for depth in range(5) -: $put ='depth is ' . depth -: for u in range(3) -: unlet l -: let l = [0, [1, [2, 3]], {4: 5, 6: {7: 8}}] -: exe "lockvar " . depth . " l" -: if u == 1 -: exe "unlockvar l" -: elseif u == 2 -: exe "unlockvar " . depth . " l" -: endif -: let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]") -: $put =ps -: let ps = '' -: try -: let l[1][1][0] = 99 -: let ps .= 'p' -: catch -: let ps .= 'F' -: endtry -: try -: let l[1][1] = [99] -: let ps .= 'p' -: catch -: let ps .= 'F' -: endtry -: try -: let l[1] = [99] -: let ps .= 'p' -: catch -: let ps .= 'F' -: endtry -: try -: let l[2]['6'][7] = 99 -: let ps .= 'p' -: catch -: let ps .= 'F' -: endtry -: try -: let l[2][6] = {99: 99} -: let ps .= 'p' -: catch -: let ps .= 'F' -: endtry -: try -: let l[2] = {99: 99} -: let ps .= 'p' -: catch -: let ps .= 'F' -: endtry -: try -: let l = [99] -: let ps .= 'p' -: catch -: let ps .= 'F' -: endtry -: $put =ps -: endfor -:endfor -:" -:" Unletting locked variables -:$put ='Unletting:' -:for depth in range(5) -: $put ='depth is ' . depth -: for u in range(3) -: unlet l -: let l = [0, [1, [2, 3]], {4: 5, 6: {7: 8}}] -: exe "lockvar " . depth . " l" -: if u == 1 -: exe "unlockvar l" -: elseif u == 2 -: exe "unlockvar " . depth . " l" -: endif -: let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]") -: $put =ps -: let ps = '' -: try -: unlet l[2]['6'][7] -: let ps .= 'p' -: catch -: let ps .= 'F' -: endtry -: try -: unlet l[2][6] -: let ps .= 'p' -: catch -: let ps .= 'F' -: endtry -: try -: unlet l[2] -: let ps .= 'p' -: catch -: let ps .= 'F' -: endtry -: try -: unlet l[1][1][0] -: let ps .= 'p' -: catch -: let ps .= 'F' -: endtry -: try -: unlet l[1][1] -: let ps .= 'p' -: catch -: let ps .= 'F' -: endtry -: try -: unlet l[1] -: let ps .= 'p' -: catch -: let ps .= 'F' -: endtry -: try -: unlet l -: let ps .= 'p' -: catch -: let ps .= 'F' -: endtry -: $put =ps -: endfor -:endfor -:" -:" Locked variables and :unlet or list / dict functions -:$put ='Locks and commands or functions:' -:" -:$put ='No :unlet after lock on dict:' -:unlet! d -:let d = {'a': 99, 'b': 100} -:lockvar 1 d -:try -: unlet d.a -: $put ='did :unlet' -:catch -: $put =v:exception[:16] -:endtry -:$put =string(d) -:" -:$put =':unlet after lock on dict item:' -:unlet! d -:let d = {'a': 99, 'b': 100} -:lockvar d.a -:try -: unlet d.a -: $put ='did :unlet' -:catch -: $put =v:exception[:16] -:endtry -:$put =string(d) -:" -:$put ='filter() after lock on dict item:' -:unlet! d -:let d = {'a': 99, 'b': 100} -:lockvar d.a -:try -: call filter(d, 'v:key != "a"') -: $put ='did filter()' -:catch -: $put =v:exception[:16] -:endtry -:$put =string(d) -:" -:$put ='map() after lock on dict:' -:unlet! d -:let d = {'a': 99, 'b': 100} -:lockvar 1 d -:try -: call map(d, 'v:val + 200') -: $put ='did map()' -:catch -: $put =v:exception[:16] -:endtry -:$put =string(d) -:" -:$put ='No extend() after lock on dict item:' -:unlet! d -:let d = {'a': 99, 'b': 100} -:lockvar d.a -:try -: $put =string(extend(d, {'a': 123})) -: $put ='did extend()' -:catch -: $put =v:exception[:14] -:endtry -:$put =string(d) -:" -:$put ='No remove() of write-protected scope-level variable:' -:fun! Tfunc(this_is_a_loooooooooong_parameter_name) -: try -: $put =string(remove(a:, 'this_is_a_loooooooooong_parameter_name')) -: $put ='did remove()' -: catch -: $put =v:exception[:14] -: endtry -:endfun -:call Tfunc('testval') -:" -:$put ='No extend() of write-protected scope-level variable:' -:fun! Tfunc(this_is_a_loooooooooong_parameter_name) -: try -: $put =string(extend(a:, {'this_is_a_loooooooooong_parameter_name': 1234})) -: $put ='did extend()' -: catch -: $put =v:exception[:14] -: endtry -:endfun -:call Tfunc('testval') -:" -:$put ='No :unlet of variable in locked scope:' -:let b:testvar = 123 -:lockvar 1 b: -:try -: unlet b:testvar -: $put ='b:testvar was :unlet: '. (!exists('b:testvar')) -:catch -: $put =v:exception[:16] -:endtry -:unlockvar 1 b: -:unlet! b:testvar -:" -:$put ='No :let += of locked list variable:' -:let l = ['a', 'b', 3] -:lockvar 1 l -:try -: let l += ['x'] -: $put ='did :let +=' -:catch -: $put =v:exception[:14] -:endtry -:$put =string(l) -:" -:unlet l -:let l = [1, 2, 3, 4] -:lockvar! l -:$put =string(l) -:unlockvar l[1] -:unlet l[0:1] -:$put =string(l) -:unlet l[1:2] -:$put =string(l) -:unlockvar l[1] -:let l[0:1] = [0, 1] -:$put =string(l) -:let l[1:2] = [0, 1] -:$put =string(l) -:unlet l -:" :lockvar/islocked() triggering script autoloading -:set rtp+=./sautest -:lockvar g:footest#x -:unlockvar g:footest#x -:$put ='locked g:footest#x:'.islocked('g:footest#x') -:$put ='exists g:footest#x:'.exists('g:footest#x') -:$put ='g:footest#x: '.g:footest#x -:" -:" a:000 function argument -:" first the tests that should fail -:try -: let a:000 = [1, 2] -:catch -: $put ='caught a:000' -:endtry -:try -: let a:000[0] = 9 -:catch -: $put ='caught a:000[0]' -:endtry -:try -: let a:000[2] = [9, 10] -:catch -: $put ='caught a:000[2]' -:endtry -:try -: let a:000[3] = {9: 10} -:catch -: $put ='caught a:000[3]' -:endtry -:" now the tests that should pass -:try -: let a:000[2][1] = 9 -: call extend(a:000[2], [5, 6]) -: let a:000[3][5] = 8 -: let a:000[3]['a'] = 12 -: $put =string(a:000) -:catch -: $put ='caught ' . v:exception -:endtry -:" -:" reverse(), sort(), uniq() -:let l = ['-0', 'A11', 2, 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5] -:$put =string(uniq(copy(l))) -:$put =string(reverse(l)) -:$put =string(reverse(reverse(l))) -:$put =string(sort(l)) -:$put =string(reverse(sort(l))) -:$put =string(sort(reverse(sort(l)))) -:$put =string(uniq(sort(l))) -:let l=[7, 9, 'one', 18, 12, 22, 'two', 10.0e-16, -1, 'three', 0xff, 0.22, 'four'] -:$put =string(sort(copy(l), 'n')) -:let l=[7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', {}, []] -:$put =string(sort(copy(l), 1)) -:$put =string(sort(copy(l), 'i')) -:$put =string(sort(copy(l))) -:" -:" splitting a string to a List -:$put =string(split(' aa bb ')) -:$put =string(split(' aa bb ', '\W\+', 0)) -:$put =string(split(' aa bb ', '\W\+', 1)) -:$put =string(split(' aa bb ', '\W', 1)) -:$put =string(split(':aa::bb:', ':', 0)) -:$put =string(split(':aa::bb:', ':', 1)) -:$put =string(split('aa,,bb, cc,', ',\s*', 1)) -:$put =string(split('abc', '\zs')) -:$put =string(split('abc', '\zs', 1)) -:" -:" compare recursively linked list and dict -:let l = [1, 2, 3, 4] -:let d = {'1': 1, '2': l, '3': 3} -:let l[1] = d -:$put =(l == l) -:$put =(d == d) -:$put =(l != deepcopy(l)) -:$put =(d != deepcopy(d)) -:" -:" compare complex recursively linked list and dict -:let l = [] -:call add(l, l) -:let dict4 = {"l": l} -:call add(dict4.l, dict4) -:let lcopy = deepcopy(l) -:let dict4copy = deepcopy(dict4) -:$put =(l == lcopy) -:$put =(dict4 == dict4copy) -:" -:" Pass the same List to extend() -:let l = [1, 2, 3, 4, 5] -:call extend(l, l) -:$put =string(l) -:" -:" Pass the same Dict to extend() -:let d = { 'a': {'b': 'B'}} -:call extend(d, d) -:$put =string(d) -:" -:" Pass the same Dict to extend() with "error" -:try -: call extend(d, d, "error") -:catch -: $put =v:exception[:15] . v:exception[-1:-1] -:endtry -:$put =string(d) -:" -:" test for range assign -:let l = [0] -:let l[:] = [1, 2] -:$put =string(l) -:endfun -:" -:call Test(1, 2, [3, 4], {5: 6}) " This may take a while -:" -:delfunc Test -:unlet dict -:call garbagecollect(1) -:" -:" test for patch 7.3.637 -:let a = 'No error caught' -:try|foldopen|catch|let a = matchstr(v:exception,'^[^ ]*')|endtry -o=a
:" -:lang C -:redir => a -:try|foobar|catch|let a = matchstr(v:exception,'^[^ ]*')|endtry -:redir END -o=a
:" -:" -:/^start:/,$wq! test.out -ENDTEST - -start: diff --git a/src/nvim/testdir/test55.ok b/src/nvim/testdir/test55.ok deleted file mode 100644 index 607a95ead9..0000000000 --- a/src/nvim/testdir/test55.ok +++ /dev/null @@ -1,199 +0,0 @@ -start: -[1, 'as''d', [1, 2, function('strlen')], {'a': 1}] -{'a': 1} -1 -Vim(put):E684: -[1, 'as''d', [1, 2, function('strlen')], {'a': 1}] -['as''d', [1, 2, function('strlen')], {'a': 1}] -[1, 'as''d', [1, 2, function('strlen')]] -[1, 'as''d', [1, 2, function('strlen')], {'a': 1}] -[] -101101 -{'1': 'asd', 'b': [1, 2, function('strlen')], '-1': {'a': 1}}asd -['-1', '1', 'b'] -['asd', [1, 2, function('strlen')], {'a': 1}] -1:'asd' -b:[1, 2, function('strlen')] --1:{'a': 1} -Vim(call):E737: 3 -{'c': 'ccc', '1': 99, 'b': [1, 2, function('strlen')], '3': 33, '-1': {'a': 1}} -{'c': 'ccc', '1': 99, '3': 33, '-1': {'a': 1}} -101101 -Vim(let):E706: d -Vim(let):E706: l -[1, 'as''d', {'a': 1}] -[4] -{'1': 99, '3': 33} -[0, 1, 2, 3] -[0, 1, 3] -[0, 1] -[0, 1] -[0, 1] -[0, 1, 2, 3] -[0, 1, 3] -[0, 3] -[3] -[3] -[3] -2 -3 -Vim(let):E687: -Vim(let):E688: -3000 2900 2001 1600 1501 -Vim(let):E716: 1500 -NONE 2999 -33=999 -{'33': 999} -len: 3 -again: 3 -Vim(call):E725: -g:dict.func-4 -a:function('3') -Vim(let):E698: -same list: 1 -depth is 0 -0000-000 -ppppppp -0000-000 -ppppppp -0000-000 -ppppppp -depth is 1 -1000-000 -ppppppF -0000-000 -ppppppp -0000-000 -ppppppp -depth is 2 -1100-100 -ppFppFF -0000-000 -ppppppp -0000-000 -ppppppp -depth is 3 -1110-110 -pFFpFFF -0010-010 -pFppFpp -0000-000 -ppppppp -depth is 4 -1111-111 -FFFFFFF -0011-011 -FFpFFpp -0000-000 -ppppppp -Unletting: -depth is 0 -0000-000 -ppppppp -0000-000 -ppppppp -0000-000 -ppppppp -depth is 1 -1000-000 -ppFppFp -0000-000 -ppppppp -0000-000 -ppppppp -depth is 2 -1100-100 -pFFpFFp -0000-000 -ppppppp -0000-000 -ppppppp -depth is 3 -1110-110 -FFFFFFp -0010-010 -FppFppp -0000-000 -ppppppp -depth is 4 -1111-111 -FFFFFFp -0011-011 -FppFppp -0000-000 -ppppppp -Locks and commands or functions: -No :unlet after lock on dict: -Vim(unlet):E741: -{'a': 99, 'b': 100} -:unlet after lock on dict item: -did :unlet -{'b': 100} -filter() after lock on dict item: -did filter() -{'b': 100} -map() after lock on dict: -did map() -{'a': 299, 'b': 300} -No extend() after lock on dict item: -Vim(put):E741: -{'a': 99, 'b': 100} -No remove() of write-protected scope-level variable: -Vim(put):E795: -No extend() of write-protected scope-level variable: -Vim(put):E742: -No :unlet of variable in locked scope: -Vim(unlet):E741: -No :let += of locked list variable: -Vim(let):E741: -['a', 'b', 3] -[1, 2, 3, 4] -[1, 2, 3, 4] -[1, 2, 3, 4] -[1, 2, 3, 4] -[1, 2, 3, 4] -locked g:footest#x:-1 -exists g:footest#x:0 -g:footest#x: 1 -caught a:000 -caught a:000[0] -caught a:000[2] -caught a:000[3] -[1, 2, [3, 9, 5, 6], {'a': 12, '5': 8}] -['-0', 'A11', 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5] -[1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0'] -[1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0'] -['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]] -[[0, 1, 2], [0, 1, 2], 4, 2, 2, 1.5, 'xaaa', 'x8', 'foo6', 'foo', 'foo', 'A11', '-0'] -['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]] -['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 4, [0, 1, 2]] -[-1, 'one', 'two', 'three', 'four', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255] -['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] -['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] -['BAR', 'Bar', 'FOO', 'FOOBAR', 'Foo', 'bar', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}] -['aa', 'bb'] -['aa', 'bb'] -['', 'aa', 'bb', ''] -['', '', 'aa', '', 'bb', '', ''] -['aa', '', 'bb'] -['', 'aa', '', 'bb', ''] -['aa', '', 'bb', 'cc', ''] -['a', 'b', 'c'] -['', 'a', '', 'b', '', 'c', ''] -1 -1 -0 -0 -1 -1 -[1, 2, 3, 4, 5, 1, 2, 3, 4, 5] -{'a': {'b': 'B'}} -Vim(call):E737: a -{'a': {'b': 'B'}} -[1, 2] -Vim(foldopen):E490: - - -Error detected while processing : -E492: Not an editor command: foobar|catch|let a = matchstr(v:exception,'^[^ ]*')|endtry - diff --git a/src/nvim/testdir/test_hardcopy.vim b/src/nvim/testdir/test_hardcopy.vim new file mode 100644 index 0000000000..4629d17dd2 --- /dev/null +++ b/src/nvim/testdir/test_hardcopy.vim @@ -0,0 +1,58 @@ +" Test :hardcopy + +func Test_printoptions_parsing() + " Only test that this doesn't throw an error. + set printoptions=left:5in,right:10pt,top:8mm,bottom:2pc + set printoptions=left:2in,top:30pt,right:16mm,bottom:3pc + set printoptions=header:3,syntax:y,number:7,wrap:n + set printoptions=duplex:short,collate:n,jobsplit:y,portrait:n + set printoptions=paper:10x14 + set printoptions=paper:A3 + set printoptions=paper:A4 + set printoptions=paper:A5 + set printoptions=paper:B4 + set printoptions=paper:B5 + set printoptions=paper:executive + set printoptions=paper:folio + set printoptions=paper:ledger + set printoptions=paper:legal + set printoptions=paper:letter + set printoptions=paper:quarto + set printoptions=paper:statement + set printoptions=paper:tabloid + set printoptions=formfeed:y + set printoptions= + set printoptions& +endfunc + +func Test_printmbfont_parsing() + " Only test that this doesn't throw an error. + set printmbfont=r:WadaMin-Regular,b:WadaMin-Bold,i:WadaMin-Italic,o:WadaMin-Bold-Italic,c:yes,a:no + set printmbfont= + set printmbfont& +endfunc + +func Test_printheader_parsing() + " Only test that this doesn't throw an error. + set printheader=%<%f\ %h%m%r%=%-14.(%l,%c%V%)\ %P + set printheader=%<%f%h%m%r%=%b\ 0x%B\ \ %l,%c%V\ %P + set printheader=%<%f%=\ [%1*%M%*%n%R%H]\ %-19(%3l,%02c%03V%)%O'%02b' + set printheader=...%r%{VarExists('b:gzflag','\ [GZ]')}%h... + set printheader= + set printheader& +endfunc + +" Test that :hardcopy produces a non-empty file. +" We don't check much of the contents. +func Test_with_syntax() + if has('postscript') + set printoptions=syntax:y + syn on + hardcopy > Xhardcopy + let lines = readfile('Xhardcopy') + call assert_true(len(lines) > 20) + call assert_true(lines[0] =~ 'PS-Adobe') + call delete('Xhardcopy') + set printoptions& + endif +endfunc diff --git a/src/nvim/testdir/test_langmap.vim b/src/nvim/testdir/test_langmap.vim new file mode 100644 index 0000000000..066c3bf2bd --- /dev/null +++ b/src/nvim/testdir/test_langmap.vim @@ -0,0 +1,24 @@ +" tests for 'langmap' + +func Test_langmap() + new + set langmap=}l,^x,%v + + call setline(1, ['abc']) + call feedkeys('gg0}^', 'tx') + call assert_equal('ac', getline(1)) + + " in Replace mode + " need silent! to avoid a delay when entering Insert mode + call setline(1, ['abcde']) + silent! call feedkeys("gg0lR%{z\<Esc>00", 'tx') + call assert_equal('a%{ze', getline(1)) + + " in Select mode + " need silent! to avoid a delay when entering Insert mode + call setline(1, ['abcde']) + silent! call feedkeys("gg0}%}\<C-G>}^\<Esc>00", 'tx') + call assert_equal('a}^de', getline(1)) + + quit! +endfunc diff --git a/src/nvim/testdir/test_listlbr.in b/src/nvim/testdir/test_listlbr.in deleted file mode 100644 index b5bac080ee..0000000000 --- a/src/nvim/testdir/test_listlbr.in +++ /dev/null @@ -1,119 +0,0 @@ -Test for linebreak and list option (non-utf8) - -STARTTEST -:if !exists("+linebreak") | e! test.ok | w! test.out | qa! | endif -:set wildchar=^E -:10new|:vsp|:vert resize 20 -:put =\"\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP \" -:norm! zt -:set ts=4 sw=4 sts=4 linebreak sbr=+ wrap -:fu! ScreenChar(width) -: let c='' -: for j in range(1,4) -: for i in range(1,a:width) -: let c.=nr2char(screenchar(j, i)) -: endfor -: let c.="\n" -: endfor -: return c -:endfu -:fu! DoRecordScreen() -: wincmd l -: $put =printf(\"\n%s\", g:test) -: $put =g:line -: wincmd p -:endfu -:" -:let g:test="Test 1: set linebreak" -:redraw! -:let line=ScreenChar(winwidth(0)) -:call DoRecordScreen() -:" -:let g:test="Test 2: set linebreak + set list" -:set linebreak list listchars= -:redraw! -:let line=ScreenChar(winwidth(0)) -:call DoRecordScreen() -:" -:let g:test ="Test 3: set linebreak nolist" -:set nolist linebreak -:redraw! -:let line=ScreenChar(winwidth(0)) -:call DoRecordScreen() -:" -:let g:test ="Test 4: set linebreak with tab and 1 line as long as screen: should break!" -:set nolist linebreak ts=8 -:let line="1\t".repeat('a', winwidth(0)-2) -:$put =line -:$ -:norm! zt -:redraw! -:let line=ScreenChar(winwidth(0)) -:call DoRecordScreen() -:let line="_S_\t bla" -:$put =line -:$ -:norm! zt -:" -:let g:test ="Test 5: set linebreak with conceal and set list and tab displayed by different char (line may not be truncated)" -:set cpo&vim list linebreak conceallevel=2 concealcursor=nv listchars=tab:ab -:syn match ConcealVar contained /_/ conceal -:syn match All /.*/ contains=ConcealVar -:let line=ScreenChar(winwidth(0)) -:call DoRecordScreen() -:set cpo&vim linebreak -:" -:let g:test ="Test 6: set linebreak with visual block mode" -:let line="REMOVE: this not" -:$put =g:test -:$put =line -:let line="REMOVE: aaaaaaaaaaaaa" -:$put =line -:1/^REMOVE: -0jf x:$put -:set cpo&vim linebreak -:" -:let g:test ="Test 7: set linebreak with visual block mode and v_b_A" -:$put =g:test -Golong line: 40afoobar aTARGET at end -:exe "norm! $3B\<C-v>eAx\<Esc>" -:set cpo&vim linebreak sbr= -:" -:let g:test ="Test 8: set linebreak with visual char mode and changing block" -:$put =g:test -Go1111-1111-1111-11-1111-1111-11110f-lv3lc2222bgj. -:" -:let g:test ="Test 9: using redo after block visual mode" -:$put =g:test -Go -aaa -aaa -a2k2j~e. -:" -:let g:test ="Test 10: using normal commands after block-visual" -:$put =g:test -:set linebreak -Go -abcd{ef -ghijklm -no}pqrs2k0f{c% -:" -:let g:test ="Test 11: using block replace mode after wrapping" -:$put =g:test -:set linebreak wrap -Go150aayypk147|jr0 -:" -:let g:test ="Test 12: set linebreak list listchars=space:_,tab:>-,tail:-,eol:$" -:set list listchars=space:_,trail:-,tab:>-,eol:$ -:$put =g:test -:let line="a aaaaaaaaaaaaaaaaaaaaaa\ta " -:$put =line -:$ -:norm! zt -:redraw! -:let line=ScreenChar(winwidth(0)) -:call DoRecordScreen() -:%w! test.out -:qa! -ENDTEST -dummy text diff --git a/src/nvim/testdir/test_listlbr.ok b/src/nvim/testdir/test_listlbr.ok deleted file mode 100644 index b32a54969e..0000000000 --- a/src/nvim/testdir/test_listlbr.ok +++ /dev/null @@ -1,62 +0,0 @@ - - abcdef hijklmn pqrstuvwxyz_1060ABCDEFGHIJKLMNOP - -Test 1: set linebreak - abcdef -+hijklmn -+pqrstuvwxyz_1060ABC -+DEFGHIJKLMNOP - -Test 2: set linebreak + set list -^Iabcdef hijklmn^I -+pqrstuvwxyz_1060ABC -+DEFGHIJKLMNOP - - -Test 3: set linebreak nolist - abcdef -+hijklmn -+pqrstuvwxyz_1060ABC -+DEFGHIJKLMNOP -1 aaaaaaaaaaaaaaaaaa - -Test 4: set linebreak with tab and 1 line as long as screen: should break! -1 -+aaaaaaaaaaaaaaaaaa -~ -~ -_S_ bla - -Test 5: set linebreak with conceal and set list and tab displayed by different char (line may not be truncated) -Sabbbbbb bla -~ -~ -~ -Test 6: set linebreak with visual block mode -this not -aaaaaaaaaaaaa -REMOVE: -REMOVE: -Test 7: set linebreak with visual block mode and v_b_A -long line: foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar TARGETx at end -Test 8: set linebreak with visual char mode and changing block -1111-2222-1111-11-1111-2222-1111 -Test 9: using redo after block visual mode - -AaA -AaA -A -Test 10: using normal commands after block-visual - -abcdpqrs -Test 11: using block replace mode after wrapping -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0aaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0aaa -Test 12: set linebreak list listchars=space:_,tab:>-,tail:-,eol:$ -a aaaaaaaaaaaaaaaaaaaaaa a - -Test 12: set linebreak list listchars=space:_,tab:>-,tail:-,eol:$ -a_ -aaaaaaaaaaaaaaaaaaaa -aa>-----a-$ -~ diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim new file mode 100644 index 0000000000..309c0f460b --- /dev/null +++ b/src/nvim/testdir/test_syntax.vim @@ -0,0 +1,63 @@ +" Test for syntax and syntax iskeyword option + +func GetSyntaxItem(pat) + let c = '' + let a = ['a', getreg('a'), getregtype('a')] + 0 + redraw! + call search(a:pat, 'W') + let synid = synID(line('.'), col('.'), 1) + while synid == synID(line('.'), col('.'), 1) + norm! v"ay + " stop at whitespace + if @a =~# '\s' + break + endif + let c .= @a + norm! l + endw + call call('setreg', a) + 0 + return c +endfunc + +func Test_syn_iskeyword() + new + call setline(1, [ + \ 'CREATE TABLE FOOBAR(', + \ ' DLTD_BY VARCHAR2(100)', + \ ');', + \ '']) + + syntax on + set ft=sql + syn match SYN /C\k\+\>/ + hi link SYN ErrorMsg + call assert_equal('DLTD_BY', GetSyntaxItem('DLTD')) + /\<D\k\+\>/:norm! ygn + call assert_equal('DLTD_BY', @0) + redir @c + syn iskeyword + redir END + call assert_equal("\nsyntax iskeyword not set", @c) + + syn iskeyword @,48-57,_,192-255 + redir @c + syn iskeyword + redir END + call assert_equal("\nsyntax iskeyword @,48-57,_,192-255", @c) + + setlocal isk-=_ + call assert_equal('DLTD_BY', GetSyntaxItem('DLTD')) + /\<D\k\+\>/:norm! ygn + let b2=@0 + call assert_equal('DLTD', @0) + + syn iskeyword clear + redir @c + syn iskeyword + redir END + call assert_equal("\nsyntax iskeyword not set", @c) + + quit! +endfunc diff --git a/src/nvim/testdir/test_unlet.vim b/src/nvim/testdir/test_unlet.vim new file mode 100644 index 0000000000..f6705997a9 --- /dev/null +++ b/src/nvim/testdir/test_unlet.vim @@ -0,0 +1,26 @@ +" Tests for :unlet + +func Test_read_only() + try + " this caused a crash + unlet count + catch + call assert_true(v:exception =~ ':E795:') + endtry +endfunc + +func Test_existing() + let does_exist = 1 + call assert_true(exists('does_exist')) + unlet does_exist + call assert_false(exists('does_exist')) +endfunc + +func Test_not_existing() + unlet! does_not_exist + try + unlet does_not_exist + catch + call assert_true(v:exception =~ ':E108:') + endtry +endfunc diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 99eb230a88..be256f3ebc 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -4,6 +4,7 @@ #include "nvim/api/vim.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii.h" +#include "nvim/main.h" #include "nvim/misc2.h" #include "nvim/os/os.h" #include "nvim/os/input.h" @@ -92,7 +93,7 @@ static void flush_input(TermInput *input, bool wait_until_empty) size_t drain_boundary = wait_until_empty ? 0 : 0xff; do { uv_mutex_lock(&input->key_buffer_mutex); - loop_schedule(&loop, event_create(1, wait_input_enqueue, 1, input)); + loop_schedule(&main_loop, event_create(1, wait_input_enqueue, 1, input)); input->waiting = true; while (input->waiting) { uv_cond_wait(&input->key_buffer_cond, &input->key_buffer_mutex); @@ -138,6 +139,9 @@ static void forward_modified_utf8(TermInput *input, TermKeyKey *key) if (key->type == TERMKEY_TYPE_KEYSYM && key->code.sym == TERMKEY_SYM_ESCAPE) { len = (size_t)snprintf(buf, sizeof(buf), "<Esc>"); + } else if (key->type == TERMKEY_TYPE_KEYSYM + && key->code.sym == TERMKEY_SYM_SUSPEND) { + len = (size_t)snprintf(buf, sizeof(buf), "<C-Z>"); } else { len = termkey_strfkey(input->tk, buf, sizeof(buf), key, TERMKEY_FORMAT_VIM); } @@ -153,7 +157,8 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key) TermKeyMouseEvent ev; termkey_interpret_mouse(input->tk, key, &ev, &button, &row, &col); - if (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG) { + if (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG + && ev != TERMKEY_MOUSE_RELEASE) { return; } @@ -190,6 +195,8 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key) } } else if (ev == TERMKEY_MOUSE_DRAG) { len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Drag"); + } else if (ev == TERMKEY_MOUSE_RELEASE) { + len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Release"); } len += (size_t)snprintf(buf + len, sizeof(buf) - len, "><%d,%d>", col, row); @@ -336,7 +343,7 @@ static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, stream_close(&input->read_stream, NULL); queue_put(input->loop->fast_events, restart_reading, 1, input); } else { - loop_schedule(&loop, event_create(1, input_done_event, 0)); + loop_schedule(&main_loop, event_create(1, input_done_event, 0)); } return; } diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 62bc81ba64..50558e644a 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -11,6 +11,7 @@ #include "nvim/vim.h" #include "nvim/ui.h" #include "nvim/map.h" +#include "nvim/main.h" #include "nvim/memory.h" #include "nvim/api/vim.h" #include "nvim/api/private/helpers.h" @@ -261,7 +262,7 @@ static void sigwinch_cb(SignalWatcher *watcher, int signum, void *data) UI *ui = data; update_size(ui); // run refresh_event in nvim main loop - loop_schedule(&loop, event_create(1, refresh_event, 0)); + loop_schedule(&main_loop, event_create(1, refresh_event, 0)); } static bool attrs_differ(HlAttrs a1, HlAttrs a2) @@ -681,7 +682,7 @@ static void invalidate(UI *ui, int top, int bot, int left, int right) intersects->right = MAX(right, intersects->right); } else { // Else just add a new entry; - kv_push(Rect, data->invalid_regions, ((Rect){top, bot, left, right})); + kv_push(data->invalid_regions, ((Rect) { top, bot, left, right })); } } diff --git a/src/nvim/ugrid.h b/src/nvim/ugrid.h index ad6d96a168..268362bf1b 100644 --- a/src/nvim/ugrid.h +++ b/src/nvim/ugrid.h @@ -23,16 +23,16 @@ struct ugrid { #define EMPTY_ATTRS ((HlAttrs){ false, false, false, false, false, -1, -1, -1 }) -#define UGRID_FOREACH_CELL(grid, top, bot, left, right, code) \ - do { \ - for (int row = top; row <= bot; ++row) { \ - UCell *row_cells = (grid)->cells[row]; \ - for (int col = left; col <= right; ++col) { \ - UCell *cell = row_cells + col; \ - (void)(cell); \ - code; \ - } \ - } \ +#define UGRID_FOREACH_CELL(grid, top, bot, left, right, code) \ + do { \ + for (int row = top; row <= bot; row++) { \ + UCell *row_cells = (grid)->cells[row]; \ + for (int col = left; col <= right; col++) { \ + UCell *cell = row_cells + col; \ + (void)(cell); \ + code; \ + } \ + } \ } while (0) #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 05322a6f64..d968cbc390 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -30,7 +30,11 @@ #include "nvim/screen.h" #include "nvim/syntax.h" #include "nvim/window.h" -#include "nvim/tui/tui.h" +#ifdef FEAT_TUI +# include "nvim/tui/tui.h" +#else +# include "nvim/msgpack_rpc/server.h" +#endif #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ui.c.generated.h" @@ -56,22 +60,22 @@ static int height, width; // See http://stackoverflow.com/a/11172679 for a better explanation of how it // works. #ifdef _MSC_VER - #define UI_CALL(funname, ...) \ - do { \ - flush_cursor_update(); \ - for (size_t i = 0; i < ui_count; i++) { \ - UI *ui = uis[i]; \ - UI_CALL_MORE(funname, __VA_ARGS__); \ - } \ +# define UI_CALL(funname, ...) \ + do { \ + flush_cursor_update(); \ + for (size_t i = 0; i < ui_count; i++) { \ + UI *ui = uis[i]; \ + UI_CALL_MORE(funname, __VA_ARGS__); \ + } \ } while (0) #else - #define UI_CALL(...) \ - do { \ - flush_cursor_update(); \ - for (size_t i = 0; i < ui_count; i++) { \ - UI *ui = uis[i]; \ - UI_CALL_HELPER(CNT(__VA_ARGS__), __VA_ARGS__); \ - } \ +# define UI_CALL(...) \ + do { \ + flush_cursor_update(); \ + for (size_t i = 0; i < ui_count; i++) { \ + UI *ui = uis[i]; \ + UI_CALL_HELPER(CNT(__VA_ARGS__), __VA_ARGS__); \ + } \ } while (0) #endif #define CNT(...) SELECT_NTH(__VA_ARGS__, MORE, MORE, MORE, MORE, ZERO, ignore) @@ -83,7 +87,22 @@ static int height, width; void ui_builtin_start(void) { +#ifdef FEAT_TUI tui_start(); +#else + fprintf(stderr, "Neovim was built without a Terminal UI," \ + "press Ctrl+C to exit\n"); + + size_t len; + char **addrs = server_address_list(&len); + if (addrs != NULL) { + fprintf(stderr, "currently listening on the following address(es)\n"); + for (size_t i = 0; i < len; i++) { + fprintf(stderr, "\t%s\n", addrs[i]); + } + xfree(addrs); + } +#endif } void ui_builtin_stop(void) @@ -188,7 +207,7 @@ void ui_mouse_off(void) UI_CALL(mouse_off); } -void ui_attach(UI *ui) +void ui_attach_impl(UI *ui) { if (ui_count == MAX_UI_COUNT) { abort(); @@ -198,7 +217,7 @@ void ui_attach(UI *ui) ui_refresh(); } -void ui_detach(UI *ui) +void ui_detach_impl(UI *ui) { size_t shift_index = MAX_UI_COUNT; diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c index fd9d4671e3..6290fb3d87 100644 --- a/src/nvim/ui_bridge.c +++ b/src/nvim/ui_bridge.c @@ -5,6 +5,7 @@ #include <stdio.h> #include <limits.h> +#include "nvim/main.h" #include "nvim/vim.h" #include "nvim/ui.h" #include "nvim/memory.h" @@ -18,9 +19,9 @@ #define UI(b) (((UIBridgeData *)b)->ui) // Call a function in the UI thread -#define UI_CALL(ui, name, argc, ...) \ - ((UIBridgeData *)ui)->scheduler( \ - event_create(1, ui_bridge_##name##_event, argc, __VA_ARGS__), UI(ui)) +#define UI_CALL(ui, name, argc, ...) \ + ((UIBridgeData *)ui)->scheduler( \ + event_create(1, ui_bridge_##name##_event, argc, __VA_ARGS__), UI(ui)) #define INT2PTR(i) ((void *)(uintptr_t)i) #define PTR2INT(p) ((int)(uintptr_t)p) @@ -71,7 +72,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler) } uv_mutex_unlock(&rv->mutex); - ui_attach(&rv->bridge); + ui_attach_impl(&rv->bridge); return &rv->bridge; } @@ -100,12 +101,12 @@ static void ui_bridge_stop(UI *b) if (stopped) { break; } - loop_poll_events(&loop, 10); + loop_poll_events(&main_loop, 10); } uv_thread_join(&bridge->ui_thread); uv_mutex_destroy(&bridge->mutex); uv_cond_destroy(&bridge->cond); - ui_detach(b); + ui_detach_impl(b); xfree(b); } static void ui_bridge_stop_event(void **argv) diff --git a/src/nvim/ui_bridge.h b/src/nvim/ui_bridge.h index 31b9a69216..561ddb6b24 100644 --- a/src/nvim/ui_bridge.h +++ b/src/nvim/ui_bridge.h @@ -28,13 +28,13 @@ struct ui_bridge_data { bool stopped; }; -#define CONTINUE(b) \ - do { \ - UIBridgeData *d = (UIBridgeData *)b; \ - uv_mutex_lock(&d->mutex); \ - d->ready = true; \ - uv_cond_signal(&d->cond); \ - uv_mutex_unlock(&d->mutex); \ +#define CONTINUE(b) \ + do { \ + UIBridgeData *d = (UIBridgeData *)b; \ + uv_mutex_lock(&d->mutex); \ + d->ready = true; \ + uv_cond_signal(&d->cond); \ + uv_mutex_unlock(&d->mutex); \ } while (0) diff --git a/src/nvim/version.c b/src/nvim/version.c index d34df421f3..5364fee953 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -64,6 +64,12 @@ static char *features[] = { #else "-jemalloc", #endif + +#ifdef FEAT_TUI + "+tui", +#else + "-tui", +#endif NULL }; @@ -79,6 +85,7 @@ static int included_patches[] = { 1755, 1753, 1728, + 1695, 1654, 1652, 1643, @@ -119,7 +126,7 @@ static int included_patches[] = { 1570, 1569, 1568, - // 1567, + 1567, // 1566 NA // 1565, // 1564, @@ -218,11 +225,11 @@ static int included_patches[] = { // 1471 NA // 1470 NA // 1469 NA - // 1468, + 1468, // 1467 NA // 1466 NA // 1465 NA - // 1464, + 1464, // 1463 NA // 1462 NA // 1461 NA @@ -289,10 +296,10 @@ static int included_patches[] = { // 1400 NA // 1399 NA // 1398 NA - // 1397, + 1397, // 1396, // 1395 NA - // 1394, + 1394, // 1393 NA // 1392 NA // 1391 NA @@ -334,7 +341,7 @@ static int included_patches[] = { // 1355 NA // 1354 NA // 1353 NA - // 1352, + 1352, // 1351 NA // 1350 NA // 1349 NA @@ -410,7 +417,7 @@ static int included_patches[] = { // 1279 NA // 1278 NA // 1277 NA - // 1276, + 1276, // 1275 NA // 1274 NA // 1273, @@ -463,7 +470,7 @@ static int included_patches[] = { // 1226 NA // 1225 NA // 1224 NA - // 1223, + 1223, // 1222 NA // 1221 NA // 1220 NA @@ -525,7 +532,7 @@ static int included_patches[] = { 1164, 1163, // 1162 NA - // 1161, + 1161, 1160, // 1159 NA // 1158 NA @@ -533,10 +540,10 @@ static int included_patches[] = { // 1156 NA // 1155 NA // 1154 NA - // 1153, + 1153, // 1152 NA - // 1151, - // 1150, + 1151, + 1150, 1149, // 1148 NA // 1147, @@ -544,7 +551,7 @@ static int included_patches[] = { // 1145 NA 1144, 1143, - // 1142, + 1142, 1141, // 1140, // 1139 NA @@ -554,20 +561,20 @@ static int included_patches[] = { // 1135 NA // 1134 NA // 1133 NA - // 1132, + 1132, // 1131 NA - // 1130, + // 1130 NA // 1129 NA // 1128 NA // 1127 NA - // 1126, + 1126, // 1125 NA // 1124 NA - // 1123, + 1123, // 1122 NA // 1121, 1120, - // 1119, + 1119, 1118, 1117, 1116, @@ -578,7 +585,7 @@ static int included_patches[] = { // 1111, 1110, // 1109 NA - // 1108, + 1108, 1107, // 1106 NA 1105, @@ -590,13 +597,13 @@ static int included_patches[] = { // 1099 NA // 1098 NA // 1097, - // 1096, + 1096, // 1095 NA - // 1094, + 1094, 1093, 1092, 1091, - // 1090, + 1090, 1089, 1088, 1087, @@ -618,7 +625,7 @@ static int included_patches[] = { 1071, // 1070 NA // 1069 NA - // 1068, + 1068, // 1067 NA // 1066 NA 1065, @@ -630,12 +637,12 @@ static int included_patches[] = { 1059, // 1058, 1057, - // 1056, + 1056, 1055, 1054, 1053, 1052, - // 1051, + 1051, 1050, 1049, 1048, @@ -1897,21 +1904,15 @@ void intro_message(int colon) N_("by Bram Moolenaar et al."), N_("Vim is open source and freely distributable"), "", - N_("First time using a vi-like editor?"), - N_("Type :Tutor<Enter> to get started!"), + N_("Type \":Tutor\" or \":help nvim\" to get started!"), "", - N_("Already know your way around Vim?"), - N_("See :help nvim-intro for an introduction to Neovim."), + N_("Still have questions? https://neovim.io/community"), "", - N_("Still have questions?"), - N_("Reach out to the Neovim community at neovim.io/community."), + N_("type :q<Enter> to exit "), + N_("type :help<Enter> or <F1> for on-line help"), "", N_("Help poor children in Uganda!"), N_("type :help iccf<Enter> for information "), - "", - N_("type :q<Enter> to exit "), - N_("type :help<Enter> or <F1> for on-line help"), - N_("type :help nvim<Enter> for Neovim help "), }; // blanklines = screen height - # message lines @@ -2013,3 +2014,4 @@ void ex_intro(exarg_T *eap) intro_message(TRUE); wait_return(TRUE); } + |