diff options
483 files changed, 18567 insertions, 9964 deletions
diff --git a/.ci/before_cache.sh b/.ci/before_cache.sh index b5678bc20c..dd1fcf2bf7 100755 --- a/.ci/before_cache.sh +++ b/.ci/before_cache.sh @@ -3,12 +3,6 @@ set -e set -o pipefail -if [[ "${TRAVIS_OS_NAME}" != linux ]]; then - # Caches are only enabled for Travis's Linux container infrastructure, - # but this script is still executed on OS X. - exit -fi - # Don't cache pip's log and selfcheck. rm -rf "${HOME}/.cache/pip/log" rm -f "${HOME}/.cache/pip/selfcheck.json" @@ -16,7 +10,7 @@ rm -f "${HOME}/.cache/pip/selfcheck.json" # Update the third-party dependency cache only if the build was successful. if [[ -f "${SUCCESS_MARKER}" ]]; then rm -rf "${HOME}/.cache/nvim-deps" - mv -T "${DEPS_BUILD_DIR}" "${HOME}/.cache/nvim-deps" + mv "${DEPS_BUILD_DIR}" "${HOME}/.cache/nvim-deps" touch "${CACHE_MARKER}" echo "Updated third-party dependencies (timestamp: $(stat -c '%y' "${CACHE_MARKER}"))." fi diff --git a/.ci/before_install.sh b/.ci/before_install.sh index 2a1ac05569..1bdd89de42 100755 --- a/.ci/before_install.sh +++ b/.ci/before_install.sh @@ -12,13 +12,13 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then fi echo "Upgrade Python 2's pip." -pip2.7 install --user --upgrade pip +pip2.7 -q install --user --upgrade pip if [[ "${TRAVIS_OS_NAME}" == osx ]]; then echo "Install Python 3." brew install python3 echo "Upgrade Python 3's pip." - pip3 install --user --upgrade pip + pip3 -q install --user --upgrade pip else # TODO: Replace with upgrade when Travis gets python3-pip package. echo "Install pip for Python 3." diff --git a/.ci/install.sh b/.ci/install.sh index fb5d1c09c1..93c9a930ac 100755 --- a/.ci/install.sh +++ b/.ci/install.sh @@ -19,14 +19,16 @@ elif [[ "${BUILD_MINGW}" == ON ]]; then fi -# Set CC to default to avoid compilation problems -# when installing Python modules. +# Use default CC to avoid compilation problems when installing Python modules. echo "Install neovim module and coveralls for Python 2." -CC=cc pip2.7 install --user --upgrade neovim cpp-coveralls +CC=cc pip2.7 -q install --user --upgrade neovim cpp-coveralls echo "Install neovim module for Python 3." if [[ "${TRAVIS_OS_NAME}" == osx ]]; then - CC=cc pip3 install --user --upgrade neovim + CC=cc pip3 -q install --user --upgrade neovim else - CC=cc pip3.3 install --user --upgrade neovim + CC=cc pip3.3 -q install --user --upgrade neovim fi + +echo "Install neovim RubyGem." +gem install --no-document --version ">= 0.2.0" neovim diff --git a/.gitignore b/.gitignore index ccb2299582..766c323c34 100644 --- a/.gitignore +++ b/.gitignore @@ -42,27 +42,12 @@ tags # luarocks, not added as a subtree because of the large number of blobs /third-party/luarocks -# luajit files -/third-party/luajit/src/host/buildvm -/third-party/luajit/src/host/buildvm_arch.h -/third-party/luajit/src/host/minilua -/third-party/luajit/src/jit/vmdef.lua -/third-party/luajit/src/libluajit.a -/third-party/luajit/src/lj_bcdef.h -/third-party/luajit/src/lj_ffdef.h -/third-party/luajit/src/lj_folddef.h -/third-party/luajit/src/lj_libdef.h -/third-party/luajit/src/lj_recdef.h -/third-party/luajit/src/lj_vm.s -/third-party/luajit/src/luajit - # local make targets local.mk # runtime/doc /runtime/doc/*.html /runtime/doc/tags.ref -/runtime/doc/doctags /runtime/doc/errors.log # clint errors, generated by `make lint` diff --git a/.travis.yml b/.travis.yml index 985a5c5381..8334b03cdf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ env: # Update PATH for pip and MinGW. - PATH="$(python2.7 -c 'import site; print(site.getuserbase())')/bin:$HOME/.local/mingw32/bin:$PATH" # LLVM symbolizer path. - - LLVM_SYMBOLIZER="$(which llvm-symbolizer-3.6)" + - LLVM_SYMBOLIZER="$(which llvm-symbolizer-3.4)" # Build directory for Neovim. - BUILD_DIR="$TRAVIS_BUILD_DIR/build" # Build directory for third-party dependencies. @@ -39,7 +39,6 @@ env: # Environment variables for Clang sanitizers. - ASAN_OPTIONS="detect_leaks=1:check_initialization_order=1:log_path=$LOG_DIR/asan" - ASAN_SYMBOLIZER_PATH="$LLVM_SYMBOLIZER" - - MSAN_SYMBOLIZER_PATH="$LLVM_SYMBOLIZER" - TSAN_OPTIONS="external_symbolizer_path=$LLVM_SYMBOLIZER log_path=$LOG_DIR/tsan" - UBSAN_OPTIONS="log_path=$LOG_DIR/ubsan" # Environment variables for Valgrind. @@ -72,13 +71,10 @@ matrix: compiler: gcc-5 -m32 env: BUILD_32BIT=ON - os: linux - compiler: clang-3.6 - env: GCOV=llvm-cov-3.6 CLANG_SANITIZER=ASAN_UBSAN CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON" - - os: linux - compiler: clang-3.6 - env: CLANG_SANITIZER=MSAN + compiler: clang + env: GCOV=llvm-cov CLANG_SANITIZER=ASAN_UBSAN CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON" - os: linux - compiler: clang-3.6 + compiler: clang env: CLANG_SANITIZER=TSAN - os: osx compiler: clang @@ -87,9 +83,6 @@ matrix: - os: linux env: BUILD_MINGW=ON fast_finish: true - allow_failures: - # TODO: Remove when all MSan errors have been fixed. - - env: CLANG_SANITIZER=MSAN before_install: .ci/before_install.sh install: .ci/install.sh @@ -103,13 +96,12 @@ addons: sources: # TODO: Remove PPA when Travis gets Python >=3.3. - deadsnakes - - llvm-toolchain-precise-3.6 - ubuntu-toolchain-r-test packages: - autoconf - automake - build-essential - - clang-3.6 + - clang-3.4 - cmake - g++-5-multilib - g++-multilib @@ -118,7 +110,7 @@ addons: - gdb - libc6-dev-i386 - libtool - - llvm-3.6-dev + - llvm-3.4-dev - pkg-config - python3.3-dev - unzip diff --git a/CMakeLists.txt b/CMakeLists.txt index 953e210397..1787f4e306 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -291,9 +291,6 @@ endif() include_directories("${PROJECT_BINARY_DIR}/config") include_directories("${PROJECT_SOURCE_DIR}/src") -# Modules used by platform auto-detection -include(CheckLibraryExists) - find_package(LibUV REQUIRED) include_directories(SYSTEM ${LIBUV_INCLUDE_DIRS}) @@ -374,7 +371,7 @@ endforeach() include(LuaHelpers) set(LUA_DEPENDENCIES lpeg mpack bit) if(NOT LUA_PRG) - foreach(CURRENT_LUA_PRG luajit lua) + foreach(CURRENT_LUA_PRG luajit lua5.1 lua5.2 lua) # If LUA_PRG is set find_program() will not search unset(LUA_PRG CACHE) unset(LUA_PRG_WORKS) @@ -504,6 +501,7 @@ if(BUSTED_PRG) add_custom_target(functionaltest COMMAND ${CMAKE_COMMAND} -DBUSTED_PRG=${BUSTED_PRG} + -DLUA_PRG=${LUA_PRG} -DNVIM_PRG=$<TARGET_FILE:nvim> -DWORKING_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DBUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} @@ -517,6 +515,7 @@ if(BUSTED_PRG) add_custom_target(benchmark COMMAND ${CMAKE_COMMAND} -DBUSTED_PRG=${BUSTED_PRG} + -DLUA_PRG=${LUA_PRG} -DNVIM_PRG=$<TARGET_FILE:nvim> -DWORKING_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DBUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} @@ -532,6 +531,7 @@ if(BUSTED_LUA_PRG) add_custom_target(functionaltest-lua COMMAND ${CMAKE_COMMAND} -DBUSTED_PRG=${BUSTED_LUA_PRG} + -DLUA_PRG=${LUA_PRG} -DNVIM_PRG=$<TARGET_FILE:nvim> -DWORKING_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DBUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1787a4322b..dbc048d939 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,160 +3,96 @@ ## Getting started - Help us review [open pull requests](https://github.com/neovim/neovim/pulls)! -- Look for [entry-level issues][entry-level] to work on. - - [Documentation](https://github.com/neovim/neovim/labels/documentation) - improvements are also much appreciated. -- Look at [Waffle][waffle] to see who is working on what issues. -- If needed, refer to [the wiki][wiki-contributing] for guidance. + See [Reviewing](#reviewing) for guidelines. +- Try an [entry-level issue][entry-level] if you are wondering where to start. +- Or [merge a Vim patch]. ## Reporting problems -Before reporting an issue, see the following wiki articles: +- Check the [**FAQ**][wiki-faq]. +- Search [existing issues][github-issues] (including closed!) +- Update Neovim to the latest version to see if your problem persists. +- If you're using a plugin manager, comment out your plugins, then add them back + in one by one, to narrow down the cause of the issue. +- Crash reports which include a stacktrace are 10x more valuable. +- [Bisecting][git-bisect] to the cause of a regression often leads to an + immediate fix. + +## Pull requests ("PRs") + +- To avoid duplicate work, you may want to create a `[WIP]` pull request so that + others know what you are working on. +- Avoid cosmetic changes to unrelated files in the same commit: extra noise + makes reviews more difficult. +- Use a [feature branch][git-feature-branch] instead of the master branch. +- [Rebase your feature branch][git-rebasing] onto (upstream) master before + opening the PR. +- After addressing the review comments, it's fine to rebase and force-push to + your review. +- Try to [tidy your history][git-history-rewriting]: combine related commits + with interactive rebasing, separate monolithic commits, etc. -- [Troubleshooting][wiki-troubleshooting] -- [Frequently asked questions][wiki-faq] +### Stages: WIP, RFC -If your issue isn't mentioned there: +Pull requests are processed in two stages: _WIP_ (Work In Progress) and _RFC_ +(Request For Comment). -- Verify that it hasn't already been reported. -- If not already running the latest version of Neovim, update to it to see if - your problem persists. -- If you're experiencing compile or runtime warnings/failures, try searching for - the error message(s) you received (if any) on [Neovim's issue tracker][github-issues]. -- For runtime issues, try reproducing it using `nvim` with the smallest - possible `vimrc` (or none at all via `nvim -u NONE`), to rule out bugs in - plugins you're using. If you're using a plugin manager, comment out your - plugins, then add them back in one by one. +- Untagged PRs are assumed to be RFC, meaning the work is ready for review and + you would like feedback. +- Preprend `[WIP]` to the PR title if you are _not_ ready for feedback and the + work is still in flux. This saves time and confusion. -Include as much detail as possible; we generally need to know: +### Commit messages -- What operating system you're using. -- Which version of Neovim you're using. To get this, run `nvim --version` from - a shell, or run `:version` from inside `nvim`. -- Whether the bug is present in Vim (not Neovim), and if so which version of - Vim. It's fine to report Vim bugs on the Neovim bug tracker, but it saves - everyone time if we know from the start that the bug is not a regression - caused by Neovim. -- This isn't required, but what commit introduced the issue for you. You can - use [`git bisect`][git-bisect] for this. +Follow [commit message hygiene][hygiene] to *make reviews easier* and to make +the VCS/git logs more valuable. -## Submitting contributions +- Try to keep the first line under 72 characters. +- **Prefix the commit subject with a _scope_:** `doc:`, `test:`, `foo.c:`, + `runtime:`, ... + - For commits that contain only style/lint changes, a single-word subject + line is preferred: `style` or `lint`. +- A blank line must separate the subject from the description. +- Use the _imperative voice_: "Fix bug" rather than "Fixed bug" or "Fixes bug." -- Make it clear in the issue tracker what you are working on. -- Be descriptive in your pull request description: what is it for, why is it - needed, etc. -- Do ***not*** make cosmetic changes to unrelated files in the same pull - request. This creates noise, making reviews harder to do. If your text - editor strips all trailing whitespace in a file when you edit it, disable - it. +### Automated builds (CI) -### Tagging in the issue tracker +Each pull request must pass the automated builds ([travis CI] and [quickbuild]). -When submitting pull requests (commonly referred to as "PRs"), include one of -the following tags prepended to the title: +- CI builds are compiled with [`-Werror`][gcc-warnings], so if your PR + introduces any compiler warnings, the build will fail. +- If any tests fail, the build will fail. + See [Building Neovim#running-tests][wiki-run-tests] to run tests locally. + Passing locally doesn't guarantee passing the CI build, because of the + different compilers and platforms tested against. +- CI runs [ASan] and other analyzers. To run valgrind locally: + `VALGRIND=1 make test` +- The `lint` build ([#3174][3174]) checks modified lines _and their immediate + neighbors_. This is to encourage incrementally updating the legacy style to + meet our style guidelines. + - A single word (`lint` or `style`) is sufficient as the subject line of + a commit that contains only style changes. +- [How to investigate QuickBuild failures](https://github.com/neovim/neovim/pull/4718#issuecomment-217631350) -- `[WIP]` - Work In Progress: the PR will change, so while there is no - immediate need for review, the submitter still might appreciate it. -- `[RFC]` - Request For Comment: the PR needs reviewing and/or comments. -- `[RDY]` - Ready: the PR has been reviewed by at least one other person and - has no outstanding issues. +### Coverity -Assuming the above criteria has been met, feel free to change your PR's tag -yourself, as opposed to waiting for a contributor to do it for you. +[Coverity](https://scan.coverity.com/projects/neovim-neovim) runs against the +master build. If you want to view the defects, just request access at the +_Contributor_ level. An Admin will grant you permission. -### Branching & history +Use this commit-message format for coverity fixes: -- Do ***not*** work on your PR on the master branch, [use a feature branch - instead][git-feature-branch]. -- [Rebase your feature branch onto][git-rebasing] (upstream) master before - opening the PR. -- Keep up to date with changes in (upstream) master so your PR is easy to - merge. -- [Try to actively tidy your history][git-history-rewriting]: combine related - commits with interactive rebasing, separate monolithic commits, etc. If your - PR is still `[WIP]`, feel free to force-push to your feature branch to tidy - your history. - -### For code pull requests - -#### Testing - -We are unlikely to merge your PR if the Travis build fails: - -- Travis builds are compiled with the [`-Werror`][gcc-warnings] flag, so if - your PR introduces any compiler warnings then the Travis build will fail. -- If any tests fail, the Travis build will fail. - See [Building Neovim#running-tests][wiki-building-running-tests] for - information on running tests locally. - Tests passing locally doesn't guarantee they'll pass in the Travis - build, as different compilers and platforms will be used. -- Travis runs [Valgrind][valgrind] for the GCC/Linux build, but you may also - do so locally by running the following from a shell: `VALGRIND=1 make test` - -#### Coding style - -We have a [style guide][style-guide] that all new code should follow. -However, large portions of the existing Vim codebase violate it to some -degree, and fixing them would increase merge conflicts and add noise to `git -blame`. - -Weigh those costs when making cosmetic changes. In general, avoid pull -requests dominated by style changes, but feel free to fix up lines that you -happen to be modifying anyway. Fix anything that looks outright -[barbarous](http://www.orwell.ru/library/essays/politics/english/e_polit), but -otherwise prefer to leave things as they are. - -For new code, run `make lint` (which runs [clint.py][clint]) to detect style -errors. It's not perfect, so some warnings may be false positives/negatives. -To have `clint.py` ignore certain cases, put `// NOLINT` at the end of the -line. - -We also provide a configuration file for [`clang-format`][clang-format], which -can be used to format code according to the style guidelines. Be aware that -this formatting method might need user supervision. To have `clang-format` -ignore certain line ranges, use the following special comments: - -```c -int formatted_code; -// clang-format off - void unformatted_code ; -// clang-format on - void formatted_code_again; -``` - -### Commit guidelines - -The purpose of these guidelines is to *make reviews easier* and make the -[VCS][vcs] logs more valuable. + coverity/<id>: <description of what fixed the defect> -- Try to keep the first line under 72 characters. -- If necessary, include further description after a blank line. - - Don't make the description too verbose by including obvious things, but - don't spare clarifications for anything that may be not so obvious. - Some commit messages are pages long, and that's fine if there's no - better place for those comments to live. - - **Recommended:** Prefix logically-related commits with a consistent - identifier in each commit message. For already used identifiers, see the - commit history for the respective file(s) you're editing. - [For example](https://github.com/neovim/neovim/commits?author=elmart), - the following commits are related by task (*Introduce nvim namespace*) and - sub-task (*Contrib YCM*). - <br/> `Introduce nvim namespace: Contrib YCM: Fix style issues` - <br/> `Introduce nvim namespace: Contrib YCM: Fix build dir calculation` - - Sub-tasks can be *activity-oriented* (doing different things on the same area) - or *scope-oriented* (doing the same thing in different areas). - - Granularity helps, but it's conceptual size that matters, not extent size. -- Use the [imperative voice][imperative]: "Fix bug" rather than "Fixed bug" or "Fixes bug." - -### Reviewing pull requests - -Using a checklist during reviews is highly recommended, so we [provide one at -the wiki][wiki-review-checklist]. If you think it could be improved, feel free -to edit it. +where `<id>` is the Coverity ID (CID). For example see [#804](https://github.com/neovim/neovim/pull/804). + +## Reviewing + +To help review pull requests, start with [this checklist][review-checklist]. Reviewing can be done on GitHub, but you may find it easier to do locally. -Using [`hub`][hub], you can do the following to create a new branch with the -contents of a pull request, such as [#1820][github-pr-1820]: +Using [`hub`][hub], you can create a new branch with the contents of a pull +request, e.g. [#1820][1820]: hub checkout https://github.com/neovim/neovim/pull/1820 @@ -165,11 +101,7 @@ commits in the feature branch which aren't in the `master` branch; `-p` shows each commit's diff. To show the whole surrounding function of a change as context, use the `-W` argument as well. -You may find it easier to instead use an interactive program for code reviews, -such as [`tig`][tig]. -[clang-format]: http://clang.llvm.org/docs/ClangFormat.html -[clint]: clint.py [entry-level]: https://github.com/neovim/neovim/issues?labels=entry-level&state=open [gcc-warnings]: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html [git-bisect]: http://git-scm.com/book/tr/v2/Git-Tools-Debugging-with-Git @@ -178,16 +110,15 @@ such as [`tig`][tig]. [git-history-rewriting]: http://git-scm.com/book/en/v2/Git-Tools-Rewriting-History [git-rebasing]: http://git-scm.com/book/en/v2/Git-Branching-Rebasing [github-issues]: https://github.com/neovim/neovim/issues -[github-pr-1820]: https://github.com/neovim/neovim/pull/1820 +[1820]: https://github.com/neovim/neovim/pull/1820 [hub]: https://hub.github.com/ -[imperative]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html +[hygiene]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html [style-guide]: http://neovim.io/develop/style-guide.xml -[tig]: https://github.com/jonas/tig -[valgrind]: http://valgrind.org/ -[vcs]: https://en.wikipedia.org/wiki/Revision_control -[waffle]: https://waffle.io/neovim/neovim -[wiki-building-running-tests]: https://github.com/neovim/neovim/wiki/Building-Neovim#running-tests -[wiki-contributing]: https://github.com/neovim/neovim/wiki/Contributing +[ASan]: http://clang.llvm.org/docs/AddressSanitizer.html +[wiki-run-tests]: https://github.com/neovim/neovim/wiki/Building-Neovim#running-tests [wiki-faq]: https://github.com/neovim/neovim/wiki/FAQ -[wiki-review-checklist]: https://github.com/neovim/neovim/wiki/Code-review-checklist -[wiki-troubleshooting]: https://github.com/neovim/neovim/wiki/Troubleshooting +[review-checklist]: https://github.com/neovim/neovim/wiki/Code-review-checklist +[3174]: https://github.com/neovim/neovim/issues/3174 +[travis CI]: https://travis-ci.org/neovim/neovim +[quickbuild]: http://neovim-qb.szakmeister.net/dashboard +[merge a Vim patch]: https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-Vim diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index d9fd758177..011739396d 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,5 +1,5 @@ -- Neovim version: -- [ ] Vim behaves differently? Vim version: +- `nvim --version`: +- Vim (version: ) behaves differently? - Operating system/version: - Terminal name/version: - `$TERM`: @@ -85,10 +85,10 @@ endif mkdir -p build touch $@ -oldtest: | nvim tags +oldtest: | nvim helptags +$(SINGLE_MAKE) -C src/nvim/testdir $(MAKEOVERRIDES) -tags: | nvim +helptags: | nvim +$(BUILD_CMD) -C build runtime/doc/tags functionaltest: | nvim @@ -119,7 +119,7 @@ install: | nvim +$(BUILD_CMD) -C build install clint: - cmake -DLINT_PRG=./clint.py \ + cmake -DLINT_PRG=./src/clint.py \ -DLINT_DIR=src \ -DLINT_SUPPRESS_URL="$(DOC_DOWNLOAD_URL_BASE)$(CLINT_ERRORS_FILE_PATH)" \ -P cmake/RunLint.cmake @@ -18,7 +18,7 @@ Neovim is a project that seeks to aggressively refactor Vim in order to: -- Simplify maintenance and encourage [contributions](https://github.com/neovim/neovim/wiki/Contributing) +- Simplify maintenance and encourage [contributions](CONTRIBUTING.md) - Split the work between multiple developers - Enable the implementation of new/modern user interfaces without any modifications to the core source @@ -42,7 +42,7 @@ See the [progress page](https://github.com/neovim/neovim/wiki/Progress) for a co ### What's being worked on now -- Port all IO to [libuv](https://github.com/libuv/libuv/blob/master/README.md) +- Port all IO to [libuv](https://github.com/libuv/libuv/) - Convert legacy tests to Lua tests - VimL => Lua translator @@ -51,10 +51,6 @@ See the [progress page](https://github.com/neovim/neovim/wiki/Progress) for a co There is a formula for OSX/homebrew, a PKGBUILD for Arch Linux, RPM, deb, and more. See [the wiki](https://github.com/neovim/neovim/wiki/Installing-Neovim)! -### Contributing - -...would be awesome! See [the wiki](https://github.com/neovim/neovim/wiki/Contributing) for more details. - ### License Neovim is licensed under the terms of the Apache 2.0 license, except for diff --git a/cmake/RunTests.cmake b/cmake/RunTests.cmake index 0858ea24ac..9fa91ffb5d 100644 --- a/cmake/RunTests.cmake +++ b/cmake/RunTests.cmake @@ -27,7 +27,7 @@ endif() execute_process( COMMAND ${BUSTED_PRG} ${TEST_TAG} ${TEST_FILTER} -v -o ${BUSTED_OUTPUT_TYPE} - --lazy --helper=${TEST_DIR}/${TEST_TYPE}/preload.lua + --lua=${LUA_PRG} --lazy --helper=${TEST_DIR}/${TEST_TYPE}/preload.lua --lpath=${BUILD_DIR}/?.lua ${TEST_PATH} WORKING_DIRECTORY ${WORKING_DIR} ERROR_VARIABLE err diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt index e794a8c5b9..cf84f8c6a4 100644 --- a/config/CMakeLists.txt +++ b/config/CMakeLists.txt @@ -27,12 +27,15 @@ if(NOT HAVE_SYS_WAIT_H AND UNIX) endif() check_include_files(sys/utsname.h HAVE_SYS_UTSNAME_H) check_include_files(utime.h HAVE_UTIME_H) +check_include_files(sys/uio.h HAVE_SYS_UIO_H) # Functions check_function_exists(fseeko HAVE_FSEEKO) check_function_exists(getpwent HAVE_GETPWENT) check_function_exists(getpwnam HAVE_GETPWNAM) check_function_exists(getpwuid HAVE_GETPWUID) +check_function_exists(uv_translate_sys_error HAVE_UV_TRANSLATE_SYS_ERROR) +check_function_exists(readv HAVE_READV) if(Iconv_FOUND) set(HAVE_ICONV 1) diff --git a/config/config.h.in b/config/config.h.in index c2f52d8c7e..4c35b3b1cb 100644 --- a/config/config.h.in +++ b/config/config.h.in @@ -30,6 +30,7 @@ #cmakedefine HAVE_PUTENV_S #cmakedefine HAVE_PWD_H #cmakedefine HAVE_READLINK +#cmakedefine HAVE_UV_TRANSLATE_SYS_ERROR // TODO: add proper cmake check // #define HAVE_SELINUX 1 #cmakedefine HAVE_SETENV @@ -48,8 +49,14 @@ #cmakedefine HAVE_WORKING_LIBINTL #cmakedefine UNIX #cmakedefine USE_FNAME_CASE +#cmakedefine HAVE_SYS_UIO_H +#ifdef HAVE_SYS_UIO_H +#cmakedefine HAVE_READV +# ifndef HAVE_READV +# undef HAVE_SYS_UIO_H +# endif +#endif -#define FEAT_CSCOPE #cmakedefine FEAT_TUI #ifndef UNIT_TESTING diff --git a/neovim.rb b/neovim.rb deleted file mode 100644 index 859ebdf39d..0000000000 --- a/neovim.rb +++ /dev/null @@ -1,9 +0,0 @@ -odie <<-EOS.undent - - Whoops, the neovim Homebrew Formula has moved! Please instead run: - - brew tap neovim/homebrew-neovim - brew install --HEAD neovim - - Thanks! -EOS diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index cad8da6ffb..0dd8b07b7a 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -2,6 +2,7 @@ set(SYN_VIM_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genvimvim.lua) set(GENERATED_RUNTIME_DIR ${PROJECT_BINARY_DIR}/runtime) set(GENERATED_SYN_VIM ${GENERATED_RUNTIME_DIR}/syntax/vim/generated.vim) set(GENERATED_HELP_TAGS ${GENERATED_RUNTIME_DIR}/doc/tags) +set(GENERATED_PACKAGE_DIR ${GENERATED_RUNTIME_DIR}/pack/dist/opt) file(MAKE_DIRECTORY ${GENERATED_RUNTIME_DIR}) file(MAKE_DIRECTORY ${GENERATED_RUNTIME_DIR}/syntax) @@ -18,6 +19,47 @@ add_custom_command(OUTPUT ${GENERATED_SYN_VIM} ${PROJECT_SOURCE_DIR}/src/nvim/eval.c ) +if(POLICY CMP0054) + cmake_policy(SET CMP0054 OLD) +endif() + +file(GLOB PACKAGES ${PROJECT_SOURCE_DIR}/runtime/pack/dist/opt/*) + +set(GENERATED_PACKAGE_TAGS) +foreach(PACKAGE ${PACKAGES}) + get_filename_component(PACKNAME ${PACKAGE} NAME) + file(GLOB "${PACKNAME}_DOC_FILES" ${PACKAGE}/doc/*.txt) + if("${PACKNAME}_DOC_FILES") + file(MAKE_DIRECTORY ${GENERATED_PACKAGE_DIR}/${PACKNAME}) + add_custom_target("${PACKNAME}-tags" + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${PACKAGE} ${GENERATED_PACKAGE_DIR}/${PACKNAME} + COMMAND "${PROJECT_BINARY_DIR}/bin/nvim" + -u NONE -i NONE -e --headless -c "helptags doc" -c quit + DEPENDS + nvim + WORKING_DIRECTORY "${GENERATED_PACKAGE_DIR}/${PACKNAME}" + ) + + add_custom_command(OUTPUT "${GENERATED_PACKAGE_DIR}/${PACKNAME}/doc/tags" + DEPENDS + "${PACKNAME}-tags" + ) + + set("${PACKNAME}_DOC_NAMES") + foreach(DF "${${PACKNAME}_DOC_FILES}") + get_filename_component(F ${DF} NAME) + list(APPEND "${PACKNAME}_DOC_NAMES" ${GENERATED_PACKAGE_DIR}/${PACKNAME}/doc/${F}) + endforeach() + + install_helper( + FILES ${GENERATED_PACKAGE_DIR}/${PACKNAME}/doc/tags "${${PACKNAME}_DOC_NAMES}" + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/nvim/runtime/pack/dist/opt/${PACKNAME}/doc) + + list(APPEND GENERATED_PACKAGE_TAGS "${GENERATED_PACKAGE_DIR}/${PACKNAME}/doc/tags") + endif() +endforeach() + file(GLOB DOCFILES ${PROJECT_SOURCE_DIR}/runtime/doc/*.txt) set(BUILDDOCFILES) @@ -26,22 +68,25 @@ foreach(DF ${DOCFILES}) list(APPEND BUILDDOCFILES ${GENERATED_RUNTIME_DIR}/doc/${F}) endforeach() -add_custom_command(OUTPUT copy_docfiles - COMMAND ${CMAKE_COMMAND} -E copy_directory +add_custom_target(helptags + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/runtime/doc ${GENERATED_RUNTIME_DIR}/doc + COMMAND "${PROJECT_BINARY_DIR}/bin/nvim" + -u NONE -i NONE -e --headless -c "helptags ++t doc" -c quit + DEPENDS + nvim + WORKING_DIRECTORY "${GENERATED_RUNTIME_DIR}" ) add_custom_command(OUTPUT ${GENERATED_HELP_TAGS} - COMMAND "${PROJECT_BINARY_DIR}/bin/nvim" - -u NONE - -i NONE - -e - --headless - -c "helptags ++t ." - -c quit DEPENDS - copy_docfiles - nvim + helptags +) + +add_custom_target(doc_html + COMMAND make html + DEPENDS + ${GENERATED_HELP_TAGS} WORKING_DIRECTORY "${GENERATED_RUNTIME_DIR}/doc" ) @@ -50,6 +95,7 @@ add_custom_target( DEPENDS ${GENERATED_SYN_VIM} ${GENERATED_HELP_TAGS} + ${GENERATED_PACKAGE_TAGS} ) # CMake is painful here. It will create the destination using the user's @@ -78,7 +124,7 @@ endforeach() file(GLOB_RECURSE RUNTIME_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - *.vim *.dict *.py *.ps *.tutor) + *.vim *.dict *.py *.rb *.ps *.tutor) foreach(F ${RUNTIME_FILES}) get_filename_component(BASEDIR ${F} PATH) diff --git a/runtime/autoload/csscomplete.vim b/runtime/autoload/csscomplete.vim index 9eebb87d5b..50048a37fd 100644 --- a/runtime/autoload/csscomplete.vim +++ b/runtime/autoload/csscomplete.vim @@ -1,429 +1,740 @@ " Vim completion script -" Language: CSS 2.1 -" Maintainer: Mikolaj Machowski ( mikmach AT wp DOT pl ) -" Last Change: 2007 May 5 +" Language: CSS +" Based on MDN CSS Reference at 2016 Jan <https://developer.mozilla.org/en-US/docs/Web/CSS/Reference> +" plus CSS Speech Module <http://www.w3.org/TR/css3-speech/> +" Maintainer: Kao, Wei-Ko(othree) ( othree AT gmail DOT com ) +" Original Author: Mikolaj Machowski ( mikmach AT wp DOT pl ) +" Last Change: 2016 Jan 11 - let s:values = split("azimuth background background-attachment background-color background-image background-position background-repeat border bottom border-collapse border-color border-spacing border-style border-top border-right border-bottom border-left border-top-color border-right-color border-bottom-color border-left-color border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width border-bottom-width border-left-width border-width caption-side clear clip color content counter-increment counter-reset cue cue-after cue-before cursor display direction elevation empty-cells float font font-family font-size font-style font-variant font-weight height left letter-spacing line-height list-style list-style-image list-style-position list-style-type margin margin-right margin-left margin-top margin-bottom max-height max-width min-height min-width orphans outline outline-color outline-style outline-width overflow padding padding-top padding-right padding-bottom padding-left page-break-after page-break-before page-break-inside pause pause-after pause-before pitch pitch-range play-during position quotes right richness speak speak-header speak-numeral speak-punctuation speech-rate stress table-layout text-align text-decoration text-indent text-transform top unicode-bidi vertical-align visibility voice-family volume white-space width widows word-spacing z-index") +let s:values = split("all additive-symbols align-content align-items align-self animation animation-delay animation-direction animation-duration animation-fill-mode animation-iteration-count animation-name animation-play-state animation-timing-function backface-visibility background background-attachment background-blend-mode background-clip background-color background-image background-origin background-position background-repeat background-size block-size border border-block-end border-block-end-color border-block-end-style border-block-end-width border-block-start border-block-start-color border-block-start-style border-block-start-width border-bottom border-bottom-color border-bottom-left-radius border-bottom-right-radius border-bottom-style border-bottom-width border-collapse border-color border-image border-image-outset border-image-repeat border-image-slice border-image-source border-image-width border-inline-end border-inline-end-color border-inline-end-style border-inline-end-width border-inline-start border-inline-start-color border-inline-start-style border-inline-start-width border-left border-left-color border-left-style border-left-width border-radius border-right border-right-color border-right-style border-right-width border-spacing border-style border-top border-top-color border-top-left-radius border-top-right-radius border-top-style border-top-width border-width bottom box-decoration-break box-shadow box-sizing break-after break-before break-inside caption-side clear clip clip-path color columns column-count column-fill column-gap column-rule column-rule-color column-rule-style column-rule-width column-span column-width content counter-increment counter-reset cue cue-before cue-after cursor direction display empty-cells fallback filter flex flex-basis flex-direction flex-flow flex-grow flex-shrink flex-wrap float font font-family font-feature-settings font-kerning font-language-override font-size font-size-adjust font-stretch font-style font-synthesis font-variant font-variant-alternates font-variant-caps font-variant-east-asian font-variant-ligatures font-variant-numeric font-variant-position font-weight grid grid-area grid-auto-columns grid-auto-flow grid-auto-position grid-auto-rows grid-column grid-column-start grid-column-end grid-row grid-row-start grid-row-end grid-template grid-template-areas grid-template-rows grid-template-columns height hyphens image-rendering image-resolution image-orientation ime-mode inline-size isolation justify-content left letter-spacing line-break line-height list-style list-style-image list-style-position list-style-type margin margin-block-end margin-block-start margin-bottom margin-inline-end margin-inline-start margin-left margin-right margin-top marks mask mask-type max-block-size max-height max-inline-size max-width max-zoom min-block-size min-height min-inline-size min-width min-zoom mix-blend-mode negative object-fit object-position offset-block-end offset-block-start offset-inline-end offset-inline-start opacity order orientation orphans outline outline-color outline-offset outline-style outline-width overflow overflow-wrap overflow-x overflow-y pad padding padding-block-end padding-block-start padding-bottom padding-inline-end padding-inline-start padding-left padding-right padding-top page-break-after page-break-before page-break-inside pause-before pause-after pause perspective perspective-origin pointer-events position prefix quotes range resize rest rest-before rest-after right ruby-align ruby-merge ruby-position scroll-behavior scroll-snap-coordinate scroll-snap-destination scroll-snap-points-x scroll-snap-points-y scroll-snap-type scroll-snap-type-x scroll-snap-type-y shape-image-threshold shape-margin shape-outside speak speak-as suffix symbols system table-layout tab-size text-align text-align-last text-combine-upright text-decoration text-decoration-color text-decoration-line text-emphasis text-emphasis-color text-emphasis-position text-emphasis-style text-indent text-orientation text-overflow text-rendering text-shadow text-transform text-underline-position top touch-action transform transform-box transform-origin transform-style transition transition-delay transition-duration transition-property transition-timing-function unicode-bidi unicode-range user-zoom vertical-align visibility voice-balance voice-duration voice-family voice-pitch voice-rate voice-range voice-stress voice-volume white-space widows width will-change word-break word-spacing word-wrap writing-mode z-index zoom") -function! csscomplete#CompleteCSS(findstart, base) - -if a:findstart - " We need whole line to proper checking - let line = getline('.') - let start = col('.') - 1 - let compl_begin = col('.') - 2 - while start >= 0 && line[start - 1] =~ '\%(\k\|-\)' - let start -= 1 - endwhile - let b:compl_context = line[0:compl_begin] - return start -endif - -" There are few chars important for context: -" ^ ; : { } /* */ -" Where ^ is start of line and /* */ are comment borders -" Depending on their relative position to cursor we will know what should -" be completed. -" 1. if nearest are ^ or { or ; current word is property -" 2. if : it is value (with exception of pseudo things) -" 3. if } we are outside of css definitions -" 4. for comments ignoring is be the easiest but assume they are the same -" as 1. -" 5. if @ complete at-rule -" 6. if ! complete important -if exists("b:compl_context") - let line = b:compl_context - unlet! b:compl_context -else - let line = a:base -endif - -let res = [] -let res2 = [] -let borders = {} - -" Check last occurrence of sequence - -let openbrace = strridx(line, '{') -let closebrace = strridx(line, '}') -let colon = strridx(line, ':') -let semicolon = strridx(line, ';') -let opencomm = strridx(line, '/*') -let closecomm = strridx(line, '*/') -let style = strridx(line, 'style\s*=') -let atrule = strridx(line, '@') -let exclam = strridx(line, '!') - -if openbrace > -1 - let borders[openbrace] = "openbrace" -endif -if closebrace > -1 - let borders[closebrace] = "closebrace" -endif -if colon > -1 - let borders[colon] = "colon" -endif -if semicolon > -1 - let borders[semicolon] = "semicolon" -endif -if opencomm > -1 - let borders[opencomm] = "opencomm" -endif -if closecomm > -1 - let borders[closecomm] = "closecomm" -endif -if style > -1 - let borders[style] = "style" -endif -if atrule > -1 - let borders[atrule] = "atrule" -endif -if exclam > -1 - let borders[exclam] = "exclam" -endif - - -if len(borders) == 0 || borders[max(keys(borders))] =~ '^\%(openbrace\|semicolon\|opencomm\|closecomm\|style\)$' - " Complete properties - - - let entered_property = matchstr(line, '.\{-}\zs[a-zA-Z-]*$') - - for m in s:values - if m =~? '^'.entered_property - call add(res, m . ':') - elseif m =~? entered_property - call add(res2, m . ':') - endif - endfor - - return res + res2 - -elseif borders[max(keys(borders))] == 'colon' - " Get name of property - let prop = tolower(matchstr(line, '\zs[a-zA-Z-]*\ze\s*:[^:]\{-}$')) - - if prop == 'azimuth' - let values = ["left-side", "far-left", "left", "center-left", "center", "center-right", "right", "far-right", "right-side", "behind", "leftwards", "rightwards"] - elseif prop == 'background-attachment' - let values = ["scroll", "fixed"] - elseif prop == 'background-color' - let values = ["transparent", "rgb(", "#"] - elseif prop == 'background-image' - let values = ["url(", "none"] - elseif prop == 'background-position' - let vals = matchstr(line, '.*:\s*\zs.*') - if vals =~ '^\%([a-zA-Z]\+\)\?$' - let values = ["top", "center", "bottom"] - elseif vals =~ '^[a-zA-Z]\+\s\+\%([a-zA-Z]\+\)\?$' - let values = ["left", "center", "right"] - else - return [] - endif - elseif prop == 'background-repeat' - let values = ["repeat", "repeat-x", "repeat-y", "no-repeat"] - elseif prop == 'background' - let values = ["url(", "scroll", "fixed", "transparent", "rgb(", "#", "none", "top", "center", "bottom" , "left", "right", "repeat", "repeat-x", "repeat-y", "no-repeat"] - elseif prop == 'border-collapse' - let values = ["collapse", "separate"] - elseif prop == 'border-color' - let values = ["rgb(", "#", "transparent"] - elseif prop == 'border-spacing' - return [] - elseif prop == 'border-style' - let values = ["none", "hidden", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"] - elseif prop =~ 'border-\%(top\|right\|bottom\|left\)$' - let vals = matchstr(line, '.*:\s*\zs.*') - if vals =~ '^\%([a-zA-Z0-9.]\+\)\?$' - let values = ["thin", "thick", "medium"] - elseif vals =~ '^[a-zA-Z0-9.]\+\s\+\%([a-zA-Z]\+\)\?$' - let values = ["none", "hidden", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"] - elseif vals =~ '^[a-zA-Z0-9.]\+\s\+[a-zA-Z]\+\s\+\%([a-zA-Z(]\+\)\?$' - let values = ["rgb(", "#", "transparent"] - else - return [] - endif - elseif prop =~ 'border-\%(top\|right\|bottom\|left\)-color' - let values = ["rgb(", "#", "transparent"] - elseif prop =~ 'border-\%(top\|right\|bottom\|left\)-style' - let values = ["none", "hidden", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"] - elseif prop =~ 'border-\%(top\|right\|bottom\|left\)-width' - let values = ["thin", "thick", "medium"] - elseif prop == 'border-width' - let values = ["thin", "thick", "medium"] - elseif prop == 'border' - let vals = matchstr(line, '.*:\s*\zs.*') - if vals =~ '^\%([a-zA-Z0-9.]\+\)\?$' - let values = ["thin", "thick", "medium"] - elseif vals =~ '^[a-zA-Z0-9.]\+\s\+\%([a-zA-Z]\+\)\?$' - let values = ["none", "hidden", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"] - elseif vals =~ '^[a-zA-Z0-9.]\+\s\+[a-zA-Z]\+\s\+\%([a-zA-Z(]\+\)\?$' - let values = ["rgb(", "#", "transparent"] - else - return [] - endif - elseif prop == 'bottom' - let values = ["auto"] - elseif prop == 'caption-side' - let values = ["top", "bottom"] - elseif prop == 'clear' - let values = ["none", "left", "right", "both"] - elseif prop == 'clip' - let values = ["auto", "rect("] - elseif prop == 'color' - let values = ["rgb(", "#"] - elseif prop == 'content' - let values = ["normal", "attr(", "open-quote", "close-quote", "no-open-quote", "no-close-quote"] - elseif prop =~ 'counter-\%(increment\|reset\)$' - let values = ["none"] - elseif prop =~ '^\%(cue-after\|cue-before\|cue\)$' - let values = ["url(", "none"] - elseif prop == 'cursor' - let values = ["url(", "auto", "crosshair", "default", "pointer", "move", "e-resize", "ne-resize", "nw-resize", "n-resize", "se-resize", "sw-resize", "s-resize", "w-resize", "text", "wait", "help", "progress"] - elseif prop == 'direction' - let values = ["ltr", "rtl"] - elseif prop == 'display' - let values = ["inline", "block", "list-item", "run-in", "inline-block", "table", "inline-table", "table-row-group", "table-header-group", "table-footer-group", "table-row", "table-column-group", "table-column", "table-cell", "table-caption", "none"] - elseif prop == 'elevation' - let values = ["below", "level", "above", "higher", "lower"] - elseif prop == 'empty-cells' - let values = ["show", "hide"] - elseif prop == 'float' - let values = ["left", "right", "none"] - elseif prop == 'font-family' - let values = ["sans-serif", "serif", "monospace", "cursive", "fantasy"] - elseif prop == 'font-size' - let values = ["xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "larger", "smaller"] - elseif prop == 'font-style' - let values = ["normal", "italic", "oblique"] - elseif prop == 'font-variant' - let values = ["normal", "small-caps"] - elseif prop == 'font-weight' - let values = ["normal", "bold", "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900"] - elseif prop == 'font' - let values = ["normal", "italic", "oblique", "small-caps", "bold", "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900", "xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "larger", "smaller", "sans-serif", "serif", "monospace", "cursive", "fantasy", "caption", "icon", "menu", "message-box", "small-caption", "status-bar"] - elseif prop =~ '^\%(height\|width\)$' - let values = ["auto"] - elseif prop =~ '^\%(left\|rigth\)$' - let values = ["auto"] - elseif prop == 'letter-spacing' - let values = ["normal"] - elseif prop == 'line-height' - let values = ["normal"] - elseif prop == 'list-style-image' - let values = ["url(", "none"] - elseif prop == 'list-style-position' - let values = ["inside", "outside"] - elseif prop == 'list-style-type' - let values = ["disc", "circle", "square", "decimal", "decimal-leading-zero", "lower-roman", "upper-roman", "lower-latin", "upper-latin", "none"] - elseif prop == 'list-style' - return [] - elseif prop == 'margin' - let values = ["auto"] - elseif prop =~ 'margin-\%(right\|left\|top\|bottom\)$' - let values = ["auto"] - elseif prop == 'max-height' - let values = ["auto"] - elseif prop == 'max-width' - let values = ["none"] - elseif prop == 'min-height' - let values = ["none"] - elseif prop == 'min-width' - let values = ["none"] - elseif prop == 'orphans' - return [] - elseif prop == 'outline-color' - let values = ["rgb(", "#"] - elseif prop == 'outline-style' - let values = ["none", "hidden", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"] - elseif prop == 'outline-width' - let values = ["thin", "thick", "medium"] - elseif prop == 'outline' - let vals = matchstr(line, '.*:\s*\zs.*') - if vals =~ '^\%([a-zA-Z0-9,()#]\+\)\?$' - let values = ["rgb(", "#"] - elseif vals =~ '^[a-zA-Z0-9,()#]\+\s\+\%([a-zA-Z]\+\)\?$' - let values = ["none", "hidden", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"] - elseif vals =~ '^[a-zA-Z0-9,()#]\+\s\+[a-zA-Z]\+\s\+\%([a-zA-Z(]\+\)\?$' - let values = ["thin", "thick", "medium"] - else - return [] - endif - elseif prop == 'overflow' - let values = ["visible", "hidden", "scroll", "auto"] - elseif prop == 'padding' - return [] - elseif prop =~ 'padding-\%(top\|right\|bottom\|left\)$' - return [] - elseif prop =~ 'page-break-\%(after\|before\)$' - let values = ["auto", "always", "avoid", "left", "right"] - elseif prop == 'page-break-inside' - let values = ["auto", "avoid"] - elseif prop =~ 'pause-\%(after\|before\)$' - return [] - elseif prop == 'pause' - return [] - elseif prop == 'pitch-range' - return [] - elseif prop == 'pitch' - let values = ["x-low", "low", "medium", "high", "x-high"] - elseif prop == 'play-during' - let values = ["url(", "mix", "repeat", "auto", "none"] - elseif prop == 'position' - let values = ["static", "relative", "absolute", "fixed"] - elseif prop == 'quotes' - let values = ["none"] - elseif prop == 'richness' - return [] - elseif prop == 'speak-header' - let values = ["once", "always"] - elseif prop == 'speak-numeral' - let values = ["digits", "continuous"] - elseif prop == 'speak-punctuation' - let values = ["code", "none"] - elseif prop == 'speak' - let values = ["normal", "none", "spell-out"] - elseif prop == 'speech-rate' - let values = ["x-slow", "slow", "medium", "fast", "x-fast", "faster", "slower"] - elseif prop == 'stress' - return [] - elseif prop == 'table-layout' - let values = ["auto", "fixed"] - elseif prop == 'text-align' - let values = ["left", "right", "center", "justify"] - elseif prop == 'text-decoration' - let values = ["none", "underline", "overline", "line-through", "blink"] - elseif prop == 'text-indent' - return [] - elseif prop == 'text-transform' - let values = ["capitalize", "uppercase", "lowercase", "none"] - elseif prop == 'top' - let values = ["auto"] - elseif prop == 'unicode-bidi' - let values = ["normal", "embed", "bidi-override"] - elseif prop == 'vertical-align' - let values = ["baseline", "sub", "super", "top", "text-top", "middle", "bottom", "text-bottom"] - elseif prop == 'visibility' - let values = ["visible", "hidden", "collapse"] - elseif prop == 'voice-family' - return [] - elseif prop == 'volume' - let values = ["silent", "x-soft", "soft", "medium", "loud", "x-loud"] - elseif prop == 'white-space' - let values = ["normal", "pre", "nowrap", "pre-wrap", "pre-line"] - elseif prop == 'widows' - return [] - elseif prop == 'word-spacing' - let values = ["normal"] - elseif prop == 'z-index' - let values = ["auto"] - else - " If no property match it is possible we are outside of {} and - " trying to complete pseudo-(class|element) - let element = tolower(matchstr(line, '\zs[a-zA-Z1-6]*\ze:[^:[:space:]]\{-}$')) - if stridx(',a,abbr,acronym,address,area,b,base,bdo,big,blockquote,body,br,button,caption,cite,code,col,colgroup,dd,del,dfn,div,dl,dt,em,fieldset,form,head,h1,h2,h3,h4,h5,h6,hr,html,i,img,input,ins,kbd,label,legend,li,link,map,meta,noscript,object,ol,optgroup,option,p,param,pre,q,samp,script,select,small,span,strong,style,sub,sup,table,tbody,td,textarea,tfoot,th,thead,title,tr,tt,ul,var,', ','.element.',') > -1 - let values = ["first-child", "link", "visited", "hover", "active", "focus", "lang", "first-line", "first-letter", "before", "after"] - else - return [] - endif - endif - - " Complete values - let entered_value = matchstr(line, '.\{-}\zs[a-zA-Z0-9#,.(_-]*$') - - for m in values - if m =~? '^'.entered_value - call add(res, m) - elseif m =~? entered_value - call add(res2, m) - endif - endfor - - return res + res2 - -elseif borders[max(keys(borders))] == 'closebrace' - - return [] - -elseif borders[max(keys(borders))] == 'exclam' - - " Complete values - let entered_imp = matchstr(line, '.\{-}!\s*\zs[a-zA-Z ]*$') - - let values = ["important"] - - for m in values - if m =~? '^'.entered_imp - call add(res, m) - endif - endfor - - return res - -elseif borders[max(keys(borders))] == 'atrule' - - let afterat = matchstr(line, '.*@\zs.*') - - if afterat =~ '\s' - - let atrulename = matchstr(line, '.*@\zs[a-zA-Z-]\+\ze') - - if atrulename == 'media' - let values = ["screen", "tty", "tv", "projection", "handheld", "print", "braille", "aural", "all"] - - let entered_atruleafter = matchstr(line, '.*@media\s\+\zs.*$') - - elseif atrulename == 'import' - let entered_atruleafter = matchstr(line, '.*@import\s\+\zs.*$') - - if entered_atruleafter =~ "^[\"']" - let filestart = matchstr(entered_atruleafter, '^.\zs.*') - let files = split(glob(filestart.'*'), '\n') - let values = map(copy(files), '"\"".v:val') - - elseif entered_atruleafter =~ "^url(" - let filestart = matchstr(entered_atruleafter, "^url([\"']\\?\\zs.*") - let files = split(glob(filestart.'*'), '\n') - let values = map(copy(files), '"url(".v:val') - - else - let values = ['"', 'url('] - - endif - - else - return [] - - endif - - for m in values - if m =~? '^'.entered_atruleafter - call add(res, m) - elseif m =~? entered_atruleafter - call add(res2, m) - endif - endfor - - return res + res2 - - endif - - let values = ["charset", "page", "media", "import", "font-face"] - let entered_atrule = matchstr(line, '.*@\zs[a-zA-Z-]*$') - - for m in values - if m =~? '^'.entered_atrule - call add(res, m .' ') - elseif m =~? entered_atrule - call add(res2, m .' ') - endif - endfor - - return res + res2 - -endif +function! csscomplete#CompleteCSS(findstart, base) -return [] + if a:findstart + " We need whole line to proper checking + let line = getline('.') + let start = col('.') - 1 + let compl_begin = col('.') - 2 + while start >= 0 && line[start - 1] =~ '\%(\k\|-\)' + let start -= 1 + endwhile + let b:after = line[compl_begin :] + let b:compl_context = line[0:compl_begin] + return start + endif + + " There are few chars important for context: + " ^ ; : { } /* */ + " Where ^ is start of line and /* */ are comment borders + " Depending on their relative position to cursor we will know what should + " be completed. + " 1. if nearest are ^ or { or ; current word is property + " 2. if : it is value (with exception of pseudo things) + " 3. if } we are outside of css definitions + " 4. for comments ignoring is be the easiest but assume they are the same + " as 1. + " 5. if @ complete at-rule + " 6. if ! complete important + if exists("b:compl_context") + let line = b:compl_context + let after = b:after + unlet! b:compl_context + else + let line = a:base + endif + + let res = [] + let res2 = [] + let borders = {} + + " Check last occurrence of sequence + + let openbrace = strridx(line, '{') + let closebrace = strridx(line, '}') + let colon = strridx(line, ':') + let semicolon = strridx(line, ';') + let opencomm = strridx(line, '/*') + let closecomm = strridx(line, '*/') + let style = strridx(line, 'style\s*=') + let atrule = strridx(line, '@') + let exclam = strridx(line, '!') + + if openbrace > -1 + let borders[openbrace] = "openbrace" + endif + if closebrace > -1 + let borders[closebrace] = "closebrace" + endif + if colon > -1 + let borders[colon] = "colon" + endif + if semicolon > -1 + let borders[semicolon] = "semicolon" + endif + if opencomm > -1 + let borders[opencomm] = "opencomm" + endif + if closecomm > -1 + let borders[closecomm] = "closecomm" + endif + if style > -1 + let borders[style] = "style" + endif + if atrule > -1 + let borders[atrule] = "atrule" + endif + if exclam > -1 + let borders[exclam] = "exclam" + endif + + + if len(borders) == 0 || borders[max(keys(borders))] =~ '^\%(openbrace\|semicolon\|opencomm\|closecomm\|style\)$' + " Complete properties + + + let entered_property = matchstr(line, '.\{-}\zs[a-zA-Z-]*$') + + for m in s:values + if m =~? '^'.entered_property + call add(res, m . ':') + elseif m =~? entered_property + call add(res2, m . ':') + endif + endfor + + return res + res2 + + elseif borders[max(keys(borders))] == 'colon' + " Get name of property + let prop = tolower(matchstr(line, '\zs[a-zA-Z-]*\ze\s*:[^:]\{-}$')) + + let wide_keywords = ["initial", "inherit", "unset"] + let color_values = ["transparent", "rgb(", "rgba(", "hsl(", "hsla(", "#"] + let border_style_values = ["none", "hidden", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"] + let border_width_values = ["thin", "thick", "medium"] + let list_style_type_values = ["decimal", "decimal-leading-zero", "arabic-indic", "armenian", "upper-armenian", "lower-armenian", "bengali", "cambodian", "khmer", "cjk-decimal", "devanagari", "georgian", "gujarati", "gurmukhi", "hebrew", "kannada", "lao", "malayalam", "mongolian", "myanmar", "oriya", "persian", "lower-roman", "upper-roman", "tamil", "telugu", "thai", "tibetan", "lower-alpha", "lower-latin", "upper-alpha", "upper-latin", "cjk-earthly-branch", "cjk-heavenly-stem", "lower-greek", "hiragana", "hiragana-iroha", "katakana", "katakana-iroha", "disc", "circle", "square", "disclosure-open", "disclosure-closed"] + let timing_functions = ["cubic-bezier(", "steps(", "linear", "ease", "ease-in", "ease-in-out", "ease-out", "step-start", "step-end"] + + if prop == 'all' + let values = [] + elseif prop == 'additive-symbols' + let values = [] + elseif prop == 'align-content' + let values = ["flex-start", "flex-end", "center", "space-between", "space-around", "stretch"] + elseif prop == 'align-items' + let values = ["flex-start", "flex-end", "center", "baseline", "stretch"] + elseif prop == 'align-self' + let values = ["auto", "flex-start", "flex-end", "center", "baseline", "stretch"] + elseif prop == 'animation' + let values = timing_functions + ["normal", "reverse", "alternate", "alternate-reverse"] + ["none", "forwards", "backwards", "both"] + ["running", "paused"] + elseif prop == 'animation-delay' + let values = [] + elseif prop == 'animation-direction' + let values = ["normal", "reverse", "alternate", "alternate-reverse"] + elseif prop == 'animation-duration' + let values = [] + elseif prop == 'animation-fill-mode' + let values = ["none", "forwards", "backwards", "both"] + elseif prop == 'animation-iteration-count' + let values = [] + elseif prop == 'animation-name' + let values = [] + elseif prop == 'animation-play-state' + let values = ["running", "paused"] + elseif prop == 'animation-timing-function' + let values = timing_functions + elseif prop == 'background-attachment' + let values = ["scroll", "fixed"] + elseif prop == 'background-color' + let values = color_values + elseif prop == 'background-image' + let values = ["url(", "none"] + elseif prop == 'background-position' + let vals = matchstr(line, '.*:\s*\zs.*') + if vals =~ '^\%([a-zA-Z]\+\)\?$' + let values = ["top", "center", "bottom"] + elseif vals =~ '^[a-zA-Z]\+\s\+\%([a-zA-Z]\+\)\?$' + let values = ["left", "center", "right"] + else + return [] + endif + elseif prop == 'background-repeat' + let values = ["repeat", "repeat-x", "repeat-y", "no-repeat"] + elseif prop == 'background-size' + let values = ["auto", "contain", "cover"] + elseif prop == 'background' + let values = ["scroll", "fixed"] + color_values + ["url(", "none"] + ["top", "center", "bottom", "left", "right"] + ["repeat", "repeat-x", "repeat-y", "no-repeat"] + ["auto", "contain", "cover"] + elseif prop =~ 'border\%(-top\|-right\|-bottom\|-left\|-block-start\|-block-end\)\?$' + let vals = matchstr(line, '.*:\s*\zs.*') + if vals =~ '^\%([a-zA-Z0-9.]\+\)\?$' + let values = border_width_values + elseif vals =~ '^[a-zA-Z0-9.]\+\s\+\%([a-zA-Z]\+\)\?$' + let values = border_style_values + elseif vals =~ '^[a-zA-Z0-9.]\+\s\+[a-zA-Z]\+\s\+\%([a-zA-Z(]\+\)\?$' + let values = color_values + else + return [] + endif + elseif prop =~ 'border-\%(top\|right\|bottom\|left\|block-start\|block-end\)-color' + let values = color_values + elseif prop =~ 'border-\%(top\|right\|bottom\|left\|block-start\|block-end\)-style' + let values = border_style_values + elseif prop =~ 'border-\%(top\|right\|bottom\|left\|block-start\|block-end\)-width' + let values = border_width_values + elseif prop == 'border-color' + let values = color_values + elseif prop == 'border-style' + let values = border_style_values + elseif prop == 'border-width' + let values = border_width_values + elseif prop == 'bottom' + let values = ["auto"] + elseif prop == 'box-decoration-break' + let values = ["slice", "clone"] + elseif prop == 'box-shadow' + let values = ["inset"] + elseif prop == 'box-sizing' + let values = ["border-box", "content-box"] + elseif prop =~ 'break-\%(before\|after\)' + let values = ["auto", "always", "avoid", "left", "right", "page", "column", "region", "recto", "verso", "avoid-page", "avoid-column", "avoid-region"] + elseif prop == 'break-inside' + let values = ["auto", "avoid", "avoid-page", "avoid-column", "avoid-region"] + elseif prop == 'caption-side' + let values = ["top", "bottom"] + elseif prop == 'clear' + let values = ["none", "left", "right", "both"] + elseif prop == 'clip' + let values = ["auto", "rect("] + elseif prop == 'clip-path' + let values = ["fill-box", "stroke-box", "view-box", "none"] + elseif prop == 'color' + let values = color_values + elseif prop == 'columns' + let values = [] + elseif prop == 'column-count' + let values = ['auto'] + elseif prop == 'column-fill' + let values = ['auto', 'balance'] + elseif prop == 'column-rule-color' + let values = color_values + elseif prop == 'column-rule-style' + let values = border_style_values + elseif prop == 'column-rule-width' + let values = border_width_values + elseif prop == 'column-rule' + let vals = matchstr(line, '.*:\s*\zs.*') + if vals =~ '^\%([a-zA-Z0-9.]\+\)\?$' + let values = border_width_values + elseif vals =~ '^[a-zA-Z0-9.]\+\s\+\%([a-zA-Z]\+\)\?$' + let values = border_style_values + elseif vals =~ '^[a-zA-Z0-9.]\+\s\+[a-zA-Z]\+\s\+\%([a-zA-Z(]\+\)\?$' + let values = color_values + else + return [] + endif + elseif prop == 'column-span' + let values = ["none", "all"] + elseif prop == 'column-width' + let values = ["auto"] + elseif prop == 'content' + let values = ["normal", "attr(", "open-quote", "close-quote", "no-open-quote", "no-close-quote"] + elseif prop =~ 'counter-\%(increment\|reset\)$' + let values = ["none"] + elseif prop =~ 'cue\%(-after\|-before\)\=$' + let values = ["url("] + elseif prop == 'cursor' + let values = ["url(", "auto", "crosshair", "default", "pointer", "move", "e-resize", "ne-resize", "nw-resize", "n-resize", "se-resize", "sw-resize", "s-resize", "w-resize", "text", "wait", "help", "progress"] + elseif prop == 'direction' + let values = ["ltr", "rtl"] + elseif prop == 'display' + let values = ["inline", "block", "list-item", "inline-list-item", "run-in", "inline-block", "table", "inline-table", "table-row-group", "table-header-group", "table-footer-group", "table-row", "table-column-group", "table-column", "table-cell", "table-caption", "none", "flex", "inline-flex", "grid", "inline-grid", "ruby", "ruby-base", "ruby-text", "ruby-base-container", "ruby-text-container", "contents"] + elseif prop == 'elevation' + let values = ["below", "level", "above", "higher", "lower"] + elseif prop == 'empty-cells' + let values = ["show", "hide"] + elseif prop == 'fallback' + let values = list_style_type_values + elseif prop == 'filter' + let values = ["blur(", "brightness(", "contrast(", "drop-shadow(", "grayscale(", "hue-rotate(", "invert(", "opacity(", "sepia(", "saturate("] + elseif prop == 'flex-basis' + let values = ["auto", "content"] + elseif prop == 'flex-flow' + let values = ["row", "row-reverse", "column", "column-reverse", "nowrap", "wrap", "wrap-reverse"] + elseif prop == 'flex-grow' + let values = [] + elseif prop == 'flex-shrink' + let values = [] + elseif prop == 'flex-wrap' + let values = ["nowrap", "wrap", "wrap-reverse"] + elseif prop == 'flex' + let values = ["nowrap", "wrap", "wrap-reverse"] + ["row", "row-reverse", "column", "column-reverse", "nowrap", "wrap", "wrap-reverse"] + ["auto", "content"] + elseif prop == 'float' + let values = ["left", "right", "none"] + elseif prop == 'font-family' + let values = ["sans-serif", "serif", "monospace", "cursive", "fantasy"] + elseif prop == 'font-feature-settings' + let values = ["normal", '"aalt"', '"abvf"', '"abvm"', '"abvs"', '"afrc"', '"akhn"', '"blwf"', '"blwm"', '"blws"', '"calt"', '"case"', '"ccmp"', '"cfar"', '"cjct"', '"clig"', '"cpct"', '"cpsp"', '"cswh"', '"curs"', '"cv', '"c2pc"', '"c2sc"', '"dist"', '"dlig"', '"dnom"', '"dtls"', '"expt"', '"falt"', '"fin2"', '"fin3"', '"fina"', '"flac"', '"frac"', '"fwid"', '"half"', '"haln"', '"halt"', '"hist"', '"hkna"', '"hlig"', '"hngl"', '"hojo"', '"hwid"', '"init"', '"isol"', '"ital"', '"jalt"', '"jp78"', '"jp83"', '"jp90"', '"jp04"', '"kern"', '"lfbd"', '"liga"', '"ljmo"', '"lnum"', '"locl"', '"ltra"', '"ltrm"', '"mark"', '"med2"', '"medi"', '"mgrk"', '"mkmk"', '"mset"', '"nalt"', '"nlck"', '"nukt"', '"numr"', '"onum"', '"opbd"', '"ordn"', '"ornm"', '"palt"', '"pcap"', '"pkna"', '"pnum"', '"pref"', '"pres"', '"pstf"', '"psts"', '"pwid"', '"qwid"', '"rand"', '"rclt"', '"rkrf"', '"rlig"', '"rphf"', '"rtbd"', '"rtla"', '"rtlm"', '"ruby"', '"salt"', '"sinf"', '"size"', '"smcp"', '"smpl"', '"ss01"', '"ss02"', '"ss03"', '"ss04"', '"ss05"', '"ss06"', '"ss07"', '"ss08"', '"ss09"', '"ss10"', '"ss11"', '"ss12"', '"ss13"', '"ss14"', '"ss15"', '"ss16"', '"ss17"', '"ss18"', '"ss19"', '"ss20"', '"ssty"', '"stch"', '"subs"', '"sups"', '"swsh"', '"titl"', '"tjmo"', '"tnam"', '"tnum"', '"trad"', '"twid"', '"unic"', '"valt"', '"vatu"', '"vert"', '"vhal"', '"vjmo"', '"vkna"', '"vkrn"', '"vpal"', '"vrt2"', '"zero"'] + elseif prop == 'font-kerning' + let values = ["auto", "normal", "none"] + elseif prop == 'font-language-override' + let values = ["normal"] + elseif prop == 'font-size' + let values = ["xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "larger", "smaller"] + elseif prop == 'font-size-adjust' + let values = [] + elseif prop == 'font-stretch' + let values = ["normal", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed", "semi-expanded", "expanded", "extra-expanded", "ultra-expanded"] + elseif prop == 'font-style' + let values = ["normal", "italic", "oblique"] + elseif prop == 'font-synthesis' + let values = ["none", "weight", "style"] + elseif prop == 'font-variant-alternates' + let values = ["normal", "historical-forms", "stylistic(", "styleset(", "character-variant(", "swash(", "ornaments(", "annotation("] + elseif prop == 'font-variant-caps' + let values = ["normal", "small-caps", "all-small-caps", "petite-caps", "all-petite-caps", "unicase", "titling-caps"] + elseif prop == 'font-variant-asian' + let values = ["normal", "ruby", "jis78", "jis83", "jis90", "jis04", "simplified", "traditional"] + elseif prop == 'font-variant-ligatures' + let values = ["normal", "none", "common-ligatures", "no-common-ligatures", "discretionary-ligatures", "no-discretionary-ligatures", "historical-ligatures", "no-historical-ligatures", "contextual", "no-contextual"] + elseif prop == 'font-variant-numeric' + let values = ["normal", "ordinal", "slashed-zero", "lining-nums", "oldstyle-nums", "proportional-nums", "tabular-nums", "diagonal-fractions", "stacked-fractions"] + elseif prop == 'font-variant-position' + let values = ["normal", "sub", "super"] + elseif prop == 'font-variant' + let values = ["normal", "historical-forms", "stylistic(", "styleset(", "character-variant(", "swash(", "ornaments(", "annotation("] + ["small-caps", "all-small-caps", "petite-caps", "all-petite-caps", "unicase", "titling-caps"] + ["ruby", "jis78", "jis83", "jis90", "jis04", "simplified", "traditional"] + ["none", "common-ligatures", "no-common-ligatures", "discretionary-ligatures", "no-discretionary-ligatures", "historical-ligatures", "no-historical-ligatures", "contextual", "no-contextual"] + ["ordinal", "slashed-zero", "lining-nums", "oldstyle-nums", "proportional-nums", "tabular-nums", "diagonal-fractions", "stacked-fractions"] + ["sub", "super"] + elseif prop == 'font-weight' + let values = ["normal", "bold", "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900"] + elseif prop == 'font' + let values = ["normal", "italic", "oblique", "small-caps", "bold", "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900", "xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "larger", "smaller", "sans-serif", "serif", "monospace", "cursive", "fantasy", "caption", "icon", "menu", "message-box", "small-caption", "status-bar"] + elseif prop =~ '^\%(height\|width\)$' + let values = ["auto", "border-box", "content-box", "max-content", "min-content", "available", "fit-content"] + elseif prop =~ '^\%(left\|rigth\)$' + let values = ["auto"] + elseif prop == 'image-rendering' + let values = ["auto", "crisp-edges", "pixelated"] + elseif prop == 'image-orientation' + let values = ["from-image", "flip"] + elseif prop == 'ime-mode' + let values = ["auto", "normal", "active", "inactive", "disabled"] + elseif prop == 'inline-size' + let values = ["auto", "border-box", "content-box", "max-content", "min-content", "available", "fit-content"] + elseif prop == 'isolation' + let values = ["auto", "isolate"] + elseif prop == 'justify-content' + let values = ["flex-start", "flex-end", "center", "space-between", "space-around"] + elseif prop == 'letter-spacing' + let values = ["normal"] + elseif prop == 'line-break' + let values = ["auto", "loose", "normal", "strict"] + elseif prop == 'line-height' + let values = ["normal"] + elseif prop == 'list-style-image' + let values = ["url(", "none"] + elseif prop == 'list-style-position' + let values = ["inside", "outside"] + elseif prop == 'list-style-type' + let values = list_style_type_values + elseif prop == 'list-style' + let values = list_style_type_values + ["inside", "outside"] + ["url(", "none"] + elseif prop == 'margin' + let values = ["auto"] + elseif prop =~ 'margin-\%(right\|left\|top\|bottom\|block-start\|block-end\|inline-start\|inline-end\)$' + let values = ["auto"] + elseif prop == 'marks' + let values = ["crop", "cross", "none"] + elseif prop == 'mask' + let values = ["url("] + elseif prop == 'mask-type' + let values = ["luminance", "alpha"] + elseif prop == '\%(max\|min\)-\%(block\|inline\)-size' + let values = ["auto", "border-box", "content-box", "max-content", "min-content", "available", "fit-content"] + elseif prop == '\%(max\|min\)-\%(height\|width\)' + let values = ["auto", "border-box", "content-box", "max-content", "min-content", "available", "fit-content"] + elseif prop == '\%(max\|min\)-zoom' + let values = ["auto"] + elseif prop == 'mix-blend-mode' + let values = ["normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"] + elseif prop == 'opacity' + let values = [] + elseif prop == 'orientation' + let values = ["auto", "portrait", "landscape"] + elseif prop == 'orphans' + let values = [] + elseif prop == 'outline-offset' + let values = [] + elseif prop == 'outline-color' + let values = color_values + elseif prop == 'outline-style' + let values = ["none", "hidden", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"] + elseif prop == 'outline-width' + let values = ["thin", "thick", "medium"] + elseif prop == 'outline' + let vals = matchstr(line, '.*:\s*\zs.*') + if vals =~ '^\%([a-zA-Z0-9,()#]\+\)\?$' + let values = color_values + elseif vals =~ '^[a-zA-Z0-9,()#]\+\s\+\%([a-zA-Z]\+\)\?$' + let values = ["none", "hidden", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"] + elseif vals =~ '^[a-zA-Z0-9,()#]\+\s\+[a-zA-Z]\+\s\+\%([a-zA-Z(]\+\)\?$' + let values = ["thin", "thick", "medium"] + else + return [] + endif + elseif prop == 'overflow-wrap' + let values = ["normal", "break-word"] + elseif prop =~ 'overflow\%(-x\|-y\)\=' + let values = ["visible", "hidden", "scroll", "auto"] + elseif prop == 'pad' + let values = [] + elseif prop == 'padding' + let values = [] + elseif prop =~ 'padding-\%(top\|right\|bottom\|left\|inline-start\|inline-end\|block-start\|block-end\)$' + let values = [] + elseif prop =~ 'page-break-\%(after\|before\)$' + let values = ["auto", "always", "avoid", "left", "right", "recto", "verso"] + elseif prop == 'page-break-inside' + let values = ["auto", "avoid"] + elseif prop =~ 'pause\%(-after\|-before\)\=$' + let values = ["none", "x-weak", "weak", "medium", "strong", "x-strong"] + elseif prop == 'perspective' + let values = ["none"] + elseif prop == 'perspective-origin' + let values = ["top", "bottom", "left", "center", " right"] + elseif prop == 'pointer-events' + let values = ["auto", "none", "visiblePainted", "visibleFill", "visibleStroke", "visible", "painted", "fill", "stroke", "all"] + elseif prop == 'position' + let values = ["static", "relative", "absolute", "fixed", "sticky"] + elseif prop == 'prefix' + let values = [] + elseif prop == 'quotes' + let values = ["none"] + elseif prop == 'range' + let values = ["auto", "infinite"] + elseif prop == 'resize' + let values = ["none", "both", "horizontal", "vertical"] + elseif prop =~ 'rest\%(-after\|-before\)\=$' + let values = ["none", "x-weak", "weak", "medium", "strong", "x-strong"] + elseif prop == 'ruby-align' + let values = ["start", "center", "space-between", "space-around"] + elseif prop == 'ruby-merge' + let values = ["separate", "collapse", "auto"] + elseif prop == 'ruby-position' + let values = ["over", "under", "inter-character"] + elseif prop == 'scroll-behavior' + let values = ["auto", "smooth"] + elseif prop == 'scroll-snap-coordinate' + let values = ["none"] + elseif prop == 'scroll-snap-destination' + return [] + elseif prop == 'scroll-snap-points-\%(x\|y\)$' + let values = ["none", "repeat("] + elseif prop == 'scroll-snap-type\%(-x\|-y\)\=$' + let values = ["none", "mandatory", "proximity"] + elseif prop == 'shape-image-threshold' + let values = [] + elseif prop == 'shape-margin' + let values = [] + elseif prop == 'shape-outside' + let values = ["margin-box", "border-box", "padding-box", "content-box", 'inset(', 'circle(', 'ellipse(', 'polygon(', 'url('] + elseif prop == 'speak' + let values = ["auto", "none", "normal"] + elseif prop == 'speak-as' + let values = ["auto", "normal", "spell-out", "digits"] + elseif prop == 'src' + let values = ["url("] + elseif prop == 'suffix' + let values = [] + elseif prop == 'symbols' + let values = [] + elseif prop == 'system' + let vals = matchstr(line, '.*:\s*\zs.*') + if vals =~ '^extends' + let values = list_style_type_values + else + let values = ["cyclic", "numeric", "alphabetic", "symbolic", "additive", "fixed", "extends"] + endif + elseif prop == 'table-layout' + let values = ["auto", "fixed"] + elseif prop == 'tab-size' + let values = [] + elseif prop == 'text-align' + let values = ["start", "end", "left", "right", "center", "justify", "match-parent"] + elseif prop == 'text-align-last' + let values = ["auto", "start", "end", "left", "right", "center", "justify"] + elseif prop == 'text-combine-upright' + let values = ["none", "all", "digits"] + elseif prop == 'text-decoration-line' + let values = ["none", "underline", "overline", "line-through", "blink"] + elseif prop == 'text-decoration-color' + let values = color_values + elseif prop == 'text-decoration-style' + let values = ["solid", "double", "dotted", "dashed", "wavy"] + elseif prop == 'text-decoration' + let values = ["none", "underline", "overline", "line-through", "blink"] + ["solid", "double", "dotted", "dashed", "wavy"] + color_values + elseif prop == 'text-emphasis-color' + let values = color_values + elseif prop == 'text-emphasis-position' + let values = ["over", "under", "left", "right"] + elseif prop == 'text-emphasis-style' + let values = ["none", "filled", "open", "dot", "circle", "double-circle", "triangle", "sesame"] + elseif prop == 'text-emphasis' + let values = color_values + ["over", "under", "left", "right"] + ["none", "filled", "open", "dot", "circle", "double-circle", "triangle", "sesame"] + elseif prop == 'text-indent' + let values = ["hanging", "each-line"] + elseif prop == 'text-orientation' + let values = ["mixed", "upright", "sideways", "sideways-right", "use-glyph-orientation"] + elseif prop == 'text-overflow' + let values = ["clip", "ellipsis"] + elseif prop == 'text-rendering' + let values = ["auto", "optimizeSpeed", "optimizeLegibility", "geometricPrecision"] + elseif prop == 'text-shadow' + let values = color_values + elseif prop == 'text-transform' + let values = ["capitalize", "uppercase", "lowercase", "full-width", "none"] + elseif prop == 'text-underline-position' + let values = ["auto", "under", "left", "right"] + elseif prop == 'touch-action' + let values = ["auto", "none", "pan-x", "pan-y", "manipulation", "pan-left", "pan-right", "pan-top", "pan-down"] + elseif prop == 'transform' + let values = ["matrix(", "translate(", "translateX(", "translateY(", "scale(", "scaleX(", "scaleY(", "rotate(", "skew(", "skewX(", "skewY(", "matrix3d(", "translate3d(", "translateZ(", "scale3d(", "scaleZ(", "rotate3d(", "rotateX(", "rotateY(", "rotateZ(", "perspective("] + elseif prop == 'transform-box' + let values = ["border-box", "fill-box", "view-box"] + elseif prop == 'transform-origin' + let values = ["left", "center", "right", "top", "bottom"] + elseif prop == 'transform-style' + let values = ["flat", "preserve-3d"] + elseif prop == 'top' + let values = ["auto"] + elseif prop == 'transition-property' + let values = ["all", "none"] + s:values + elseif prop == 'transition-duration' + let values = [] + elseif prop == 'transition-delay' + let values = [] + elseif prop == 'transition-timing-function' + let values = timing_functions + elseif prop == 'transition' + let values = ["all", "none"] + s:values + timing_functions + elseif prop == 'unicode-bidi' + let values = ["normal", "embed", "isolate", "bidi-override", "isolate-override", "plaintext"] + elseif prop == 'unicode-range' + let values = ["U+"] + elseif prop == 'user-zoom' + let values = ["zoom", "fixed"] + elseif prop == 'vertical-align' + let values = ["baseline", "sub", "super", "top", "text-top", "middle", "bottom", "text-bottom"] + elseif prop == 'visibility' + let values = ["visible", "hidden", "collapse"] + elseif prop == 'voice-volume' + let values = ["silent", "x-soft", "soft", "medium", "loud", "x-loud"] + elseif prop == 'voice-balance' + let values = ["left", "center", "right", "leftwards", "rightwards"] + elseif prop == 'voice-family' + let values = [] + elseif prop == 'voice-rate' + let values = ["normal", "x-slow", "slow", "medium", "fast", "x-fast"] + elseif prop == 'voice-pitch' + let values = ["absolute", "x-low", "low", "medium", "high", "x-high"] + elseif prop == 'voice-range' + let values = ["absolute", "x-low", "low", "medium", "high", "x-high"] + elseif prop == 'voice-stress' + let values = ["normal", "strong", "moderate", "none", "reduced "] + elseif prop == 'voice-duration' + let values = ["auto"] + elseif prop == 'white-space' + let values = ["normal", "pre", "nowrap", "pre-wrap", "pre-line"] + elseif prop == 'widows' + let values = [] + elseif prop == 'will-change' + let values = ["auto", "scroll-position", "contents"] + s:values + elseif prop == 'word-break' + let values = ["normal", "break-all", "keep-all"] + elseif prop == 'word-spacing' + let values = ["normal"] + elseif prop == 'word-wrap' + let values = ["normal", "break-word"] + elseif prop == 'writing-mode' + let values = ["horizontal-tb", "vertical-rl", "vertical-lr", "sideways-rl", "sideways-lr"] + elseif prop == 'z-index' + let values = ["auto"] + elseif prop == 'zoom' + let values = ["auto"] + else + " If no property match it is possible we are outside of {} and + " trying to complete pseudo-(class|element) + let element = tolower(matchstr(line, '\zs[a-zA-Z1-6]*\ze:[^:[:space:]]\{-}$')) + if stridx('a,abbr,address,area,article,aside,audio,b,base,bdi,bdo,bgsound,blockquote,body,br,button,canvas,caption,center,cite,code,col,colgroup,command,content,data,datalist,dd,del,details,dfn,dialog,div,dl,dt,element,em,embed,fieldset,figcaption,figure,font,footer,form,frame,frameset,head,header,hgroup,hr,html,i,iframe,image,img,input,ins,isindex,kbd,keygen,label,legend,li,link,main,map,mark,menu,menuitem,meta,meter,nav,nobr,noframes,noscript,object,ol,optgroup,option,output,p,param,picture,pre,progress,q,rp,rt,rtc,ruby,s,samp,script,section,select,shadow,small,source,span,strong,style,sub,summary,sup,table,tbody,td,template,textarea,tfoot,th,thead,time,title,tr,track,u,ul,var,video,wbr', ','.element.',') > -1 + let values = ["active", "any", "checked", "default", "dir(", "disabled", "empty", "enabled", "first", "first-child", "first-of-type", "fullscreen", "focus", "hover", "indeterminate", "in-range", "invalid", "lang(", "last-child", "last-of-type", "left", "link", "not(", "nth-child(", "nth-last-child(", "nth-last-of-type(", "nth-of-type(", "only-child", "only-of-type", "optional", "out-of-range", "read-only", "read-write", "required", "right", "root", "scope", "target", "valid", "visited", "first-line", "first-letter", "before", "after", "selection", "backdrop"] + else + return [] + endif + endif + + let values = wide_keywords + values + " Complete values + let entered_value = matchstr(line, '.\{-}\zs[a-zA-Z0-9#,.(_-]*$') + + for m in values + if m =~? '^'.entered_value + call add(res, m) + elseif m =~? entered_value + call add(res2, m) + endif + endfor + + return res + res2 + + elseif borders[max(keys(borders))] == 'closebrace' + + return [] + + elseif borders[max(keys(borders))] == 'exclam' + + " Complete values + let entered_imp = matchstr(line, '.\{-}!\s*\zs[a-zA-Z ]*$') + + let values = ["important"] + + for m in values + if m =~? '^'.entered_imp + call add(res, m) + endif + endfor + + return res + + elseif borders[max(keys(borders))] == 'atrule' + + let afterat = matchstr(line, '.*@\zs.*') + + if afterat =~ '\s' + + let atrulename = matchstr(line, '.*@\zs[a-zA-Z-]\+\ze') + + if atrulename == 'media' + let entered_atruleafter = matchstr(line, '.*@media\s\+\zs.*$') + + if entered_atruleafter =~ "([^)]*$" + let entered_atruleafter = matchstr(entered_atruleafter, '(\s*\zs[^)]*$') + let values = ["max-width", "min-width", "width", "max-height", "min-height", "height", "max-aspect-ration", "min-aspect-ration", "aspect-ratio", "orientation", "max-resolution", "min-resolution", "resolution", "scan", "grid", "update-frequency", "overflow-block", "overflow-inline", "max-color", "min-color", "color", "max-color-index", "min-color-index", "color-index", "monochrome", "inverted-colors", "pointer", "hover", "any-pointer", "any-hover", "light-level", "scripting"] + else + let values = ["screen", "print", "speech", "all", "not", "and", "("] + endif + + elseif atrulename == 'supports' + let entered_atruleafter = matchstr(line, '.*@supports\s\+\zs.*$') + + if entered_atruleafter =~ "([^)]*$" + let entered_atruleafter = matchstr(entered_atruleafter, '(\s*\zs.*$') + let values = s:values + else + let values = ["("] + endif + + elseif atrulename == 'charset' + let entered_atruleafter = matchstr(line, '.*@charset\s\+\zs.*$') + let values = [ + \ '"UTF-8";', '"ANSI_X3.4-1968";', '"ISO_8859-1:1987";', '"ISO_8859-2:1987";', '"ISO_8859-3:1988";', '"ISO_8859-4:1988";', '"ISO_8859-5:1988";', + \ '"ISO_8859-6:1987";', '"ISO_8859-7:1987";', '"ISO_8859-8:1988";', '"ISO_8859-9:1989";', '"ISO-8859-10";', '"ISO_6937-2-add";', '"JIS_X0201";', + \ '"JIS_Encoding";', '"Shift_JIS";', '"Extended_UNIX_Code_Packed_Format_for_Japanese";', '"Extended_UNIX_Code_Fixed_Width_for_Japanese";', + \ '"BS_4730";', '"SEN_850200_C";', '"IT";', '"ES";', '"DIN_66003";', '"NS_4551-1";', '"NF_Z_62-010";', '"ISO-10646-UTF-1";', '"ISO_646.basic:1983";', + \ '"INVARIANT";', '"ISO_646.irv:1983";', '"NATS-SEFI";', '"NATS-SEFI-ADD";', '"NATS-DANO";', '"NATS-DANO-ADD";', '"SEN_850200_B";', '"KS_C_5601-1987";', + \ '"ISO-2022-KR";', '"EUC-KR";', '"ISO-2022-JP";', '"ISO-2022-JP-2";', '"JIS_C6220-1969-jp";', '"JIS_C6220-1969-ro";', '"PT";', '"greek7-old";', + \ '"latin-greek";', '"NF_Z_62-010_(1973)";', '"Latin-greek-1";', '"ISO_5427";', '"JIS_C6226-1978";', '"BS_viewdata";', '"INIS";', '"INIS-8";', + \ '"INIS-cyrillic";', '"ISO_5427:1981";', '"ISO_5428:1980";', '"GB_1988-80";', '"GB_2312-80";', '"NS_4551-2";', '"videotex-suppl";', '"PT2";', + \ '"ES2";', '"MSZ_7795.3";', '"JIS_C6226-1983";', '"greek7";', '"ASMO_449";', '"iso-ir-90";', '"JIS_C6229-1984-a";', '"JIS_C6229-1984-b";', + \ '"JIS_C6229-1984-b-add";', '"JIS_C6229-1984-hand";', '"JIS_C6229-1984-hand-add";', '"JIS_C6229-1984-kana";', '"ISO_2033-1983";', + \ '"ANSI_X3.110-1983";', '"T.61-7bit";', '"T.61-8bit";', '"ECMA-cyrillic";', '"CSA_Z243.4-1985-1";', '"CSA_Z243.4-1985-2";', '"CSA_Z243.4-1985-gr";', + \ '"ISO_8859-6-E";', '"ISO_8859-6-I";', '"T.101-G2";', '"ISO_8859-8-E";', '"ISO_8859-8-I";', '"CSN_369103";', '"JUS_I.B1.002";', '"IEC_P27-1";', + \ '"JUS_I.B1.003-serb";', '"JUS_I.B1.003-mac";', '"greek-ccitt";', '"NC_NC00-10:81";', '"ISO_6937-2-25";', '"GOST_19768-74";', '"ISO_8859-supp";', + \ '"ISO_10367-box";', '"latin-lap";', '"JIS_X0212-1990";', '"DS_2089";', '"us-dk";', '"dk-us";', '"KSC5636";', '"UNICODE-1-1-UTF-7";', '"ISO-2022-CN";', + \ '"ISO-2022-CN-EXT";', '"ISO-8859-13";', '"ISO-8859-14";', '"ISO-8859-15";', '"ISO-8859-16";', '"GBK";', '"GB18030";', '"OSD_EBCDIC_DF04_15";', + \ '"OSD_EBCDIC_DF03_IRV";', '"OSD_EBCDIC_DF04_1";', '"ISO-11548-1";', '"KZ-1048";', '"ISO-10646-UCS-2";', '"ISO-10646-UCS-4";', '"ISO-10646-UCS-Basic";', + \ '"ISO-10646-Unicode-Latin1";', '"ISO-10646-J-1";', '"ISO-Unicode-IBM-1261";', '"ISO-Unicode-IBM-1268";', '"ISO-Unicode-IBM-1276";', + \ '"ISO-Unicode-IBM-1264";', '"ISO-Unicode-IBM-1265";', '"UNICODE-1-1";', '"SCSU";', '"UTF-7";', '"UTF-16BE";', '"UTF-16LE";', '"UTF-16";', '"CESU-8";', + \ '"UTF-32";', '"UTF-32BE";', '"UTF-32LE";', '"BOCU-1";', '"ISO-8859-1-Windows-3.0-Latin-1";', '"ISO-8859-1-Windows-3.1-Latin-1";', + \ '"ISO-8859-2-Windows-Latin-2";', '"ISO-8859-9-Windows-Latin-5";', '"hp-roman8";', '"Adobe-Standard-Encoding";', '"Ventura-US";', + \ '"Ventura-International";', '"DEC-MCS";', '"IBM850";', '"PC8-Danish-Norwegian";', '"IBM862";', '"PC8-Turkish";', '"IBM-Symbols";', '"IBM-Thai";', + \ '"HP-Legal";', '"HP-Pi-font";', '"HP-Math8";', '"Adobe-Symbol-Encoding";', '"HP-DeskTop";', '"Ventura-Math";', '"Microsoft-Publishing";', + \ '"Windows-31J";', '"GB2312";', '"Big5";', '"macintosh";', '"IBM037";', '"IBM038";', '"IBM273";', '"IBM274";', '"IBM275";', '"IBM277";', '"IBM278";', + \ '"IBM280";', '"IBM281";', '"IBM284";', '"IBM285";', '"IBM290";', '"IBM297";', '"IBM420";', '"IBM423";', '"IBM424";', '"IBM437";', '"IBM500";', '"IBM851";', + \ '"IBM852";', '"IBM855";', '"IBM857";', '"IBM860";', '"IBM861";', '"IBM863";', '"IBM864";', '"IBM865";', '"IBM868";', '"IBM869";', '"IBM870";', '"IBM871";', + \ '"IBM880";', '"IBM891";', '"IBM903";', '"IBM904";', '"IBM905";', '"IBM918";', '"IBM1026";', '"EBCDIC-AT-DE";', '"EBCDIC-AT-DE-A";', '"EBCDIC-CA-FR";', + \ '"EBCDIC-DK-NO";', '"EBCDIC-DK-NO-A";', '"EBCDIC-FI-SE";', '"EBCDIC-FI-SE-A";', '"EBCDIC-FR";', '"EBCDIC-IT";', '"EBCDIC-PT";', '"EBCDIC-ES";', + \ '"EBCDIC-ES-A";', '"EBCDIC-ES-S";', '"EBCDIC-UK";', '"EBCDIC-US";', '"UNKNOWN-8BIT";', '"MNEMONIC";', '"MNEM";', '"VISCII";', '"VIQR";', '"KOI8-R";', + \ '"HZ-GB-2312";', '"IBM866";', '"IBM775";', '"KOI8-U";', '"IBM00858";', '"IBM00924";', '"IBM01140";', '"IBM01141";', '"IBM01142";', '"IBM01143";', + \ '"IBM01144";', '"IBM01145";', '"IBM01146";', '"IBM01147";', '"IBM01148";', '"IBM01149";', '"Big5-HKSCS";', '"IBM1047";', '"PTCP154";', '"Amiga-1251";', + \ '"KOI7-switched";', '"BRF";', '"TSCII";', '"windows-1250";', '"windows-1251";', '"windows-1252";', '"windows-1253";', '"windows-1254";', '"windows-1255";', + \ '"windows-1256";', '"windows-1257";', '"windows-1258";', '"TIS-620";'] + + elseif atrulename == 'namespace' + let entered_atruleafter = matchstr(line, '.*@namespace\s\+\zs.*$') + let values = ["url("] + + elseif atrulename == 'document' + let entered_atruleafter = matchstr(line, '.*@document\s\+\zs.*$') + let values = ["url(", "url-prefix(", "domain(", "regexp("] + + elseif atrulename == 'import' + let entered_atruleafter = matchstr(line, '.*@import\s\+\zs.*$') + + if entered_atruleafter =~ "^[\"']" + let filestart = matchstr(entered_atruleafter, '^.\zs.*') + let files = split(glob(filestart.'*'), '\n') + let values = map(copy(files), '"\"".v:val') + + elseif entered_atruleafter =~ "^url(" + let filestart = matchstr(entered_atruleafter, "^url([\"']\\?\\zs.*") + let files = split(glob(filestart.'*'), '\n') + let values = map(copy(files), '"url(".v:val') + + else + let values = ['"', 'url('] + + endif + + else + return [] + + endif + + for m in values + if m =~? '^'.entered_atruleafter + if entered_atruleafter =~? '^"' && m =~? '^"' + let m = m[1:] + endif + if b:after =~? '"' && stridx(m, '"') > -1 + let m = m[0:stridx(m, '"')-1] + endif + call add(res, m) + elseif m =~? entered_atruleafter + if m =~? '^"' + let m = m[1:] + endif + call add(res2, m) + endif + endfor + + return res + res2 + + endif + + let values = ["charset", "page", "media", "import", "font-face", "namespace", "supports", "keyframes", "viewport", "document"] + + let entered_atrule = matchstr(line, '.*@\zs[a-zA-Z-]*$') + + for m in values + if m =~? '^'.entered_atrule + call add(res, m .' ') + elseif m =~? entered_atrule + call add(res2, m .' ') + endif + endfor + + return res + res2 + + endif + + return [] endfunction diff --git a/runtime/autoload/health.vim b/runtime/autoload/health.vim new file mode 100644 index 0000000000..0a698e6492 --- /dev/null +++ b/runtime/autoload/health.vim @@ -0,0 +1,468 @@ +function! s:trim(s) abort + return substitute(a:s, '^\_s*\|\_s*$', '', 'g') +endfunction + + +" Simple version comparison. +function! s:version_cmp(a, b) abort + let a = split(a:a, '\.') + let b = split(a:b, '\.') + + for i in range(len(a)) + if a[i] > b[i] + return 1 + elseif a[i] < b[i] + return -1 + endif + endfor + + return 0 +endfunction + + +" Fetch the contents of a URL. +function! s:download(url) abort + let content = '' + if executable('curl') + let content = system('curl -sL "'.a:url.'"') + endif + + if empty(content) && executable('python') + let script = " + \try:\n + \ from urllib.request import urlopen\n + \except ImportError:\n + \ from urllib2 import urlopen\n + \\n + \try:\n + \ response = urlopen('".a:url."')\n + \ print(response.read().decode('utf8'))\n + \except Exception:\n + \ pass\n + \" + let content = system('python -c "'.script.'" 2>/dev/null') + endif + + return content +endfunction + + +" Get the latest Neovim Python client version from PyPI. The result is +" cached. +function! s:latest_pypi_version() + if exists('s:pypi_version') + return s:pypi_version + endif + + let s:pypi_version = 'unknown' + let pypi_info = s:download('https://pypi.python.org/pypi/neovim/json') + if !empty(pypi_info) + let pypi_data = json_decode(pypi_info) + let s:pypi_version = get(get(pypi_data, 'info', {}), 'version', 'unknown') + return s:pypi_version + endif +endfunction + + +" Get version information using the specified interpreter. The interpreter is +" used directly in case breaking changes were introduced since the last time +" Neovim's Python client was updated. +function! s:version_info(python) abort + let pypi_version = s:latest_pypi_version() + let python_version = s:trim(system( + \ printf('"%s" -c "import sys; print(''.''.join(str(x) ' + \ . 'for x in sys.version_info[:3]))"', a:python))) + if empty(python_version) + let python_version = 'unknown' + endif + + let nvim_path = s:trim(system(printf('"%s" -c "import sys, neovim;' + \ . 'print(neovim.__file__)" 2>/dev/null', a:python))) + if empty(nvim_path) + return [python_version, 'not found', pypi_version, 'unknown'] + endif + + let nvim_version = 'unknown' + let base = fnamemodify(nvim_path, ':h') + for meta in glob(base.'-*/METADATA', 1, 1) + glob(base.'-*/PKG-INFO', 1, 1) + for meta_line in readfile(meta) + if meta_line =~# '^Version:' + let nvim_version = matchstr(meta_line, '^Version: \zs\S\+') + endif + endfor + endfor + + let version_status = 'unknown' + if nvim_version != 'unknown' && pypi_version != 'unknown' + if s:version_cmp(nvim_version, pypi_version) == -1 + let version_status = 'outdated' + else + let version_status = 'up to date' + endif + endif + + return [python_version, nvim_version, pypi_version, version_status] +endfunction + + +" Check the Python interpreter's usability. +function! s:check_bin(bin, notes) abort + if !filereadable(a:bin) + call add(a:notes, printf('Error: "%s" was not found.', a:bin)) + return 0 + elseif executable(a:bin) != 1 + call add(a:notes, printf('Error: "%s" is not executable.', a:bin)) + return 0 + endif + return 1 +endfunction + + +" Text wrapping that returns a list of lines +function! s:textwrap(text, width) abort + let pattern = '.*\%(\s\+\|\_$\)\zs\%<'.a:width.'c' + return map(split(a:text, pattern), 's:trim(v:val)') +endfunction + + +" Echo wrapped notes +function! s:echo_notes(notes) abort + if empty(a:notes) + return + endif + + echo ' Messages:' + for msg in a:notes + if msg =~# "\n" + let msg_lines = [] + for msgl in filter(split(msg, "\n"), 'v:val !~# ''^\s*$''') + call extend(msg_lines, s:textwrap(msgl, 74)) + endfor + else + let msg_lines = s:textwrap(msg, 74) + endif + + if !len(msg_lines) + continue + endif + echo ' *' msg_lines[0] + if len(msg_lines) > 1 + echo join(map(msg_lines[1:], '" ".v:val'), "\n") + endif + endfor +endfunction + + +" Load the remote plugin manifest file and check for unregistered plugins +function! s:diagnose_manifest() abort + echo 'Checking: Remote Plugins' + let existing_rplugins = {} + + for item in remote#host#PluginsForHost('python') + let existing_rplugins[item.path] = 'python' + endfor + + for item in remote#host#PluginsForHost('python3') + let existing_rplugins[item.path] = 'python3' + endfor + + let require_update = 0 + let notes = [] + + for path in map(split(&rtp, ','), 'resolve(v:val)') + let python_glob = glob(path.'/rplugin/python*', 1, 1) + if empty(python_glob) + continue + endif + + let python_dir = python_glob[0] + let python_version = fnamemodify(python_dir, ':t') + + for script in glob(python_dir.'/*.py', 1, 1) + \ + glob(python_dir.'/*/__init__.py', 1, 1) + let contents = join(readfile(script)) + if contents =~# '\<\%(from\|import\)\s\+neovim\>' + if script =~# '/__init__\.py$' + let script = fnamemodify(script, ':h') + endif + + if !has_key(existing_rplugins, script) + let msg = printf('"%s" is not registered.', fnamemodify(path, ':t')) + if python_version == 'pythonx' + if !has('python2') && !has('python3') + let msg .= ' (python2 and python3 not available)' + endif + elseif !has(python_version) + let msg .= printf(' (%s not available)', python_version) + else + let require_update = 1 + endif + + call add(notes, msg) + endif + + break + endif + endfor + endfor + + echo ' Status: ' + if require_update + echon 'Out of date' + call add(notes, 'Run :UpdateRemotePlugins') + else + echon 'Up to date' + endif + + call s:echo_notes(notes) +endfunction + + +function! s:diagnose_python(version) abort + let python_bin_name = 'python'.(a:version == 2 ? '' : '3') + let pyenv = resolve(exepath('pyenv')) + let pyenv_root = exists('$PYENV_ROOT') ? resolve($PYENV_ROOT) : '' + let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : '' + let host_prog_var = python_bin_name.'_host_prog' + let host_skip_var = python_bin_name.'_host_skip_check' + let python_bin = '' + let python_multiple = [] + let notes = [] + + if exists('g:'.host_prog_var) + call add(notes, printf('Using: g:%s = "%s"', host_prog_var, get(g:, host_prog_var))) + endif + + let [python_bin_name, pythonx_errs] = provider#pythonx#Detect(a:version) + if empty(python_bin_name) + call add(notes, 'Warning: No Python interpreter was found with the neovim ' + \ . 'module. Using the first available for diagnostics.') + if !empty(pythonx_errs) + call add(notes, pythonx_errs) + endif + let old_skip = get(g:, host_skip_var, 0) + let g:[host_skip_var] = 1 + let [python_bin_name, pythonx_errs] = provider#pythonx#Detect(a:version) + let g:[host_skip_var] = old_skip + endif + + if !empty(python_bin_name) + if exists('g:'.host_prog_var) + let python_bin = exepath(python_bin_name) + endif + let python_bin_name = fnamemodify(python_bin_name, ':t') + endif + + if !empty(pythonx_errs) + call add(notes, pythonx_errs) + endif + + if !empty(python_bin_name) && empty(python_bin) && empty(pythonx_errs) + if !exists('g:'.host_prog_var) + call add(notes, printf('Warning: "g:%s" is not set. Searching for ' + \ . '%s in the environment.', host_prog_var, python_bin_name)) + endif + + if !empty(pyenv) + if empty(pyenv_root) + call add(notes, 'Warning: pyenv was found, but $PYENV_ROOT ' + \ . 'is not set. Did you follow the final install ' + \ . 'instructions?') + else + call add(notes, printf('Notice: pyenv found: "%s"', pyenv)) + endif + + let python_bin = s:trim(system( + \ printf('"%s" which %s 2>/dev/null', pyenv, python_bin_name))) + + if empty(python_bin) + call add(notes, printf('Warning: pyenv couldn''t find %s.', python_bin_name)) + endif + endif + + if empty(python_bin) + let python_bin = exepath(python_bin_name) + + if exists('$PATH') + for path in split($PATH, ':') + let path_bin = path.'/'.python_bin_name + if path_bin != python_bin && index(python_multiple, path_bin) == -1 + \ && executable(path_bin) + call add(python_multiple, path_bin) + endif + endfor + + if len(python_multiple) + " This is worth noting since the user may install something + " that changes $PATH, like homebrew. + call add(notes, printf('Suggestion: There are multiple %s executables found. ' + \ . 'Set "g:%s" to avoid surprises.', python_bin_name, host_prog_var)) + endif + + if python_bin =~# '\<shims\>' + call add(notes, printf('Warning: "%s" appears to be a pyenv shim. ' + \ . 'This could mean that a) the "pyenv" executable is not in ' + \ . '$PATH, b) your pyenv installation is broken. ' + \ . 'You should set "g:%s" to avoid surprises.', + \ python_bin, host_prog_var)) + endif + endif + endif + endif + + if !empty(python_bin) + if !empty(pyenv) && !exists('g:'.host_prog_var) && !empty(pyenv_root) + \ && resolve(python_bin) !~# '^'.pyenv_root.'/' + call add(notes, printf('Suggestion: Create a virtualenv specifically ' + \ . 'for Neovim using pyenv and use "g:%s". This will avoid ' + \ . 'the need to install Neovim''s Python client in each ' + \ . 'version/virtualenv.', host_prog_var)) + endif + + if !empty(venv) && exists('g:'.host_prog_var) + if !empty(pyenv_root) + let venv_root = pyenv_root + else + let venv_root = fnamemodify(venv, ':h') + endif + + if resolve(python_bin) !~# '^'.venv_root.'/' + call add(notes, printf('Suggestion: Create a virtualenv specifically ' + \ . 'for Neovim and use "g:%s". This will avoid ' + \ . 'the need to install Neovim''s Python client in each ' + \ . 'virtualenv.', host_prog_var)) + endif + endif + endif + + if empty(python_bin) && !empty(python_bin_name) + " An error message should have already printed. + call add(notes, printf('Error: "%s" was not found.', python_bin_name)) + elseif !empty(python_bin) && !s:check_bin(python_bin, notes) + let python_bin = '' + endif + + " Check if $VIRTUAL_ENV is active + let virtualenv_inactive = 0 + + if exists('$VIRTUAL_ENV') + if !empty(pyenv) + let pyenv_prefix = resolve(s:trim(system(printf('"%s" prefix', pyenv)))) + if $VIRTUAL_ENV != pyenv_prefix + let virtualenv_inactive = 1 + endif + elseif !empty(python_bin_name) && exepath(python_bin_name) !~# '^'.$VIRTUAL_ENV.'/' + let virtualenv_inactive = 1 + endif + endif + + if virtualenv_inactive + call add(notes, 'Warning: $VIRTUAL_ENV exists but appears to be ' + \ . 'inactive. This could lead to unexpected results. If you are ' + \ . 'using Zsh, see: http://vi.stackexchange.com/a/7654/5229') + endif + + " Diagnostic output + echo 'Checking: Python' a:version + echo ' Executable:' (empty(python_bin) ? 'Not found' : python_bin) + if len(python_multiple) + for path_bin in python_multiple + echo ' (other):' path_bin + endfor + endif + + if !empty(python_bin) + let [pyversion, current, latest, status] = s:version_info(python_bin) + if a:version != str2nr(pyversion) + call add(notes, 'Warning: Got an unexpected version of Python. ' + \ . 'This could lead to confusing error messages. Please ' + \ . 'consider this before reporting bugs to plugin developers.') + endif + if a:version == 3 && str2float(pyversion) < 3.3 + call add(notes, 'Warning: Python 3.3+ is recommended.') + endif + + echo ' Python Version:' pyversion + echo printf(' %s-neovim Version: %s', python_bin_name, current) + + if current == 'not found' + call add(notes, 'Error: Neovim Python client is not installed.') + endif + + if latest == 'unknown' + call add(notes, 'Warning: Unable to fetch latest Neovim Python client version.') + endif + + if status == 'outdated' + echon ' (latest: '.latest.')' + else + echon ' ('.status.')' + endif + endif + + call s:echo_notes(notes) +endfunction + + +function! s:diagnose_ruby() abort + echo 'Checking: Ruby' + let ruby_vers = systemlist('ruby -v')[0] + let ruby_prog = provider#ruby#Detect() + let notes = [] + + if empty(ruby_prog) + let ruby_prog = 'not found' + let prog_vers = 'not found' + call add(notes, 'Suggestion: Install the neovim RubyGem using ' . + \ '`gem install neovim`.') + else + silent let prog_vers = systemlist(ruby_prog . ' --version')[0] + + if v:shell_error + let prog_vers = 'outdated' + call add(notes, 'Suggestion: Install the latest neovim RubyGem using ' . + \ '`gem install neovim`.') + elseif s:version_cmp(prog_vers, "0.2.0") == -1 + let prog_vers .= ' (outdated)' + call add(notes, 'Suggestion: Install the latest neovim RubyGem using ' . + \ '`gem install neovim`.') + endif + endif + + echo ' Ruby Version: ' . ruby_vers + echo ' Host Executable: ' . ruby_prog + echo ' Host Version: ' . prog_vers + + call s:echo_notes(notes) +endfunction + + +function! health#check(bang) abort + redir => report + try + silent call s:diagnose_python(2) + silent echo '' + silent call s:diagnose_python(3) + silent echo '' + silent call s:diagnose_ruby() + silent echo '' + silent call s:diagnose_manifest() + silent echo '' + finally + redir END + endtry + + if a:bang + new + setlocal bufhidden=wipe + call setline(1, split(report, "\n")) + setlocal nomodified + else + echo report + echo "\nTip: Use " + echohl Identifier + echon ":CheckHealth!" + echohl None + echon " to open this in a new buffer." + endif +endfunction diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim index 53668b15be..64c08e98fa 100644 --- a/runtime/autoload/netrw.vim +++ b/runtime/autoload/netrw.vim @@ -1,10 +1,10 @@ " netrw.vim: Handles file transfer and remote directory listing across " AUTOLOAD SECTION -" Date: Oct 23, 2015 -" Version: 154 +" Date: Feb 16, 2016 +" Version: 155 ASTRO-ONLY " Maintainer: Charles E Campbell <NdrOchip@ScampbellPfamily.AbizM-NOSPAM> " GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim -" Copyright: Copyright (C) 1999-2015 Charles E. Campbell {{{1 +" Copyright: Copyright (C) 2016 Charles E. Campbell {{{1 " Permission is hereby granted to use and distribute this code, " with or without modifications, provided that this copyright " notice is copied with it. Like anything else that's free, @@ -30,7 +30,7 @@ if v:version < 704 || !has("patch213") let s:needpatch213= 1 finish endif -let g:loaded_netrw = "v154" +let g:loaded_netrw = "v155" if !exists("s:NOTE") let s:NOTE = 0 let s:WARNING = 1 @@ -55,7 +55,7 @@ setl cpo&vim " Usage: netrw#ErrorMsg(s:NOTE | s:WARNING | s:ERROR,"some message",error-number) " netrw#ErrorMsg(s:NOTE | s:WARNING | s:ERROR,["message1","message2",...],error-number) " (this function can optionally take a list of messages) -" Oct 09, 2015 : max errnum currently is 102 +" Jan 19, 2016 : max errnum currently is 103 fun! netrw#ErrorMsg(level,msg,errnum) " call Dfunc("netrw#ErrorMsg(level=".a:level." msg<".a:msg."> errnum=".a:errnum.") g:netrw_use_errorwindow=".g:netrw_use_errorwindow) @@ -77,7 +77,7 @@ fun! netrw#ErrorMsg(level,msg,errnum) " (default) netrw creates a one-line window to show error/warning " messages (reliably displayed) - " record current window number for NetrwRestorePosn()'s benefit + " record current window number let s:winBeforeErr= winnr() " call Decho("s:winBeforeErr=".s:winBeforeErr,'~'.expand("<slnum>")) @@ -416,18 +416,20 @@ if !exists("g:netrw_localmovecmd") let g:netrw_localmovecmd= "" endif endif -if exists("g:netrw_local_rmdir") - let g:netrw_localrmdir= g:netrw_local_rmdir - call netrw#ErrorMsg(s:NOTE,"g:netrw_local_rmdir is deprecated in favor of g:netrw_localrmdir",86) -endif -if has("win32") || has("win95") || has("win64") || has("win16") - if g:netrw_cygwin - call s:NetrwInit("g:netrw_localrmdir","rmdir") - else - let g:netrw_localrmdir= expand("$COMSPEC")." /c rmdir" - endif -else - call s:NetrwInit("g:netrw_localrmdir","rmdir") +if v:version < 704 || !has("patch1109") + if exists("g:netrw_local_rmdir") + let g:netrw_localrmdir= g:netrw_local_rmdir + call netrw#ErrorMsg(s:NOTE,"g:netrw_local_rmdir is deprecated in favor of g:netrw_localrmdir",86) + endif + if has("win32") || has("win95") || has("win64") || has("win16") + if g:netrw_cygwin + call s:NetrwInit("g:netrw_localrmdir","rmdir") + else + let g:netrw_localrmdir= expand("$COMSPEC")." /c rmdir" + endif + else + call s:NetrwInit("g:netrw_localrmdir","rmdir") + endif endif call s:NetrwInit("g:netrw_liststyle" , s:THINLIST) " sanity checks @@ -489,6 +491,7 @@ endif call s:NetrwInit("g:netrw_special_syntax" , 0) call s:NetrwInit("g:netrw_ssh_browse_reject", '^total\s\+\d\+$') call s:NetrwInit("g:netrw_use_noswf" , 1) +call s:NetrwInit("g:netrw_sizestyle" ,"b") " Default values - t-w ---------- {{{3 call s:NetrwInit("g:netrw_timefmt","%c") if !exists("g:netrw_xstrlen") @@ -614,7 +617,7 @@ endif " == 4: Vexplore style == 5: Vexplore! " == 6: Texplore fun! netrw#Explore(indx,dosplit,style,...) -" call Dfunc("netrw#Explore(indx=".a:indx." dosplit=".a:dosplit." style=".a:style.",a:1<".a:1.">) &modified=".&modified." modifiable=".&modifiable." a:0=".a:0." win#".winnr()." buf#".bufnr("%")) +" call Dfunc("netrw#Explore(indx=".a:indx." dosplit=".a:dosplit." style=".a:style.",a:1<".a:1.">) &modified=".&modified." modifiable=".&modifiable." a:0=".a:0." win#".winnr()." buf#".bufnr("%")." ft=".&ft) " call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("<slnum>")) if !exists("b:netrw_curdir") let b:netrw_curdir= getcwd() @@ -1165,7 +1168,8 @@ fun! netrw#Lexplore(count,rightside,...) " call Decho("t:netrw_lexbufnr#".t:netrw_lexbufnr.": close down netrw window",'~'.expand("<slnum>")) exe lexwinnr."wincmd w" let g:netrw_winsize = -winwidth(0) - let t:netrw_lexposn = netrw#SavePosn() + let t:netrw_lexposn = winsaveview() +" call Decho("saving posn to t:netrw_lexposn<".string(t:netrw_lexposn).">",'~'.expand("<slnum>")) " call Decho("saving t:netrw_lexposn",'~'.expand("<slnum>")) close if lexwinnr < curwin @@ -1205,7 +1209,8 @@ fun! netrw#Lexplore(count,rightside,...) let t:netrw_lexbufnr = bufnr("%") if exists("t:netrw_lexposn") " call Decho("restoring to t:netrw_lexposn",'~'.expand("<slnum>")) - call netrw#RestorePosn(t:netrw_lexposn) +" call Decho("restoring posn to t:netrw_lexposn<".string(t:netrw_lexposn).">",'~'.expand("<slnum>")) + call winrestview(t:netrw_lexposn) unlet t:netrw_lexposn endif endif @@ -1273,7 +1278,8 @@ endfun fun! netrw#MakeTgt(dname) " call Dfunc("netrw#MakeTgt(dname<".a:dname.">)") " simplify the target (eg. /abc/def/../ghi -> /abc/ghi) - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let s:netrwmftgt_islocal= (a:dname !~ '^\a\{3,}://') " call Decho("s:netrwmftgt_islocal=".s:netrwmftgt_islocal,'~'.expand("<slnum>")) if s:netrwmftgt_islocal @@ -1290,7 +1296,8 @@ fun! netrw#MakeTgt(dname) if g:netrw_fastbrowse <= 1 call s:NetrwRefresh((b:netrw_curdir !~ '\a\{3,}://'),b:netrw_curdir) endif - call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))" + call winrestview(svpos) " call Dret("netrw#MakeTgt") endfun @@ -1532,9 +1539,11 @@ endfun " netrw#Nread: save position, call netrw#NetRead(), and restore position {{{2 fun! netrw#Nread(mode,fname) " call Dfunc("netrw#Nread(mode=".a:mode." fname<".a:fname.">)") - call netrw#SavePosn() + let svpos= winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) call netrw#NetRead(a:mode,a:fname) - call netrw#RestorePosn() +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + call winrestview(svpos) if exists("w:netrw_liststyle") && w:netrw_liststyle != s:TREELIST if exists("w:netrw_bannercnt") @@ -1552,8 +1561,8 @@ fun! s:NetrwOptionRestore(vt) " call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>")) if !exists("{a:vt}netrw_optionsave") if exists("s:nbcd_curpos_{bufnr('%')}") -" call Decho("restoring previous position (s:nbcd_curpos_".bufnr('%')." exists)",'~'.expand("<slnum>")) - NetrwKeepj call netrw#RestorePosn(s:nbcd_curpos_{bufnr('%')}) +" call Decho("restoring posn to s:nbcd_curpos_".bufnr('%')."<".string(s:nbcd_curpos_{bufnr('%')}).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(s:nbcd_curpos_{bufnr('%')}) " call Decho("win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> winnr($)=".winnr("$"),'~'.expand("<slnum>")) " call Decho("unlet s:nbcd_curpos_".bufnr('%'),'~'.expand("<slnum>")) unlet s:nbcd_curpos_{bufnr('%')} @@ -1629,8 +1638,10 @@ fun! s:NetrwOptionRestore(vt) setl directory= unlet {a:vt}netrw_swfkeep elseif &l:swf != {a:vt}netrw_swfkeep - " following line causes a Press ENTER in windows -- can't seem to work around it!!! - sil! let &l:swf= {a:vt}netrw_swfkeep + if !g:netrw_use_noswf + " following line causes a Press ENTER in windows -- can't seem to work around it!!! + sil! let &l:swf= {a:vt}netrw_swfkeep + endif unlet {a:vt}netrw_swfkeep endif endif @@ -1646,8 +1657,8 @@ fun! s:NetrwOptionRestore(vt) endif if exists("{a:vt}netrw_regslash")|sil! let @/= {a:vt}netrw_regslash|unlet {a:vt}netrw_regslash|endif if exists("s:nbcd_curpos_{bufnr('%')}") -" call Decho("restoring previous position (s:nbcd_curpos_".bufnr('%')." exists)",'~'.expand("<slnum>")) - NetrwKeepj call netrw#RestorePosn(s:nbcd_curpos_{bufnr('%')}) +" call Decho("restoring posn to s:nbcd_curpos_".bufnr('%')."<".string(s:nbcd_curpos_{bufnr('%')}).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(s:nbcd_curpos_{bufnr('%')}) " call Decho("unlet s:nbcd_curpos_".bufnr('%'),'~'.expand("<slnum>")) if exists("s:nbcd_curpos_".bufnr('%')) unlet s:nbcd_curpos_{bufnr('%')} @@ -1729,11 +1740,11 @@ fun! s:NetrwOptionSave(vt) let {a:vt}netrw_rokeep = &l:ro let {a:vt}netrw_selkeep = &l:sel let {a:vt}netrw_spellkeep = &l:spell - if g:netrw_use_noswf - let {a:vt}netrw_swfkeep = &l:swf + if !g:netrw_use_noswf + let {a:vt}netrw_swfkeep = &l:swf endif if has("clipboard") - let {a:vt}netrw_starkeep = @* + let {a:vt}netrw_starkeep = @* endif let {a:vt}netrw_tskeep = &l:ts let {a:vt}netrw_twkeep = &l:tw " textwidth @@ -2664,7 +2675,9 @@ fun! netrw#NetSource(...) " call Decho("exe so ".fnameescape(s:netrw_tmpfile),'~'.expand("<slnum>")) exe "so ".fnameescape(s:netrw_tmpfile) " call Decho("delete(".s:netrw_tmpfile.")",'~'.expand("<slnum>")) - call delete(s:netrw_tmpfile) + if delete(s:netrw_tmpfile) + call netrw#ErrorMsg(s:ERROR,"unable to delete directory <".s:netrw_tmpfile.">!",103) + endif unlet s:netrw_tmpfile else call netrw#ErrorMsg(s:ERROR,"unable to source <".a:{i}.">!",48) @@ -3504,7 +3517,11 @@ fun! s:NetrwBookHistSave() let savefile= s:NetrwHome()."/.netrwhist" 1split call s:NetrwEnew() - setl cino= com= cpo-=a cpo-=A fo=nroql2 tw=0 report=10000 noswf + if g:netrw_use_noswf + setl cino= com= cpo-=a cpo-=A fo=nroql2 tw=0 report=10000 noswf + else + setl cino= com= cpo-=a cpo-=A fo=nroql2 tw=0 report=10000 + endif setl nocin noai noci magic nospell nohid wig= noaw setl ma noro write if exists("+acd") | setl noacd | endif @@ -3566,6 +3583,7 @@ fun! s:NetrwBrowse(islocal,dirname) " This is useful when one edits a local file, then :e ., then :Rex if a:islocal && !exists("w:netrw_rexfile") && bufname("#") != "" let w:netrw_rexfile= bufname("#") +" call Decho("setting w:netrw_rexfile<".w:netrw_rexfile."> win#".winnr()) endif " s:NetrwBrowse : initialize history {{{3 @@ -3683,7 +3701,8 @@ fun! s:NetrwBrowse(islocal,dirname) " get/set-up buffer {{{3 " call Decho("saving position across a buffer refresh",'~'.expand("<slnum>")) - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let reusing= s:NetrwGetBuffer(a:islocal,dirname) " maintain markfile highlighting @@ -3792,10 +3811,18 @@ fun! s:NetrwBrowse(islocal,dirname) NetrwKeepj call s:NetrwCommands(a:islocal) NetrwKeepj call s:PerformListing(a:islocal) + " restore option(s) + call s:NetrwOptionRestore("w:") +" call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("<slnum>")) + " If there is a rexposn: restore position with rexposn " Otherwise : set rexposn if exists("s:rexposn_".bufnr("%")) - NetrwKeepj call netrw#RestorePosn(s:rexposn_{bufnr('%')}) +" call Decho("restoring posn to s:rexposn_".bufnr('%')."<".string(s:rexposn_{bufnr('%')}).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(s:rexposn_{bufnr('%')}) + if exists("w:netrw_bannercnt") && line(".") < w:netrw_bannercnt + NetrwKeepj exe w:netrw_bannercnt + endif else NetrwKeepj call s:SetRexDir(a:islocal,b:netrw_curdir) endif @@ -3804,13 +3831,11 @@ fun! s:NetrwBrowse(islocal,dirname) " call Decho("set up balloon help: l:bexpr=".&l:bexpr,'~'.expand("<slnum>")) setl beval endif - call s:NetrwOptionRestore("w:") -" call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("<slnum>")) " restore position if reusing -" call Decho("reusing=".reusing.": restoring position across buffer refresh",'~'.expand("<slnum>")) - call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + call winrestview(svpos) endif " The s:LocalBrowseRefresh() function is called by an autocmd @@ -3828,7 +3853,19 @@ endfun " differ from vim's. This function insures that netrw's idea of the current " directory is used. fun! s:NetrwFile(fname) -" call Dfunc("s:NetrwFile(fname<".a:fname.">)") +" call Dfunc("s:NetrwFile(fname<".a:fname.">) win#".winnr()) +" call Decho("g:netrw_keepdir =".(exists("g:netrw_keepdir")? g:netrw_keepdir : 'n/a')) +" call Decho("g:netrw_cygwin =".(exists("g:netrw_cygwin")? g:netrw_cygwin : 'n/a')) +" call Decho("g:netrw_liststyle=".(exists("g:netrw_liststyle")? g:netrw_liststyle : 'n/a')) +" call Decho("w:netrw_liststyle=".(exists("w:netrw_liststyle")? w:netrw_liststyle : 'n/a')) + + " clean up any leading treedepthstring + if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST + let fname= substitute(a:fname,'^'.s:treedepthstring.'\+','','') +" call Decho("clean up any leading treedepthstring: fname<".fname.">") + else + let fname= a:fname + endif if g:netrw_keepdir " vim's idea of the current directory possibly may differ from netrw's @@ -3837,28 +3874,28 @@ fun! s:NetrwFile(fname) endif if !exists("g:netrw_cygwin") && (has("win32") || has("win95") || has("win64") || has("win16")) - if a:fname =~ '^\' || a:fname =~ '^\a:\' + if fname =~ '^\' || fname =~ '^\a:\' " windows, but full path given - let ret= a:fname -" call Decho("windows+full path: isdirectory(".a:fname.")",'~'.expand("<slnum>")) + let ret= fname +" call Decho("windows+full path: isdirectory(".fname.")",'~'.expand("<slnum>")) else " windows, relative path given - let ret= s:ComposePath(b:netrw_curdir,a:fname) -" call Decho("windows+rltv path: isdirectory(".a:fname.")",'~'.expand("<slnum>")) + let ret= s:ComposePath(b:netrw_curdir,fname) +" call Decho("windows+rltv path: isdirectory(".fname.")",'~'.expand("<slnum>")) endif - elseif a:fname =~ '^/' + elseif fname =~ '^/' " not windows, full path given - let ret= a:fname -" call Decho("unix+full path: isdirectory(".a:fname.")",'~'.expand("<slnum>")) + let ret= fname +" call Decho("unix+full path: isdirectory(".fname.")",'~'.expand("<slnum>")) else " not windows, relative path given - let ret= s:ComposePath(b:netrw_curdir,a:fname) -" call Decho("unix+rltv path: isdirectory(".a:fname.")",'~'.expand("<slnum>")) + let ret= s:ComposePath(b:netrw_curdir,fname) +" call Decho("unix+rltv path: isdirectory(".fname.")",'~'.expand("<slnum>")) endif else " vim and netrw agree on the current directory - let ret= a:fname + let ret= fname " call Decho("vim and netrw agree on current directory (g:netrw_keepdir=".g:netrw_keepdir.")",'~'.expand("<slnum>")) endif @@ -3872,23 +3909,29 @@ fun! s:NetrwFileInfo(islocal,fname) " call Dfunc("s:NetrwFileInfo(islocal=".a:islocal." fname<".a:fname.">) b:netrw_curdir<".b:netrw_curdir.">") let ykeep= @@ if a:islocal + let lsopt= "-lsad" + if g:netrw_sizestyle =~ 'H' + let lsopt= "-lsadh" + elseif g:netrw_sizestyle =~ 'h' + let lsopt= "-lsadh --si" + endif if (has("unix") || has("macunix")) && executable("/bin/ls") if getline(".") == "../" - echo system("/bin/ls -lsad ".s:ShellEscape("..")) + echo system("/bin/ls ".lsopt." ".s:ShellEscape("..")) " call Decho("#1: echo system(/bin/ls -lsad ".s:ShellEscape(..).")",'~'.expand("<slnum>")) elseif w:netrw_liststyle == s:TREELIST && getline(".") !~ '^'.s:treedepthstring - echo system("/bin/ls -lsad ".s:ShellEscape(b:netrw_curdir)) + echo system("/bin/ls ".lsopt." ".s:ShellEscape(b:netrw_curdir)) " call Decho("#2: echo system(/bin/ls -lsad ".s:ShellEscape(b:netrw_curdir).")",'~'.expand("<slnum>")) elseif exists("b:netrw_curdir") - echo system("/bin/ls -lsad ".s:ShellEscape(s:ComposePath(b:netrw_curdir,a:fname))) + echo system("/bin/ls ".lsopt." ".s:ShellEscape(s:ComposePath(b:netrw_curdir,a:fname))) " call Decho("#3: echo system(/bin/ls -lsad ".s:ShellEscape(b:netrw_curdir.a:fname).")",'~'.expand("<slnum>")) else " call Decho('using ls '.a:fname." using cwd<".getcwd().">",'~'.expand("<slnum>")) - echo system("/bin/ls -lsad ".s:ShellEscape(s:NetrwFile(a:fname))) + echo system("/bin/ls ".lsopt." ".s:ShellEscape(s:NetrwFile(a:fname))) " call Decho("#5: echo system(/bin/ls -lsad ".s:ShellEscape(a:fname).")",'~'.expand("<slnum>")) endif else @@ -3901,6 +3944,9 @@ fun! s:NetrwFileInfo(islocal,fname) endif let t = getftime(s:NetrwFile(fname)) let sz = getfsize(s:NetrwFile(fname)) + if g:netrw_sizestyle =~ "[hH]" + let sz= s:NetrwHumanReadable(sz) + endif echo a:fname.": ".sz." ".strftime(g:netrw_timefmt,getftime(s:NetrwFile(fname))) " call Decho("fname.": ".sz." ".strftime(g:netrw_timefmt,getftime(fname)),'~'.expand("<slnum>")) endif @@ -4029,11 +4075,15 @@ fun! s:NetrwGetBuffer(islocal,dirname) let w:netrw_treebufnr= bufnr("%") " call Decho(" exe sil! keepalt file NetrwTreeListing ".fnameescape(s:netrw_treelistnum),'~'.expand("<slnum>")) exe 'sil! keepalt file NetrwTreeListing\ '.fnameescape(s:netrw_treelistnum) - setl bt=nofile noswf - nnoremap <silent> <buffer> [ :sil call <SID>TreeListMove('[')<cr> - nnoremap <silent> <buffer> ] :sil call <SID>TreeListMove(']')<cr> - nnoremap <silent> <buffer> [[ :sil call <SID>TreeListMove('[')<cr> - nnoremap <silent> <buffer> ]] :sil call <SID>TreeListMove(']')<cr> + if g:netrw_use_noswf + setl nobl bt=nofile noswf + else + setl nobl bt=nofile + endif + nnoremap <silent> <buffer> [[ :sil call <SID>TreeListMove('[[')<cr> + nnoremap <silent> <buffer> ]] :sil call <SID>TreeListMove(']]')<cr> + nnoremap <silent> <buffer> [] :sil call <SID>TreeListMove('[]')<cr> + nnoremap <silent> <buffer> ][ :sil call <SID>TreeListMove('][')<cr> " call Decho(" tree listing#".s:netrw_treelistnum." bufnr=".w:netrw_treebufnr,'~'.expand("<slnum>")) else " let v:errmsg = "" " Decho @@ -4197,7 +4247,7 @@ fun! s:NetrwGetWord() NetrwKeepj norm! 0 let dirname= substitute(getline('.'),'^\(\%(\S\+ \)*\S\+\).\{-}$','\1','e') - elseif w:netrw_liststyle == s:TREELIST + elseif exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST " call Decho("treelist handling",'~'.expand("<slnum>")) let dirname= substitute(getline('.'),'^\('.s:treedepthstring.'\)*','','e') let dirname= substitute(dirname,'\t -->.*$','','') @@ -4286,7 +4336,8 @@ fun! s:NetrwListStyle(islocal) let ykeep = @@ let fname = s:NetrwGetWord() if !exists("w:netrw_liststyle")|let w:netrw_liststyle= g:netrw_liststyle|endif - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let w:netrw_liststyle = (w:netrw_liststyle + 1) % s:MAXLIST " call Decho("fname<".fname.">",'~'.expand("<slnum>")) " call Decho("chgd w:netrw_liststyle to ".w:netrw_liststyle,'~'.expand("<slnum>")) @@ -4307,7 +4358,7 @@ fun! s:NetrwListStyle(islocal) " call Decho("use wide list",'~'.expand("<slnum>")) let g:netrw_list_cmd = substitute(g:netrw_list_cmd,' -l','','ge') - elseif w:netrw_liststyle == s:TREELIST + elseif exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST " call Decho("use tree list",'~'.expand("<slnum>")) let g:netrw_list_cmd = substitute(g:netrw_list_cmd,' -l','','ge') @@ -4334,7 +4385,8 @@ fun! s:NetrwListStyle(islocal) NetrwKeepj call s:NetrwCursor() " restore position; keep cursor on the filename - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) let @@= ykeep " call Dret("NetrwListStyle".(exists("w:netrw_liststyle")? ' : w:netrw_liststyle='.w:netrw_liststyle : "")) @@ -4350,7 +4402,8 @@ fun! s:NetrwBannerCtrl(islocal) let g:netrw_banner= !g:netrw_banner " refresh the listing - let svpos= netrw#SavePosn() + let svpos= winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) " keep cursor on the filename @@ -4385,7 +4438,8 @@ fun! s:NetrwBookmark(del,...) if exists("s:netrwmarkfilelist_{curbufnr}") " for every filename in the marked list " call Decho("bookmark every filename in marked list",'~'.expand("<slnum>")) - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let islocal= expand("%") !~ '^\a\{3,}://' for fname in s:netrwmarkfilelist_{curbufnr} if a:del|call s:DeleteBookmark(fname)|else|call s:MakeBookmark(fname)|endif @@ -4393,7 +4447,8 @@ fun! s:NetrwBookmark(del,...) let curdir = exists("b:netrw_curdir")? b:netrw_curdir : getcwd() call s:NetrwUnmarkList(curbufnr,curdir) NetrwKeepj call s:NetrwRefresh(islocal,s:NetrwBrowseChgDir(islocal,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) else let fname= s:NetrwGetWord() if a:del|call s:DeleteBookmark(fname)|else|call s:MakeBookmark(fname)|endif @@ -4528,9 +4583,9 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...) " call Decho("saving options",'~'.expand("<slnum>")) NetrwKeepj call s:NetrwOptionSave("s:") NetrwKeepj call s:NetrwSafeOptions() - let nbcd_curpos = netrw#SavePosn() + let nbcd_curpos = winsaveview() +" call Decho("saving posn to nbcd_curpos<".string(nbcd_curpos).">",'~'.expand("<slnum>")) let s:nbcd_curpos_{bufnr('%')} = nbcd_curpos -" call Decho("setting s:nbcd_curpos_".bufnr('%')." to SavePosn",'~'.expand("<slnum>")) if (has("win32") || has("win95") || has("win64") || has("win16")) let dirname = substitute(b:netrw_curdir,'\\','/','ge') else @@ -4553,7 +4608,8 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...) setl ma noro nowrap NetrwKeepj call setline(line('.'),'" Quick Help: <F1>:help '.s:QuickHelp[g:netrw_quickhelp]) setl noma nomod nowrap - NetrwKeepj call netrw#RestorePosn(nbcd_curpos) +" call Decho("restoring posn to nbcd_curpos<".string(nbcd_curpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(nbcd_curpos) NetrwKeepj call s:NetrwOptionRestore("s:") " call Decho("ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>")) endif @@ -4585,8 +4641,8 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...) " call Decho('edit-a-file: case "handling a file": newdir<'.newdir.'> !~ dirpat<'.dirpat.">",'~'.expand("<slnum>")) " save position for benefit of Rexplore - let s:rexposn_{bufnr("%")}= netrw#SavePosn() -" call Decho("edit-a-file: setting s:rexposn_".bufnr("%")."<".bufname("%")."> to SavePosn",'~'.expand("<slnum>")) + let s:rexposn_{bufnr("%")}= winsaveview() +" call Decho("edit-a-file: saving posn to s:rexposn_".bufnr("%")."<".string(s:rexposn_{bufnr("%")}).">",'~'.expand("<slnum>")) " call Decho("edit-a-file: win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> ft=".&ft,'~'.expand("<slnum>")) " call Decho("edit-a-file: w:netrw_liststyle=".(exists("w:netrw_liststyle")? w:netrw_liststyle : 'n/a')." w:netrw_treedict:".(exists("w:netrw_treedict")? "exists" : 'n/a')." newdir<".newdir.">",'~'.expand("<slnum>")) @@ -4602,6 +4658,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...) " call Decho("edit-a-file: dirname<".dirname.">",'~'.expand("<slnum>")) " call Decho("edit-a-file: tree listing",'~'.expand("<slnum>")) elseif newdir =~ '^\(/\|\a:\)' +" call Decho("edit-a-file: handle an url or path starting with /: <".newdir.">") let dirname= newdir else let dirname= s:ComposePath(dirname,newdir) @@ -4609,8 +4666,9 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...) " call Decho("edit-a-file: handling a file: dirname<".dirname."> (a:0=".a:0.")",'~'.expand("<slnum>")) " this lets netrw#BrowseX avoid the edit if a:0 < 1 -" call Decho("edit-a-file: set up windows for editing<".fnameescape(dirname)."> didsplit=".(exists("s:didsplit")? s:didsplit : "doesn't exist"),'~'.expand("<slnum>")) +" call Decho("edit-a-file: (a:0=".a:0."<1) set up windows for editing<".fnameescape(dirname)."> didsplit=".(exists("s:didsplit")? s:didsplit : "doesn't exist"),'~'.expand("<slnum>")) NetrwKeepj call s:NetrwOptionRestore("s:") + let curdir= b:netrw_curdir if !exists("s:didsplit") " call Decho("edit-a-file: s:didsplit does not exist; g:netrw_browse_split=".string(g:netrw_browse_split)." win#".winnr(),'~'.expand("<slnum>")) if type(g:netrw_browse_split) == 3 @@ -4627,6 +4685,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...) if !&ea keepalt wincmd _ endif + call s:SetRexDir(a:islocal,b:netrw_curdir) elseif g:netrw_browse_split == 2 " vertically splitting the window first " call Decho("edit-a-file: vertically splitting window prior to edit",'~'.expand("<slnum>")) @@ -4634,10 +4693,12 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...) if !&ea keepalt wincmd | endif + call s:SetRexDir(a:islocal,b:netrw_curdir) elseif g:netrw_browse_split == 3 " open file in new tab " call Decho("edit-a-file: opening new tab prior to edit",'~'.expand("<slnum>")) keepalt tabnew + call s:SetRexDir(a:islocal,b:netrw_curdir) elseif g:netrw_browse_split == 4 " act like "P" (ie. open previous window) " call Decho("edit-a-file: use previous window for edit",'~'.expand("<slnum>")) @@ -4646,6 +4707,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...) " call Dret("s:NetrwBrowseChgDir") return endif + call s:SetRexDir(a:islocal,b:netrw_curdir) else " handling a file, didn't split, so remove menu " call Decho("edit-a-file: handling a file+didn't split, so remove menu",'~'.expand("<slnum>")) @@ -4663,6 +4725,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...) endif exe "NetrwKeepj keepalt ".g:netrw_chgwin."wincmd w" endif + call s:SetRexDir(a:islocal,curdir) endif endif @@ -4802,7 +4865,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...) " call Decho("tree-list: w:netrw_treedict<".string(w:netrw_treedict).">",'~'.expand("<slnum>")) " search treedict for tree dir as-is -" call Decho("search treedict for tree dir as-is",'~'.expand("<slnum>")) +" call Decho("tree-list: search treedict for tree dir as-is",'~'.expand("<slnum>")) if has_key(w:netrw_treedict,treedir) " call Decho('tree-list: ....searched for treedir<'.treedir.'> : found it!','~'.expand("<slnum>")) let haskey= 1 @@ -4811,7 +4874,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...) endif " search treedict for treedir with a [/@] appended -" call Decho("search treedict for treedir with a [/@] appended",'~'.expand("<slnum>")) +" call Decho("tree-list: search treedict for treedir with a [/@] appended",'~'.expand("<slnum>")) if !haskey && treedir !~ '[/@]$' if has_key(w:netrw_treedict,treedir."/") let treedir= treedir."/" @@ -4823,7 +4886,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...) endif " search treedict for treedir with any trailing / elided -" call Decho("search treedict for treedir with any trailing / elided",'~'.expand("<slnum>")) +" call Decho("tree-list: search treedict for treedir with any trailing / elided",'~'.expand("<slnum>")) if !haskey && treedir =~ '/$' let treedir= substitute(treedir,'/$','','') if has_key(w:netrw_treedict,treedir) @@ -4967,14 +5030,15 @@ fun! netrw#BrowseX(fname,remote) " call Dfunc("netrw#BrowseX(fname<".a:fname."> remote=".a:remote.")") " if its really just a directory, then do a "gf" instead - if a:fname =~ '/$' + if (a:remote == 0 && isdirectory(a:fname)) || (a:remote == 1 && fname =~ '/$' && fname !~ '^https\=:') norm! gf " call Dret("netrw#BrowseX : did gf instead") endif let ykeep = @@ - let screenposn = netrw#SavePosn() + let screenposn = winsaveview() +" call Decho("saving posn to screenposn<".string(screenposn).">",'~'.expand("<slnum>")) " need to save and restore aw setting as gx can invoke this function from non-netrw buffers let awkeep = &aw @@ -4996,7 +5060,8 @@ fun! netrw#BrowseX(fname,remote) endif endfor endif - call netrw#RestorePosn(screenposn) +" call Decho("restoring posn to screenposn<".string(screenposn).">,'~'.expand("<slnum>"))" + call winrestview(screenposn) let @@= ykeep let &aw= awkeep " call Dret("netrw#BrowseX : coredump handler invoked") @@ -5167,7 +5232,8 @@ fun! netrw#BrowseX(fname,remote) exe "sil! NetrwKeepj norm! \<c-o>" " redraw! endif - call netrw#RestorePosn(screenposn) +" call Decho("restoring posn to screenposn<".string(screenposn).">",'~'.expand("<slnum>")) + call winrestview(screenposn) let @@ = ykeep let &aw= awkeep @@ -5310,6 +5376,32 @@ fun! s:NetrwForceChgDir(islocal,newdir) endfun " --------------------------------------------------------------------- +" s:NetrwGlob: does glob() if local, remote listing otherwise {{{2 +fun! s:NetrwGlob(direntry,expr) +" call Dfunc("s:NetrwGlob(direntry<".a:direntry."> expr<".a:expr.">)") + if netrw#CheckIfRemote() + keepalt 1sp + keepalt enew + let keep_liststyle = w:netrw_liststyle + let w:netrw_liststyle = s:THINLIST + if s:NetrwRemoteListing() == 0 + keepj keepalt %s@/@@ + let filelist= getline(1,$) + q! + else + " remote listing error -- leave treedict unchanged + let filelist= w:netrw_treedict[a:direntry] + endif + let w:netrw_liststyle= keep_liststyle + else + let filelist= glob(s:ComposePath(a:direntry,a:expr),0,1,1) + let filelist= map(filelist,'substitute(v:val, "^.*/", "", "")') + endif +" call Dret("s:NetrwGlob ".string(filelist)) + return filelist +endfun + +" --------------------------------------------------------------------- " s:NetrwForceFile: (gf support) Force treatment as a file {{{2 fun! s:NetrwForceFile(islocal,newfile) " call Dfunc("s:NetrwForceFile(islocal=".a:islocal." newdir<".a:newfile.">)") @@ -5336,7 +5428,8 @@ endfun fun! s:NetrwHide(islocal) " call Dfunc("NetrwHide(islocal=".a:islocal.") g:netrw_hide=".g:netrw_hide) let ykeep= @@ - let svpos= netrw#SavePosn() + let svpos= winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) if exists("s:netrwmarkfilelist_{bufnr('%')}") " call Decho("((g:netrw_hide == 1)? "unhide" : "hide")." files in markfilelist<".string(s:netrwmarkfilelist_{bufnr("%")}).">",'~'.expand("<slnum>")) @@ -5378,7 +5471,8 @@ fun! s:NetrwHide(islocal) endif NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) let @@= ykeep " call Dret("NetrwHide") endfun @@ -5390,7 +5484,8 @@ fun! s:NetrwHideEdit(islocal) let ykeep= @@ " save current cursor position - let svpos= netrw#SavePosn() + let svpos= winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) " get new hiding list from user call inputsave() @@ -5403,7 +5498,8 @@ fun! s:NetrwHideEdit(islocal) sil NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,"./")) " restore cursor position - call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + call winrestview(svpos) let @@= ykeep " call Dret("NetrwHideEdit") @@ -5415,7 +5511,8 @@ fun! s:NetrwHidden(islocal) " call Dfunc("s:NetrwHidden()") let ykeep= @@ " save current position - let svpos= netrw#SavePosn() + let svpos= winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) if g:netrw_list_hide =~ '\(^\|,\)\\(^\\|\\s\\s\\)\\zs\\.\\S\\+' " remove pattern from hiding list @@ -5428,7 +5525,8 @@ fun! s:NetrwHidden(islocal) " refresh screen and return to saved position NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) let @@= ykeep " call Dret("s:NetrwHidden") endfun @@ -5540,10 +5638,10 @@ fun! s:NetrwServerEdit(islocal,fname) if (islocal && isdirectory(s:NetrwFile(a:fname))) || (!islocal && a:fname =~ '/$') " handle directories in the local window -- not in the remote vim server - " user must have closed the NETRWSERVER window. Treat as a normal editing from netrw. + " user must have closed the NETRWSERVER window. Treat as normal editing from netrw. " call Decho("handling directory in client window",'~'.expand("<slnum>")) let g:netrw_browse_split= 0 - if exists("s:netrw_browse_split_".winnr()) + if exists("s:netrw_browse_split") && exists("s:netrw_browse_split_".winnr()) let g:netrw_browse_split= s:netrw_browse_split_{winnr()} unlet s:netrw_browse_split_{winnr()} endif @@ -5820,9 +5918,11 @@ fun! s:NetrwMakeDir(usrhost) if v:shell_error == 0 " refresh listing " call Decho("refresh listing",'~'.expand("<slnum>")) - let svpos= netrw#SavePosn() + let svpos= winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./')) - call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + call winrestview(svpos) elseif !exists("g:netrw_quiet") call netrw#ErrorMsg(s:ERROR,"unable to make directory<".newdirname.">",26) endif @@ -5836,9 +5936,11 @@ fun! s:NetrwMakeDir(usrhost) call s:NetrwExe("sil! !".mkdircmd." ".s:ShellEscape(newdirname,1)) if v:shell_error == 0 " refresh listing - let svpos= netrw#SavePosn() + let svpos= winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) elseif !exists("g:netrw_quiet") NetrwKeepj call netrw#ErrorMsg(s:ERROR,"unable to make directory<".newdirname.">",27) endif @@ -5846,7 +5948,8 @@ fun! s:NetrwMakeDir(usrhost) elseif b:netrw_method == 2 " Remote mkdir: using ftp+.netrc - let svpos= netrw#SavePosn() + let svpos= winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) " call Decho("b:netrw_curdir<".b:netrw_curdir.">",'~'.expand("<slnum>")) if exists("b:netrw_fname") " call Decho("b:netrw_fname<".b:netrw_fname.">",'~'.expand("<slnum>")) @@ -5856,11 +5959,13 @@ fun! s:NetrwMakeDir(usrhost) endif call s:NetrwRemoteFtpCmd(remotepath,g:netrw_remote_mkdir.' "'.newdirname.'"') NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) elseif b:netrw_method == 3 " Remote mkdir: using ftp + machine, id, passwd, and fname (ie. no .netrc) - let svpos= netrw#SavePosn() + let svpos= winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) " call Decho("b:netrw_curdir<".b:netrw_curdir.">",'~'.expand("<slnum>")) if exists("b:netrw_fname") " call Decho("b:netrw_fname<".b:netrw_fname.">",'~'.expand("<slnum>")) @@ -5870,7 +5975,8 @@ fun! s:NetrwMakeDir(usrhost) endif call s:NetrwRemoteFtpCmd(remotepath,g:netrw_remote_mkdir.' "'.newdirname.'"') NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) endif let @@= ykeep @@ -5884,22 +5990,30 @@ fun! s:TreeSqueezeDir(islocal) if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST && exists("w:netrw_treedict") " its a tree-listing style let curdepth = substitute(getline('.'),'^\(\%('.s:treedepthstring.'\)*\)[^'.s:treedepthstring.'].\{-}$','\1','e') - let iline = line(".") - 1 let stopline = (exists("w:netrw_bannercnt")? (w:netrw_bannercnt + 1) : 1) -" call Decho("curdepth=".curdepth,'~'.expand("<slnum>")) + let depth = strchars(substitute(curdepth,' ','','g')) + let srch = -1 +" call Decho("curdepth<".curdepth.'>','~'.expand("<slnum>")) +" call Decho("depth =".depth,'~'.expand("<slnum>")) " call Decho("stopline#".stopline,'~'.expand("<slnum>")) -" call Decho("starting with line#".line(".").": ".getline('.'),'~'.expand("<slnum>")) - while iline > stopline - " find a line that has less depth - let depth = substitute(getline('.'),'^\(\%('.s:treedepthstring.'\)*\)[^'.s:treedepthstring.'].\{-}$','\1','e') -" call Decho("considering line#".line(".").": ".getline('.'),'~'.expand("<slnum>")) - if depth < curdepth - break - endif - norm! k - endwhile -" call Decho("squeezing at line#".line(".").": ".getline('.'),'~'.expand("<slnum>")) - call s:NetrwBrowse(a:islocal,s:NetrwBrowseChgDir(a:islocal,s:NetrwGetWord())) +" call Decho("curline#".line(".")."<".getline('.').'>','~'.expand("<slnum>")) + if depth >= 2 + NetrwKeepj norm! 0 + let curdepthm1= substitute(curdepth,'^'.s:treedepthstring,'','') + let srch = search('^'.curdepthm1.'\%('.s:treedepthstring.'\)\@!','bW',stopline) +" call Decho("curdepthm1<".curdepthm1.'>','~'.expand("<slnum>")) +" call Decho("case depth>=2: srch<".srch.'>','~'.expand("<slnum>")) + elseif depth == 1 + NetrwKeepj norm! 0 + let treedepthchr= substitute(s:treedepthstring,' ','','') + let srch = search('^[^'.treedepthchr.']','bW',stopline) +" call Decho("case depth==1: srch<".srch.'>','~'.expand("<slnum>")) + endif + if srch > 0 +" call Decho("squeezing at line#".line(".").": ".getline('.'),'~'.expand("<slnum>")) + call s:NetrwBrowse(a:islocal,s:NetrwBrowseChgDir(a:islocal,s:NetrwGetWord())) + exe srch + endif endif " call Dret("s:TreeSqueezeDir") endfun @@ -5927,23 +6041,24 @@ fun! s:NetrwMaps(islocal) if a:islocal " call Decho("make local maps",'~'.expand("<slnum>")) " local normal-mode maps - nnoremap <buffer> <silent> <nowait> a :call <SID>NetrwHide(1)<cr> - nnoremap <buffer> <silent> <nowait> % :call <SID>NetrwOpenFile(1)<cr> - nnoremap <buffer> <silent> <nowait> c :call <SID>NetrwLcd(b:netrw_curdir)<cr> + nnoremap <buffer> <silent> <nowait> a :<c-u>call <SID>NetrwHide(1)<cr> + nnoremap <buffer> <silent> <nowait> - :<c-u>call <SID>NetrwBrowseUpDir(1)<cr> + nnoremap <buffer> <silent> <nowait> % :<c-u>call <SID>NetrwOpenFile(1)<cr> + nnoremap <buffer> <silent> <nowait> c :<c-u>call <SID>NetrwLcd(b:netrw_curdir)<cr> nnoremap <buffer> <silent> <nowait> C :<c-u>call <SID>NetrwSetChgwin()<cr> - nnoremap <buffer> <silent> <nowait> <cr> :call netrw#LocalBrowseCheck(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord()))<cr> - nnoremap <buffer> <silent> <nowait> <s-cr> :call <SID>TreeSqueezeDir(1)<cr> - nnoremap <buffer> <silent> <nowait> <c-r> :call <SID>NetrwServerEdit(3,<SID>NetrwGetWord())<cr> - nnoremap <buffer> <silent> <nowait> d :call <SID>NetrwMakeDir("")<cr> - nnoremap <buffer> <silent> <nowait> - :call <SID>NetrwBrowseUpDir(1)<cr> + nnoremap <buffer> <silent> <nowait> <cr> :<c-u>call netrw#LocalBrowseCheck(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord()))<cr> + nnoremap <buffer> <silent> <nowait> <c-r> :<c-u>call <SID>NetrwServerEdit(3,<SID>NetrwGetWord())<cr> + nnoremap <buffer> <silent> <nowait> d :<c-u>call <SID>NetrwMakeDir("")<cr> nnoremap <buffer> <silent> <nowait> gb :<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr> nnoremap <buffer> <silent> <nowait> gd :<c-u>call <SID>NetrwForceChgDir(1,<SID>NetrwGetWord())<cr> nnoremap <buffer> <silent> <nowait> gf :<c-u>call <SID>NetrwForceFile(1,<SID>NetrwGetWord())<cr> nnoremap <buffer> <silent> <nowait> gh :<c-u>call <SID>NetrwHidden(1)<cr> nnoremap <buffer> <silent> <nowait> gn :<c-u>call netrw#SetTreetop(<SID>NetrwGetWord())<cr> nnoremap <buffer> <silent> <nowait> gp :<c-u>call <SID>NetrwChgPerm(1,b:netrw_curdir)<cr> - nnoremap <buffer> <silent> <nowait> I :call <SID>NetrwBannerCtrl(1)<cr> - nnoremap <buffer> <silent> <nowait> i :call <SID>NetrwListStyle(1)<cr> + nnoremap <buffer> <silent> <nowait> I :<c-u>call <SID>NetrwBannerCtrl(1)<cr> + nnoremap <buffer> <silent> <nowait> i :<c-u>call <SID>NetrwListStyle(1)<cr> + nnoremap <buffer> <silent> <nowait> ma :<c-u>call <SID>NetrwMarkFileArgList(1,0)<cr> + nnoremap <buffer> <silent> <nowait> mA :<c-u>call <SID>NetrwMarkFileArgList(1,1)<cr> nnoremap <buffer> <silent> <nowait> mb :<c-u>call <SID>NetrwBookHistHandler(0,b:netrw_curdir)<cr> nnoremap <buffer> <silent> <nowait> mB :<c-u>call <SID>NetrwBookHistHandler(6,b:netrw_curdir)<cr> nnoremap <buffer> <silent> <nowait> mc :<c-u>call <SID>NetrwMarkFileCopy(1)<cr> @@ -5957,104 +6072,110 @@ fun! s:NetrwMaps(islocal) nnoremap <buffer> <silent> <nowait> mp :<c-u>call <SID>NetrwMarkFilePrint(1)<cr> nnoremap <buffer> <silent> <nowait> mr :<c-u>call <SID>NetrwMarkFileRegexp(1)<cr> nnoremap <buffer> <silent> <nowait> ms :<c-u>call <SID>NetrwMarkFileSource(1)<cr> - nnoremap <buffer> <silent> <nowait> mt :<c-u>call <SID>NetrwMarkFileTgt(1)<cr> nnoremap <buffer> <silent> <nowait> mT :<c-u>call <SID>NetrwMarkFileTag(1)<cr> + nnoremap <buffer> <silent> <nowait> mt :<c-u>call <SID>NetrwMarkFileTgt(1)<cr> nnoremap <buffer> <silent> <nowait> mu :<c-u>call <SID>NetrwUnMarkFile(1)<cr> nnoremap <buffer> <silent> <nowait> mv :<c-u>call <SID>NetrwMarkFileVimCmd(1)<cr> nnoremap <buffer> <silent> <nowait> mx :<c-u>call <SID>NetrwMarkFileExe(1,0)<cr> nnoremap <buffer> <silent> <nowait> mX :<c-u>call <SID>NetrwMarkFileExe(1,1)<cr> nnoremap <buffer> <silent> <nowait> mz :<c-u>call <SID>NetrwMarkFileCompress(1)<cr> - nnoremap <buffer> <silent> <nowait> O :call <SID>NetrwObtain(1)<cr> + nnoremap <buffer> <silent> <nowait> O :<c-u>call <SID>NetrwObtain(1)<cr> nnoremap <buffer> <silent> <nowait> o :call <SID>NetrwSplit(3)<cr> - nnoremap <buffer> <silent> <nowait> p :call <SID>NetrwPreview(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1))<cr> - nnoremap <buffer> <silent> <nowait> P :call <SID>NetrwPrevWinOpen(1)<cr> + nnoremap <buffer> <silent> <nowait> p :<c-u>call <SID>NetrwPreview(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1))<cr> + nnoremap <buffer> <silent> <nowait> P :<c-u>call <SID>NetrwPrevWinOpen(1)<cr> nnoremap <buffer> <silent> <nowait> qb :<c-u>call <SID>NetrwBookHistHandler(2,b:netrw_curdir)<cr> nnoremap <buffer> <silent> <nowait> qf :<c-u>call <SID>NetrwFileInfo(1,<SID>NetrwGetWord())<cr> nnoremap <buffer> <silent> <nowait> qF :<c-u>call <SID>NetrwMarkFileQFEL(1,getqflist())<cr> - nnoremap <buffer> <silent> <nowait> r :let g:netrw_sort_direction= (g:netrw_sort_direction =~ 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,'./'))<cr> + nnoremap <buffer> <silent> <nowait> qL :<c-u>call <SID>NetrwMarkFileQFEL(1,getloclist(v:count))<cr> + nnoremap <buffer> <silent> <nowait> r :<c-u>let g:netrw_sort_direction= (g:netrw_sort_direction =~ 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,'./'))<cr> nnoremap <buffer> <silent> <nowait> s :call <SID>NetrwSortStyle(1)<cr> - nnoremap <buffer> <silent> <nowait> S :call <SID>NetSortSequence(1)<cr> + nnoremap <buffer> <silent> <nowait> S :<c-u>call <SID>NetSortSequence(1)<cr> + nnoremap <buffer> <silent> <nowait> Tb :<c-u>call <SID>NetrwSetTgt(1,'b',v:count1)<cr> nnoremap <buffer> <silent> <nowait> t :call <SID>NetrwSplit(4)<cr> - nnoremap <buffer> <silent> <nowait> Tb :<c-u>call <SID>NetrwSetTgt('b',v:count1)<cr> - nnoremap <buffer> <silent> <nowait> Th :<c-u>call <SID>NetrwSetTgt('h',v:count)<cr> + nnoremap <buffer> <silent> <nowait> Th :<c-u>call <SID>NetrwSetTgt(1,'h',v:count)<cr> nnoremap <buffer> <silent> <nowait> u :<c-u>call <SID>NetrwBookHistHandler(4,expand("%"))<cr> nnoremap <buffer> <silent> <nowait> U :<c-u>call <SID>NetrwBookHistHandler(5,expand("%"))<cr> nnoremap <buffer> <silent> <nowait> v :call <SID>NetrwSplit(5)<cr> - nnoremap <buffer> <silent> <nowait> x :call netrw#BrowseX(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),0),0)"<cr> - nnoremap <buffer> <silent> <nowait> X :call <SID>NetrwLocalExecute(expand("<cword>"))"<cr> - " local insert-mode maps - inoremap <buffer> <silent> <nowait> a <c-o>:call <SID>NetrwHide(1)<cr> - inoremap <buffer> <silent> <nowait> c <c-o>:exe "NetrwKeepj lcd ".fnameescape(b:netrw_curdir)<cr> - inoremap <buffer> <silent> <nowait> c <c-o>:call <SID>NetrwLcd(b:netrw_curdir)<cr> - inoremap <buffer> <silent> <nowait> C <c-o>:call <SID>NetrwSetChgwin()<cr> - inoremap <buffer> <silent> <nowait> % <c-o>:call <SID>NetrwOpenFile(1)<cr> - inoremap <buffer> <silent> <nowait> - <c-o>:call <SID>NetrwBrowseUpDir(1)<cr> - inoremap <buffer> <silent> <nowait> <cr> <c-o>:call netrw#LocalBrowseCheck(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord()))<cr> - inoremap <buffer> <silent> <nowait> <s-cr> <c-o>:call <SID>TreeSqueezeDir(1)<cr> - inoremap <buffer> <silent> <nowait> d <c-o>:call <SID>NetrwMakeDir("")<cr> - inoremap <buffer> <silent> <nowait> gb <c-o>:<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr> - inoremap <buffer> <silent> <nowait> gh <c-o>:<c-u>call <SID>NetrwHidden(1)<cr> - nnoremap <buffer> <silent> <nowait> gn :<c-u>call netrw#SetTreetop(<SID>NetrwGetWord())<cr> - inoremap <buffer> <silent> <nowait> gp <c-o>:<c-u>call <SID>NetrwChgPerm(1,b:netrw_curdir)<cr> - inoremap <buffer> <silent> <nowait> I <c-o>:call <SID>NetrwBannerCtrl(1)<cr> - inoremap <buffer> <silent> <nowait> i <c-o>:call <SID>NetrwListStyle(1)<cr> - inoremap <buffer> <silent> <nowait> mb <c-o>:<c-u>call <SID>NetrwBookHistHandler(0,b:netrw_curdir)<cr> - inoremap <buffer> <silent> <nowait> mB <c-o>:<c-u>call <SID>NetrwBookHistHandler(6,b:netrw_curdir)<cr> - inoremap <buffer> <silent> <nowait> mc <c-o>:<c-u>call <SID>NetrwMarkFileCopy(1)<cr> - inoremap <buffer> <silent> <nowait> md <c-o>:<c-u>call <SID>NetrwMarkFileDiff(1)<cr> - inoremap <buffer> <silent> <nowait> me <c-o>:<c-u>call <SID>NetrwMarkFileEdit(1)<cr> - inoremap <buffer> <silent> <nowait> mf <c-o>:<c-u>call <SID>NetrwMarkFile(1,<SID>NetrwGetWord())<cr> - inoremap <buffer> <silent> <nowait> mg <c-o>:<c-u>call <SID>NetrwMarkFileGrep(1)<cr> - inoremap <buffer> <silent> <nowait> mh <c-o>:<c-u>call <SID>NetrwMarkHideSfx(1)<cr> - inoremap <buffer> <silent> <nowait> mm <c-o>:<c-u>call <SID>NetrwMarkFileMove(1)<cr> - inoremap <buffer> <silent> <nowait> mp <c-o>:<c-u>call <SID>NetrwMarkFilePrint(1)<cr> - inoremap <buffer> <silent> <nowait> mr <c-o>:<c-u>call <SID>NetrwMarkFileRegexp(1)<cr> - inoremap <buffer> <silent> <nowait> ms <c-o>:<c-u>call <SID>NetrwMarkFileSource(1)<cr> - inoremap <buffer> <silent> <nowait> mT <c-o>:<c-u>call <SID>NetrwMarkFileTag(1)<cr> - inoremap <buffer> <silent> <nowait> mt <c-o>:<c-u>call <SID>NetrwMarkFileTgt(1)<cr> - inoremap <buffer> <silent> <nowait> mu <c-o>:<c-u>call <SID>NetrwUnMarkFile(1)<cr> - inoremap <buffer> <silent> <nowait> mv <c-o>:<c-u>call <SID>NetrwMarkFileVimCmd(1)<cr> - inoremap <buffer> <silent> <nowait> mx <c-o>:<c-u>call <SID>NetrwMarkFileExe(1,0)<cr> - inoremap <buffer> <silent> <nowait> mX <c-o>:<c-u>call <SID>NetrwMarkFileExe(1,1)<cr> - inoremap <buffer> <silent> <nowait> mz <c-o>:<c-u>call <SID>NetrwMarkFileCompress(1)<cr> - inoremap <buffer> <silent> <nowait> O <c-o>:call <SID>NetrwObtain(1)<cr> - inoremap <buffer> <silent> <nowait> o <c-o>:call <SID>NetrwSplit(3)<cr> - inoremap <buffer> <silent> <nowait> p <c-o>:call <SID>NetrwPreview(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1))<cr> - inoremap <buffer> <silent> <nowait> P <c-o>:call <SID>NetrwPrevWinOpen(1)<cr> - inoremap <buffer> <silent> <nowait> qb <c-o>:<c-u>call <SID>NetrwBookHistHandler(2,b:netrw_curdir)<cr> - inoremap <buffer> <silent> <nowait> qf <c-o>:<c-u>call <SID>NetrwFileInfo(1,<SID>NetrwGetWord())<cr> - inoremap <buffer> <silent> <nowait> qF :<c-u>call <SID>NetrwMarkFileQFEL(1,getqflist())<cr> - inoremap <buffer> <silent> <nowait> r <c-o>:let g:netrw_sort_direction= (g:netrw_sort_direction =~ 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,'./'))<cr> - inoremap <buffer> <silent> <nowait> s <c-o>:call <SID>NetrwSortStyle(1)<cr> - inoremap <buffer> <silent> <nowait> S <c-o>:call <SID>NetSortSequence(1)<cr> - inoremap <buffer> <silent> <nowait> t <c-o>:call <SID>NetrwSplit(4)<cr> - inoremap <buffer> <silent> <nowait> Tb <c-o>:<c-u>call <SID>NetrwSetTgt('b',v:count1)<cr> - inoremap <buffer> <silent> <nowait> Th <c-o>:<c-u>call <SID>NetrwSetTgt('h',v:count)<cr> - inoremap <buffer> <silent> <nowait> u <c-o>:<c-u>call <SID>NetrwBookHistHandler(4,expand("%"))<cr> - inoremap <buffer> <silent> <nowait> U <c-o>:<c-u>call <SID>NetrwBookHistHandler(5,expand("%"))<cr> - inoremap <buffer> <silent> <nowait> v <c-o>:call <SID>NetrwSplit(5)<cr> - inoremap <buffer> <silent> <nowait> x <c-o>:call netrw#BrowseX(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),0),0)"<cr> + nnoremap <buffer> <silent> <nowait> x :<c-u>call netrw#BrowseX(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),0),0)"<cr> + nnoremap <buffer> <silent> <nowait> X :<c-u>call <SID>NetrwLocalExecute(expand("<cword>"))"<cr> +" " local insert-mode maps +" inoremap <buffer> <silent> <nowait> a <c-o>:call <SID>NetrwHide(1)<cr> +" inoremap <buffer> <silent> <nowait> c <c-o>:exe "NetrwKeepj lcd ".fnameescape(b:netrw_curdir)<cr> +" inoremap <buffer> <silent> <nowait> c <c-o>:call <SID>NetrwLcd(b:netrw_curdir)<cr> +" inoremap <buffer> <silent> <nowait> C <c-o>:call <SID>NetrwSetChgwin()<cr> +" inoremap <buffer> <silent> <nowait> % <c-o>:call <SID>NetrwOpenFile(1)<cr> +" inoremap <buffer> <silent> <nowait> - <c-o>:call <SID>NetrwBrowseUpDir(1)<cr> +" inoremap <buffer> <silent> <nowait> <cr> <c-o>:call netrw#LocalBrowseCheck(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord()))<cr> +" inoremap <buffer> <silent> <nowait> d <c-o>:call <SID>NetrwMakeDir("")<cr> +" inoremap <buffer> <silent> <nowait> gb <c-o>:<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr> +" inoremap <buffer> <silent> <nowait> gh <c-o>:<c-u>call <SID>NetrwHidden(1)<cr> +" nnoremap <buffer> <silent> <nowait> gn :<c-u>call netrw#SetTreetop(<SID>NetrwGetWord())<cr> +" inoremap <buffer> <silent> <nowait> gp <c-o>:<c-u>call <SID>NetrwChgPerm(1,b:netrw_curdir)<cr> +" inoremap <buffer> <silent> <nowait> I <c-o>:call <SID>NetrwBannerCtrl(1)<cr> +" inoremap <buffer> <silent> <nowait> i <c-o>:call <SID>NetrwListStyle(1)<cr> +" inoremap <buffer> <silent> <nowait> mb <c-o>:<c-u>call <SID>NetrwBookHistHandler(0,b:netrw_curdir)<cr> +" inoremap <buffer> <silent> <nowait> mB <c-o>:<c-u>call <SID>NetrwBookHistHandler(6,b:netrw_curdir)<cr> +" inoremap <buffer> <silent> <nowait> mc <c-o>:<c-u>call <SID>NetrwMarkFileCopy(1)<cr> +" inoremap <buffer> <silent> <nowait> md <c-o>:<c-u>call <SID>NetrwMarkFileDiff(1)<cr> +" inoremap <buffer> <silent> <nowait> me <c-o>:<c-u>call <SID>NetrwMarkFileEdit(1)<cr> +" inoremap <buffer> <silent> <nowait> mf <c-o>:<c-u>call <SID>NetrwMarkFile(1,<SID>NetrwGetWord())<cr> +" inoremap <buffer> <silent> <nowait> mg <c-o>:<c-u>call <SID>NetrwMarkFileGrep(1)<cr> +" inoremap <buffer> <silent> <nowait> mh <c-o>:<c-u>call <SID>NetrwMarkHideSfx(1)<cr> +" inoremap <buffer> <silent> <nowait> mm <c-o>:<c-u>call <SID>NetrwMarkFileMove(1)<cr> +" inoremap <buffer> <silent> <nowait> mp <c-o>:<c-u>call <SID>NetrwMarkFilePrint(1)<cr> +" inoremap <buffer> <silent> <nowait> mr <c-o>:<c-u>call <SID>NetrwMarkFileRegexp(1)<cr> +" inoremap <buffer> <silent> <nowait> ms <c-o>:<c-u>call <SID>NetrwMarkFileSource(1)<cr> +" inoremap <buffer> <silent> <nowait> mT <c-o>:<c-u>call <SID>NetrwMarkFileTag(1)<cr> +" inoremap <buffer> <silent> <nowait> mt <c-o>:<c-u>call <SID>NetrwMarkFileTgt(1)<cr> +" inoremap <buffer> <silent> <nowait> mu <c-o>:<c-u>call <SID>NetrwUnMarkFile(1)<cr> +" inoremap <buffer> <silent> <nowait> mv <c-o>:<c-u>call <SID>NetrwMarkFileVimCmd(1)<cr> +" inoremap <buffer> <silent> <nowait> mx <c-o>:<c-u>call <SID>NetrwMarkFileExe(1,0)<cr> +" inoremap <buffer> <silent> <nowait> mX <c-o>:<c-u>call <SID>NetrwMarkFileExe(1,1)<cr> +" inoremap <buffer> <silent> <nowait> mz <c-o>:<c-u>call <SID>NetrwMarkFileCompress(1)<cr> +" inoremap <buffer> <silent> <nowait> O <c-o>:call <SID>NetrwObtain(1)<cr> +" inoremap <buffer> <silent> <nowait> o <c-o>:call <SID>NetrwSplit(3)<cr> +" inoremap <buffer> <silent> <nowait> p <c-o>:call <SID>NetrwPreview(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1))<cr> +" inoremap <buffer> <silent> <nowait> P <c-o>:call <SID>NetrwPrevWinOpen(1)<cr> +" inoremap <buffer> <silent> <nowait> qb <c-o>:<c-u>call <SID>NetrwBookHistHandler(2,b:netrw_curdir)<cr> +" inoremap <buffer> <silent> <nowait> qf <c-o>:<c-u>call <SID>NetrwFileInfo(1,<SID>NetrwGetWord())<cr> +" inoremap <buffer> <silent> <nowait> qF :<c-u>call <SID>NetrwMarkFileQFEL(1,getqflist())<cr> +" inoremap <buffer> <silent> <nowait> qL :<c-u>call <SID>NetrwMarkFileQFEL(1,getloclist(v:count))<cr> +" inoremap <buffer> <silent> <nowait> r <c-o>:let g:netrw_sort_direction= (g:netrw_sort_direction =~ 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,'./'))<cr> +" inoremap <buffer> <silent> <nowait> s <c-o>:call <SID>NetrwSortStyle(1)<cr> +" inoremap <buffer> <silent> <nowait> S <c-o>:call <SID>NetSortSequence(1)<cr> +" inoremap <buffer> <silent> <nowait> t <c-o>:call <SID>NetrwSplit(4)<cr> +" inoremap <buffer> <silent> <nowait> Tb <c-o>:<c-u>call <SID>NetrwSetTgt(1,'b',v:count1)<cr> +" inoremap <buffer> <silent> <nowait> Th <c-o>:<c-u>call <SID>NetrwSetTgt(1,'h',v:count)<cr> +" inoremap <buffer> <silent> <nowait> u <c-o>:<c-u>call <SID>NetrwBookHistHandler(4,expand("%"))<cr> +" inoremap <buffer> <silent> <nowait> U <c-o>:<c-u>call <SID>NetrwBookHistHandler(5,expand("%"))<cr> +" inoremap <buffer> <silent> <nowait> v <c-o>:call <SID>NetrwSplit(5)<cr> +" inoremap <buffer> <silent> <nowait> x <c-o>:call netrw#BrowseX(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),0),0)"<cr> if !hasmapto('<Plug>NetrwHideEdit') nmap <buffer> <unique> <c-h> <Plug>NetrwHideEdit - imap <buffer> <unique> <c-h> <Plug>NetrwHideEdit +" imap <buffer> <unique> <c-h> <c-o><Plug>NetrwHideEdit endif - nnoremap <buffer> <silent> <Plug>NetrwHideEdit :call <SID>NetrwHideEdit(1)<cr> + nnoremap <buffer> <silent> <Plug>NetrwHideEdit :call <SID>NetrwHideEdit(1)<cr> if !hasmapto('<Plug>NetrwRefresh') nmap <buffer> <unique> <c-l> <Plug>NetrwRefresh - imap <buffer> <unique> <c-l> <Plug>NetrwRefresh +" imap <buffer> <unique> <c-l> <c-o><Plug>NetrwRefresh endif - nnoremap <buffer> <silent> <Plug>NetrwRefresh :call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,(w:netrw_liststyle == 3)? w:netrw_treetop : './'))<cr> + nnoremap <buffer> <silent> <Plug>NetrwRefresh <c-l>:call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,(w:netrw_liststyle == 3)? w:netrw_treetop : './'))<cr> if s:didstarstar || !mapcheck("<s-down>","n") nnoremap <buffer> <silent> <s-down> :Nexplore<cr> - inoremap <buffer> <silent> <s-down> :Nexplore<cr> +" inoremap <buffer> <silent> <s-down> <c-o>:Nexplore<cr> endif if s:didstarstar || !mapcheck("<s-up>","n") nnoremap <buffer> <silent> <s-up> :Pexplore<cr> - inoremap <buffer> <silent> <s-up> :Pexplore<cr> +" inoremap <buffer> <silent> <s-up> <c-o>:Pexplore<cr> + endif + if !hasmapto('<Plug>NetrwTreeSqueeze') + nmap <buffer> <silent> <nowait> <s-cr> <Plug>NetrwTreeSqueeze +" imap <buffer> <silent> <nowait> <s-cr> <c-o><Plug>NetrwTreeSqueeze endif + nnoremap <buffer> <silent> <Plug>NetrwTreeSqueeze :call <SID>TreeSqueezeDir(1)<cr> let mapsafecurdir = escape(b:netrw_curdir, s:netrw_map_escape) if g:netrw_mousemaps == 1 - nmap <buffer> <leftmouse> <Plug>NetrwLeftmouse + nmap <buffer> <leftmouse> <Plug>NetrwLeftmouse nno <buffer> <silent> <Plug>NetrwLeftmouse <leftmouse>:call <SID>NetrwLeftmouse(1)<cr> nmap <buffer> <c-leftmouse> <Plug>NetrwCLeftmouse nno <buffer> <silent> <Plug>NetrwCLeftmouse <leftmouse>:call <SID>NetrwCLeftmouse(1)<cr> @@ -6067,14 +6188,14 @@ fun! s:NetrwMaps(islocal) nmap <buffer> <2-leftmouse> <Plug>Netrw2Leftmouse nmap <buffer> <silent> <Plug>Netrw2Leftmouse - imap <buffer> <leftmouse> <Plug>ILeftmouse - ino <buffer> <silent> <Plug>ILeftmouse <c-o><leftmouse><c-o>:call <SID>NetrwLeftmouse(1)<cr> +" ino <buffer> <silent> <Plug>ILeftmouse <c-o><leftmouse><c-o>:call <SID>NetrwLeftmouse(1)<cr> imap <buffer> <middlemouse> <Plug>IMiddlemouse - ino <buffer> <silent> <Plug>IMiddlemouse <c-o><leftmouse><c-o>:call <SID>NetrwPrevWinOpen(1)<cr> - imap <buffer> <s-leftmouse> <Plug>ISLeftmouse - ino <buffer> <silent> <Plug>ISLeftmouse <c-o><leftmouse><c-o>:call <SID>NetrwMarkFile(1,<SID>NetrwGetWord())<cr> +" ino <buffer> <silent> <Plug>IMiddlemouse <c-o><leftmouse><c-o>:call <SID>NetrwPrevWinOpen(1)<cr> +" imap <buffer> <s-leftmouse> <Plug>ISLeftmouse +" ino <buffer> <silent> <Plug>ISLeftmouse <c-o><leftmouse><c-o>:call <SID>NetrwMarkFile(1,<SID>NetrwGetWord())<cr> exe 'nnoremap <buffer> <silent> <rightmouse> <leftmouse>:call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>' exe 'vnoremap <buffer> <silent> <rightmouse> <leftmouse>:call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>' - exe 'inoremap <buffer> <silent> <rightmouse> <c-o><leftmouse><c-o>:call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>' +" exe 'inoremap <buffer> <silent> <rightmouse> <c-o><leftmouse><c-o>:call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>' endif exe 'nnoremap <buffer> <silent> <nowait> <del> :call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>' exe 'nnoremap <buffer> <silent> <nowait> D :call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>' @@ -6083,10 +6204,10 @@ fun! s:NetrwMaps(islocal) exe 'vnoremap <buffer> <silent> <nowait> <del> :call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>' exe 'vnoremap <buffer> <silent> <nowait> D :call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>' exe 'vnoremap <buffer> <silent> <nowait> R :call <SID>NetrwLocalRename("'.mapsafecurdir.'")<cr>' - exe 'inoremap <buffer> <silent> <nowait> <del> <c-o>:call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>' - exe 'inoremap <buffer> <silent> <nowait> D <c-o>:call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>' - exe 'inoremap <buffer> <silent> <nowait> R <c-o>:call <SID>NetrwLocalRename("'.mapsafecurdir.'")<cr>' - exe 'inoremap <buffer> <silent> <nowait> d <c-o>:call <SID>NetrwMakeDir("")<cr>' +" exe 'inoremap <buffer> <silent> <nowait> <del> <c-o>:call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>' +" exe 'inoremap <buffer> <silent> <nowait> D <c-o>:call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>' +" exe 'inoremap <buffer> <silent> <nowait> R <c-o>:call <SID>NetrwLocalRename("'.mapsafecurdir.'")<cr>' +" exe 'inoremap <buffer> <silent> <nowait> d <c-o>:call <SID>NetrwMakeDir("")<cr>' nnoremap <buffer> <F1> :he netrw-quickhelp<cr> " support user-specified maps @@ -6096,13 +6217,24 @@ fun! s:NetrwMaps(islocal) " call Decho("make remote maps",'~'.expand("<slnum>")) call s:RemotePathAnalysis(b:netrw_curdir) " remote normal-mode maps - nnoremap <buffer> <silent> <nowait> <cr> :call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()))<cr> - nnoremap <buffer> <silent> <nowait> <s-cr> :call <SID>TreeSqueezeDir(0)<cr> - nnoremap <buffer> <silent> <nowait> <c-l> :call <SID>NetrwRefresh(0,<SID>NetrwBrowseChgDir(0,'./'))<cr> - nnoremap <buffer> <silent> <nowait> <c-r> :call <SID>NetrwServerEdit(2,<SID>NetrwGetWord())<cr> - nnoremap <buffer> <silent> <nowait> - :call <SID>NetrwBrowseUpDir(0)<cr> - nnoremap <buffer> <silent> <nowait> a :call <SID>NetrwHide(0)<cr> + nnoremap <buffer> <silent> <nowait> a :<c-u>call <SID>NetrwHide(0)<cr> + nnoremap <buffer> <silent> <nowait> - :<c-u>call <SID>NetrwBrowseUpDir(0)<cr> + nnoremap <buffer> <silent> <nowait> % :<c-u>call <SID>NetrwOpenFile(0)<cr> + nnoremap <buffer> <silent> <nowait> C :<c-u>call <SID>NetrwSetChgwin()<cr> + nnoremap <buffer> <silent> <nowait> <c-l> :<c-u>call <SID>NetrwRefresh(0,<SID>NetrwBrowseChgDir(0,'./'))<cr> + nnoremap <buffer> <silent> <nowait> <cr> :<c-u>call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()))<cr> + nnoremap <buffer> <silent> <nowait> <c-r> :<c-u>call <SID>NetrwServerEdit(2,<SID>NetrwGetWord())<cr> + nnoremap <buffer> <silent> <nowait> gb :<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr> + nnoremap <buffer> <silent> <nowait> gd :<c-u>call <SID>NetrwForceChgDir(0,<SID>NetrwGetWord())<cr> + nnoremap <buffer> <silent> <nowait> gf :<c-u>call <SID>NetrwForceFile(0,<SID>NetrwGetWord())<cr> + nnoremap <buffer> <silent> <nowait> gh :<c-u>call <SID>NetrwHidden(0)<cr> + nnoremap <buffer> <silent> <nowait> gp :<c-u>call <SID>NetrwChgPerm(0,b:netrw_curdir)<cr> + nnoremap <buffer> <silent> <nowait> I :<c-u>call <SID>NetrwBannerCtrl(1)<cr> + nnoremap <buffer> <silent> <nowait> i :<c-u>call <SID>NetrwListStyle(0)<cr> + nnoremap <buffer> <silent> <nowait> ma :<c-u>call <SID>NetrwMarkFileArgList(0,0)<cr> + nnoremap <buffer> <silent> <nowait> mA :<c-u>call <SID>NetrwMarkFileArgList(0,1)<cr> nnoremap <buffer> <silent> <nowait> mb :<c-u>call <SID>NetrwBookHistHandler(0,b:netrw_curdir)<cr> + nnoremap <buffer> <silent> <nowait> mB :<c-u>call <SID>NetrwBookHistHandler(6,b:netrw_curdir)<cr> nnoremap <buffer> <silent> <nowait> mc :<c-u>call <SID>NetrwMarkFileCopy(0)<cr> nnoremap <buffer> <silent> <nowait> md :<c-u>call <SID>NetrwMarkFileDiff(0)<cr> nnoremap <buffer> <silent> <nowait> me :<c-u>call <SID>NetrwMarkFileEdit(0)<cr> @@ -6114,99 +6246,96 @@ fun! s:NetrwMaps(islocal) nnoremap <buffer> <silent> <nowait> mp :<c-u>call <SID>NetrwMarkFilePrint(0)<cr> nnoremap <buffer> <silent> <nowait> mr :<c-u>call <SID>NetrwMarkFileRegexp(0)<cr> nnoremap <buffer> <silent> <nowait> ms :<c-u>call <SID>NetrwMarkFileSource(0)<cr> - nnoremap <buffer> <silent> <nowait> mt :<c-u>call <SID>NetrwMarkFileTgt(0)<cr> nnoremap <buffer> <silent> <nowait> mT :<c-u>call <SID>NetrwMarkFileTag(0)<cr> + nnoremap <buffer> <silent> <nowait> mt :<c-u>call <SID>NetrwMarkFileTgt(0)<cr> nnoremap <buffer> <silent> <nowait> mu :<c-u>call <SID>NetrwUnMarkFile(0)<cr> nnoremap <buffer> <silent> <nowait> mv :<c-u>call <SID>NetrwMarkFileVimCmd(0)<cr> nnoremap <buffer> <silent> <nowait> mx :<c-u>call <SID>NetrwMarkFileExe(0,0)<cr> nnoremap <buffer> <silent> <nowait> mX :<c-u>call <SID>NetrwMarkFileExe(0,1)<cr> nnoremap <buffer> <silent> <nowait> mz :<c-u>call <SID>NetrwMarkFileCompress(0)<cr> - nnoremap <buffer> <silent> <nowait> gb :<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr> - nnoremap <buffer> <silent> <nowait> gd :<c-u>call <SID>NetrwForceChgDir(0,<SID>NetrwGetWord())<cr> - nnoremap <buffer> <silent> <nowait> gf :<c-u>call <SID>NetrwForceFile(0,<SID>NetrwGetWord())<cr> - nnoremap <buffer> <silent> <nowait> gh :<c-u>call <SID>NetrwHidden(0)<cr> - nnoremap <buffer> <silent> <nowait> gp :<c-u>call <SID>NetrwChgPerm(0,b:netrw_curdir)<cr> - nnoremap <buffer> <silent> <nowait> C :<c-u>call <SID>NetrwSetChgwin()<cr> - nnoremap <buffer> <silent> <nowait> i :call <SID>NetrwListStyle(0)<cr> - nnoremap <buffer> <silent> <nowait> I :call <SID>NetrwBannerCtrl(1)<cr> - nnoremap <buffer> <silent> <nowait> o :call <SID>NetrwSplit(0)<cr> - nnoremap <buffer> <silent> <nowait> O :call <SID>NetrwObtain(0)<cr> - nnoremap <buffer> <silent> <nowait> p :call <SID>NetrwPreview(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1))<cr> - nnoremap <buffer> <silent> <nowait> P :call <SID>NetrwPrevWinOpen(0)<cr> + nnoremap <buffer> <silent> <nowait> O :<c-u>call <SID>NetrwObtain(0)<cr> + nnoremap <buffer> <silent> <nowait> o :call <SID>NetrwSplit(0)<cr> + nnoremap <buffer> <silent> <nowait> p :<c-u>call <SID>NetrwPreview(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1))<cr> + nnoremap <buffer> <silent> <nowait> P :<c-u>call <SID>NetrwPrevWinOpen(0)<cr> nnoremap <buffer> <silent> <nowait> qb :<c-u>call <SID>NetrwBookHistHandler(2,b:netrw_curdir)<cr> - nnoremap <buffer> <silent> <nowait> mB :<c-u>call <SID>NetrwBookHistHandler(6,b:netrw_curdir)<cr> nnoremap <buffer> <silent> <nowait> qf :<c-u>call <SID>NetrwFileInfo(0,<SID>NetrwGetWord())<cr> nnoremap <buffer> <silent> <nowait> qF :<c-u>call <SID>NetrwMarkFileQFEL(0,getqflist())<cr> - nnoremap <buffer> <silent> <nowait> r :let g:netrw_sort_direction= (g:netrw_sort_direction =~ 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,'./'))<cr> - nnoremap <buffer> <silent> <nowait> s :call <SID>NetrwSortStyle(0)<cr> - nnoremap <buffer> <silent> <nowait> S :call <SID>NetSortSequence(0)<cr> - nnoremap <buffer> <silent> <nowait> t :call <SID>NetrwSplit(1)<cr> - nnoremap <buffer> <silent> <nowait> Tb :<c-u>call <SID>NetrwSetTgt('b',v:count1)<cr> - nnoremap <buffer> <silent> <nowait> Th :<c-u>call <SID>NetrwSetTgt('h',v:count)<cr> - nnoremap <buffer> <silent> <nowait> u :<c-u>call <SID>NetrwBookHistHandler(4,b:netrw_curdir)<cr> - nnoremap <buffer> <silent> <nowait> U :<c-u>call <SID>NetrwBookHistHandler(5,b:netrw_curdir)<cr> - nnoremap <buffer> <silent> <nowait> v :call <SID>NetrwSplit(2)<cr> - nnoremap <buffer> <silent> <nowait> x :call netrw#BrowseX(<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()),1)<cr> - nnoremap <buffer> <silent> <nowait> % :call <SID>NetrwOpenFile(0)<cr> - " remote insert-mode maps - inoremap <buffer> <silent> <nowait> <cr> <c-o>:call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()))<cr> - inoremap <buffer> <silent> <nowait> <c-l> <c-o>:call <SID>NetrwRefresh(0,<SID>NetrwBrowseChgDir(0,'./'))<cr> - inoremap <buffer> <silent> <nowait> <s-cr> <c-o>:call <SID>TreeSqueezeDir(0)<cr> - inoremap <buffer> <silent> <nowait> - <c-o>:call <SID>NetrwBrowseUpDir(0)<cr> - inoremap <buffer> <silent> <nowait> a <c-o>:call <SID>NetrwHide(0)<cr> - inoremap <buffer> <silent> <nowait> mb <c-o>:<c-u>call <SID>NetrwBookHistHandler(0,b:netrw_curdir)<cr> - inoremap <buffer> <silent> <nowait> mc <c-o>:<c-u>call <SID>NetrwMarkFileCopy(0)<cr> - inoremap <buffer> <silent> <nowait> md <c-o>:<c-u>call <SID>NetrwMarkFileDiff(0)<cr> - inoremap <buffer> <silent> <nowait> me <c-o>:<c-u>call <SID>NetrwMarkFileEdit(0)<cr> - inoremap <buffer> <silent> <nowait> mf <c-o>:<c-u>call <SID>NetrwMarkFile(0,<SID>NetrwGetWord())<cr> - inoremap <buffer> <silent> <nowait> mg <c-o>:<c-u>call <SID>NetrwMarkFileGrep(0)<cr> - inoremap <buffer> <silent> <nowait> mh <c-o>:<c-u>call <SID>NetrwMarkHideSfx(0)<cr> - inoremap <buffer> <silent> <nowait> mm <c-o>:<c-u>call <SID>NetrwMarkFileMove(0)<cr> - inoremap <buffer> <silent> <nowait> mp <c-o>:<c-u>call <SID>NetrwMarkFilePrint(0)<cr> - inoremap <buffer> <silent> <nowait> mr <c-o>:<c-u>call <SID>NetrwMarkFileRegexp(0)<cr> - inoremap <buffer> <silent> <nowait> ms <c-o>:<c-u>call <SID>NetrwMarkFileSource(0)<cr> - inoremap <buffer> <silent> <nowait> mt <c-o>:<c-u>call <SID>NetrwMarkFileTgt(0)<cr> - inoremap <buffer> <silent> <nowait> mT <c-o>:<c-u>call <SID>NetrwMarkFileTag(0)<cr> - inoremap <buffer> <silent> <nowait> mu <c-o>:<c-u>call <SID>NetrwUnMarkFile(0)<cr> - nnoremap <buffer> <silent> <nowait> mv :<c-u>call <SID>NetrwMarkFileVimCmd(1)<cr> - inoremap <buffer> <silent> <nowait> mx <c-o>:<c-u>call <SID>NetrwMarkFileExe(0,0)<cr> - inoremap <buffer> <silent> <nowait> mX <c-o>:<c-u>call <SID>NetrwMarkFileExe(0,1)<cr> - inoremap <buffer> <silent> <nowait> mv <c-o>:<c-u>call <SID>NetrwMarkFileVimCmd(0)<cr> - inoremap <buffer> <silent> <nowait> mz <c-o>:<c-u>call <SID>NetrwMarkFileCompress(0)<cr> - inoremap <buffer> <silent> <nowait> gb <c-o>:<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr> - inoremap <buffer> <silent> <nowait> gh <c-o>:<c-u>call <SID>NetrwHidden(0)<cr> - inoremap <buffer> <silent> <nowait> gp <c-o>:<c-u>call <SID>NetrwChgPerm(0,b:netrw_curdir)<cr> - inoremap <buffer> <silent> <nowait> C <c-o>:call <SID>NetrwSetChgwin()<cr> - inoremap <buffer> <silent> <nowait> i <c-o>:call <SID>NetrwListStyle(0)<cr> - inoremap <buffer> <silent> <nowait> I <c-o>:call <SID>NetrwBannerCtrl(1)<cr> - inoremap <buffer> <silent> <nowait> o <c-o>:call <SID>NetrwSplit(0)<cr> - inoremap <buffer> <silent> <nowait> O <c-o>:call <SID>NetrwObtain(0)<cr> - inoremap <buffer> <silent> <nowait> p <c-o>:call <SID>NetrwPreview(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1))<cr> - inoremap <buffer> <silent> <nowait> P <c-o>:call <SID>NetrwPrevWinOpen(0)<cr> - inoremap <buffer> <silent> <nowait> qb <c-o>:<c-u>call <SID>NetrwBookHistHandler(2,b:netrw_curdir)<cr> - inoremap <buffer> <silent> <nowait> mB <c-o>:<c-u>call <SID>NetrwBookHistHandler(6,b:netrw_curdir)<cr> - inoremap <buffer> <silent> <nowait> qf <c-o>:<c-u>call <SID>NetrwFileInfo(0,<SID>NetrwGetWord())<cr> - inoremap <buffer> <silent> <nowait> qF :<c-u>call <SID>NetrwMarkFileQFEL(0,getqflist())<cr> - inoremap <buffer> <silent> <nowait> r <c-o>:let g:netrw_sort_direction= (g:netrw_sort_direction =~ 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,'./'))<cr> - inoremap <buffer> <silent> <nowait> s <c-o>:call <SID>NetrwSortStyle(0)<cr> - inoremap <buffer> <silent> <nowait> S <c-o>:call <SID>NetSortSequence(0)<cr> - inoremap <buffer> <silent> <nowait> t <c-o>:call <SID>NetrwSplit(1)<cr> - inoremap <buffer> <silent> <nowait> Tb <c-o>:<c-u>call <SID>NetrwSetTgt('b',v:count1)<cr> - inoremap <buffer> <silent> <nowait> Th <c-o>:<c-u>call <SID>NetrwSetTgt('h',v:count)<cr> - inoremap <buffer> <silent> <nowait> u <c-o>:<c-u>call <SID>NetrwBookHistHandler(4,b:netrw_curdir)<cr> - inoremap <buffer> <silent> <nowait> U <c-o>:<c-u>call <SID>NetrwBookHistHandler(5,b:netrw_curdir)<cr> - inoremap <buffer> <silent> <nowait> v <c-o>:call <SID>NetrwSplit(2)<cr> - inoremap <buffer> <silent> <nowait> x <c-o>:call netrw#BrowseX(<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()),1)<cr> - inoremap <buffer> <silent> <nowait> % <c-o>:call <SID>NetrwOpenFile(0)<cr> + nnoremap <buffer> <silent> <nowait> qL :<c-u>call <SID>NetrwMarkFileQFEL(0,getloclist(v:count))<cr> + nnoremap <buffer> <silent> <nowait> r :<c-u>let g:netrw_sort_direction= (g:netrw_sort_direction =~ 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,'./'))<cr> + nnoremap <buffer> <silent> <nowait> s :call <SID>NetrwSortStyle(0)<cr> + nnoremap <buffer> <silent> <nowait> S :<c-u>call <SID>NetSortSequence(0)<cr> + nnoremap <buffer> <silent> <nowait> Tb :<c-u>call <SID>NetrwSetTgt(0,'b',v:count1)<cr> + nnoremap <buffer> <silent> <nowait> t :call <SID>NetrwSplit(1)<cr> + nnoremap <buffer> <silent> <nowait> Th :<c-u>call <SID>NetrwSetTgt(0,'h',v:count)<cr> + nnoremap <buffer> <silent> <nowait> u :<c-u>call <SID>NetrwBookHistHandler(4,b:netrw_curdir)<cr> + nnoremap <buffer> <silent> <nowait> U :<c-u>call <SID>NetrwBookHistHandler(5,b:netrw_curdir)<cr> + nnoremap <buffer> <silent> <nowait> v :call <SID>NetrwSplit(2)<cr> + nnoremap <buffer> <silent> <nowait> x :<c-u>call netrw#BrowseX(<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()),1)<cr> +" " remote insert-mode maps +" inoremap <buffer> <silent> <nowait> <cr> <c-o>:call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()))<cr> +" inoremap <buffer> <silent> <nowait> <c-l> <c-o>:call <SID>NetrwRefresh(0,<SID>NetrwBrowseChgDir(0,'./'))<cr> +" inoremap <buffer> <silent> <nowait> <s-cr> <c-o>:call <SID>TreeSqueezeDir(0)<cr> +" inoremap <buffer> <silent> <nowait> - <c-o>:call <SID>NetrwBrowseUpDir(0)<cr> +" inoremap <buffer> <silent> <nowait> a <c-o>:call <SID>NetrwHide(0)<cr> +" inoremap <buffer> <silent> <nowait> mb <c-o>:<c-u>call <SID>NetrwBookHistHandler(0,b:netrw_curdir)<cr> +" inoremap <buffer> <silent> <nowait> mc <c-o>:<c-u>call <SID>NetrwMarkFileCopy(0)<cr> +" inoremap <buffer> <silent> <nowait> md <c-o>:<c-u>call <SID>NetrwMarkFileDiff(0)<cr> +" inoremap <buffer> <silent> <nowait> me <c-o>:<c-u>call <SID>NetrwMarkFileEdit(0)<cr> +" inoremap <buffer> <silent> <nowait> mf <c-o>:<c-u>call <SID>NetrwMarkFile(0,<SID>NetrwGetWord())<cr> +" inoremap <buffer> <silent> <nowait> mg <c-o>:<c-u>call <SID>NetrwMarkFileGrep(0)<cr> +" inoremap <buffer> <silent> <nowait> mh <c-o>:<c-u>call <SID>NetrwMarkHideSfx(0)<cr> +" inoremap <buffer> <silent> <nowait> mm <c-o>:<c-u>call <SID>NetrwMarkFileMove(0)<cr> +" inoremap <buffer> <silent> <nowait> mp <c-o>:<c-u>call <SID>NetrwMarkFilePrint(0)<cr> +" inoremap <buffer> <silent> <nowait> mr <c-o>:<c-u>call <SID>NetrwMarkFileRegexp(0)<cr> +" inoremap <buffer> <silent> <nowait> ms <c-o>:<c-u>call <SID>NetrwMarkFileSource(0)<cr> +" inoremap <buffer> <silent> <nowait> mt <c-o>:<c-u>call <SID>NetrwMarkFileTgt(0)<cr> +" inoremap <buffer> <silent> <nowait> mT <c-o>:<c-u>call <SID>NetrwMarkFileTag(0)<cr> +" inoremap <buffer> <silent> <nowait> mu <c-o>:<c-u>call <SID>NetrwUnMarkFile(0)<cr> +" nnoremap <buffer> <silent> <nowait> mv :<c-u>call <SID>NetrwMarkFileVimCmd(1)<cr> +" inoremap <buffer> <silent> <nowait> mx <c-o>:<c-u>call <SID>NetrwMarkFileExe(0,0)<cr> +" inoremap <buffer> <silent> <nowait> mX <c-o>:<c-u>call <SID>NetrwMarkFileExe(0,1)<cr> +" inoremap <buffer> <silent> <nowait> mv <c-o>:<c-u>call <SID>NetrwMarkFileVimCmd(0)<cr> +" inoremap <buffer> <silent> <nowait> mz <c-o>:<c-u>call <SID>NetrwMarkFileCompress(0)<cr> +" inoremap <buffer> <silent> <nowait> gb <c-o>:<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr> +" inoremap <buffer> <silent> <nowait> gh <c-o>:<c-u>call <SID>NetrwHidden(0)<cr> +" inoremap <buffer> <silent> <nowait> gp <c-o>:<c-u>call <SID>NetrwChgPerm(0,b:netrw_curdir)<cr> +" inoremap <buffer> <silent> <nowait> C <c-o>:call <SID>NetrwSetChgwin()<cr> +" inoremap <buffer> <silent> <nowait> i <c-o>:call <SID>NetrwListStyle(0)<cr> +" inoremap <buffer> <silent> <nowait> I <c-o>:call <SID>NetrwBannerCtrl(1)<cr> +" inoremap <buffer> <silent> <nowait> o <c-o>:call <SID>NetrwSplit(0)<cr> +" inoremap <buffer> <silent> <nowait> O <c-o>:call <SID>NetrwObtain(0)<cr> +" inoremap <buffer> <silent> <nowait> p <c-o>:call <SID>NetrwPreview(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1))<cr> +" inoremap <buffer> <silent> <nowait> P <c-o>:call <SID>NetrwPrevWinOpen(0)<cr> +" inoremap <buffer> <silent> <nowait> qb <c-o>:<c-u>call <SID>NetrwBookHistHandler(2,b:netrw_curdir)<cr> +" inoremap <buffer> <silent> <nowait> mB <c-o>:<c-u>call <SID>NetrwBookHistHandler(6,b:netrw_curdir)<cr> +" inoremap <buffer> <silent> <nowait> qf <c-o>:<c-u>call <SID>NetrwFileInfo(0,<SID>NetrwGetWord())<cr> +" inoremap <buffer> <silent> <nowait> qF :<c-u>call <SID>NetrwMarkFileQFEL(0,getqflist())<cr> +" inoremap <buffer> <silent> <nowait> qL :<c-u>call <SID>NetrwMarkFileQFEL(0,getloclist(v:count))<cr> +" inoremap <buffer> <silent> <nowait> r <c-o>:let g:netrw_sort_direction= (g:netrw_sort_direction =~ 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,'./'))<cr> +" inoremap <buffer> <silent> <nowait> s <c-o>:call <SID>NetrwSortStyle(0)<cr> +" inoremap <buffer> <silent> <nowait> S <c-o>:call <SID>NetSortSequence(0)<cr> +" inoremap <buffer> <silent> <nowait> t <c-o>:call <SID>NetrwSplit(1)<cr> +" inoremap <buffer> <silent> <nowait> Tb <c-o>:<c-u>call <SID>NetrwSetTgt('b',v:count1)<cr> +" inoremap <buffer> <silent> <nowait> Th <c-o>:<c-u>call <SID>NetrwSetTgt('h',v:count)<cr> +" inoremap <buffer> <silent> <nowait> u <c-o>:<c-u>call <SID>NetrwBookHistHandler(4,b:netrw_curdir)<cr> +" inoremap <buffer> <silent> <nowait> U <c-o>:<c-u>call <SID>NetrwBookHistHandler(5,b:netrw_curdir)<cr> +" inoremap <buffer> <silent> <nowait> v <c-o>:call <SID>NetrwSplit(2)<cr> +" inoremap <buffer> <silent> <nowait> x <c-o>:call netrw#BrowseX(<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()),1)<cr> +" inoremap <buffer> <silent> <nowait> % <c-o>:call <SID>NetrwOpenFile(0)<cr> if !hasmapto('<Plug>NetrwHideEdit') nmap <buffer> <c-h> <Plug>NetrwHideEdit - imap <buffer> <c-h> <Plug>NetrwHideEdit +" imap <buffer> <c-h> <Plug>NetrwHideEdit endif nnoremap <buffer> <silent> <Plug>NetrwHideEdit :call <SID>NetrwHideEdit(0)<cr> if !hasmapto('<Plug>NetrwRefresh') nmap <buffer> <c-l> <Plug>NetrwRefresh - imap <buffer> <c-l> <Plug>NetrwRefresh +" imap <buffer> <c-l> <Plug>NetrwRefresh endif + if !hasmapto('<Plug>NetrwTreeSqueeze') + nmap <buffer> <silent> <nowait> <s-cr> <Plug>NetrwTreeSqueeze +" imap <buffer> <silent> <nowait> <s-cr> <c-o><Plug>NetrwTreeSqueeze + endif + nnoremap <buffer> <silent> <Plug>NetrwTreeSqueeze :call <SID>TreeSqueezeDir(0)<cr> let mapsafepath = escape(s:path, s:netrw_map_escape) let mapsafeusermach = escape(((s:user == "")? "" : s:user."@").s:machine, s:netrw_map_escape) @@ -6226,14 +6355,14 @@ fun! s:NetrwMaps(islocal) nmap <buffer> <2-leftmouse> <Plug>Netrw2Leftmouse nmap <buffer> <silent> <Plug>Netrw2Leftmouse - imap <buffer> <leftmouse> <Plug>ILeftmouse - ino <buffer> <silent> <Plug>ILeftmouse <c-o><leftmouse><c-o>:call <SID>NetrwLeftmouse(0)<cr> +" ino <buffer> <silent> <Plug>ILeftmouse <c-o><leftmouse><c-o>:call <SID>NetrwLeftmouse(0)<cr> imap <buffer> <middlemouse> <Plug>IMiddlemouse - ino <buffer> <silent> <Plug>IMiddlemouse <c-o><leftmouse><c-o>:call <SID>NetrwPrevWinOpen(0)<cr> +" ino <buffer> <silent> <Plug>IMiddlemouse <c-o><leftmouse><c-o>:call <SID>NetrwPrevWinOpen(0)<cr> imap <buffer> <s-leftmouse> <Plug>ISLeftmouse - ino <buffer> <silent> <Plug>ISLeftmouse <c-o><leftmouse><c-o>:call <SID>NetrwMarkFile(0,<SID>NetrwGetWord())<cr> +" ino <buffer> <silent> <Plug>ISLeftmouse <c-o><leftmouse><c-o>:call <SID>NetrwMarkFile(0,<SID>NetrwGetWord())<cr> exe 'nnoremap <buffer> <silent> <rightmouse> <leftmouse>:call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>' exe 'vnoremap <buffer> <silent> <rightmouse> <leftmouse>:call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>' - exe 'inoremap <buffer> <silent> <rightmouse> <c-o><leftmouse><c-o>:call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>' +" exe 'inoremap <buffer> <silent> <rightmouse> <c-o><leftmouse><c-o>:call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>' endif exe 'nnoremap <buffer> <silent> <nowait> <del> :call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>' exe 'nnoremap <buffer> <silent> <nowait> d :call <SID>NetrwMakeDir("'.mapsafeusermach.'")<cr>' @@ -6242,12 +6371,12 @@ fun! s:NetrwMaps(islocal) exe 'vnoremap <buffer> <silent> <nowait> <del> :call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>' exe 'vnoremap <buffer> <silent> <nowait> D :call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>' exe 'vnoremap <buffer> <silent> <nowait> R :call <SID>NetrwRemoteRename("'.mapsafeusermach.'","'.mapsafepath.'")<cr>' - exe 'inoremap <buffer> <silent> <nowait> <del> <c-o>:call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>' - exe 'inoremap <buffer> <silent> <nowait> d <c-o>:call <SID>NetrwMakeDir("'.mapsafeusermach.'")<cr>' - exe 'inoremap <buffer> <silent> <nowait> D <c-o>:call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>' - exe 'inoremap <buffer> <silent> <nowait> R <c-o>:call <SID>NetrwRemoteRename("'.mapsafeusermach.'","'.mapsafepath.'")<cr>' +" exe 'inoremap <buffer> <silent> <nowait> <del> <c-o>:call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>' +" exe 'inoremap <buffer> <silent> <nowait> d <c-o>:call <SID>NetrwMakeDir("'.mapsafeusermach.'")<cr>' +" exe 'inoremap <buffer> <silent> <nowait> D <c-o>:call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>' +" exe 'inoremap <buffer> <silent> <nowait> R <c-o>:call <SID>NetrwRemoteRename("'.mapsafeusermach.'","'.mapsafepath.'")<cr>' nnoremap <buffer> <F1> :he netrw-quickhelp<cr> - inoremap <buffer> <F1> <c-o>:he netrw-quickhelp<cr> +" inoremap <buffer> <F1> <c-o>:he netrw-quickhelp<cr> " support user-specified maps call netrw#UserMaps(0) @@ -6257,7 +6386,7 @@ fun! s:NetrwMaps(islocal) endfun " --------------------------------------------------------------------- -" s:NetrwCommands: sets up commands {{{2 +" s:NetrwCommands: set up commands {{{2 " If -buffer, the command is only available from within netrw buffers " Otherwise, the command is available from any window, so long as netrw " has been used at least once in the session. @@ -6266,7 +6395,7 @@ fun! s:NetrwCommands(islocal) com! -nargs=* -complete=file -bang NetrwMB call s:NetrwBookmark(<bang>0,<f-args>) com! -nargs=* NetrwC call s:NetrwSetChgwin(<q-args>) - com! Rexplore if exists("w:netrw_rexlocal")|call s:NetrwRexplore(w:netrw_rexlocal,exists("w:netrw_rexdir")? w:netrw_rexdir : ".")|else|call netrw#ErrorMsg(s:WARNING,"not a former netrw window",79)|endif + com! Rexplore if exists("w:netrw_rexlocal")|call s:NetrwRexplore(w:netrw_rexlocal,exists("w:netrw_rexdir")? w:netrw_rexdir : ".")|else|call netrw#ErrorMsg(s:WARNING,"win#".winnr()." not a former netrw window",79)|endif if a:islocal com! -buffer -nargs=+ -complete=file MF call s:NetrwMarkFiles(1,<f-args>) else @@ -6319,9 +6448,11 @@ fun! s:NetrwMarkTarget(...) let s:netrwmftgt = tgt let s:netrwmftgt_islocal = tgt !~ '^\a\{3,}://' let curislocal = b:netrw_curdir !~ '^\a\{3,}://' - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) call s:NetrwRefresh(curislocal,s:NetrwBrowseChgDir(curislocal,'./')) - call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + call winrestview(svpos) " call Dret("s:NetrwMarkTarget") endfun @@ -6460,6 +6591,48 @@ fun! s:NetrwMarkFile(islocal,fname) endfun " --------------------------------------------------------------------- +" s:NetrwMarkFileArgList: ma: move the marked file list to the argument list (tomflist=0) {{{2 +" mA: move the argument list to marked file list (tomflist=1) +" Uses the global marked file list +fun! s:NetrwMarkFileArgList(islocal,tomflist) +" call Dfunc("s:NetrwMarkFileArgList(islocal=".a:islocal.",tomflist=".a:tomflist.")") + + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + let curdir = s:NetrwGetCurdir(a:islocal) + let curbufnr = bufnr("%") + + if a:tomflist + " mA: move argument list to marked file list + while argc() + let fname= argv(0) +" call Decho("exe argdel ".fname,'~'.expand("<slnum>")) + exe "argdel ".fnameescape(fname) + call s:NetrwMarkFile(a:islocal,fname) + endwhile + + else + " ma: move marked file list to argument list + if exists("s:netrwmarkfilelist") + + " for every filename in the marked list + for fname in s:netrwmarkfilelist +" call Decho("exe argadd ".fname,'~'.expand("<slnum>")) + exe "argadd ".fnameescape(fname) + endfor " for every file in the marked list + + " unmark list and refresh + call s:NetrwUnmarkList(curbufnr,curdir) + NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) + endif + endif + +" call Dret("s:NetrwMarkFileArgList") +endfun + +" --------------------------------------------------------------------- " s:NetrwMarkFileCompress: (invoked by mz) This function is used to {{{2 " compress/decompress files using the programs " in g:netrw_compress and g:netrw_uncompress, @@ -6469,7 +6642,8 @@ endfun " g:netrw_decompress = { ".gz" : "gunzip" , ".bz2" : "bunzip2" , ".zip" : "unzip" , ".tar" : "tar -xf", ".xz" : "unxz"} fun! s:NetrwMarkFileCompress(islocal) " call Dfunc("s:NetrwMarkFileCompress(islocal=".a:islocal.")") - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let curdir = s:NetrwGetCurdir(a:islocal) let curbufnr = bufnr("%") @@ -6524,7 +6698,8 @@ fun! s:NetrwMarkFileCompress(islocal) call s:NetrwUnmarkList(curbufnr,curdir) NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) endif " call Dret("s:NetrwMarkFileCompress") endfun @@ -6541,6 +6716,12 @@ fun! s:NetrwMarkFileCopy(islocal,...) let curdir = s:NetrwGetCurdir(a:islocal) let curbufnr = bufnr("%") + if b:netrw_curdir !~ '/$' + if !exists("b:netrw_curdir") + let b:netrw_curdir= curdir + endif + let b:netrw_curdir= b:netrw_curdir."/" + endif " sanity check if !exists("s:netrwmarkfilelist_{curbufnr}") || empty(s:netrwmarkfilelist_{curbufnr}) @@ -6557,7 +6738,7 @@ fun! s:NetrwMarkFileCopy(islocal,...) endif " call Decho("sanity chk passed: s:netrwmftgt<".s:netrwmftgt.">",'~'.expand("<slnum>")) - if a:islocal && s:netrwmftgt_islocal + if a:islocal && s:netrwmftgt_islocal " Copy marked files, local directory to local directory " call Decho("copy from local to local",'~'.expand("<slnum>")) if !executable(g:netrw_localcopycmd) && g:netrw_localcopycmd !~ '^'.expand("$COMSPEC").'\s' @@ -6571,12 +6752,12 @@ fun! s:NetrwMarkFileCopy(islocal,...) if len(s:netrwmarkfilelist_{bufnr('%')}) == 1 " only one marked file " call Decho("case: only one marked file",'~'.expand("<slnum>")) - let args = s:ShellEscape(b:netrw_curdir."/".s:netrwmarkfilelist_{bufnr('%')}[0]) + let args = s:ShellEscape(b:netrw_curdir.s:netrwmarkfilelist_{bufnr('%')}[0]) let oldname = s:netrwmarkfilelist_{bufnr('%')}[0] elseif a:0 == 1 " call Decho("case: handling one input argument",'~'.expand("<slnum>")) " this happens when the next case was used to recursively call s:NetrwMarkFileCopy() - let args = s:ShellEscape(b:netrw_curdir."/".a:1) + let args = s:ShellEscape(b:netrw_curdir.a:1) let oldname = a:1 else " copy multiple marked files inside the same directory @@ -6611,9 +6792,12 @@ fun! s:NetrwMarkFileCopy(islocal,...) let args= substitute(args,'/','\\','g') let tgt = substitute(tgt, '/','\\','g') endif - if args =~ "'"|let args= substitute(args,"'\\(.*\\)'",'\1','')|endif - if tgt =~ "'"|let tgt = substitute(tgt,"'\\(.*\\)'",'\1','') |endif - if args =~ '//$'|let args= substitute(args,'//$','/','')|endif + if args =~ "'" |let args= substitute(args,"'\\(.*\\)'",'\1','')|endif + if tgt =~ "'" |let tgt = substitute(tgt ,"'\\(.*\\)'",'\1','')|endif + if args =~ '//'|let args= substitute(args,'//','/','g')|endif + if tgt =~ '//'|let tgt = substitute(tgt ,'//','/','g')|endif +" call Decho("args <".args.">",'~'.expand("<slnum>")) +" call Decho("tgt <".tgt.">",'~'.expand("<slnum>")) if isdirectory(s:NetrwFile(args)) " call Decho("args<".args."> is a directory",'~'.expand("<slnum>")) let copycmd= g:netrw_localcopydircmd @@ -6688,11 +6872,17 @@ fun! s:NetrwMarkFileCopy(islocal,...) NetrwKeepj call s:NetrwDelete(fname) endfor call s:NetrwLcd(curdir) - call s:NetrwExe("sil !".g:netrw_localrmdir." ".s:ShellEscape(tmpdir,1)) - if v:shell_error != 0 - call netrw#ErrorMsg(s:WARNING,"consider setting g:netrw_localrmdir<".g:netrw_localrmdir."> to something that works",80) -" call Dret("s:NetrwMarkFileCopy : failed: sil !".g:netrw_localrmdir." ".s:ShellEscape(tmpdir,1) ) - return + if v:version < 704 || !has("patch1109") + call s:NetrwExe("sil !".g:netrw_localrmdir." ".s:ShellEscape(tmpdir,1)) + if v:shell_error != 0 + call netrw#ErrorMsg(s:WARNING,"consider setting g:netrw_localrmdir<".g:netrw_localrmdir."> to something that works",80) +" " call Dret("s:NetrwMarkFileCopy : failed: sil !".g:netrw_localrmdir." ".s:ShellEscape(tmpdir,1) ) + return + endif + else + if delete(tmpdir,"d") + call netrw#ErrorMsg(s:ERROR,"unable to delete directory <".tmpdir.">!",103) + endif endif else call s:NetrwLcd(curdir) @@ -6703,21 +6893,38 @@ fun! s:NetrwMarkFileCopy(islocal,...) " ------- " cleanup " ------- -" call Decho("cleanup",'~'.expand("<slnum>")) - if !exists("s:recursive") - " remove markings from local buffer - call s:NetrwUnmarkList(curbufnr,curdir) - endif - - " refresh buffers - if !s:netrwmftgt_islocal - call s:NetrwRefreshDir(s:netrwmftgt_islocal,s:netrwmftgt) - endif - if a:islocal - NetrwKeepj call s:NetrwRefreshDir(a:islocal,curdir) +" call Decho("cleanup",'~'.expand("<slnum>")) +" call Decho(" g:netrw_fastbrowse =".g:netrw_fastbrowse,'~'.expand("<slnum>")) +" call Decho(" s:netrwmftgt =".s:netrwmftgt,'~'.expand("<slnum>")) +" call Decho(" s:netrwmftgt_islocal=".s:netrwmftgt_islocal,'~'.expand("<slnum>")) +" call Decho(" curdir =".curdir,'~'.expand("<slnum>")) +" call Decho(" a:islocal =".a:islocal,'~'.expand("<slnum>")) +" call Decho(" curbufnr =".curbufnr,'~'.expand("<slnum>")) + if exists("s:recursive") +" call Decho(" s:recursive =".s:recursive,'~'.expand("<slnum>")) + else +" call Decho(" s:recursive =n/a",'~'.expand("<slnum>")) endif + " see s:LocalFastBrowser() for g:netrw_fastbrowse interpretation (refreshing done for both slow and medium) if g:netrw_fastbrowse <= 1 NetrwKeepj call s:LocalBrowseRefresh() + else + " refresh local and targets for fast browsing + if !exists("s:recursive") + " remove markings from local buffer +" call Decho(" remove markings from local buffer",'~'.expand("<slnum>")) + NetrwKeepj call s:NetrwUnmarkList(curbufnr,curdir) + endif + + " refresh buffers + if s:netrwmftgt_islocal +" call Decho(" refresh s:netrwmftgt=".s:netrwmftgt,'~'.expand("<slnum>")) + NetrwKeepj call s:NetrwRefreshDir(s:netrwmftgt_islocal,s:netrwmftgt) + endif + if a:islocal && s:netrwmftgt != curdir +" call Decho(" refresh curdir=".curdir,'~'.expand("<slnum>")) + NetrwKeepj call s:NetrwRefreshDir(a:islocal,curdir) + endif endif " call Dret("s:NetrwMarkFileCopy 1") @@ -6798,7 +7005,7 @@ fun! s:NetrwMarkFileEdit(islocal) endfun " --------------------------------------------------------------------- -" s:NetrwMarkFileQFEL: convert a quickfix-error list into a marked file list {{{2 +" s:NetrwMarkFileQFEL: convert a quickfix-error or location list into a marked file list {{{2 fun! s:NetrwMarkFileQFEL(islocal,qfel) " call Dfunc("s:NetrwMarkFileQFEL(islocal=".a:islocal.",qfel)") call s:NetrwUnmarkAll() @@ -6834,7 +7041,8 @@ endfun " mX enbloc=1: Uses the global marked-file list, applies command to entire list fun! s:NetrwMarkFileExe(islocal,enbloc) " call Dfunc("s:NetrwMarkFileExe(islocal=".a:islocal.",enbloc=".a:enbloc.")") - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let curdir = s:NetrwGetCurdir(a:islocal) let curbufnr = bufnr("%") @@ -6894,7 +7102,8 @@ fun! s:NetrwMarkFileExe(islocal,enbloc) " refresh the listing NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) else NetrwKeepj call netrw#ErrorMsg(s:ERROR,"no files marked!",59) endif @@ -6926,7 +7135,8 @@ fun! s:NetrwMarkFileExe(islocal,enbloc) " refresh the listing NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) endif @@ -6939,7 +7149,8 @@ endfun " Uses the local marked file list. fun! s:NetrwMarkHideSfx(islocal) " call Dfunc("s:NetrwMarkHideSfx(islocal=".a:islocal.")") - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let curbufnr = bufnr("%") " s:netrwmarkfilelist_{curbufnr}: the List of marked files @@ -6982,7 +7193,8 @@ fun! s:NetrwMarkHideSfx(islocal) " refresh the listing NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) else NetrwKeepj call netrw#ErrorMsg(s:ERROR,"no files marked!",59) endif @@ -6995,7 +7207,8 @@ endfun " Uses the local marked-file list. fun! s:NetrwMarkFileVimCmd(islocal) " call Dfunc("s:NetrwMarkFileVimCmd(islocal=".a:islocal.")") - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let curdir = s:NetrwGetCurdir(a:islocal) let curbufnr = bufnr("%") @@ -7039,7 +7252,8 @@ fun! s:NetrwMarkFileVimCmd(islocal) " refresh the listing NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) else NetrwKeepj call netrw#ErrorMsg(s:ERROR,"no files marked!",59) endif @@ -7053,7 +7267,8 @@ endfun " Uses the local marked file list. fun! s:NetrwMarkHideSfx(islocal) " call Dfunc("s:NetrwMarkHideSfx(islocal=".a:islocal.")") - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let curbufnr = bufnr("%") " s:netrwmarkfilelist_{curbufnr}: the List of marked files @@ -7096,7 +7311,8 @@ fun! s:NetrwMarkHideSfx(islocal) " refresh the listing NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) else NetrwKeepj call netrw#ErrorMsg(s:ERROR,"no files marked!",59) endif @@ -7109,7 +7325,8 @@ endfun " Uses the global markfilelist fun! s:NetrwMarkFileGrep(islocal) " call Dfunc("s:NetrwMarkFileGrep(islocal=".a:islocal.")") - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let curbufnr = bufnr("%") let curdir = s:NetrwGetCurdir(a:islocal) @@ -7150,7 +7367,8 @@ fun! s:NetrwMarkFileGrep(islocal) echo "(use :cn, :cp to navigate, :Rex to return)" 2match none - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) if exists("nonisi") " original, user-supplied pattern did not begin with a character from isident @@ -7456,7 +7674,8 @@ endfun " Uses the global markfilelist fun! s:NetrwMarkFileTag(islocal) " call Dfunc("s:NetrwMarkFileTag(islocal=".a:islocal.")") - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let curdir = s:NetrwGetCurdir(a:islocal) let curbufnr = bufnr("%") @@ -7494,7 +7713,8 @@ fun! s:NetrwMarkFileTag(islocal) endif 2match none call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) - call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + call winrestview(svpos) endif " call Dret("s:NetrwMarkFileTag") @@ -7507,8 +7727,9 @@ endfun " s:netrwmftgt_islocal : 0=target directory is remote " 1=target directory is local fun! s:NetrwMarkFileTgt(islocal) -" call Dfunc("s:NetrwMarkFileTgt(islocal=".a:islocal.")") - let svpos = netrw#SavePosn() +" call Dfunc("s:NetrwMarkFileTgt(islocal=".a:islocal.")") + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let curdir = s:NetrwGetCurdir(a:islocal) let hadtgt = exists("s:netrwmftgt") if !exists("w:netrw_bannercnt") @@ -7526,7 +7747,8 @@ fun! s:NetrwMarkFileTgt(islocal) call s:LocalBrowseRefresh() endif call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) - call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + call winrestview(svpos) " call Dret("s:NetrwMarkFileTgt : removed target") return else @@ -7570,12 +7792,13 @@ fun! s:NetrwMarkFileTgt(islocal) call s:LocalBrowseRefresh() endif " call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) - if w:netrw_liststyle == s:TREELIST + if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,w:netrw_treetop)) else call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) endif - call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + call winrestview(svpos) if !hadtgt sil! NetrwKeepj norm! j endif @@ -7590,7 +7813,7 @@ endfun fun! s:NetrwGetCurdir(islocal) " call Dfunc("s:NetrwGetCurdir(islocal=".a:islocal.")") - if w:netrw_liststyle == s:TREELIST + if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST let b:netrw_curdir = s:NetrwTreePath(w:netrw_treetop) " call Decho("set b:netrw_curdir<".b:netrw_curdir."> (used s:NetrwTreeDir)",'~'.expand("<slnum>")) elseif !exists("b:netrw_curdir") @@ -7626,8 +7849,8 @@ fun! s:NetrwOpenFile(islocal) endif let g:netrw_quiet = 1 " save position for benefit of Rexplore - let s:rexposn_{bufnr("%")}= netrw#SavePosn() -" call Decho("setting s:rexposn_".bufnr("%")."<".bufname("%")."> to SavePosn",'~'.expand("<slnum>")) + let s:rexposn_{bufnr("%")}= winsaveview() +" call Decho("saving posn to s:rexposn_".bufnr("%")."<".string(s:rexposn_{bufnr("%")}).">",'~'.expand("<slnum>")) if b:netrw_curdir =~ '/$' exe "NetrwKeepj e ".fnameescape(b:netrw_curdir.fname) else @@ -7702,7 +7925,8 @@ fun! s:NetSortSequence(islocal) " call Dfunc("NetSortSequence(islocal=".a:islocal.")") let ykeep= @@ - let svpos= netrw#SavePosn() + let svpos= winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) call inputsave() let newsortseq= input("Edit Sorting Sequence: ",g:netrw_sort_sequence) call inputrestore() @@ -7710,7 +7934,8 @@ fun! s:NetSortSequence(islocal) " refresh the listing let g:netrw_sort_sequence= newsortseq NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) let @@= ykeep " call Dret("NetSortSequence") @@ -7785,7 +8010,8 @@ endfun " s:netrwmarkfilemtch_# -- used with 2match to display marked files fun! s:NetrwUnMarkFile(islocal) " call Dfunc("s:NetrwUnMarkFile(islocal=".a:islocal.")") - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let curbufnr = bufnr("%") " unmark marked file list @@ -7806,7 +8032,8 @@ fun! s:NetrwUnMarkFile(islocal) 2match none " call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) - call netrw#RestorePosn(svpos) +"call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) +call winrestview(svpos) " call Dret("s:NetrwUnMarkFile") endfun @@ -8276,7 +8503,8 @@ fun! s:NetrwRefresh(islocal,dirname) let ykeep = @@ " save the cursor position before refresh. - let screenposn = netrw#SavePosn() + let screenposn = winsaveview() +" call Decho("saving posn to screenposn<".string(screenposn).">",'~'.expand("<slnum>")) " call Decho("win#".winnr().": ".winheight(0)."x".winwidth(0)." curfile<".expand("%").">",'~'.expand("<slnum>")) " call Decho("clearing buffer prior to refresh",'~'.expand("<slnum>")) @@ -8288,7 +8516,8 @@ fun! s:NetrwRefresh(islocal,dirname) endif " restore position - NetrwKeepj call netrw#RestorePosn(screenposn) +" call Decho("restoring posn to screenposn<".string(screenposn).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(screenposn) " restore file marks if exists("s:netrwmarkfilemtch_{bufnr('%')}") && s:netrwmarkfilemtch_{bufnr("%")} != "" @@ -8439,8 +8668,8 @@ endfun " Implements [count]Tb (bookhist<b>) " [count]Th (bookhist<h>) " See :help netrw-qb for how to make the choice. -fun! s:NetrwSetTgt(bookhist,choice) -" call Dfunc("s:NetrwSetTgt(bookhist<".a:bookhist."> choice#".a:choice.")") +fun! s:NetrwSetTgt(islocal,bookhist,choice) +" call Dfunc("s:NetrwSetTgt(islocal=".a:islocal." bookhist<".a:bookhist."> choice#".a:choice.")") if a:bookhist == 'b' " supports choosing a bookmark as a target using a qb-generated list @@ -8462,6 +8691,12 @@ fun! s:NetrwSetTgt(bookhist,choice) endif endif + " refresh the display + if !exists("b:netrw_curdir") + let b:netrw_curdir= getcwd() + endif + call s:NetrwRefresh(a:islocal,b:netrw_curdir) + " call Dret("s:NetrwSetTgt") endfun @@ -8470,12 +8705,14 @@ endfun fun! s:NetrwSortStyle(islocal) " call Dfunc("s:NetrwSortStyle(islocal=".a:islocal.") netrw_sort_by<".g:netrw_sort_by.">") NetrwKeepj call s:NetrwSaveWordPosn() - let svpos= netrw#SavePosn() + let svpos= winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let g:netrw_sort_by= (g:netrw_sort_by =~ '^n')? 'time' : (g:netrw_sort_by =~ '^t')? 'size' : (g:netrw_sort_by =~ '^siz')? 'exten' : 'name' NetrwKeepj norm! 0 NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) " call Dret("s:NetrwSortStyle : netrw_sort_by<".g:netrw_sort_by.">") endfun @@ -8653,6 +8890,9 @@ endfun " (full path directory with trailing slash returned) fun! s:NetrwTreeDir(islocal) " call Dfunc("s:NetrwTreeDir(islocal=".a:islocal.") getline(".line(".").")"."<".getline('.')."> b:netrw_curdir<".b:netrw_curdir."> tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> ft=".&ft) +" call Decho("g:netrw_keepdir =".(exists("g:netrw_keepdir")? g:netrw_keepdir : 'n/a')) +" call Decho("w:netrw_liststyle=".(exists("w:netrw_liststyle")? w:netrw_liststyle : 'n/a')) +" call Decho("w:netrw_treetop =".(exists("w:netrw_treetop")? w:netrw_treetop : 'n/a')) if exists("s:treedir") " s:NetrwPrevWinOpen opens a "previous" window -- and thus needs to and does call s:NetrwTreeDir early @@ -8665,12 +8905,13 @@ fun! s:NetrwTreeDir(islocal) if !exists("b:netrw_curdir") || b:netrw_curdir == "" let b:netrw_curdir= getcwd() endif - let treedir = b:netrw_curdir " call Decho("set initial treedir<".treedir.">",'~'.expand("<slnum>")) - let s:treecurpos= netrw#SavePosn() - if w:netrw_liststyle == s:TREELIST + let s:treecurpos= winsaveview() +" call Decho("saving posn to s:treecurpos<".string(s:treecurpos).">",'~'.expand("<slnum>")) + + if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST " call Decho("w:netrw_liststyle is TREELIST:",'~'.expand("<slnum>")) " call Decho("line#".line(".")." getline(.)<".getline('.')."> treecurpos<".string(s:treecurpos).">",'~'.expand("<slnum>")) @@ -8701,13 +8942,12 @@ fun! s:NetrwTreeDir(islocal) " call Dret("s:NetrwTreeDir <".treedir."> : (side effect) s:treecurpos<".(exists("s:treecurpos")? string(s:treecurpos) : 'n/a').">") return b:netrw_curdir " else " Decho -" call Decho(".user did not attempt to close treeroot",'~'.expand("<slnum>")) +" call Decho(".user not attempting to close treeroot",'~'.expand("<slnum>")) endif " call Decho("islocal=".a:islocal." curline<".curline.">",'~'.expand("<slnum>")) -" call Decho("after subst<".substitute(curline,'^'.s:treedepthstring.'\+ \(.*\)$','\1','').">",'~'.expand("<slnum>")) - let potentialdir= substitute(curline,'^'.s:treedepthstring.'* \(.*\)@$','\1','') -" call Decho("potentialdir<".potentialdir."> isdir=".isdirectory(s:NetrwFile(potentialdir)),'~'.expand("<slnum>")) + let potentialdir= s:NetrwFile(substitute(curline,'^'.s:treedepthstring.'\+ \(.*\)@$','\1','')) +" call Decho("potentialdir<".potentialdir."> isdir=".isdirectory(potentialdir),'~'.expand("<slnum>")) " COMBAK: a symbolic link may point anywhere -- so it will be used to start a new treetop " if a:islocal && curline =~ '@$' && isdirectory(s:NetrwFile(potentialdir)) @@ -8763,9 +9003,13 @@ fun! s:NetrwTreeDisplay(dir,depth) let depth= s:treedepthstring.a:depth " call Decho("display subtrees with depth<".depth."> and current leaves",'~'.expand("<slnum>")) -" call Decho("w:netrw_treedict[".dir."]=".string(w:netrw_treedict[dir]),'~'.expand("<slnum>")) +" call Decho("for every entry in w:netrw_treedict[".dir."]=".string(w:netrw_treedict[dir]),'~'.expand("<slnum>")) for entry in w:netrw_treedict[dir] - let direntry= substitute(dir.'/'.entry,'[@/]$','','e') + if dir =~ '/$' + let direntry= substitute(dir.entry,'[@/]$','','e') + else + let direntry= substitute(dir.'/'.entry,'[@/]$','','e') + endif " call Decho("dir<".dir."> entry<".entry."> direntry<".direntry.">",'~'.expand("<slnum>")) if entry =~ '/$' && has_key(w:netrw_treedict,direntry) " call Decho("<".direntry."> is a key in treedict - display subtree for it",'~'.expand("<slnum>")) @@ -8786,10 +9030,48 @@ fun! s:NetrwTreeDisplay(dir,depth) endfun " --------------------------------------------------------------------- +" s:NetrwRefreshTreeDict: updates the contents information for a tree (w:netrw_treedict) {{{2 +fun! s:NetrwRefreshTreeDict(dir) +" call Dfunc("s:NetrwRefreshTreeDict(dir<".a:dir.">)") + for entry in w:netrw_treedict[a:dir] + let direntry= substitute(a:dir.'/'.entry,'[@/]$','','e') +" call Decho("a:dir<".a:dir."> entry<".entry."> direntry<".direntry.">",'~'.expand("<slnum>")) + + if entry =~ '/$' && has_key(w:netrw_treedict,direntry) +" call Decho("<".direntry."> is a key in treedict - display subtree for it",'~'.expand("<slnum>")) + NetrwKeepj call s:NetrwRefreshTreeDict(direntry) + let liststar = s:NetrwGlob(direntry,'*') + let listdotstar = s:NetrwGlob(direntry,'.*') + let w:netrw_treedict[direntry] = liststar + listdotstar +" call Decho("updating w:netrw_treedict[".direntry.']='.string(w:netrw_treedict[direntry]),'~'.expand("<slnum>")) + + elseif entry =~ '/$' && has_key(w:netrw_treedict,direntry.'/') +" call Decho("<".direntry."/> is a key in treedict - display subtree for it",'~'.expand("<slnum>")) + NetrwKeepj call s:NetrwRefreshTreeDict(direntry.'/') + let liststar = s:NetrwGlob(direntry.'/','*') + let listdotstar= s:NetrwGlob(direntry.'/','.*') + let w:netrw_treedict[direntry]= liststar + listdotstar +" call Decho("updating w:netrw_treedict[".direntry.']='.string(w:netrw_treedict[direntry]),'~'.expand("<slnum>")) + + elseif entry =~ '@$' && has_key(w:netrw_treedict,direntry.'@') +" call Decho("<".direntry."/> is a key in treedict - display subtree for it",'~'.expand("<slnum>")) + NetrwKeepj call s:NetrwRefreshTreeDict(direntry.'/') + let liststar = s:NetrwGlob(direntry.'/','*') + let listdotstar= s:NetrwGlob(direntry.'/','.*') +" call Decho("updating w:netrw_treedict[".direntry.']='.string(w:netrw_treedict[direntry]),'~'.expand("<slnum>")) + + else +" call Decho('not updating w:netrw_treedict['.direntry.'] with entry<'.entry.'> (no subtree)',,'~'.expand("<slnum>")) + endif + endfor +" call Dret("s:NetrwRefreshTreeDict") +endfun + +" --------------------------------------------------------------------- " s:NetrwTreeListing: displays tree listing from treetop on down, using NetrwTreeDisplay() {{{2 " Called by s:PerformListing() fun! s:NetrwTreeListing(dirname) - if w:netrw_liststyle == s:TREELIST + if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST " call Dfunc("NetrwTreeListing() bufname<".expand("%").">") " call Decho("curdir<".a:dirname.">",'~'.expand("<slnum>")) " call Decho("win#".winnr().": w:netrw_treetop ".(exists("w:netrw_treetop")? "exists" : "doesn't exist")." w:netrw_treedict ".(exists("w:netrw_treedict")? "exists" : "doesn't exit"),'~'.expand("<slnum>")) @@ -8811,13 +9093,13 @@ fun! s:NetrwTreeListing(dirname) let w:netrw_treedict= {} endif - " update the directory listing for the current directory -" call Decho("updating dictionary with ".a:dirname.":[..directory listing..]",'~'.expand("<slnum>")) + " update the dictionary for the current directory +" call Decho("updating: w:netrw_treedict[".a:dirname.'] -> [directory listing]','~'.expand("<slnum>")) " call Decho("w:netrw_bannercnt=".w:netrw_bannercnt." line($)=".line("$"),'~'.expand("<slnum>")) - exe "sil! NetrwKeepj ".w:netrw_bannercnt.',$g@^\.\.\=/$@d' + exe "sil! NetrwKeepj ".w:netrw_bannercnt.',$g@^\.\.\=/$@d _' let w:netrw_treedict[a:dirname]= getline(w:netrw_bannercnt,line("$")) " call Decho("w:treedict[".a:dirname."]= ".string(w:netrw_treedict[a:dirname]),'~'.expand("<slnum>")) - exe "sil! NetrwKeepj ".w:netrw_bannercnt.",$d" + exe "sil! NetrwKeepj ".w:netrw_bannercnt.",$d _" " if past banner, record word if exists("w:netrw_bannercnt") && line(".") > w:netrw_bannercnt @@ -8852,6 +9134,8 @@ endfun " wipes that out prior to calling this function fun! s:NetrwTreePath(treetop) " call Dfunc("s:NetrwTreePath() line#".line(".")."<".getline(".").">") + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let depth = substitute(getline('.'),'^\(\%('.s:treedepthstring.'\)*\)[^'.s:treedepthstring.'].\{-}$','\1','e') " call Decho("depth<".depth."> 1st subst",'~'.expand("<slnum>")) let depth = substitute(depth,'^'.s:treedepthstring,'','') @@ -8886,6 +9170,8 @@ fun! s:NetrwTreePath(treetop) let treedir= a:treetop.'/'.treedir endif let treedir= substitute(treedir,'//$','/','') +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))" + call winrestview(svpos) " call Dret("s:NetrwTreePath <".treedir.">") return treedir endfun @@ -8930,6 +9216,7 @@ fun! s:NetrwWideListing() " call Decho("bannercnt=".w:netrw_bannercnt." fpl=".w:netrw_fpl." fpc=".fpc." newcol[".newcolstart.",".newcolend."]",'~'.expand("<slnum>")) if has("clipboard") sil! let keepregstar = @* + sil! let keepregplus = @+ endif while line("$") >= newcolstart if newcolend > line("$") | let newcolend= line("$") | endif @@ -8940,11 +9227,12 @@ fun! s:NetrwWideListing() else exe "sil! NetrwKeepj norm! 0\<c-v>".newcolqty.'j$hx'.w:netrw_bannercnt.'G$p' endif - exe "sil! NetrwKeepj ".newcolstart.','.newcolend.'d' + exe "sil! NetrwKeepj ".newcolstart.','.newcolend.'d _' exe 'sil! NetrwKeepj '.w:netrw_bannercnt endwhile if has("clipboard") sil! let @*= keepregstar + sil! let @+= keepregplus endif exe "sil! NetrwKeepj ".w:netrw_bannercnt.',$s/\s\+$//e' NetrwKeepj call histdel("/",-1) @@ -9205,7 +9493,7 @@ fun! s:PerformListing(islocal) " call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo. " (internal#3)",'~'.expand("<slnum>")) " resolve symbolic links if local and (thin or tree) - if a:islocal && (w:netrw_liststyle == s:THINLIST || w:netrw_liststyle == s:TREELIST) + if a:islocal && (w:netrw_liststyle == s:THINLIST || (exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST)) " call Decho("--resolve symbolic links if local and thin|tree",'~'.expand("<slnum>")) g/@$/call s:ShowLink() endif @@ -9247,7 +9535,8 @@ fun! s:PerformListing(islocal) if exists("s:treecurpos") " call Decho("s:treecurpos exists; restore posn",'~'.expand("<slnum>")) " call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo. " (internal#8)",'~'.expand("<slnum>")) - NetrwKeepj call netrw#RestorePosn(s:treecurpos) +" call Decho("restoring posn to s:treecurpos<".string(s:treecurpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(s:treecurpos) unlet s:treecurpos endif @@ -9310,7 +9599,7 @@ endfun " enforced here. fun! s:NetrwRemoteFtpCmd(path,listcmd) " call Dfunc("NetrwRemoteFtpCmd(path<".a:path."> listcmd<".a:listcmd.">) w:netrw_method=".(exists("w:netrw_method")? w:netrw_method : (exists("b:netrw_method")? b:netrw_method : "???"))) -" call Decho("line($)=".line("$")." w:netrw_bannercnt=".w:netrw_bannercnt,'~'.expand("<slnum>")) +" call Decho("line($)=".line("$")." win#".winnr()." w:netrw_bannercnt=".w:netrw_bannercnt,'~'.expand("<slnum>")) " sanity check: {{{3 if !exists("w:netrw_method") if exists("b:netrw_method") @@ -9329,8 +9618,8 @@ fun! s:NetrwRemoteFtpCmd(path,listcmd) " clear off any older non-banner lines " {{{3 " note that w:netrw_bannercnt indexes the line after the banner -" call Decho('exe sil! NetrwKeepj '.w:netrw_bannercnt.",$d (clear off old non-banner lines)",'~'.expand("<slnum>")) - exe "sil! NetrwKeepj ".w:netrw_bannercnt.",$d" +" call Decho('exe sil! NetrwKeepj '.w:netrw_bannercnt.",$d _ (clear off old non-banner lines)",'~'.expand("<slnum>")) + exe "sil! NetrwKeepj ".w:netrw_bannercnt.",$d _" "......................................... if w:netrw_method == 2 || w:netrw_method == 5 " {{{3 @@ -9427,7 +9716,7 @@ fun! s:NetrwRemoteFtpCmd(path,listcmd) sil! NetrwKeepj g/l\%([-r][-w][-x]\)\{3}/NetrwKeepj s/$/@/e NetrwKeepj call histdel("/",-1) NetrwKeepj call histdel("/",-1) - if w:netrw_liststyle == s:THINLIST || w:netrw_liststyle == s:WIDELIST || w:netrw_liststyle == s:TREELIST + if w:netrw_liststyle == s:THINLIST || w:netrw_liststyle == s:WIDELIST || (exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST) exe "sil! NetrwKeepj ".w:netrw_bannercnt.',$s/^\%(\S\+\s\+\)\{8}//e' NetrwKeepj call histdel("/",-1) endif @@ -9451,7 +9740,7 @@ endfun " --------------------------------------------------------------------- " s:NetrwRemoteListing: {{{2 fun! s:NetrwRemoteListing() -" call Dfunc("s:NetrwRemoteListing() b:netrw_curdir<".b:netrw_curdir.">)") +" call Dfunc("s:NetrwRemoteListing() b:netrw_curdir<".b:netrw_curdir.">) win#".winnr()) if !exists("w:netrw_bannercnt") && exists("s:bannercnt") let w:netrw_bannercnt= s:bannercnt @@ -9515,7 +9804,7 @@ fun! s:NetrwRemoteListing() let mesg= getline(".") if exists("w:netrw_bannercnt") setl ma - exe w:netrw_bannercnt.",$d" + exe w:netrw_bannercnt.",$d _" setl noma endif NetrwKeepj call s:NetrwOptionRestore("w:") @@ -9524,7 +9813,7 @@ fun! s:NetrwRemoteListing() return -1 endif - if w:netrw_liststyle == s:THINLIST || w:netrw_liststyle == s:WIDELIST || w:netrw_liststyle == s:TREELIST + if w:netrw_liststyle == s:THINLIST || w:netrw_liststyle == s:WIDELIST || (exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST) " shorten the listing " call Decho("generate short listing",'~'.expand("<slnum>")) exe "sil! keepalt NetrwKeepj ".w:netrw_bannercnt @@ -9654,7 +9943,8 @@ endfun fun! s:NetrwRemoteRm(usrhost,path) range " call Dfunc("s:NetrwRemoteRm(usrhost<".a:usrhost."> path<".a:path.">) virtcol=".virtcol(".")) " call Decho("firstline=".a:firstline." lastline=".a:lastline,'~'.expand("<slnum>")) - let svpos= netrw#SavePosn() + let svpos= winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let all= 0 if exists("s:netrwmarkfilelist_{bufnr('%')}") @@ -9696,7 +9986,8 @@ fun! s:NetrwRemoteRm(usrhost,path) range " refresh the (remote) directory listing " call Decho("refresh remote directory listing",'~'.expand("<slnum>")) NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) " call Dret("s:NetrwRemoteRm") endfun @@ -9736,7 +10027,7 @@ fun! s:NetrwRemoteRmFile(path,rmfile,all) if path =~ '^\a\{3,}://' let path= substitute(path,'^\a\{3,}://[^/]\+/','','') endif - sil! NetrwKeepj .,$d + sil! NetrwKeepj .,$d _ call s:NetrwRemoteFtpCmd(path,"delete ".'"'.a:rmfile.'"') else " call Decho("case ssh: g:netrw_rm_cmd<".g:netrw_rm_cmd.">",'~'.expand("<slnum>")) @@ -9827,7 +10118,8 @@ fun! s:NetrwRemoteRename(usrhost,path) range " call Dfunc("NetrwRemoteRename(usrhost<".a:usrhost."> path<".a:path.">)") " preparation for removing multiple files/directories - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) let ctr = a:firstline let rename_cmd = s:MakeSshCmd(g:netrw_rename_cmd) @@ -9893,7 +10185,8 @@ fun! s:NetrwRemoteRename(usrhost,path) range " refresh the directory NetrwKeepj call s:NetrwRefresh(0,s:NetrwBrowseChgDir(0,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) " call Dret("NetrwRemoteRename") endfun @@ -9955,7 +10248,7 @@ endfun " --------------------------------------------------------------------- " netrw#LocalBrowseCheck: {{{2 fun! netrw#LocalBrowseCheck(dirname) - " This function is called by netrwPlugin.vim's s:LocalBrowse() and by s:NetrwRexplore() + " This function is called by netrwPlugin.vim's s:LocalBrowse(), s:NetrwRexplore(), and by <cr> when atop listed file/directory " unfortunate interaction -- split window debugging can't be " used here, must use D-echoRemOn or D-echoTabOn -- the BufEnter " event triggers another call to LocalBrowseCheck() when attempts @@ -10074,6 +10367,9 @@ fun! s:LocalBrowseRefresh() let g:netrw_quickhelp= g:netrw_quickhelp - 1 endif " call Decho("#3: quickhelp=".g:netrw_quickhelp,'~'.expand("<slnum>")) + if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST + NetrwKeepj call s:NetrwRefreshTreeDict(w:netrw_treetop) + endif NetrwKeepj call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./')) endif let ibl= ibl + 1 @@ -10263,6 +10559,9 @@ fun! s:LocalListing() if w:netrw_liststyle == s:LONGLIST let sz = getfsize(filename) + if g:netrw_sizestyle =~ "[hH]" + let sz= s:NetrwHumanReadable(sz) + endif let fsz = strpart(" ",1,15-strlen(sz)).sz let pfile= pfile."\t".fsz." ".strftime(g:netrw_timefmt,getftime(filename)) " call Decho("sz=".sz." fsz=".fsz,'~'.expand("<slnum>")) @@ -10281,6 +10580,9 @@ fun! s:LocalListing() " sort by size (handles file sizes up to 1 quintillion bytes, US) " call Decho("getfsize(".filename.")=".getfsize(filename),'~'.expand("<slnum>")) let sz = getfsize(filename) + if g:netrw_sizestyle =~ "[hH]" + let sz= s:NetrwHumanReadable(sz) + endif let fsz = strpart("000000000000000000",1,18-strlen(sz)).sz " call Decho("exe NetrwKeepj put ='".fsz.'/'.filename."'",'~'.expand("<slnum>")) let fszpfile= fsz.'/'.pfile @@ -10339,7 +10641,8 @@ fun! s:NetrwLocalRename(path) range " preparation for removing multiple files/directories let ykeep = @@ let ctr = a:firstline - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) " rename files given by the markfilelist if exists("s:netrwmarkfilelist_{bufnr('%')}") @@ -10405,7 +10708,8 @@ fun! s:NetrwLocalRename(path) range " refresh the directory " call Decho("refresh the directory listing",'~'.expand("<slnum>")) NetrwKeepj call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) let @@= ykeep " call Dret("NetrwLocalRename") @@ -10421,7 +10725,8 @@ fun! s:NetrwLocalRm(path) range let ykeep = @@ let ret = 0 let all = 0 - let svpos = netrw#SavePosn() + let svpos = winsaveview() +" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) if exists("s:netrwmarkfilelist_{bufnr('%')}") " remove all marked files @@ -10471,7 +10776,8 @@ fun! s:NetrwLocalRm(path) range " call Decho("bufname<".bufname("%").">",'~'.expand("<slnum>")) if bufname("%") != "NetrwMessage" NetrwKeepj call s:NetrwRefresh(1,s:NetrwBrowseChgDir(1,'./')) - NetrwKeepj call netrw#RestorePosn(svpos) +" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(svpos) endif let @@= ykeep @@ -10533,28 +10839,34 @@ fun! s:NetrwLocalRmFile(path,fname,all) let rmfile= substitute(rmfile,'[\/]$','','e') if all || ok =~ 'y\%[es]' || ok == "" -" call Decho("1st attempt: system(netrw#WinPath(".g:netrw_localrmdir.') '.s:ShellEscape(rmfile).')','~'.expand("<slnum>")) - call system(netrw#WinPath(g:netrw_localrmdir).' '.s:ShellEscape(rmfile)) -" call Decho("v:shell_error=".v:shell_error,'~'.expand("<slnum>")) + if v:version < 704 || !has("patch1109") +" " call Decho("1st attempt: system(netrw#WinPath(".g:netrw_localrmdir.') '.s:ShellEscape(rmfile).')','~'.expand("<slnum>")) + call system(netrw#WinPath(g:netrw_localrmdir).' '.s:ShellEscape(rmfile)) +" " call Decho("v:shell_error=".v:shell_error,'~'.expand("<slnum>")) - if v:shell_error != 0 -" call Decho("2nd attempt to remove directory<".rmfile.">",'~'.expand("<slnum>")) - let errcode= s:NetrwDelete(rmfile) -" call Decho("errcode=".errcode,'~'.expand("<slnum>")) - - if errcode != 0 - if has("unix") -" call Decho("3rd attempt to remove directory<".rmfile.">",'~'.expand("<slnum>")) - call system("rm ".s:ShellEscape(rmfile)) - if v:shell_error != 0 && !exists("g:netrw_quiet") - call netrw#ErrorMsg(s:ERROR,"unable to remove directory<".rmfile."> -- is it empty?",34) + if v:shell_error != 0 +" " call Decho("2nd attempt to remove directory<".rmfile.">",'~'.expand("<slnum>")) + let errcode= s:NetrwDelete(rmfile) +" " call Decho("errcode=".errcode,'~'.expand("<slnum>")) + + if errcode != 0 + if has("unix") +" " call Decho("3rd attempt to remove directory<".rmfile.">",'~'.expand("<slnum>")) + call system("rm ".s:ShellEscape(rmfile)) + if v:shell_error != 0 && !exists("g:netrw_quiet") + call netrw#ErrorMsg(s:ERROR,"unable to remove directory<".rmfile."> -- is it empty?",34) + let ok="no" + endif + elseif !exists("g:netrw_quiet") + call netrw#ErrorMsg(s:ERROR,"unable to remove directory<".rmfile."> -- is it empty?",35) let ok="no" endif - elseif !exists("g:netrw_quiet") - call netrw#ErrorMsg(s:ERROR,"unable to remove directory<".rmfile."> -- is it empty?",35) - let ok="no" endif endif + else + if delete(rmfile,"d") + call netrw#ErrorMsg(s:ERROR,"unable to delete directory <".rmfile.">!",103) + endif endif endif endif @@ -10594,81 +10906,6 @@ fun! netrw#Call(funcname,...) endfun " ------------------------------------------------------------------------ -" netrw#RestorePosn: restores the cursor and file position as saved by netrw#SavePosn() {{{2 -fun! netrw#RestorePosn(...) -" call Dfunc("netrw#RestorePosn() a:0=".a:0." winnr=".(exists("w:netrw_winnr")? w:netrw_winnr : -1)." line=".(exists("w:netrw_line")? w:netrw_line : -1)." col=".(exists("w:netrw_col")? w:netrw_col : -1)." hline=".(exists("w:netrw_hline")? w:netrw_hline : -1)) - let eikeep= &ei - setl ei=all - if expand("%") == "NetrwMessage" - if exists("s:winBeforeErr") - exe s:winBeforeErr."wincmd w" - endif - endif - - if a:0 > 0 - exe "keepj ".a:1 - endif -" "call Decho("a:1 = ".((a:0 > 0)? a:1 : 'n/a'),'~'.expand("<slnum>")) -" "call Decho("liststyle = ".(exists("liststyle")? liststyle : 'n/a'). " w:netrw_liststyle=".(exists("w:netrw_liststyle")? w:netrw_liststyle : 'n/a'),'~'.expand("<slnum>")) - if exists("liststyle") && exists("w:netrw_liststyle") && liststyle != w:netrw_liststyle - let usesrch= 1 - else - let usesrch= 0 - endif - -" "call Decho("winh = ".(exists("w:netrw_winh")? w:netrw_winh : -1),'~'.expand("<slnum>")) -" "call Decho("winw = ".(exists("w:netrw_winw")? w:netrw_winw : -1),'~'.expand("<slnum>")) -" "call Decho("cur winheight=".winheight(0)." winwidth=".winwidth(0),'~'.expand("<slnum>")) -" "call Decho("w:netrw_winfile = ".(exists("w:netrw_winfile")? w:netrw_winfile : 'n/a'),'~'.expand("<slnum>")) - - " restore window - if exists("w:netrw_winnr") -" "call Decho("restore window: exe sil! ".w:netrw_winnr."wincmd w",'~'.expand("<slnum>")) - exe "sil! ".w:netrw_winnr."wincmd w" - endif -" if v:shell_error == 0 - " as suggested by Bram M: redraw on no error - " allows protocol error messages to remain visible -" redraw! -" endif - - " restore top-of-screen line - if exists("w:netrw_hline") -" "call Decho("restore topofscreen: exe keepj norm! ".w:netrw_hline."G0z",'~'.expand("<slnum>")) - exe "keepj norm! ".w:netrw_hline."G0z\<CR>" - endif - - " restore position - " when the window's height x width has changed, the line,col is no longer useful - if w:netrw_winh == winheight(0) && w:netrw_winw == winwidth(0) && exists("w:netrw_line") && exists("w:netrw_col") && !usesrch -" "call Decho("using posn: exe keepj norm! ".w:netrw_line."G0".w:netrw_col."|",'~'.expand("<slnum>")) - exe "keepj norm! ".w:netrw_line."G0".w:netrw_col."\<bar>" - - elseif exists("w:netrw_winfile") - if !search('\<'.escape(w:netrw_winfile,g:netrw_fname_escape),'cw') - if exists("w:netrw_bannercnt") -" "call Decho("using bannercnt: win#".winnr()." ".winheight(0)."x".winwidth(0)." w:netrw_winfile<".w:netrw_winfile.">",'~'.expand("<slnum>")) - exe "keepj ".w:netrw_bannercnt - norm! 0 - else - " go to upper left corner -" "call Decho("goto ulc: win#".winnr()." ".winheight(0)."x".winwidth(0)." w:netrw_winfile<".w:netrw_winfile.">",'~'.expand("<slnum>")) - keepj 1 - norm! 0 - endif - else -" "call Decho("used search: w:netrw_winfile<".w:netrw_winfile.">",'~'.expand("<slnum>")) - endif - - else -" "call Decho("goto ulc: win#".winnr()." ".winheight(0)."x".winwidth(0),'~'.expand("<slnum>")) - keepj 1 - norm! 0 - endif - - let &ei= eikeep -" call Dret("netrw#RestorePosn : line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol()) -endfun " --------------------------------------------------------------------- " netrw#Expose: allows UserMaps and pchk to look at otherwise script-local variables {{{2 @@ -10713,48 +10950,6 @@ fun! netrw#RFC2396(fname) endfun " --------------------------------------------------------------------- -" netrw#SavePosn: saves position of cursor on screen {{{2 -fun! netrw#SavePosn() -" call Dfunc("netrw#SavePosn() win#".winnr()." line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol()) - " Save current line and column - let w:netrw_winnr= winnr() - let w:netrw_line = line(".") - let w:netrw_col = virtcol(".") -" "call Decho("currently, win#".w:netrw_winnr." line#".w:netrw_line." col#".w:netrw_col,'~'.expand("<slnum>")) - - " save filename under cursor -" "call Decho("line#".line(".")." w:netrw_bannercnt=".(exists("w:netrw_bannercnt")? w:netrw_bannercnt : 'n/a'),'~'.expand("<slnum>")) - if exists("w:netrw_bannercnt") && line(".") >= w:netrw_bannercnt && &ft == "netrw" - let winfile = "|let w:netrw_winfile=\"".fnameescape(s:NetrwGetWord())."\"" - else - let winfile= "" - endif -" "call Decho("winfile<".winfile.">",'~'.expand("<slnum>")) - if exists("w:netrw_liststyle") - let liststyle = "|let liststyle=".w:netrw_liststyle - else - let liststyle= "" - endif -" "call Decho("liststyle=".liststyle,'~'.expand("<slnum>")) - - " Save top-of-screen line - keepj norm! H0 - let w:netrw_hline= line(".") - - " save up alternate position information - " use this when window height x width has changed - let w:netrw_winh = winheight(0) - let w:netrw_winw = winwidth(0) - - " set up string holding position parameters - let ret = "let w:netrw_winnr=".w:netrw_winnr."|let w:netrw_line=".w:netrw_line."|let w:netrw_col=".w:netrw_col."|let w:netrw_hline=".w:netrw_hline."|let w:netrw_winh=".w:netrw_winh."|let w:netrw_winw=".w:netrw_winw.liststyle.winfile - - keepj call netrw#RestorePosn() -" call Dret("netrw#SavePosn : win#=".(exists("w:netrw_winnr")? w:netrw_winnr : "n/a")." line=".(exists("w:netrw_line")? w:netrw_line : "n/a")." col=".(exists("w:netrw_col")? w:netrw_col : "n/a")." hline=".(exists("w:netrw_hline")? w:netrw_hline : "n/a")) - return ret -endfun - -" --------------------------------------------------------------------- " netrw#UserMaps: supports user-specified maps {{{2 " see :help function() " @@ -11198,6 +11393,9 @@ fun! s:NetrwEnew(...) NetrwKeepj call s:NetrwOptionRestore("w:") " call Decho("generate a buffer with NetrwKeepj keepalt enew!",'~'.expand("<slnum>")) + " when tree listing uses file TreeListing... a new buffer is made. + " Want the old buffer to be unlisted. + setl nobl let netrw_keepdiff= &l:diff noswapfile NetrwKeepj keepalt enew! let &l:diff= netrw_keepdiff @@ -11227,8 +11425,9 @@ fun! s:NetrwEnew(...) let b:netrw_curdir= a:1 if b:netrw_curdir =~ '/$' if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST + setl nobl file NetrwTreeListing - setl bt=nowrite noswf bh=hide + setl nobl bt=nowrite bh=hide nno <silent> <buffer> [ :sil call <SID>TreeListMove('[')<cr> nno <silent> <buffer> ] :sil call <SID>TreeListMove(']')<cr> else @@ -11331,6 +11530,50 @@ fun! s:NetrwSaveWordPosn() endfun " --------------------------------------------------------------------- +" s:NetrwHumanReadable: takes a number and makes it "human readable" {{{2 +" 1000 -> 1K, 1000000 -> 1M, 1000000000 -> 1G +fun! s:NetrwHumanReadable(sz) +" call Dfunc("s:NetrwHumanReadable(sz=".a:sz.") type=".type(a:sz)." style=".g:netrw_sizestyle ) + + if g:netrw_sizestyle == 'h' + if a:sz >= 1000000000 + let sz = printf("%.1f",a:sz/1000000000.0)."g" + elseif a:sz >= 10000000 + let sz = printf("%d",a:sz/1000000)."m" + elseif a:sz >= 1000000 + let sz = printf("%.1f",a:sz/1000000.0)."m" + elseif a:sz >= 10000 + let sz = printf("%d",a:sz/1000)."k" + elseif a:sz >= 1000 + let sz = printf("%.1f",a:sz/1000.0)."k" + else + let sz= a:sz + endif + + elseif g:netrw_sizestyle == 'H' + if a:sz >= 1073741824 + let sz = printf("%.1f",a:sz/1073741824.0)."G" + elseif a:sz >= 10485760 + let sz = printf("%d",a:sz/1048576)."M" + elseif a:sz >= 1048576 + let sz = printf("%.1f",a:sz/1048576.0)."M" + elseif a:sz >= 10240 + let sz = printf("%d",a:sz/1024)."K" + elseif a:sz >= 1024 + let sz = printf("%.1f",a:sz/1024.0)."K" + else + let sz= a:sz + endif + + else + let sz= a:sz + endif + +" call Dret("s:NetrwHumanReadable ".sz) + return sz +endfun + +" --------------------------------------------------------------------- " s:NetrwRestoreWordPosn: used to keep cursor on same word after refresh, {{{2 " changed sorting, etc. Also see s:NetrwSaveWordPosn(). fun! s:NetrwRestoreWordPosn() @@ -11449,7 +11692,7 @@ fun! s:NetrwRexplore(islocal,dirname) if exists("s:netrwdrag") return endif -" call Dfunc("s:NetrwRexplore() w:netrw_rexlocal=".w:netrw_rexlocal." w:netrw_rexdir<".w:netrw_rexdir.">") +" call Dfunc("s:NetrwRexplore() w:netrw_rexlocal=".w:netrw_rexlocal." w:netrw_rexdir<".w:netrw_rexdir."> win#".winnr()) " call Decho("currently in bufname<".bufname("%").">",'~'.expand("<slnum>")) " call Decho("ft=".&ft." win#".winnr()." w:netrw_rexfile<".(exists("w:netrw_rexfile")? w:netrw_rexfile : 'n/a').">",'~'.expand("<slnum>")) @@ -11474,7 +11717,7 @@ fun! s:NetrwRexplore(islocal,dirname) " call Decho("set w:netrw_rexfile<".w:netrw_rexfile."> (win#".winnr().")",'~'.expand("<slnum>")) if !exists("w:netrw_rexlocal") -" call Dret("s:NetrwRexplore w:netrw_rexlocal doesn't exist (".&ft.")") +" call Dret("s:NetrwRexplore w:netrw_rexlocal doesn't exist (".&ft." win#".winnr().")") return endif " call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo,'~'.expand("<slnum>")) @@ -11489,7 +11732,8 @@ fun! s:NetrwRexplore(islocal,dirname) if exists("s:rexposn_".bufnr("%")) " call Decho("restore posn, then unlet s:rexposn_".bufnr('%')."<".bufname("%").">",'~'.expand("<slnum>")) " restore position in directory listing - NetrwKeepj call netrw#RestorePosn(s:rexposn_{bufnr('%')}) +" call Decho("restoring posn to s:rexposn_".bufnr('%')."<".string(s:rexposn_{bufnr('%')}).">",'~'.expand("<slnum>")) + NetrwKeepj call winrestview(s:rexposn_{bufnr('%')}) if exists("s:rexposn_".bufnr('%')) unlet s:rexposn_{bufnr('%')} endif @@ -11571,10 +11815,13 @@ endfun " --------------------------------------------------------------------- " s:SetRexDir: set directory for :Rexplore {{{2 fun! s:SetRexDir(islocal,dirname) -" call Dfunc("s:SetRexDir(islocal=".a:islocal." dirname<".a:dirname.">)") +" call Dfunc("s:SetRexDir(islocal=".a:islocal." dirname<".a:dirname.">) win#".winnr()) let w:netrw_rexdir = a:dirname let w:netrw_rexlocal = a:islocal - let s:rexposn_{bufnr("%")} = netrw#SavePosn() + let s:rexposn_{bufnr("%")} = winsaveview() +" call Decho("setting w:netrw_rexdir =".w:netrw_rexdir) +" call Decho("setting w:netrw_rexlocal=".w:netrw_rexlocal) +" call Decho("saving posn to s:rexposn_".bufnr("%")."<".string(s:rexposn_{bufnr("%")}).">",'~'.expand("<slnum>")) " call Decho("setting s:rexposn_".bufnr("%")."<".bufname("%")."> to SavePosn",'~'.expand("<slnum>")) " call Dret("s:SetRexDir : win#".winnr()." ".(a:islocal? "local" : "remote")." dir: ".a:dirname) endfun @@ -11685,56 +11932,39 @@ fun! s:ShellEscape(s, ...) endfun " --------------------------------------------------------------------- -" s:TreeListMove: {{{2 +" s:TreeListMove: supports [[, ]], [], and ][ in tree mode {{{2 fun! s:TreeListMove(dir) " call Dfunc("s:TreeListMove(dir<".a:dir.">)") - let curline = getline('.') - let prvline = (line(".") > 1)? getline(line(".")-1) : '' - let nxtline = (line(".") < line("$"))? getline(line(".")+1) : '' - let curindent= substitute(curline,'^\([| ]*\).\{-}$','\1','') - let indentm1 = substitute(curindent,'^'.s:treedepthstring.' ','','') -" call Decho("prvline <".prvline."> #".line(".")-1,'~'.expand("<slnum>")) -" call Decho("curline <".curline."> #".line("."),'~'.expand("<slnum>")) -" call Decho("nxtline <".nxtline."> #".line(".")+1,'~'.expand("<slnum>")) -" call Decho("curindent<".curindent.">",'~'.expand("<slnum>")) -" call Decho("indentm1 <".indentm1.">",'~'.expand("<slnum>")) - + let curline = getline('.') + let prvline = (line(".") > 1)? getline(line(".")-1) : '' + let nxtline = (line(".") < line("$"))? getline(line(".")+1) : '' + let curindent = substitute(getline('.'),'^\(\%('.s:treedepthstring.'\)*\)[^'.s:treedepthstring.'].\{-}$','\1','e') + let indentm1 = substitute(curindent,'^'.s:treedepthstring,'','') + let treedepthchr = substitute(s:treedepthstring,' ','','g') + let stopline = exists("w:netrw_bannercnt")? w:netrw_bannercnt : 1 +" call Decho("prvline <".prvline."> #".(line(".")-1), '~'.expand("<slnum>")) +" call Decho("curline <".curline."> #".line(".") , '~'.expand("<slnum>")) +" call Decho("nxtline <".nxtline."> #".(line(".")+1), '~'.expand("<slnum>")) +" call Decho("curindent<".curindent.">" , '~'.expand("<slnum>")) +" call Decho("indentm1 <".indentm1.">" , '~'.expand("<slnum>")) + " COMBAK : need to handle when on a directory + " COMBAK : need to handle ]] and ][. In general, needs work!!! if curline !~ '/$' -" call Decho('regfile','~'.expand("<slnum>")) - if a:dir == '[' && prvline != '' + if a:dir == '[[' && prvline != '' NetrwKeepj norm! 0 - let nl = search('^'.indentm1.'[^'.s:treedepthstring.']','bWe') " search backwards from regular file + let nl = search('^'.indentm1.'\%('.s:treedepthstring.'\)\@!','bWe',stopline) " search backwards " call Decho("regfile srch back: ".nl,'~'.expand("<slnum>")) - elseif a:dir == ']' && nxtline != '' - NetrwKeepj norm! $ - let nl = search('^'.indentm1.'[^'.s:treedepthstring.']','We') " search forwards from regular file -" call Decho("regfile srch fwd: ".nl,'~'.expand("<slnum>")) - endif - - elseif a:dir == '[' && prvline != '' - NetrwKeepj norm! 0 - let curline= line(".") - let nl = search('^'.curindent.'[^'.s:treedepthstring.']','bWe') " search backwards From directory, same indentation -" call Decho("dir srch back ind: ".nl,'~'.expand("<slnum>")) - if nl != 0 - if line(".") == curline-1 - let nl= search('^'.indentm1.'[^'.s:treedepthstring.']','bWe') " search backwards from directory, indentation - 1 -" call Decho("dir srch back ind-1: ".nl,'~'.expand("<slnum>")) - endif - endif - - elseif a:dir == ']' && nxtline != '' - NetrwKeepj norm! $ - let curline = line(".") - let nl = search('^'.curindent.'[^'.s:treedepthstring.']','We') " search forwards from directory, same indentation -" call Decho("dir srch fwd ind: ".nl,'~'.expand("<slnum>")) - if nl != 0 - if line(".") == curline+1 - let nl= search('^'.indentm1.'[^'.s:treedepthstring.']','We') " search forwards from directory, indentation - 1 -" call Decho("dir srch fwd ind-1: ".nl,'~'.expand("<slnum>")) + elseif a:dir == '[]' && nxtline != '' + NetrwKeepj norm! 0 +" call Decho('srchpat<'.'^\%('.curindent.'\)\@!'.'>') + let nl = search('^\%('.curindent.'\)\@!','We') " search forwards + if nl != 0 + NetrwKeepj norm! k + else + NetrwKeepj norm! G endif +" call Decho("regfile srch fwd: ".nl,'~'.expand("<slnum>")) endif - endif " call Dret("s:TreeListMove") diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim index c7cb14ded7..0f4aa78ddd 100644 --- a/runtime/autoload/provider/clipboard.vim +++ b/runtime/autoload/provider/clipboard.vim @@ -58,18 +58,17 @@ elseif executable('doitclient') let s:copy['*'] = s:copy['+'] let s:paste['*'] = s:paste['+'] else - echom 'clipboard: No clipboard tool available. See :help nvim-clipboard' + echom 'clipboard: No clipboard tool available. See :help clipboard' finish endif let s:clipboard = {} function! s:clipboard.get(reg) - let reg = a:reg == '"' ? '+' : a:reg - if s:selections[reg].owner > 0 - return s:selections[reg].data + if s:selections[a:reg].owner > 0 + return s:selections[a:reg].data end - return s:try_cmd(s:paste[reg]) + return s:try_cmd(s:paste[a:reg]) endfunction function! s:clipboard.set(lines, regtype, reg) @@ -94,6 +93,7 @@ function! s:clipboard.set(lines, regtype, reg) let selection.data = [a:lines, a:regtype] let argv = split(s:copy[a:reg], " ") let selection.detach = s:cache_enabled + let selection.cwd = "/" let jobid = jobstart(argv, selection) if jobid <= 0 echohl WarningMsg diff --git a/runtime/autoload/provider/python.vim b/runtime/autoload/provider/python.vim index cb9d5c5296..b99a046375 100644 --- a/runtime/autoload/provider/python.vim +++ b/runtime/autoload/provider/python.vim @@ -1,5 +1,5 @@ " The Python provider uses a Python host to emulate an environment for running -" python-vim plugins. See ":help nvim-provider" for more information. +" python-vim plugins. See ":help provider". " " Associating the plugin with the Python host is the first step because plugins " will be passed as command-line arguments diff --git a/runtime/autoload/provider/python3.vim b/runtime/autoload/provider/python3.vim index f4a751e7a2..4f47a03a9b 100644 --- a/runtime/autoload/provider/python3.vim +++ b/runtime/autoload/provider/python3.vim @@ -1,5 +1,5 @@ " The Python3 provider uses a Python3 host to emulate an environment for running -" python3 plugins. See ":help nvim-provider" for more information. +" python3 plugins. See ":help provider". " " Associating the plugin with the Python3 host is the first step because " plugins will be passed as command-line arguments diff --git a/runtime/autoload/provider/pythonx.vim b/runtime/autoload/provider/pythonx.vim index 05815a4896..0ebf00112f 100644 --- a/runtime/autoload/provider/pythonx.vim +++ b/runtime/autoload/provider/pythonx.vim @@ -18,9 +18,9 @@ function! provider#pythonx#Require(host) abort endfor try - let channel_id = rpcstart((ver == '2' ? + let channel_id = rpcstart((ver ==# '2' ? \ provider#python#Prog() : provider#python3#Prog()), args) - if rpcrequest(channel_id, 'poll') == 'ok' + if rpcrequest(channel_id, 'poll') ==# 'ok' return channel_id endif catch @@ -70,7 +70,7 @@ endfunction function! s:check_interpreter(prog, major_ver, skip) abort let prog_path = exepath(a:prog) - if prog_path == '' + if prog_path ==# '' return [0, a:prog . ' not found in search path or not executable.'] endif @@ -83,8 +83,8 @@ function! s:check_interpreter(prog, major_ver, skip) abort " Try to load neovim module, and output Python version. " Return codes: " 0 Neovim module can be loaded. - " 1 Something else went wrong. " 2 Neovim module cannot be loaded. + " Otherwise something else went wrong (e.g. 1 or 127). let prog_ver = system([ a:prog , '-c' , \ 'import sys; ' . \ 'sys.path.remove(""); ' . @@ -93,7 +93,8 @@ function! s:check_interpreter(prog, major_ver, skip) abort \ 'exit(2*int(pkgutil.get_loader("neovim") is None))' \ ]) - if prog_ver + if v:shell_error == 2 || v:shell_error == 0 + " Check version only for expected return codes. if prog_ver !~ '^' . a:major_ver return [0, prog_path . ' is Python ' . prog_ver . ' and cannot provide Python ' \ . a:major_ver . '.'] @@ -103,12 +104,16 @@ function! s:check_interpreter(prog, major_ver, skip) abort endif endif - if v:shell_error == 1 + if v:shell_error == 2 + return [0, prog_path . ' does not have the neovim module installed. ' + \ . 'See ":help provider-python".'] + elseif v:shell_error == 127 + " This can happen with pyenv's shims. + return [0, prog_path . ' does not exist: ' . prog_ver] + elseif v:shell_error return [0, 'Checking ' . prog_path . ' caused an unknown error. ' - \ . 'Please report this at github.com/neovim/neovim.'] - elseif v:shell_error == 2 - return [0, prog_path . ' does have not have the neovim module installed. ' - \ . 'See ":help nvim-python".'] + \ . '(' . v:shell_error . ', output: ' . prog_ver . ')' + \ . ' Please report this at github.com/neovim/neovim.'] endif return [1, ''] diff --git a/runtime/autoload/provider/ruby.vim b/runtime/autoload/provider/ruby.vim index aad8c09d28..e9130b98c1 100644 --- a/runtime/autoload/provider/ruby.vim +++ b/runtime/autoload/provider/ruby.vim @@ -1,12 +1,18 @@ " The Ruby provider helper -if exists('s:loaded_ruby_provider') +if exists('g:loaded_ruby_provider') finish endif +let g:loaded_ruby_provider = 1 -let s:loaded_ruby_provider = 1 +function! provider#ruby#Detect() abort + return exepath('neovim-ruby-host') +endfunction + +function! provider#ruby#Prog() + return s:prog +endfunction function! provider#ruby#Require(host) abort - " Collect registered Ruby plugins into args let args = [] let ruby_plugins = remote#host#PluginsForHost(a:host.name) @@ -16,19 +22,43 @@ function! provider#ruby#Require(host) abort try let channel_id = rpcstart(provider#ruby#Prog(), args) - - if rpcrequest(channel_id, 'poll') == 'ok' + if rpcrequest(channel_id, 'poll') ==# 'ok' return channel_id endif catch echomsg v:throwpoint echomsg v:exception endtry - - throw remote#host#LoadErrorForHost(a:host.orig_name, - \ '$NVIM_RUBY_LOG_FILE') + throw remote#host#LoadErrorForHost(a:host.orig_name, '$NVIM_RUBY_LOG_FILE') endfunction -function! provider#ruby#Prog() abort - return 'neovim-ruby-host' +function! provider#ruby#Call(method, args) + if s:err != '' + echoerr s:err + return + endif + + if !exists('s:host') + try + let s:host = remote#host#Require('legacy-ruby-provider') + catch + let s:err = v:exception + echohl WarningMsg + echomsg v:exception + echohl None + return + endtry + endif + return call('rpcrequest', insert(insert(a:args, 'ruby_'.a:method), s:host)) endfunction + +let s:err = '' +let s:prog = provider#ruby#Detect() +let s:plugin_path = expand('<sfile>:p:h') . '/script_host.rb' + +if empty(s:prog) + let s:err = 'Cannot find the neovim RubyGem. Try :CheckHealth' +endif + +call remote#host#RegisterClone('legacy-ruby-provider', 'ruby') +call remote#host#RegisterPlugin('legacy-ruby-provider', s:plugin_path, []) diff --git a/runtime/autoload/provider/script_host.rb b/runtime/autoload/provider/script_host.rb new file mode 100644 index 0000000000..1dade766c7 --- /dev/null +++ b/runtime/autoload/provider/script_host.rb @@ -0,0 +1,8 @@ +begin + require "neovim/ruby_provider" +rescue LoadError + warn( + "Your neovim RubyGem is missing or out of date. " + + "Install the latest version using `gem install neovim`." + ) +end diff --git a/runtime/autoload/remote/host.vim b/runtime/autoload/remote/host.vim index a63c6a923b..4ec2eeb5b7 100644 --- a/runtime/autoload/remote/host.vim +++ b/runtime/autoload/remote/host.vim @@ -1,7 +1,5 @@ let s:hosts = {} let s:plugin_patterns = {} -let s:remote_plugins_manifest = fnamemodify(expand($MYVIMRC, 1), ':h') - \.'/.'.fnamemodify($MYVIMRC, ':t').'-rplugin~' let s:plugins_for_host = {} @@ -120,9 +118,18 @@ function! remote#host#RegisterPlugin(host, path, specs) abort endfunction +function! s:GetManifest() abort + let prefix = exists('$MYVIMRC') + \ ? $MYVIMRC + \ : matchstr(get(split(capture('scriptnames'), '\n'), 0, ''), '\f\+$') + return fnamemodify(expand(prefix, 1), ':h') + \.'/.'.fnamemodify(prefix, ':t').'-rplugin~' +endfunction + + function! remote#host#LoadRemotePlugins() abort - if filereadable(s:remote_plugins_manifest) - exe 'source '.s:remote_plugins_manifest + if filereadable(s:GetManifest()) + exe 'source '.s:GetManifest() endif endfunction @@ -194,9 +201,9 @@ function! remote#host#UpdateRemotePlugins() abort endtry endif endfor - call writefile(commands, s:remote_plugins_manifest) + call writefile(commands, s:GetManifest()) echomsg printf('remote/host: generated the manifest file in "%s"', - \ s:remote_plugins_manifest) + \ s:GetManifest()) endfunction @@ -210,12 +217,12 @@ endfunction function! remote#host#LoadErrorForHost(host, log) abort return 'Failed to load '. a:host . ' host. '. - \ 'You can try to see what happened '. - \ 'by starting Neovim with the environment variable '. - \ a:log . ' set to a file and opening the generated '. - \ 'log file. Also, the host stderr will be available '. - \ 'in Neovim log, so it may contain useful information. '. - \ 'See also ~/.nvimlog.' + \ 'You can try to see what happened '. + \ 'by starting Neovim with the environment variable '. + \ a:log . ' set to a file and opening the generated '. + \ 'log file. Also, the host stderr will be available '. + \ 'in Neovim log, so it may contain useful information. '. + \ 'See also ~/.nvimlog.' endfunction diff --git a/runtime/autoload/sqlcomplete.vim b/runtime/autoload/sqlcomplete.vim index 4a8863e15f..e80729add4 100644 --- a/runtime/autoload/sqlcomplete.vim +++ b/runtime/autoload/sqlcomplete.vim @@ -1,8 +1,8 @@ " Vim OMNI completion script for SQL " Language: SQL " Maintainer: David Fishburn <dfishburn dot vim at gmail dot com> -" Version: 15.0 -" Last Change: 2013 May 13 +" Version: 16.0 +" Last Change: 2015 Dec 29 " Homepage: http://www.vim.org/scripts/script.php?script_id=1572 " Usage: For detailed help " ":help sql.txt" @@ -16,6 +16,12 @@ " look backwards to a FROM clause and find the first table " and complete it. " +" Version 16.0 (Dec 2015) +" - NF: If reseting the cache and table, procedure or view completion +" had been used via dbext, have dbext delete or recreate the +" dictionary so that new objects are picked up for the +" next completion. +" " Version 15.0 (May 2013) " - NF: Changed the SQL precached syntax items, omni_sql_precache_syntax_groups, " to use regular expressions to pick up extended syntax group names. @@ -103,7 +109,7 @@ endif if exists('g:loaded_sql_completion') finish endif -let g:loaded_sql_completion = 150 +let g:loaded_sql_completion = 160 let s:keepcpo= &cpo set cpo&vim @@ -459,6 +465,29 @@ function! sqlcomplete#Complete(findstart, base) let s:tbl_cols = [] let s:syn_list = [] let s:syn_value = [] + + if s:sql_file_table != "" + if g:loaded_dbext >= 2300 + call DB_DictionaryDelete("table") + else + DBCompleteTables! + endif + endif + if s:sql_file_procedure != "" + if g:loaded_dbext >= 2300 + call DB_DictionaryDelete("procedure") + else + DBCompleteProcedures! + endif + endif + if s:sql_file_view != "" + if g:loaded_dbext >= 2300 + call DB_DictionaryDelete("view") + else + DBCompleteViews! + endif + endif + let s:sql_file_table = "" let s:sql_file_procedure = "" let s:sql_file_view = "" diff --git a/runtime/doc/Makefile b/runtime/doc/Makefile index 7423e63673..3d10d0ea98 100644 --- a/runtime/doc/Makefile +++ b/runtime/doc/Makefile @@ -6,32 +6,14 @@ AWK = awk -# Set to $(VIMTARGET) when executed from src/Makefile. -VIMEXE = vim - DOCS = $(wildcard *.txt) HTMLS = $(DOCS:.txt=.html) .SUFFIXES: .SUFFIXES: .c .o .txt .html -all: tags html - -# Use Vim to generate the tags file. Can only be used when Vim has been -# compiled and installed. Supports multiple languages. -vimtags: $(DOCS) - $(VIMEXE) -u NONE -es -c "helptags ++t ." -c quit - -# Use "doctags" to generate the tags file. Only works for English! -tags: doctags $(DOCS) - ./doctags $(DOCS) | LANG=C LC_ALL=C sort >tags - uniq -d -2 tags - -doctags: doctags.c - $(CC) doctags.c -o doctags - # Awk version of .txt to .html conversion. -html: noerrors tags $(HTMLS) +html: noerrors $(HTMLS) @if test -f errors.log; then cat errors.log; fi noerrors: @@ -54,5 +36,5 @@ tags.ref tags.html: tags $(AWK) -f maketags.awk tags >tags.html clean: - -rm -f doctags *.html tags.ref $(HTMLS) errors.log + -rm -f *.html tags.ref $(HTMLS) errors.log diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index ca79465e0d..bdeca367b1 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -1,31 +1,32 @@ -*api.txt* For Nvim. {Nvim} +*api.txt* {Nvim} NVIM REFERENCE MANUAL by Thiago de Arruda -The C API of Nvim *nvim-api* -1. Introduction |nvim-api-intro| -2. API Types |nvim-api-types| -3. API metadata |nvim-api-metadata| -4. Buffer highlighting |nvim-api-highlights| +C API for Nvim *API* *api* + +1. Introduction |api-intro| +2. API Types |api-types| +3. API metadata |api-metadata| +4. Buffer highlighting |api-highlights| ============================================================================== -1. Introduction *nvim-api-intro* +1. Introduction *api-intro* -Nvim defines a C API as the primary way for external code to interact with -the NVim core. In the present version of Nvim the API is primarily used by -external processes to interact with Nvim using the msgpack-rpc protocol, see -|msgpack-rpc|. The API will also be used from vimscript to access new Nvim core -features, but this is not implemented yet. Later on, Nvim might be embeddable -in C applications as libnvim, and the application will then control the -embedded instance by calling the C API directly. +Nvim exposes a public API for external code to interact with the Nvim core. In +the present version of Nvim the API is primarily used by external processes to +interact with Nvim using the msgpack-rpc protocol, see |msgpack-rpc|. The API +will also be used from vimscript to access new Nvim core features, but this is +not implemented yet. Later on, Nvim might be embeddable in C applications as +libnvim, and the application will then control the embedded instance by +calling the C API directly. ============================================================================== -2. API Types *nvim-api-types* +2. API Types *api-types* Nvim's C API uses custom types for all functions. Some are just typedefs -around C99 standard types, and some are Nvim defined data structures. +around C99 standard types, and some are Nvim-defined data structures. Boolean -> bool Integer (signed 64-bit integer) -> int64_t @@ -46,7 +47,7 @@ Window -> enum value kObjectTypeWindow Tabpage -> enum value kObjectTypeTabpage ============================================================================== -3. API metadata *nvim-api-metadata* +3. API metadata *api-metadata* Nvim exposes metadata about the API as a Dictionary with the following keys: @@ -54,11 +55,11 @@ functions calling signature of the API functions types The custom handle types defined by Nvim error_types The possible kinds of errors an API function can exit with. -This metadata is mostly useful for external programs accessing the api over -msgpack-api, see |msgpack-rpc-api|. +This metadata is mostly useful for external programs accessing the API via +RPC, see |rpc-api|. ============================================================================== -4. Buffer highlighting *nvim-api-highlights* +4. Buffer highlighting *api-highlights* Nvim allows plugins to add position-based highlights to buffers. This is similar to |matchaddpos()| but with some key differences. The added highlights diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 25ae94f784..dc37ff1d6d 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -1,4 +1,4 @@ -*autocmd.txt* For Vim version 7.4. Last change: 2015 Dec 05 +*autocmd.txt* For Vim version 7.4. Last change: 2016 Mar 26 VIM REFERENCE MANUAL by Bram Moolenaar @@ -912,8 +912,7 @@ TermClose When a terminal buffer ends. {Nvim} *TermOpen* TermOpen When a terminal buffer is starting. This can be used to configure the terminal emulator by - setting buffer variables. - See |nvim-terminal-emulator| for details. + setting buffer variables. |terminal-emulator| *TermResponse* TermResponse After the response to |t_RV| is received from the terminal. The value of |v:termresponse| diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index c8eb0705f6..2ccb9188a9 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1,4 +1,4 @@ -*change.txt* For Vim version 7.4. Last change: 2016 Jan 02 +*change.txt* For Vim version 7.4. Last change: 2016 Mar 08 VIM REFERENCE MANUAL by Bram Moolenaar @@ -97,10 +97,10 @@ These commands delete text. You can repeat them with the `.` command An exception for the d{motion} command: If the motion is not linewise, the start and end of the motion are not in the same line, and there are only -blanks before the start and after the end of the motion, the delete becomes -linewise. This means that the delete also removes the line of blanks that you -might expect to remain. Use the |o_v| operator to force the motion to be -characterwise. +blanks before the start and there are no non-blanks after the end of the +motion, the delete becomes linewise. This means that the delete also removes +the line of blanks that you might expect to remain. Use the |o_v| operator to +force the motion to be characterwise. Trying to delete an empty region of text (e.g., "d0" in the first column) is an error when 'cpoptions' includes the 'E' flag. @@ -108,7 +108,9 @@ is an error when 'cpoptions' includes the 'E' flag. *J* J Join [count] lines, with a minimum of two lines. Remove the indent and insert up to two spaces (see - below). + below). Fails when on the last line of the buffer. + If [count] is too big it is reduce to the number of + lines available. *v_J* {Visual}J Join the highlighted lines, with a minimum of two @@ -396,6 +398,11 @@ CTRL-X Subtract [count] from the number or alphabetic {Visual}CTRL-X Subtract [count] from the number or alphabetic character in the highlighted text. {not in Vi} + On MS-Windows, this is mapped to cut Visual text + |dos-standard-mappings|. If you want to disable the + mapping, use this: > + silent! vunmap <C-X> +< *v_g_CTRL-X* {Visual}g CTRL-X Subtract [count] from the number or alphabetic character in the highlighted text. If several lines @@ -1245,7 +1252,7 @@ register. Use these registers for storing and retrieving the selected text for the GUI. See |quotestar| and |quoteplus|. When the clipboard is not available or not working, the unnamed register is used instead. For Unix systems and Mac OS X, -see |nvim-clipboard|. +see |primary-selection|. 9. Black hole register "_ *quote_* When writing to this register, nothing happens. This can be used to delete diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt index 668790358b..6ecbf9fb0d 100644 --- a/runtime/doc/develop.txt +++ b/runtime/doc/develop.txt @@ -1,23 +1,19 @@ -*develop.txt* For Vim version 7.4. Last change: 2014 Mar 27 +*develop.txt* - VIM REFERENCE MANUAL by Bram Moolenaar + NVIM REFERENCE MANUAL -Development of Vim. *development* - -This text is important for those who want to be involved in further developing -Vim. +Development of Nvim. *development* 1. Design goals |design-goals| 2. Design decisions |design-decisions| -See the file "src/nvim/README.md" for a high-level overview of the source -code. +Nvim is open source software. Everybody is encouraged to contribute. + https://github.com/neovim/neovim/blob/master/CONTRIBUTING.md -Vim is open source software. Everybody is encouraged to contribute to help -improving Vim. For sending patches a context diff "diff -c" is preferred. -Also see http://vim.wikia.com/wiki/How_to_make_and_submit_a_patch. +See src/nvim/README.md for a high-level overview of the source code: + https://github.com/neovim/neovim/blob/master/src/nvim/README.md ============================================================================== 1. Design goals *design-goals* @@ -28,7 +24,7 @@ Note that quite a few items are contradicting. This is intentional. A balance must be found between them. -VIM IS... IMPROVED *design-improved* +NVIM IS... IMPROVED *design-improved* The IMproved bits of Vim should make it a better Vi, without becoming a completely different editor. Extensions are done with a "Vi spirit". @@ -49,7 +45,7 @@ completely different editor. Extensions are done with a "Vi spirit". implement and (3) someone actually implementing it. -VIM IS... MULTI PLATFORM *design-multi-platform* +NVIM IS... MULTI PLATFORM *design-multi-platform* Vim tries to help as many users on as many platforms as possible. - Support many kinds of terminals. The minimal demands are cursor positioning @@ -68,7 +64,7 @@ Vim tries to help as many users on as many platforms as possible. contradicts the previous item, these two must be balanced.] -VIM IS... WELL DOCUMENTED *design-documented* +NVIM IS... WELL DOCUMENTED *design-documented* - A feature that isn't documented is a useless feature. A patch for a new feature must include the documentation. @@ -76,9 +72,14 @@ VIM IS... WELL DOCUMENTED *design-documented* recommended. - Don't make the text unnecessarily long. Less documentation means that an item is easier to find. +- Do not prefix doc-tags with "nvim-". Use |vim_diff.txt| to document + differences from Vim. The {Nvim} annotation is also available + to mark a specific feature. No other distinction is necessary. +- If a feature is removed, delete its doc entry and move its tag to + |vim_diff.txt|. -VIM IS... HIGH SPEED AND SMALL IN SIZE *design-speed-size* +NVIM IS... HIGH SPEED AND SMALL IN SIZE *design-speed-size* Using Vim must not be a big attack on system resources. Keep it small and fast. @@ -89,13 +90,11 @@ fast. possible. Useful commands may take longer. - Don't forget that some people use Vim over a slow connection. Minimize the communication overhead. -- Items that add considerably to the size and are not used by many people - should be a feature that can be disabled. - Vim is a component among other components. Don't turn it into a massive application, but have it work well together with other programs. -VIM IS... MAINTAINABLE *design-maintain* +NVIM IS... MAINTAINABLE *design-maintain* - The source code should not become a mess. It should be reliable code. - Use comments in a useful way! Quoting the function name and argument names @@ -106,7 +105,7 @@ VIM IS... MAINTAINABLE *design-maintain* knowledge spread to other parts of the code. -VIM IS... FLEXIBLE *design-flexible* +NVIM IS... FLEXIBLE *design-flexible* Vim should make it easy for users to work in their preferred styles rather than coercing its users into particular patterns of work. This can be for @@ -117,28 +116,22 @@ be used to adjust Vim to the desire of the user and its environment. NVIM IS... NOT *design-not* -Nvim is not an Operating System; instead it should be composed with other -tools, or hosted as a component. Marvim once said: "Unlike Emacs, Nvim does -not attempt to include everything but the kitchen sink, but some people use it -for plumbing." +Nvim is not an operating system; instead it should be composed with other +tools or hosted as a component. Marvim once said: "Unlike Emacs, Nvim does not +include the kitchen sink... but you can use it for plumbing." ============================================================================== 2. Design decisions *design-decisions* -Folding - -Several forms of folding should be possible for the same buffer. For example, -have one window that shows the text with function bodies folded, another -window that shows a function body. - -Folding is a way to display the text. It should not change the text itself. -Therefore the folding has been implemented as a filter between the text stored -in a buffer (buffer lines) and the text displayed in a window (logical lines). - +Jargon *dev-jargon* -Naming the window +Host ~ +A plugin "host" is both a client (of the Nvim API) and a server (of an +external platform, e.g. python). It is a remote plugin that hosts other +plugins. +Window ~ The word "window" is commonly used for several things: A window on the screen, the xterm window, a window inside Vim to view a buffer. To avoid confusion, other items that are sometimes called window have been @@ -152,111 +145,52 @@ window View on a buffer. There can be several windows in Vim, together with the command line, menubar, toolbar, etc. they fit in the shell. +Providers *dev-provider* + +A goal of Nvim is to allow extension of the editor without special knowledge +in the core. But some Vim components are too tightly coupled; in those cases +a "provider" hook is exposed. + +Consider two examples of integration with external systems that are +implemented in Vim and are now decoupled from Nvim core as providers: + +1. In the Vim source code, clipboard logic accounts for more than 1k lines of + C source code (ui.c), to perform two tasks that are now accomplished with + shell commands such as xclip or pbcopy/pbpaste. + +2. Python scripting support: Vim has three files dedicated to embedding the + Python interpreter: if_python.c, if_python3.c and if_py_both.h. Together + these files sum about 9.5k lines of C source code. In contrast, Nvim Python + scripting is performed by an external host process implemented in ~2k lines + of Python. + +Ideally we could implement Python and clipboard integration in pure vimscript +and without touching the C code. But this is infeasible without compromising +backwards compatibility with Vim; that's where providers help. + +The provider framework helps call vimscript from C. It is composed of two +functions in eval.c: + +- eval_call_provider(name, method, arguments): calls provider#(name)#Call + with the method and arguments. +- eval_has_provider(name): Checks if a provider is implemented. Returns true + if the provider#(name)#Call function is implemented. Called by |has()| + (vimscript) to check if features are available. + +The provider#(name)#Call function implements integration with an external +system, because shell commands and |RPC| clients are easier to work with in +vimscript. + +For example, the Python provider is implemented by the +autoload/provider/python.vim script; the provider#python#Call function is only +defined if a valid external Python host is found. That works well with the +`has('python')` expression (normally used by Python plugins) because if the +Python host isn't installed then the plugin will "think" it is running in +a Vim compiled without the |+python| feature. + -Spell checking *develop-spell* - -When spell checking was going to be added to Vim a survey was done over the -available spell checking libraries and programs. Unfortunately, the result -was that none of them provided sufficient capabilities to be used as the spell -checking engine in Vim, for various reasons: - -- Missing support for multi-byte encodings. At least UTF-8 must be supported, - so that more than one language can be used in the same file. - Doing on-the-fly conversion is not always possible (would require iconv - support). -- For the programs and libraries: Using them as-is would require installing - them separately from Vim. That's mostly not impossible, but a drawback. -- Performance: A few tests showed that it's possible to check spelling on the - fly (while redrawing), just like syntax highlighting. But the mechanisms - used by other code are much slower. Myspell uses a hashtable, for example. - The affix compression that most spell checkers use makes it slower too. -- For using an external program like aspell a communication mechanism would - have to be setup. That's complicated to do in a portable way (Unix-only - would be relatively simple, but that's not good enough). And performance - will become a problem (lots of process switching involved). -- Missing support for words with non-word characters, such as "Etten-Leur" and - "et al.", would require marking the pieces of them OK, lowering the - reliability. -- Missing support for regions or dialects. Makes it difficult to accept - all English words and highlight non-Canadian words differently. -- Missing support for rare words. Many words are correct but hardly ever used - and could be a misspelled often-used word. -- For making suggestions the speed is less important and requiring to install - another program or library would be acceptable. But the word lists probably - differ, the suggestions may be wrong words. - - -Spelling suggestions *develop-spell-suggestions* - -For making suggestions there are two basic mechanisms: -1. Try changing the bad word a little bit and check for a match with a good - word. Or go through the list of good words, change them a little bit and - check for a match with the bad word. The changes are deleting a character, - inserting a character, swapping two characters, etc. -2. Perform soundfolding on both the bad word and the good words and then find - matches, possibly with a few changes like with the first mechanism. - -The first is good for finding typing mistakes. After experimenting with -hashtables and looking at solutions from other spell checkers the conclusion -was that a trie (a kind of tree structure) is ideal for this. Both for -reducing memory use and being able to try sensible changes. For example, when -inserting a character only characters that lead to good words need to be -tried. Other mechanisms (with hashtables) need to try all possible letters at -every position in the word. Also, a hashtable has the requirement that word -boundaries are identified separately, while a trie does not require this. -That makes the mechanism a lot simpler. - -Soundfolding is useful when someone knows how the words sounds but doesn't -know how it is spelled. For example, the word "dictionary" might be written -as "daktonerie". The number of changes that the first method would need to -try is very big, it's hard to find the good word that way. After soundfolding -the words become "tktnr" and "tkxnry", these differ by only two letters. - -To find words by their soundfolded equivalent (soundalike word) we need a list -of all soundfolded words. A few experiments have been done to find out what -the best method is. Alternatives: -1. Do the sound folding on the fly when looking for suggestions. This means - walking through the trie of good words, soundfolding each word and - checking how different it is from the bad word. This is very efficient for - memory use, but takes a long time. On a fast PC it takes a couple of - seconds for English, which can be acceptable for interactive use. But for - some languages it takes more than ten seconds (e.g., German, Catalan), - which is unacceptable slow. For batch processing (automatic corrections) - it's too slow for all languages. -2. Use a trie for the soundfolded words, so that searching can be done just - like how it works without soundfolding. This requires remembering a list - of good words for each soundfolded word. This makes finding matches very - fast but requires quite a lot of memory, in the order of 1 to 10 Mbyte. - For some languages more than the original word list. -3. Like the second alternative, but reduce the amount of memory by using affix - compression and store only the soundfolded basic word. This is what Aspell - does. Disadvantage is that affixes need to be stripped from the bad word - before soundfolding it, which means that mistakes at the start and/or end - of the word will cause the mechanism to fail. Also, this becomes slow when - the bad word is quite different from the good word. - -The choice made is to use the second mechanism and use a separate file. This -way a user with sufficient memory can get very good suggestions while a user -who is short of memory or just wants the spell checking and no suggestions -doesn't use so much memory. - - -Word frequency - -For sorting suggestions it helps to know which words are common. In theory we -could store a word frequency with the word in the dictionary. However, this -requires storing a count per word. That degrades word tree compression a lot. -And maintaining the word frequency for all languages will be a heavy task. -Also, it would be nice to prefer words that are already in the text. This way -the words that appear in the specific text are preferred for suggestions. - -What has been implemented is to count words that have been seen during -displaying. A hashtable is used to quickly find the word count. The count is -initialized from words listed in COMMON items in the affix file, so that it -also works when starting a new file. - -This isn't ideal, because the longer Vim is running the higher the counts -become. But in practice it is a noticeable improvement over not using the word -count. +RPC API +API client +remote plugin vim:tw=78:ts=8:ft=help:norl: diff --git a/runtime/doc/doctags.c b/runtime/doc/doctags.c deleted file mode 100644 index 9213dd9c1e..0000000000 --- a/runtime/doc/doctags.c +++ /dev/null @@ -1,83 +0,0 @@ -/* vim:set ts=4 sw=4: - * this program makes a tags file for vim_ref.txt - * - * Usage: doctags vim_ref.txt vim_win.txt ... >tags - * - * A tag in this context is an identifier between stars, e.g. *c_files* - */ - -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <stdlib.h> - -#define LINELEN 200 - - int -main(argc, argv) - int argc; - char **argv; -{ - char line[LINELEN]; - char *p1, *p2; - char *p; - FILE *fd; - - if (argc <= 1) - { - fprintf(stderr, "Usage: doctags docfile ... >tags\n"); - exit(1); - } - printf("help-tags\ttags\t1\n"); - while (--argc > 0) - { - ++argv; - fd = fopen(argv[0], "r"); - if (fd == NULL) - { - fprintf(stderr, "Unable to open %s for reading\n", argv[0]); - continue; - } - while (fgets(line, LINELEN, fd) != NULL) - { - p1 = strchr(line, '*'); /* find first '*' */ - while (p1 != NULL) - { - p2 = strchr(p1 + 1, '*'); /* find second '*' */ - if (p2 != NULL && p2 > p1 + 1) /* skip "*" and "**" */ - { - for (p = p1 + 1; p < p2; ++p) - if (*p == ' ' || *p == '\t' || *p == '|') - break; - /* - * Only accept a *tag* when it consists of valid - * characters, there is white space before it and is - * followed by a white character or end-of-line. - */ - if (p == p2 - && (p1 == line || p1[-1] == ' ' || p1[-1] == '\t') - && (strchr(" \t\n\r", p[1]) != NULL - || p[1] == '\0')) - { - *p2 = '\0'; - ++p1; - printf("%s\t%s\t/*", p1, argv[0]); - while (*p1) - { - /* insert backslash before '\\' and '/' */ - if (*p1 == '\\' || *p1 == '/') - putchar('\\'); - putchar(*p1); - ++p1; - } - printf("*\n"); - p2 = strchr(p2 + 1, '*'); /* find next '*' */ - } - } - p1 = p2; - } - } - fclose(fd); - } - return 0; -} diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt index c51286a350..6f85436ab4 100644 --- a/runtime/doc/editing.txt +++ b/runtime/doc/editing.txt @@ -1,4 +1,4 @@ -*editing.txt* For Vim version 7.4. Last change: 2016 Jan 03 +*editing.txt* For Vim version 7.4. Last change: 2016 Mar 28 VIM REFERENCE MANUAL by Bram Moolenaar @@ -358,7 +358,7 @@ These are the common ones: To avoid the special meaning of the wildcards prepend a backslash. However, on MS-Windows the backslash is a path separator and "path\[abc]" is still seen as a wildcard when "[" is in the 'isfname' option. A simple way to avoid this -is to use "path\[[]abc]". Then the file "path[abc]" literally. +is to use "path\[[]abc]", this matches the file "path\[abc]". *starstar-wildcard* Expanding "**" is possible on Unix, Win32, Mac OS/X and a few other systems. @@ -368,16 +368,21 @@ Note there are some commands where this works slightly differently, see Example: > :n **/*.txt Finds files: - ttt.txt - subdir/ttt.txt - a/b/c/d/ttt.txt -When non-wildcard characters are used these are only matched in the first -directory. Example: > - :n /usr/inc**/*.h + aaa.txt ~ + subdir/bbb.txt ~ + a/b/c/d/ccc.txt ~ +When non-wildcard characters are used right before or after "**" these are +only matched in the top directory. They are not used for directories further +down in the tree. For example: > + :n /usr/inc**/types.h Finds files: - /usr/include/types.h - /usr/include/sys/types.h - /usr/inc_old/types.h + /usr/include/types.h ~ + /usr/include/sys/types.h ~ + /usr/inc/old/types.h ~ +Note that the path with "/sys" is included because it does not need to match +"/inc". Thus it's like matching "/usr/inc*/*/*...", not +"/usr/inc*/inc*/inc*". + *backtick-expansion* *`-expansion* On Unix and a few other systems you can also use backticks for the file name argument, for example: > @@ -596,6 +601,7 @@ list of the current window. :0argadd x x a b c :1argadd x a x b c :$argadd x a b c x + And after the last one: :+2argadd y a b c x y There is no check for duplicates, it is possible to add a file to the argument list twice. @@ -946,7 +952,7 @@ the newly written file (it might be there but contain bogus data). In that case try recovery, because the swap file is synced to disk and might still be there. |:recover| -The directories given with the 'backupdir' option is used to put the backup +The directories given with the 'backupdir' option are used to put the backup file in. (default: same directory as the written file). Whether the backup is a new file, which is a copy of the original file, or the diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index a8504e2a2a..0ca41370e9 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 7.4. Last change: 2016 Jan 16 +*eval.txt* For Vim version 7.4. Last change: 2016 Apr 12 VIM REFERENCE MANUAL by Bram Moolenaar @@ -100,6 +100,9 @@ When mixing Number and Float the Number is converted to Float. Otherwise there is no automatic conversion of Float. You can use str2float() for String to Float, printf() for Float to String and float2nr() for Float to Number. + *E891* *E892* *E893* *E894* +When expecting a Float a Number can also be used, but nothing else. + *E706* *sticky-type-checking* You will get an error if you try to change the type of a variable. You need to |:unlet| it first to avoid this error. String and Number are considered @@ -410,7 +413,8 @@ only appear once. Examples: > A key is always a String. You can use a Number, it will be converted to a String automatically. Thus the String '4' and the number 4 will find the same entry. Note that the String '04' and the Number 04 are different, since the -Number will be converted to the String '4'. +Number will be converted to the String '4'. The empty string can be used as a +key. A value can be any expression. Using a Dictionary for a value creates a nested Dictionary: > @@ -858,11 +862,12 @@ These three can be repeated and mixed. Examples: expr8 *expr8* ----- expr8[expr1] item of String or |List| *expr-[]* *E111* + *subscript* If expr8 is a Number or String this results in a String that contains the expr1'th single byte from expr8. expr8 is used as a String, expr1 as a Number. This doesn't recognize multi-byte encodings, see |byteidx()| for -an alternative. +an alternative, or use `split()` to turn the string into a list of characters. Index zero gives the first byte. This is like it works in C. Careful: text column numbers start with one! Example, to get the byte under the @@ -870,7 +875,7 @@ cursor: > :let c = getline(".")[col(".") - 1] If the length of the String is less than the index, the result is an empty -String. A negative index always results in an empty string (reason: backwards +String. A negative index always results in an empty string (reason: backward compatibility). Use [-1:] to get the last byte. If expr8 is a |List| then it results the item at index expr1. See |list-index| @@ -1650,9 +1655,9 @@ v:scrollstart String describing the script or function that caused the hit-enter prompt. *v:servername* *servername-variable* + *$NVIM_LISTEN_ADDRESS* v:servername Default {Nvim} server address. Equivalent to - |$NVIM_LISTEN_ADDRESS| on startup, but may differ if the - latter is modified or unset. |serverstop()| + |$NVIM_LISTEN_ADDRESS| on startup. |serverstop()| Read-only. @@ -1780,6 +1785,7 @@ abs({expr}) Float or Number absolute value of {expr} acos({expr}) Float arc cosine of {expr} add({list}, {item}) List append {item} to |List| {list} and({expr}, {expr}) Number bitwise AND +api_info() Dict api metadata append({lnum}, {string}) Number append {string} below line {lnum} append({lnum}, {list}) Number append lines {list} below line {lnum} argc() Number number of files in the argument list @@ -1788,8 +1794,8 @@ arglistid([{winnr} [, {tabnr}]]) Number argument list id argv({nr}) String {nr} entry of the argument list argv() List the argument list assert_equal({exp}, {act} [, {msg}]) none assert {exp} equals {act} -assert_exception({error} [, {msg}]) none assert {error} is in v:exception -assert_fails( {cmd} [, {error}]) none assert {cmd} fails +assert_exception( {error} [, {msg}]) none assert {error} is in v:exception +assert_fails( {cmd} [, {error}]) none assert {cmd} fails assert_false({actual} [, {msg}]) none assert {actual} is false assert_true({actual} [, {msg}]) none assert {actual} is true asin({expr}) Float arc sine of {expr} @@ -1809,6 +1815,7 @@ byteidx({expr}, {nr}) Number byte index of {nr}'th char in {expr} byteidxcomp({expr}, {nr}) Number byte index of {nr}'th char in {expr} call({func}, {arglist} [, {dict}]) any call {func} with arguments {arglist} +capture({command}) String capture output of {command} ceil({expr}) Float round {expr} up changenr() Number current change number char2nr({expr}[, {utf8}]) Number ASCII/UTF8 value of first char in {expr} @@ -1887,7 +1894,7 @@ getcmdpos() Number return cursor position in command-line getcmdtype() String return current command-line type getcmdwintype() String return current command-line window type getcurpos() List position of the cursor -getcwd([{scope}]) String the current working directory +getcwd([{winnr} [, {tabnr}]]) String the current working directory getfontname([{name}]) String name of font being used getfperm({fname}) String file permissions of file {fname} getfsize({fname}) Number size in bytes of file {fname} @@ -1918,10 +1925,11 @@ globpath({path}, {expr} [, {nosuf} [, {list} [, {alllinks}]]]) String do glob({expr}) for all dirs in {path} has({feature}) Number TRUE if feature {feature} supported has_key({dict}, {key}) Number TRUE if {dict} has entry {key} -haslocaldir() Number TRUE if current window executed |:lcd| +haslocaldir([{winnr} [, {tabnr}]]) + Number TRUE if current window executed |:lcd| hasmapto({what} [, {mode} [, {abbr}]]) Number TRUE if mapping to {what} exists -histadd({history},{item}) String add an item to a history +histadd({history}, {item}) String add an item to a history histdel({history} [, {item}]) String remove an item from a history histget({history} [, {index}]) String get the item {index} from a history histnr({history}) Number highest index of a history @@ -2027,11 +2035,11 @@ resolve({filename}) String get filename a shortcut points to reverse({list}) List reverse {list} in-place round({expr}) Float round off {expr} rpcnotify({channel}, {event}[, {args}...]) - Sends a |msgpack-rpc| notification to {channel} + Sends an |RPC| notification to {channel} rpcrequest({channel}, {method}[, {args}...]) - Sends a |msgpack-rpc| request to {channel} -rpcstart({prog}[, {argv}]) Spawns {prog} and opens a |msgpack-rpc| channel -rpcstop({channel}) Closes a |msgpack-rpc| {channel} + Sends an |RPC| request to {channel} +rpcstart({prog}[, {argv}]) Spawns {prog} and opens an |RPC| channel +rpcstop({channel}) Closes an |RPC| {channel} screenattr({row}, {col}) Number attribute at screen position screenchar({row}, {col}) Number character at screen position screencol() Number current cursor column @@ -2149,6 +2157,7 @@ writefile({list}, {fname} [, {flags}]) Number write list of lines to file {fname} xor({expr}, {expr}) Number bitwise XOR + abs({expr}) *abs()* Return the absolute value of {expr}. When {expr} evaluates to a |Float| abs() returns a |Float|. When {expr} can be @@ -2192,6 +2201,10 @@ and({expr}, {expr}) *and()* :let flag = and(bits, 0x80) +api_info() *api_info()* + Returns Dictionary of |api-metadata|. + + append({lnum}, {expr}) *append()* When {expr} is a |List|: Append each item of the |List| as a text line below line {lnum} in the current buffer. @@ -2212,7 +2225,7 @@ argidx() The result is the current index in the argument list. 0 is the first file. argc() - 1 is the last one. See |arglist|. *arglistid()* -arglistid([{winnr}, [ {tabnr} ]]) +arglistid([{winnr} [, {tabnr}]]) Return the argument list ID. This is a number which identifies the argument list being used. Zero is used for the global argument list. See |arglist|. @@ -2487,6 +2500,21 @@ call({func}, {arglist} [, {dict}]) *call()* *E699* {dict} is for functions with the "dict" attribute. It will be used to set the local variable "self". |Dictionary-function| +capture({command}) *capture()* + Capture output of {command}. + If {command} is a |String|, returns {command} output. + If {command} is a |List|, returns concatenated outputs. + Examples: > + echo capture('echon "foo"') +< foo > + echo capture(['echon "foo"', 'echon "bar"']) +< foobar + This function is not available in the |sandbox|. + Note: {command} executes as if prepended with |:silent| + (output is collected, but not displayed). If nested, an outer + capture() will not observe the output of inner calls. + Note: Text attributes (highlights) are not captured. + ceil({expr}) *ceil()* Return the smallest integral value greater than or equal to {expr} as a |Float| (round up). @@ -2754,6 +2782,7 @@ cursor({list}) When there is one argument {list} this is used as a |List| with two, three or four item: + [{lnum}, {col}] [{lnum}, {col}, {off}] [{lnum}, {col}, {off}, {curswant}] This is like the return value of |getpos()| or |getcurpos()|, @@ -2820,6 +2849,13 @@ dictwatcheradd({dict}, {pattern}, {callback}) *dictwatcheradd()* After this is called, every change on {dict} and on keys matching {pattern} will result in {callback} being invoked. + For example, to watch all global variables: > + silent! call dictwatcherdel(g:, '*', 'OnDictChanged') + function! OnDictChanged(d,k,z) + echomsg string(a:k) string(a:z) + endfunction + call dictwatcheradd(g:, '*', 'OnDictChanged') +< For now {pattern} only accepts very simple patterns that can contain a '*' at the end of the string, in which case it will match every key that begins with the substring before the '*'. @@ -2830,7 +2866,7 @@ dictwatcheradd({dict}, {pattern}, {callback}) *dictwatcheradd()* - The dictionary being watched. - The key which changed. - - A dictionary containg the new and old values for the key. + - A dictionary containing the new and old values for the key. The type of change can be determined by examining the keys present on the third argument: @@ -3171,6 +3207,14 @@ feedkeys({string} [, {mode}]) *feedkeys()* if coming from a mapping. This matters for undo, opening folds, etc. 'i' Insert the string instead of appending (see above). + 'x' Execute commands until typeahead is empty. This is + similar to using ":normal!". You can call feedkeys() + several times without 'x' and then one time with 'x' + (possibly with an empty {string}) to execute all the + typeahead. Note that when Vim ends in Insert mode it + will behave as if <Esc> is typed, to avoid getting + stuck, waiting for a character to be typed before the + script continues. Return value is always 0. filereadable({file}) *filereadable()* @@ -3590,17 +3634,17 @@ getcurpos() Get the position of the cursor. This is like getpos('.'), but MoveTheCursorAround call setpos('.', save_cursor) < -getcwd([{window}[, {tab}]]) *getcwd()* +getcwd([{winnr}[, {tabnr}]]) *getcwd()* With no arguments the result is a String, which is the name of - the current effective working directory. With {window} or - {tab} the working directory of that scope is returned. + the current effective working directory. With {winnr} or + {tabnr} the working directory of that scope is returned. Tabs and windows are identified by their respective numbers, 0 means current tab or window. Missing argument implies 0. Thus the following are equivalent: > getcwd() getcwd(0) getcwd(0, 0) -< If {window} is -1 it is ignored, only the tab is resolved. +< If {winnr} is -1 it is ignored, only the tab is resolved. getfsize({fname}) *getfsize()* @@ -3665,7 +3709,8 @@ getftype({fname}) *getftype()* getftype("/home") < Note that a type such as "link" will only be returned on systems that support it. On some systems only "dir" and - "file" are returned. + "file" are returned. On MS-Windows a symbolic link to a + directory returns "dir" instead of "link". *getline()* getline({lnum} [, {end}]) @@ -3938,7 +3983,7 @@ has_key({dict}, {key}) *has_key()* The result is a Number, which is 1 if |Dictionary| {dict} has an entry with key {key}. Zero otherwise. -haslocaldir([{window}[, {tab}]]) *haslocaldir()* +haslocaldir([{winnr}[, {tabnr}]]) *haslocaldir()* The result is a Number, which is 1 when the specified tabpage or window has a local path set via |:lcd| or |:tcd|, and 0 otherwise. @@ -3949,7 +3994,7 @@ haslocaldir([{window}[, {tab}]]) *haslocaldir()* haslocaldir() haslocaldir(0) haslocaldir(0, 0) -< If {window} is -1 it is ignored, only the tab is resolved. +< If {winnr} is -1 it is ignored, only the tab is resolved. hasmapto({what} [, {mode} [, {abbr}]]) *hasmapto()* The result is a Number, which is 1 if there is a mapping that @@ -4292,40 +4337,37 @@ jobsend({job}, {data}) {Nvim} *jobsend()* < will send "abc<NL>123<NUL>456<NL>". jobstart({cmd}[, {opts}]) {Nvim} *jobstart()* - Spawns {cmd} as a job. If {cmd} is a |List|, it will be run - directly. If {cmd} is a |string|, it will be roughly - equivalent to > - :call jobstart(split(&shell) + split(&shellcmdflag) + ['{cmd}']) + Spawns {cmd} as a job. If {cmd} is a |List| it is run + directly. If {cmd} is a |String| it is processed like this: > + :call jobstart(split(&shell) + split(&shellcmdflag) + ['{cmd}']) < NOTE: read |shell-unquoting| before constructing any lists with 'shell' or 'shellcmdflag' options. The above call is only written to show the idea, one needs to perform unquoting and do split taking quotes into account. - If passed, {opts} must be a dictionary with any of the - following keys: - - on_stdout: stdout event handler - - on_stderr: stderr event handler - - on_exit: exit event handler - - pty: If set, the job will be connected to a new pseudo - terminal, and the job streams are connected to the master - file descriptor. - - width: Width of the terminal screen(only if pty is set) - - height: Height of the terminal screen(only if pty is set) - - TERM: $TERM environment variable(only if pty is set) - - detach: Detach the job process from the nvim process. The - process won't get killed when nvim exists. If the process - dies before nvim exits, on_exit will still be invoked. - This option is only allowed for non-pty jobs. - Either funcrefs or function names can be passed as event - handlers. The {opts} object is also used as the "self" - argument for the callback, so the caller may pass arbitrary - data by setting other key.(see |Dictionary-function| for more - information). + + {opts} is a dictionary with these keys: + on_stdout: stdout event handler (function name or |Funcref|) + on_stderr: stderr event handler (function name or |Funcref|) + on_exit : exit event handler (function name or |Funcref|) + cwd : Working directory of the job; defaults to + |current-directory|. + pty : If set, the job will be connected to a new pseudo + terminal, and the job streams are connected to + the master file descriptor. + width : (pty only) Width of the terminal screen + height : (pty only) Height of the terminal screen + TERM : (pty only) $TERM environment variable + detach : (non-pty only) Detach the job process from the + nvim process. The process will not get killed + when nvim exits. If the process dies before + nvim exits, on_exit will still be invoked. + + {opts} is passed as |self| to the callback; the caller may + pass arbitrary data by setting other keys. Returns: - - The job ID on success, which is used by |jobsend()| and - |jobstop()| - - 0 when the job table is full or on invalid arguments - - -1 when {cmd}[0] is not executable. Will never fail if - {cmd} is a string unless 'shell' is not executable. + - job ID on success, used by |jobsend()| and |jobstop()| + - 0 on invalid arguments or if the job table is full + - -1 if {cmd}[0] is not executable. See |job-control| for more information. jobstop({job}) {Nvim} *jobstop()* @@ -4746,8 +4788,8 @@ matchadd({group}, {pattern}[, {priority}[, {id} [, {dict}]]]) respectively. If the {id} argument is not specified or -1, |matchadd()| automatically chooses a free ID. - The optional {dict} argmument allows for further custom - values. Currently this is used to specify a match specifc + The optional {dict} argument allows for further custom + values. Currently this is used to specify a match specific conceal character that will be shown for |hl-Conceal| highlighted matches. The dict can have the following members: @@ -5513,31 +5555,31 @@ round({expr}) *round()* < -5.0 rpcnotify({channel}, {event}[, {args}...]) {Nvim} *rpcnotify()* - Sends {event} to {channel} via |msgpack-rpc| and returns - immediately. If {channel} is 0, the event is broadcast to all - channels. Example: > + Sends {event} to {channel} via |RPC| and returns immediately. + If {channel} is 0, the event is broadcast to all channels. + Example: > :au VimLeave call rpcnotify(0, "leaving") rpcrequest({channel}, {method}[, {args}...]) {Nvim} *rpcrequest()* Sends a request to {channel} to invoke {method} via - |msgpack-rpc| and blocks until a response is received. + |RPC| and blocks until a response is received. Example: > :let result = rpcrequest(rpc_chan, "func", 1, 2, 3) rpcstart({prog}[, {argv}]) {Nvim} *rpcstart()* Spawns {prog} as a job (optionally passing the list {argv}), - and opens a |msgpack-rpc| channel with the spawned process's - stdin/stdout. It returns: - - The channel id on success, which is used by |rpcrequest()|, + and opens an |RPC| channel with the spawned process's + stdin/stdout. Returns: + - channel id on success, which is used by |rpcrequest()|, |rpcnotify()| and |rpcstop()| - - 0 on failure. + - 0 on failure Example: > :let rpc_chan = rpcstart('prog', ['arg1', 'arg2']) rpcstop({channel}) {Nvim} *rpcstop()* - Closes a |msgpack-rpc| {channel}, possibly created via + Closes an |RPC| {channel}, possibly created via |rpcstart()|. Also closes channels created by connections to - |$NVIM_LISTEN_ADDRESS|. + |v:servername|. screenattr(row, col) *screenattr()* Like screenchar(), but return the attribute. This is a rather @@ -5600,7 +5642,7 @@ search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *search()* 'ignorecase', 'smartcase' and 'magic' are used. - When the 'z' flag is not given seaching always starts in + When the 'z' flag is not given, searching always starts in column zero and then matches before the cursor are skipped. When the 'c' flag is present in 'cpo' the next search starts after the match. Without the 'c' flag the next search starts @@ -6026,7 +6068,7 @@ setqflist({list} [, {action}[, {title}]]) *setqflist()* *setreg()* -setreg({regname}, {value} [,{options}]) +setreg({regname}, {value} [, {options}]) Set the register {regname} to {value}. {value} may be any value returned by |getreg()|, including a |List|. @@ -6207,6 +6249,9 @@ sort({list} [, {func} [, {dict}]]) *sort()* *E702* sorted numerical. This is like 'n' but a string containing digits will be used as the number they represent. + When {func} is given and it is 'f' then all items will be + sorted numerical. All values must be a Number or a Float. + When {func} is a |Funcref| or a function name, this function is called to compare items. The function is invoked with two items as argument and must return zero if they are equal, 1 or @@ -6825,7 +6870,7 @@ termopen({cmd}[, {opts}]) {Nvim} *termopen()* and `$TERM` is set to "xterm-256color". Returns the same values as |jobstart()|. - See |nvim-terminal-emulator| for more information. + See |terminal-emulator| for more information. tan({expr}) *tan()* Return the tangent of {expr}, measured in radians, as a |Float| @@ -7287,7 +7332,7 @@ dialog_gui Compiled with GUI dialog support. digraphs Compiled with support for digraphs. eval Compiled with expression evaluation support. Always true, of course! -ex_extra Compiled with extra Ex commands |+ex_extra|. +ex_extra |+ex_extra|, always true now extra_search Compiled with support for |'incsearch'| and |'hlsearch'| farsi Compiled with Farsi support |farsi|. @@ -7370,6 +7415,7 @@ unix Unix version of Vim. user_commands User-defined commands. vertsplit Compiled with vertically split windows |:vsplit|. vim_starting True while initial source'ing takes place. |startup| + *vim_starting* virtualedit Compiled with 'virtualedit' option. visual Compiled with Visual mode. visualextra Compiled with extra Visual mode commands. @@ -7994,7 +8040,7 @@ This does NOT work: > From Vim version 4.5 until 5.0, every Ex command in between the ":if" and ":endif" is ignored. These two commands were just to allow for future expansions in a - backwards compatible way. Nesting was allowed. Note + backward compatible way. Nesting was allowed. Note that any ":else" or ":elseif" was ignored, the "else" part was not executed either. diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt index 8d97678af2..e2fb501ac5 100644 --- a/runtime/doc/gui.txt +++ b/runtime/doc/gui.txt @@ -395,9 +395,9 @@ You may make selections with the mouse (see |gui-mouse-select|), or by using Vim's Visual mode (see |v|). If 'a' is present in 'guioptions', then whenever a selection is started (Visual or Select mode), or when the selection is changed, Vim becomes the owner of the windowing system's primary selection -(on MS-Windows the |gui-clipboard| is used). +(on MS-Windows the |clipboard| is used). - *clipboard* + *primary-selection* There is a special register for storing this selection, it is the "* register. Nothing is put in here unless the information about what text is selected is about to change (e.g. with a left mouse click somewhere), or when diff --git a/runtime/doc/gui_w32.txt b/runtime/doc/gui_w32.txt deleted file mode 100644 index 228be9eab2..0000000000 --- a/runtime/doc/gui_w32.txt +++ /dev/null @@ -1,437 +0,0 @@ -*gui_w32.txt* For Vim version 7.4. Last change: 2014 Dec 20 - - - VIM REFERENCE MANUAL by Bram Moolenaar - - -Vim's Win32 Graphical User Interface *gui-w32* *win32-gui* - -1. Starting the GUI |gui-w32-start| -2. Vim as default editor |vim-default-editor| -3. Using the clipboard |gui-clipboard| -4. Shell Commands |gui-shell-win32| -5. Special colors |win32-colors| -6. Windows dialogs & browsers |gui-w32-dialogs| -7. Command line arguments |gui-w32-cmdargs| -8. Various |gui-w32-various| - -Other relevant documentation: -|gui.txt| For generic items of the GUI. -|os_win32.txt| For Win32 specific items. - -============================================================================== -1. Starting the GUI *gui-w32-start* - -The Win32 GUI version of Vim will always start the GUI, no matter how you -start it or what it's called. - -The GUI will always run in the Windows subsystem. Mostly shells automatically -return with a command prompt after starting gvim. If not, you should use the -"start" command: > - start gvim [options] file .. - -Note: All fonts (bold, italic) must be of the same size!!! If you don't do -this, text will disappear or mess up the display. Vim does not check the font -sizes. It's the size in screen pixels that must be the same. Note that some -fonts that have the same point size don't have the same pixel size! -Additionally, the positioning of the fonts must be the same (ascent and -descent). - -The Win32 GUI has an extra menu item: "Edit/Select Font". It brings up the -standard Windows font selector. - -Setting the menu height doesn't work for the Win32 GUI. - - *gui-win32-maximized* -If you want Vim to start with a maximized window, add this command to your -vimrc or gvimrc file: > - au GUIEnter * simalt ~x -< -============================================================================== -2. Vim as default editor *vim-default-editor* - -To set Vim as the default editor for a file type: -1. Start a Windows Explorer -2. Choose View/Options -> File Types -3. Select the path to gvim for every file type that you want to use it for. - (you can also use three spaces in the file type field, for files without an - extension). - In the "open" action, use: > - gvim "%1" -< The quotes are required for using file names with embedded spaces. - You can also use this: > - gvim "%L" -< This should avoid short (8.3 character) file names in some situations. But - I'm not sure if this works everywhere. - -When you open a file in Vim by double clicking it, Vim changes to that -file's directory. - -If you want Vim to start full-screen, use this for the Open action: > - gvim -c "simalt ~x" "%1" - -Another method, which also works when you put Vim in another directory (e.g., -when you have got a new version): -1. select a file you want to use Vim with -2. <Shift-F10> -3. select "Open With..." menu entry -4. click "Other..." -5. browse to the (new) location of Vim and click "Open" -6. make "Always Use this program..." checked -7. <OK> - - *send-to-menu* *sendto* -You can also install Vim in the "Send To" menu: -1. Start a Windows Explorer -2. Navigate to your sendto directory: - Windows NT: %windir%\profiles\%user%\sendto (e.g. - "c:\winnt\profiles\mattha\sendto"). -3. Right-click in the file pane and select New->Shortcut -4. Follow the shortcut wizard, using the full path to VIM/GVIM. - -When you 'send a file to Vim', Vim changes to that file's directory. Note, -however, that any long directory names will appear in their short (MS-DOS) -form. This is a limitation of the Windows "Send To" mechanism. - - *notepad* -You could replace notepad.exe with gvim.exe, but that has a few side effects. -Some programs rely on notepad arguments, which are not recognized by Vim. For -example "notepad -p" is used by some applications to print a file. It's -better to leave notepad where it is and use another way to start Vim. - - *win32-popup-menu* -A more drastic approach is to install an "Edit with Vim" entry in the popup -menu for the right mouse button. With this you can edit any file with Vim. - -This can co-exist with the file associations mentioned above. The difference -is that the file associations will make starting Vim the default action. With -the "Edit with Vim" menu entry you can keep the existing file association for -double clicking on the file, and edit the file with Vim when you want. For -example, you can associate "*.mak" with your make program. You can execute -the makefile by double clicking it and use the "Edit with Vim" entry to edit -the makefile. - -You can select any files and right-click to see a menu option called "Edit -with gvim". Choosing this menu option will invoke gvim with the file you have -selected. If you select multiple files, you will find two gvim-related menu -options: -"Edit with multiple gvims" -- one gvim for each file in the selection -"Edit with single gvim" -- one gvim for all the files in the selection -And if there already is a gvim running: -"Edit with existing gvim" -- edit the file with the running gvim - -The "edit with existing Vim" entries can be disabled by adding an entry in the -registry under HKLM\Software\Vim\Gvim, named DisableEditWithExisting, and with -any value. - *install-registry* -You can add the "Edit with Vim" menu entry in an easy way by using the -"install.exe" program. It will add several registry entries for you. - -You can also do this by hand. This is complicated! Use the install.exe if -you can. - -1. Start the registry editor with "regedit". -2. Add these keys: - key value name value ~ - HKEY_CLASSES_ROOT\CLSID\{51EEE242-AD87-11d3-9C1E-0090278BBD99} - {default} Vim Shell Extension - HKEY_CLASSES_ROOT\CLSID\{51EEE242-AD87-11d3-9C1E-0090278BBD99}\InProcServer32 - {default} {path}\gvimext.dll - ThreadingModel Apartment - HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\gvim - {default} {51EEE242-AD87-11d3-9C1E-0090278BBD99} - HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved - {51EEE242-AD87-11d3-9C1E-0090278BBD99} - Vim Shell Extension - HKEY_LOCAL_MACHINE\Software\Vim\Gvim - path {path}\gvim.exe - HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\vim 5.6 - DisplayName Vim 5.6: Edit with Vim popup menu entry - UninstallString {path}\uninstal.exe - - Replace {path} with the path that leads to the executable. - Don't type {default}, this is the value for the key itself. - -To remove "Edit with Vim" from the popup menu, just remove the registry -entries mentioned above. The "uninstal.exe" program can do this for you. You -can also use the entry in the Windows standard "Add/Remove Programs" list. - -If you notice that this entry overrules other file type associations, set -those associations again by hand (using Windows Explorer, see above). This -only seems to happen on some Windows NT versions (Windows bug?). Procedure: -1. Find the name of the file type. This can be done by starting the registry - editor, and searching for the extension in \\HKEY_CLASSES_ROOT -2. In a Windows Explorer, use View/Options/File Types. Search for the file - type in the list and click "Edit". In the actions list, you can select on - to be used as the default (normally the "open" action) and click on the - "Set Default" button. - - -Vim in the "Open With..." context menu *win32-open-with-menu* - -If you use the Vim install program you have the choice to add Vim to the "Open -With..." menu. This means you can use Vim to edit many files. Not every file -(for unclear reasons...), thus the "Edit with Vim" menu entry is still useful. - -One reason to add this is to be able to edit HTML files directly from Internet -Explorer. To enable this use the "Tools" menu, "Internet Options..." entry. -In the dialog select the "Programs" tab and select Vim in the "HTML editor" -choice. If it's not there than installing didn't work properly. - -Doing this manually can be done with this script: - ----------------------------------------------------------- -REGEDIT4 - -[HKEY_CLASSES_ROOT\Applications\gvim.exe] - -[HKEY_CLASSES_ROOT\Applications\gvim.exe\shell] - -[HKEY_CLASSES_ROOT\Applications\gvim.exe\shell\edit] - -[HKEY_CLASSES_ROOT\Applications\gvim.exe\shell\edit\command] -@="c:\\vim\\vim62\\gvim.exe \"%1\"" - -[HKEY_CLASSES_ROOT\.htm\OpenWithList\gvim.exe] - -[HKEY_CLASSES_ROOT\*\OpenWithList\gvim.exe] - ----------------------------------------------------------- - -Change the "c:\\vim\\vim62" bit to where gvim.exe is actually located. - -To uninstall this run the Vim uninstall program or manually delete the -registry entries with "regedit". - -============================================================================== -3. Using the clipboard *gui-clipboard* - -Windows has a clipboard, where you can copy text to, and paste text from. Vim -supports this in several ways. For other systems see |gui-selections|. - -The "* register reflects the contents of the clipboard. |quotestar| - -When the "unnamed" string is included in the 'clipboard' option, the unnamed -register is the same. Thus you can yank to and paste from the clipboard -without prepending "* to commands. - -The 'a' flag in 'guioptions' is not included by default. This means that text -is only put on the clipboard when an operation is performed on it. Just -Visually selecting text doesn't put it on the clipboard. When the 'a' flag is -included, the text is copied to the clipboard even when it is not operated -upon. - - *mswin.vim* -To use the standard MS-Windows way of CTRL-X, CTRL-C and CTRL-V, use the -$VIMRUNTIME/mswin.vim script. You could add this line to your _vimrc file: > - source $VIMRUNTIME/mswin.vim - -Since CTRL-C is used to copy the text to the clipboard, it can't be used to -cancel an operation. Use CTRL-Break for that. - -CTRL-Z is used for undo. This means you can't suspend Vim with this key, use -|:suspend| instead (if it's supported at all). - - *CTRL-V-alternative* *CTRL-Q* -Since CTRL-V is used to paste, you can't use it to start a blockwise Visual -selection. You can use CTRL-Q instead. You can also use CTRL-Q in Insert -mode and Command-line mode to get the old meaning of CTRL-V. But CTRL-Q -doesn't work for terminals when it's used for control flow. - -NOTE: The clipboard support still has a number of bugs. - -============================================================================== -4. Shell Commands *gui-shell-win32* - -Vim uses another window for external commands, to make it possible to run any -command. The external command gets its own environment for running, just like -it was started from a DOS prompt. - - *win32-vimrun* -Executing an external command is done indirectly by the "vimrun" command. The -"vimrun.exe" must be in the path for this to work. Or it must be in the same -directory as the Vim executable. If "vimrun" cannot be found, the command is -executed directly, but then the DOS window closes immediately after the -external command has finished. -WARNING: If you close this window with the "X" button, and confirm the -question if you really want to kill the application, Vim may be killed too! -(This does not apply to commands run asynchronously with ":!start".) - - *win32-!start* -Normally, Vim waits for a command to complete before continuing (this makes -sense for most shell commands which produce output for Vim to use). If you -want Vim to start a program and return immediately, you can use the following -syntax on W95 & NT: > - :!start [/min] {command} -The optional "/min" causes the window to be minimized. - -============================================================================== -5. Special colors *win32-colors* - -On Win32, the normal DOS colors can be used. See |dos-colors|. - -Additionally the system configured colors can also be used. These are known -by the names Sys_XXX, where XXX is the appropriate system color name, from the -following list (see the Win32 documentation for full descriptions). Case is -ignored. - -Sys_3DDKShadow Sys_3DFace Sys_BTNFace -Sys_3DHilight Sys_3DHighlight Sys_BTNHilight -Sys_BTNHighlight Sys_3DLight Sys_3DShadow -Sys_BTNShadow Sys_ActiveBorder Sys_ActiveCaption -Sys_AppWorkspace Sys_Background Sys_Desktop -Sys_BTNText Sys_CaptionText Sys_GrayText -Sys_Highlight Sys_HighlightText Sys_InactiveBorder -Sys_InactiveCaption Sys_InactiveCaptionText Sys_InfoBK -Sys_InfoText Sys_Menu Sys_MenuText -Sys_ScrollBar Sys_Window Sys_WindowFrame -Sys_WindowText - -Probably the most useful values are - Sys_Window Normal window background - Sys_WindowText Normal window text - Sys_Highlight Highlighted background - Sys_HighlightText Highlighted text - -These extra colors are also available: -Gray, Grey, LightYellow, SeaGreen, Orange, Purple, SlateBlue, Violet, - - *rgb.txt* -Additionally, colors defined by a "rgb.txt" file can be used. This file is -well known from X11. A few lines from it: > - - 255 218 185 peach puff - 205 133 63 peru - 255 181 197 pink - -This shows the layout of the file: First the R, G and B value as a decimal -number, followed by the name of the color. The four fields are separated by -spaces. - -You can get an rgb.txt file from any X11 distribution. It is located in a -directory like "/usr/X11R6/lib/X11/". For Vim it must be located in the -$VIMRUNTIME directory. Thus the file can be found with "$VIMRUNTIME/rgb.txt". - -============================================================================== - *gui-w32-dialogs* *dialog* -6. Windows dialogs & browsers - -The Win32 GUI can use familiar Windows components for some operations, as well -as the traditional interface shared with the console version. - - -6.1 Dialogs - -The dialogs displayed by the "confirm" family (i.e. the 'confirm' option, -|:confirm| command and |confirm()| function) are GUI-based rather than the -console-based ones used by other versions. The 'c' flag in 'guioptions' -changes this. - - -6.2 File Browsers - -When prepending ":browse" before file editing commands, a file requester is -used to allow you to select an existing file. See |:browse|. - -============================================================================== -7. Command line arguments *gui-w32-cmdargs* - -Analysis of a command line into parameters is not standardised in MS Windows. -Gvim has to provide logic to analyse a command line. This logic is likely to -be different from the default logic provided by a compilation system used to -build vim. The differences relate to unusual double quote (") usage. -The arguments "C:\My Music\freude.txt" and "+/Sch\"iller" are handled in the -same way. The argument "+/Sch""iller" may be handled different by gvim and -vim, depending what it was compiled with. - -The rules are: - a) A parameter is a sequence of graphic characters. - b) Parameters are separated by white space. - c) A parameter can be enclosed in double quotes to include white space. - d) A sequence of zero or more backslashes (\) and a double quote (") - is special. The effective number of backslashes is halved, rounded - down. An even number of backslashes reverses the acceptability of - spaces and tabs, an odd number of backslashes produces a literal - double quote. - -So: - " is a special double quote - \" is a literal double quote - \\" is a literal backslash and a special double quote - \\\" is a literal backslash and a literal double quote - \\\\" is 2 literal backslashes and a special double quote - \\\\\" is 2 literal backslashes and a literal double quote - etc. - -Example: > - gvim "C:\My Music\freude" +"set ignorecase" +/"\"foo\\" +\"bar\\\" - -opens "C:\My Music\freude" and executes the line mode commands: > - set ignorecase; /"foo\ and /bar\" - -============================================================================== -8. Various *gui-w32-various* - - *gui-w32-printing* -The "File/Print" menu prints the text with syntax highlighting, see -|:hardcopy|. If you just want to print the raw text and have a default -printer installed this should also work: > - :w >>prn - -Vim supports a number of standard MS Windows features. Some of these are -detailed elsewhere: see |'mouse'|, |win32-hidden-menus|. - - *drag-n-drop-win32* -You can drag and drop one or more files into the Vim window, where they will -be opened as normal. See |drag-n-drop|. - - *:simalt* *:sim* -:sim[alt] {key} simulate pressing {key} while holding Alt pressed. - {only for Win32 versions} - -Normally, Vim takes control of all Alt-<Key> combinations, to increase the -number of possible mappings. This clashes with the standard use of Alt as the -key for accessing menus. -The quick way of getting standard behavior is to set the 'winaltkeys' option -to "yes". This however prevents you from mapping Alt keys at all. -Another way is to set 'winaltkeys' to "menu". Menu shortcut keys are then -handled by windows, other ALT keys can be mapped. This doesn't allow a -dependency on the current state though. -To get round this, the :simalt command allows Vim (when 'winaltkeys' is not -"yes") to fake a Windows-style Alt keypress. You can use this to map Alt key -combinations (or anything else for that matter) to produce standard Windows -actions. Here are some examples: > - - :map <M-f> :simalt f<CR> -This makes Alt-F pop down the 'File' menu (with the stock Menu.vim) by -simulating the keystrokes Alt, F. > - :map <M-Space> :simalt ~<CR> -This maps Alt-Space to pop down the system menu for the Vim window. Note that -~ is used by simalt to represent the <Space> character. > - :map <C-n> :simalt ~n<CR> -Maps Control-N to produce the keys Alt-Space followed by N. This minimizes the -Vim window via the system menu. - -Note that the key changes depending on the language you are using. - - *intellimouse-wheel-problems* -When using the Intellimouse mouse wheel causes Vim to stop accepting input, go -to: - ControlPanel - Mouse - Wheel - UniversalScrolling - Exceptions - -And add gvim to the list of applications. This problem only appears to happen -with the Intellimouse driver 2.2 and when "Universal Scrolling" is turned on. - - -XPM support *w32-xpm-support* - -Gvim can be build on MS-Windows with support for XPM files. |+xpm_w32| -See the Make_mvc.mak file for instructions, search for XPM. - -To try out if XPM support works do this: > - :help - :exe 'sign define vimxpm icon=' . $VIMRUNTIME . '\\vim16x16.xpm' - :exe 'sign place 1 line=1 name=vimxpm file=' . expand('%:p') -< - - vim:tw=78:sw=4:ts=8:ft=help:norl: diff --git a/runtime/doc/help.txt b/runtime/doc/help.txt index 342c475f9b..fc4816a6c8 100644 --- a/runtime/doc/help.txt +++ b/runtime/doc/help.txt @@ -1,4 +1,4 @@ -*help.txt* For Vim version 7.4. Last change: 2016 Jan 10 +*help.txt* For Vim version 7.4. Last change: 2016 Mar 31 VIM - main help file k diff --git a/runtime/doc/helphelp.txt b/runtime/doc/helphelp.txt index f3533b8815..ca341af200 100644 --- a/runtime/doc/helphelp.txt +++ b/runtime/doc/helphelp.txt @@ -1,4 +1,4 @@ -*helphelp.txt* For Vim version 7.4. Last change: 2014 Sep 19 +*helphelp.txt* For Vim version 7.4. Last change: 2016 Apr 01 VIM REFERENCE MANUAL by Bram Moolenaar @@ -188,6 +188,9 @@ command: > *E154* *E150* *E151* *E152* *E153* *E670* :helpt[ags] [++t] {dir} Generate the help tags file(s) for directory {dir}. + When {dir} is ALL then all "doc" directories in + 'runtimepath' will be used. + All "*.txt" and "*.??x" files in the directory and sub-directories are scanned for a help tag definition in between stars. The "*.??x" files are for @@ -196,9 +199,11 @@ command: > sorted. When there are duplicates an error message is given. An existing tags file is silently overwritten. + The optional "++t" argument forces adding the "help-tags" tag. This is also done when the {dir} is equal to $VIMRUNTIME/doc. + To rebuild the help tags in the runtime directory (requires write permission there): > :helptags $VIMRUNTIME/doc @@ -249,7 +254,9 @@ The second one finds the English user manual, even when 'helplang' is set to When using command-line completion for the ":help" command, the "@en" extension is only shown when a tag exists for multiple languages. When the -tag only exists for English "@en" is omitted. +tag only exists for English "@en" is omitted. When the first candidate has an +"@ab" extension and it matches the first language in 'helplang' "@ab" is also +omitted. When using |CTRL-]| or ":help!" in a non-English help file Vim will try to find the tag in the same language. If not found then 'helplang' will be used @@ -306,6 +313,10 @@ aligned on a line. When referring to an existing help tag and to create a hot-link, place the name between two bars (|) eg. |help-writing|. +When referring to a Vim command and to create a hot-link, place the +name between two backticks, eg. inside `:filetype`. You will see this is +highlighted as a command, like a code block (see below). + When referring to a Vim option in the help file, place the option name between two single quotes, eg. 'statusline' diff --git a/runtime/doc/if_pyth.txt b/runtime/doc/if_pyth.txt index f6bd365299..8946dd2e5a 100644 --- a/runtime/doc/if_pyth.txt +++ b/runtime/doc/if_pyth.txt @@ -16,7 +16,7 @@ The Python Interface to Vim *python* *Python* 8. pyeval(), py3eval() Vim functions |python-pyeval| 9. Python 3 |python3| -See |nvim-python| for more information. {Nvim} +See |provider-python| for more information. {Nvim} ============================================================================== 1. Commands *python-commands* diff --git a/runtime/doc/if_ruby.txt b/runtime/doc/if_ruby.txt new file mode 100644 index 0000000000..fdd63501ea --- /dev/null +++ b/runtime/doc/if_ruby.txt @@ -0,0 +1,185 @@ +*if_ruby.txt* + + + VIM REFERENCE MANUAL by Shugo Maeda + +The Ruby Interface to Vim *ruby* *Ruby* + + +1. Commands |ruby-commands| +2. The VIM module |ruby-vim| +3. VIM::Buffer objects |ruby-buffer| +4. VIM::Window objects |ruby-window| +5. Global variables |ruby-globals| + + *E266* *E267* *E268* *E269* *E270* *E271* *E272* *E273* + +The home page for ruby is http://www.ruby-lang.org/. You can find links for +downloading Ruby there. + +============================================================================== +1. Commands *ruby-commands* + + *:ruby* *:rub* +:rub[y] {cmd} Execute Ruby command {cmd}. A command to try it out: > + :ruby print "Hello" + +:rub[y] << {endpattern} +{script} +{endpattern} + Execute Ruby script {script}. + {endpattern} must NOT be preceded by any white space. + If {endpattern} is omitted, it defaults to a dot '.' + like for the |:append| and |:insert| commands. This + form of the |:ruby| command is mainly useful for + including ruby code in vim scripts. + Note: This command doesn't work when the Ruby feature + wasn't compiled in. To avoid errors, see + |script-here|. + +Example Vim script: > + + function! RedGem() + ruby << EOF + class Garnet + def initialize(s) + @buffer = VIM::Buffer.current + vimputs(s) + end + def vimputs(s) + @buffer.append(@buffer.count,s) + end + end + gem = Garnet.new("pretty") + EOF + endfunction +< + + *:rubydo* *:rubyd* *E265* +:[range]rubyd[o] {cmd} Evaluate Ruby command {cmd} for each line in the + [range], with $_ being set to the text of each line in + turn, without a trailing <EOL>. Setting $_ will change + the text, but note that it is not possible to add or + delete lines using this command. + The default for [range] is the whole file: "1,$". + + *:rubyfile* *:rubyf* +:rubyf[ile] {file} Execute the Ruby script in {file}. This is the same as + ":ruby load 'file'", but allows file name completion. + +Executing Ruby commands is not possible in the |sandbox|. + +============================================================================== +2. The VIM module *ruby-vim* + +Ruby code gets all of its access to vim via the "VIM" module. + +Overview > + print "Hello" # displays a message + VIM.command(cmd) # execute an Ex command + num = VIM::Window.count # gets the number of windows + w = VIM::Window[n] # gets window "n" + cw = VIM::Window.current # gets the current window + num = VIM::Buffer.count # gets the number of buffers + b = VIM::Buffer[n] # gets buffer "n" + cb = VIM::Buffer.current # gets the current buffer + w.height = lines # sets the window height + w.cursor = [row, col] # sets the window cursor position + pos = w.cursor # gets an array [row, col] + name = b.name # gets the buffer file name + line = b[n] # gets a line from the buffer + num = b.count # gets the number of lines + b[n] = str # sets a line in the buffer + b.delete(n) # deletes a line + b.append(n, str) # appends a line after n + line = VIM::Buffer.current.line # gets the current line + num = VIM::Buffer.current.line_number # gets the current line number + VIM::Buffer.current.line = "test" # sets the current line number +< + +Module Functions: + + *ruby-message* +VIM::message({msg}) + Displays the message {msg}. + + *ruby-set_option* +VIM::set_option({arg}) + Sets a vim option. {arg} can be any argument that the ":set" command + accepts. Note that this means that no spaces are allowed in the + argument! See |:set|. + + *ruby-command* +VIM::command({cmd}) + Executes Ex command {cmd}. + + *ruby-evaluate* +VIM::evaluate({expr}) + Evaluates {expr} using the vim internal expression evaluator (see + |expression|). Returns the expression result as a string. + A |List| is turned into a string by joining the items and inserting + line breaks. + +============================================================================== +3. VIM::Buffer objects *ruby-buffer* + +VIM::Buffer objects represent vim buffers. + +Class Methods: + +current Returns the current buffer object. +count Returns the number of buffers. +self[{n}] Returns the buffer object for the number {n}. The first number + is 0. + +Methods: + +name Returns the name of the buffer. +number Returns the number of the buffer. +count Returns the number of lines. +length Returns the number of lines. +self[{n}] Returns a line from the buffer. {n} is the line number. +self[{n}] = {str} + Sets a line in the buffer. {n} is the line number. +delete({n}) Deletes a line from the buffer. {n} is the line number. +append({n}, {str}) + Appends a line after the line {n}. +line Returns the current line of the buffer if the buffer is + active. +line = {str} Sets the current line of the buffer if the buffer is active. +line_number Returns the number of the current line if the buffer is + active. + +============================================================================== +4. VIM::Window objects *ruby-window* + +VIM::Window objects represent vim windows. + +Class Methods: + +current Returns the current window object. +count Returns the number of windows. +self[{n}] Returns the window object for the number {n}. The first number + is 0. + +Methods: + +buffer Returns the buffer displayed in the window. +height Returns the height of the window. +height = {n} Sets the window height to {n}. +width Returns the width of the window. +width = {n} Sets the window width to {n}. +cursor Returns a [row, col] array for the cursor position. +cursor = [{row}, {col}] + Sets the cursor position to {row} and {col}. + +============================================================================== +5. Global variables *ruby-globals* + +There are two global variables. + +$curwin The current window object. +$curbuf The current buffer object. + +============================================================================== + vim:tw=78:ts=8:ft=help:norl: diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index e98f0400c4..bd2df5d1e5 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1,4 +1,4 @@ -*index.txt* For Vim version 7.4. Last change: 2016 Jan 10 +*index.txt* For Vim version 7.4. Last change: 2016 Mar 12 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1378,6 +1378,8 @@ tag command action ~ |:ounmap| :ou[nmap] like ":unmap" but for Operator-pending mode |:ounmenu| :ounme[nu] remove menu for Operator-pending mode |:ownsyntax| :ow[nsyntax] set new local syntax highlight for this window +|:packadd| :pa[ckadd] add a plugin from 'packpath' +|:packloadall| :packl[oadall] load all packages under 'packpath' |:pclose| :pc[lose] close preview window |:pedit| :ped[it] edit file in the preview window |:print| :p[rint] print lines @@ -1515,14 +1517,14 @@ tag command action ~ |:tabdo| :tabdo execute command in each tab page |:tabedit| :tabe[dit] edit a file in a new tab page |:tabfind| :tabf[ind] find file in 'path', edit it in a new tab page -|:tabfirst| :tabfir[st] got to first tab page -|:tablast| :tabl[ast] got to last tab page +|:tabfirst| :tabfir[st] go to first tab page +|:tablast| :tabl[ast] go to last tab page |:tabmove| :tabm[ove] move tab page to other position |:tabnew| :tabnew edit a file in a new tab page |:tabnext| :tabn[ext] go to next tab page |:tabonly| :tabo[nly] close all tab pages except the current one |:tabprevious| :tabp[revious] go to previous tab page -|:tabrewind| :tabr[ewind] got to first tab page +|:tabrewind| :tabr[ewind] go to first tab page |:tabs| :tabs list the tab pages and what they contain |:tab| :tab create new tab when opening new window |:tag| :ta[g] jump to tag diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt index f931dfa341..818d6cf64c 100644 --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -1,4 +1,4 @@ -*insert.txt* For Vim version 7.4. Last change: 2015 Sep 15 +*insert.txt* For Vim version 7.4. Last change: 2016 Jan 31 VIM REFERENCE MANUAL by Bram Moolenaar diff --git a/runtime/doc/job_control.txt b/runtime/doc/job_control.txt index 587eba4162..5cb172f90a 100644 --- a/runtime/doc/job_control.txt +++ b/runtime/doc/job_control.txt @@ -40,7 +40,7 @@ for details. Job control is achieved by calling a combination of the |jobstart()|, |jobsend()| and |jobstop()| functions. Here's an example: > - function s:JobHandler(job_id, data, event) + function! s:JobHandler(job_id, data, event) if a:event == 'stdout' let str = self.shell.' stdout: '.join(a:data) elseif a:event == 'stderr' @@ -84,6 +84,19 @@ Here's what is happening: program. 2: The event type, which is "stdout", "stderr" or "exit". + Note: Buffered stdout/stderr data which has not been flushed by the sender + will not trigger the "stdout" callback (but if the process ends, the + "exit" callback will be triggered). + For example, "ruby -e" buffers output, so small strings will be + buffered unless "auto-flushing" ($stdout.sync=true) is enabled. > + function! Receive(job_id, data, event) + echom printf('%s: %s',a:event,string(a:data)) + endfunction + call jobstart(['ruby', '-e', + \ '$stdout.sync = true; 5.times do sleep 1 and puts "Hello Ruby!" end'], + \ {'on_stdout': 'Receive'}) +< https://github.com/neovim/neovim/issues/1592 + The options dictionary is passed as the "self" variable to the callback function. Here's a more object-oriented version of the above: > diff --git a/runtime/doc/message.txt b/runtime/doc/message.txt index 114bb61d99..7ceddeb674 100644 --- a/runtime/doc/message.txt +++ b/runtime/doc/message.txt @@ -1,4 +1,4 @@ -*message.txt* For Vim version 7.4. Last change: 2013 Feb 23 +*message.txt* For Vim version 7.4. Last change: 2016 Feb 27 VIM REFERENCE MANUAL by Bram Moolenaar diff --git a/runtime/doc/mlang.txt b/runtime/doc/mlang.txt index 5f4642274c..a2be3cfd49 100644 --- a/runtime/doc/mlang.txt +++ b/runtime/doc/mlang.txt @@ -1,4 +1,4 @@ -*mlang.txt* For Vim version 7.4. Last change: 2012 Jan 15 +*mlang.txt* For Vim version 7.4. Last change: 2016 Jan 16 VIM REFERENCE MANUAL by Bram Moolenaar @@ -94,13 +94,15 @@ If you used the self-installing .exe file, message translations should work already. Otherwise get the libintl.dll file if you don't have it yet: http://sourceforge.net/projects/gettext +Or: + https://mlocati.github.io/gettext-iconv-windows/ This also contains tools xgettext, msgformat and others. libintl.dll should be placed in same directory with (g)vim.exe, or some -place where PATH environment value describe. Message files (vim.mo) -have to be placed in "$VIMRUNTIME/lang/xx/LC_MESSAGES", where "xx" is the -abbreviation of the language (mostly two letters). +place where PATH environment value describe. Vim also finds libintl-8.dll. +Message files (vim.mo) have to be placed in "$VIMRUNTIME/lang/xx/LC_MESSAGES", +where "xx" is the abbreviation of the language (mostly two letters). If you write your own translations you need to generate the .po file and convert it to a .mo file. You need to get the source distribution and read diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index bafb9dfc2c..cfd9084cfc 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -1,97 +1,89 @@ -*msgpack_rpc.txt* For Nvim. {Nvim} +*msgpack_rpc.txt* {Nvim} NVIM REFERENCE MANUAL by Thiago de Arruda -The Msgpack-RPC Interface to Nvim *msgpack-rpc* +RPC API for Nvim *RPC* *rpc* *msgpack-rpc* -1. Introduction |msgpack-rpc-intro| -2. API mapping |msgpack-rpc-api| -3. Connecting |msgpack-rpc-connecting| -4. Clients |msgpack-rpc-clients| -5. Types |msgpack-rpc-types| -6. Wrapping methods |msgpack-rpc-wrap-methods| -7. Vimscript functions |msgpack-rpc-vim-functions| +1. Introduction |rpc-intro| +2. API mapping |rpc-api| +3. Connecting |rpc-connecting| +4. Clients |rpc-api-client| +5. Types |rpc-types| +6. Vimscript functions |rpc-vim-functions| ============================================================================== -1. Introduction *msgpack-rpc-intro* +1. Introduction *rpc-intro* -The primary way to control a running Nvim instance is through -MessagePack-RPC, a messaging protocol that uses the MessagePack serialization -format: https://github.com/msgpack/msgpack/blob/7498cf3/spec.md. -From now on, we refer to the protocol as msgpack-rpc. +The primary way to control Nvim programmatically is the RPC API, which speaks +MessagePack-RPC ("msgpack-rpc"), a messaging protocol that uses the +MessagePack serialization format: + https://github.com/msgpack/msgpack/blob/0b8f5ac/spec.md -At this point, only plugins use msgpack-rpc, but eventually even user -interaction will happen through it, since user interfaces will be separate -programs that control a headless Nvim instance. +All kinds of Nvim "clients" use the RPC API: user interfaces (GUIs), remote +plugins, scripts like "nvr" (https://github.com/mhinz/neovim-remote), and even +`nvim` itself can control other `nvim` instances. By connecting to the RPC API +programs can: -By connecting to the msgpack-rpc interface, programs can: + - Call any API function + - Listen for events + - Receive remote calls from Nvim -- Call any Nvim API function -- Listen for Nvim events -- Receive remote calls from Nvim - -Nvim's msgpack-rpc interface is like a more powerful version of Vim's -`clientserver` feature. +The RPC API is like a more powerful version of Vim's `clientserver` feature. ============================================================================== -2. API mapping *msgpack-rpc-api* + 2. API mapping *rpc-api* -The Nvim C API, see |nvim-api|, is automatically exposed to the msgpack-rpc -interface by the build system, which parses headers at src/nvim/api from the -project root. A dispatch function is generated, which matches msgpack-rpc method -names with non-static API functions, converting/validating arguments and return -values back to msgpack. +The Nvim C |API| is automatically exposed to the RPC API by the build system, +which parses headers at src/nvim/api/*. A dispatch function is generated which +matches RPC API method names with public API functions, converting/validating +arguments and return values back to msgpack. -Client libraries will normally provide wrappers that hide msgpack-rpc details -from programmers. The wrappers can be automatically generated by reading -bundled API metadata from a compiled Nvim instance. +Client libraries (|api-client|s) normally provide wrappers that hide +msgpack-rpc details from application developers. The wrappers can be +automatically generated by reading bundled API metadata from a compiled Nvim +instance. -There are two ways to obtain API metadata: +There are three ways to obtain API metadata: -1. By connecting to a running Nvim instance and calling `vim_get_api_info` - via msgpack-rpc. This is best for clients written in dynamically-typed - languages, which can define functions at runtime. + 1. Connect to a running Nvim instance and call `vim_get_api_info` via + msgpack-rpc. This is best for clients written in dynamic languages which + can define functions at runtime. -2. By starting Nvim with the `--api-info` command-line option, which makes Nvim - dump a blob of msgpack metadata to standard output and exit. This is best - for clients written in statically-typed languages, which require a separate - compilation step. + 2. Start Nvim with the |--api-info| option. Useful for clients written in + statically-compiled languages. -Here's a simple way to get human-readable description of the API (requires -Python and the `pyyaml`/`msgpack-python` pip packages): -> - nvim --api-info | python -c 'import msgpack, sys, yaml; print yaml.dump(msgpack.unpackb(sys.stdin.read()))' > api.yaml + 3. Use the |api_info()| vimscript function. + +To get a human-readable list of API functions: > + :new|put =map(api_info().functions, 'v:val.name') +< +To get a formatted dump of the API using python (requires the `pyyaml` and +`msgpack-python` packages): > + nvim --api-info | python -c 'import msgpack, sys, yaml; print yaml.dump(msgpack.unpackb(sys.stdin.read()))' < ============================================================================== -3. Connecting *msgpack-rpc-connecting* +3. Connecting *rpc-connecting* -There are four ways to open msgpack-rpc streams to Nvim: +There are several ways to open a msgpack-rpc stream to an Nvim server: -1. Through Nvim's stdin/stdout when it's started with the `--embed` option. - This is how other programs can embed Nvim. + 1. Through stdin/stdout when `nvim` is started with `--embed`. This is how + applications can embed Nvim. -2. Through the stdin/stdout of a program spawned by the |rpcstart()| function. + 2. Through stdin/stdout of some other process spawned by |rpcstart()|. - *$NVIM_LISTEN_ADDRESS* -3. Through the socket automatically created with each instance. To get the - socket location for a running Nvim instance (which is random by default), - see the |$NVIM_LISTEN_ADDRESS| environment variable: -> - :echo $NVIM_LISTEN_ADDRESS -< - See also |v:servername|. + 3. Through the socket automatically created with each instance. The socket + location is stored in |v:servername|. -4. Through a TCP/IP socket. To make Nvim listen on a TCP/IP socket, set the - |$NVIM_LISTEN_ADDRESS| environment variable in a shell before starting Nvim: -> + 4. Through a TCP/IP socket. To make Nvim listen on a TCP/IP socket, set the + |$NVIM_LISTEN_ADDRESS| environment variable before starting Nvim: > NVIM_LISTEN_ADDRESS=127.0.0.1:6666 nvim < -Connecting to the socket is the easiest way a programmer can test the API, which -can be done through any msgpack-rpc client library or fully-featured Nvim client -(which we'll see in the next section). Here's a Ruby script that prints 'hello -world!' in the current Nvim instance: +Connecting to the socket is the easiest way a programmer can test the API, +which can be done through any msgpack-rpc client library or full-featured +|api-client|. Here's a Ruby script that prints 'hello world!' in the current +Nvim instance: > #!/usr/bin/env ruby # Requires msgpack-rpc: gem install msgpack-rpc @@ -118,72 +110,103 @@ functions can be called interactively: >>> nvim = attach('socket', path='[address]') >>> nvim.command('echo "hello world!"') < -One can also spawn and connect to an embedded Nvim instance via |rpcstart()| +You can also embed an Nvim instance via |rpcstart()| > let vim = rpcstart('nvim', ['--embed']) echo rpcrequest(vim, 'vim_eval', '"Hello " . "world!"') call rpcstop(vim) < ============================================================================== -4. Implementing new clients *msgpack-rpc-clients* - -Nvim is still in alpha, so there's no in-depth documentation explaining how to -properly implement a client library yet. The Python client (the pip package -"neovim") will always be up-to-date with the latest API changes, so its source -code is the best documentation currently available. There are some guidelines -however: - -- Separate the transport layer from the rest of the library. See - |msgpack-rpc-connecting| for details on how clients can connect to Nvim. -- Use a MessagePack library that implements at least version 5 of the - MessagePack spec, which supports the `bin` and `ext` types used by Nvim. -- Read API metadata in order to create client-side wrappers for all - msgpack-rpc methods. -- Use a single-threaded event loop library/pattern. -- Use a fiber/coroutine library for the language being used for implementing a - client. These greatly simplify concurrency and allow the library to expose a - blocking API on top of a non-blocking event loop without the complexity that - comes with preemptive multitasking. -- Don't assume anything about the order that responses to msgpack-rpc requests - will arrive. -- Clients should expect msgpack-rpc requests, which need to be handled - immediately because Nvim is blocked while waiting for the client response. -- Clients should expect to receive msgpack-rpc notifications, but these don't - need to be handled immediately because they won't block Nvim (although they - should probably be handled immediately anyway). - -Most of the complexity could be handled by a msgpack-rpc library that supports -server to client requests and notifications, but it's not clear if this is part -of the msgpack-rpc spec. At least the Ruby msgpack-rpc library does not seem -to support it: - +4. Implementing API clients *rpc-api-client* *api-client* + +All external UIs and remote plugins (as opposed to regular Vim plugins) are +"clients" in general; but we call something an "API client" if its purpose is +to abstract or wrap the RPC API for the convenience of other applications +(just like a REST client or SDK such as boto3 for AWS: you can speak AWS REST +using an HTTP client like curl, but boto3 wraps that in a convenient python +interface). For example, the lua-client is an API client: + https://github.com/neovim/lua-client + +The Python client (pip package "neovim") is the reference implementation of an +API client. It is always up-to-date with the Nvim API, so its source code and +test suite are an authoritative reference. + https://github.com/neovim/python-client + +API client implementation guidelines ~ + + - Separate the transport layer from the rest of the library. See + |rpc-connecting| for details on how clients can connect to Nvim. + - Use a MessagePack library that implements at least version 5 of the + MessagePack spec, which supports the `bin` and `ext` types used by Nvim. + - Read API metadata in order to create client-side wrappers for all + msgpack-rpc methods. + - Use a single-threaded event loop library/pattern. + - Use a fiber/coroutine library for the language being used for implementing + a client. These greatly simplify concurrency and allow the library to + expose a blocking API on top of a non-blocking event loop without the + complexity that comes with preemptive multitasking. + - Don't assume anything about the order that responses to msgpack-rpc + requests will arrive. + - Clients should expect msgpack-rpc requests, which need to be handled + immediately because Nvim is blocked while waiting for the client response. + - Clients should expect to receive msgpack-rpc notifications, but these + don't need to be handled immediately because they won't block Nvim + (although they should probably be handled immediately anyway). + +Note: Most of the complexity could be handled by a msgpack-rpc library that +supports server to client requests and notifications, but it's not clear if +this is part of the msgpack-rpc spec. At least the Ruby msgpack-rpc library +does not seem to support it: https://github.com/msgpack-rpc/msgpack-rpc-ruby/blob/master/lib/msgpack/rpc/transport/tcp.rb#L150-L158 +API metadata object ~ + +API clients exist to hide msgpack-rpc details. The API metadata object +contains information that makes this task easier (see also |rpc-types|): + + - The "functions" key contains a list of metadata objects for individual + functions. + - Each function metadata object has |rpc-types| information about the return + value and parameters. These can be used for generating strongly-typed APIs + in static languages. + - Container types may be decorated with type/size constraints, e.g. + ArrayOf(Buffer) or ArrayOf(Integer, 2). This can be useful to generate + even more strongly-typed APIs. + - Methods that operate on instances of Nvim special types (msgpack EXT) are + prefixed with the type name in lower case, e.g. `buffer_get_line` + represents the `get_line` method of a Buffer instance. + - Global methods are prefixed with `vim`, e.g. `vim_get_buffers`. + +So for an object-oriented language, an API client contains the classes +representing Nvim special types, and the methods of each class could be +defined by inspecting the method name prefix. There could also be a singleton +Vim class with methods mapped to functions prefixed with `vim_`. + ============================================================================== -5. Types *msgpack-rpc-types* +5. Types *rpc-types* -Nvim's C API uses custom types for all functions, se |nvim-api-types|. -For the purpose of mapping to msgpack, he types can be split into two groups: +The Nvim C API uses custom types for all functions. |api-types| +For the purpose of mapping to msgpack, the types can be split into two groups: -- Basic types that map natively to msgpack (and probably have a default - representation in msgpack-supported programming languages) -- Special Nvim types that map to msgpack EXT with custom type codes. + - Basic types that map natively to msgpack (and probably have a default + representation in msgpack-supported programming languages) + - Special Nvim types that map to msgpack EXT with custom type codes. -Basic type mapping: +Basic types ~ -Nil -> msgpack nil -Boolean -> msgpack boolean -Integer (signed 64-bit integer) -> msgpack integer -Float (IEEE 754 double precision) -> msgpack float -String -> msgpack string -Array -> msgpack array -Dictionary -> msgpack map + Nil -> msgpack nil + Boolean -> msgpack boolean + Integer (signed 64-bit integer) -> msgpack integer + Float (IEEE 754 double precision) -> msgpack float + String -> msgpack string + Array -> msgpack array + Dictionary -> msgpack map -Special Nvim types that use msgpack EXT: +Special types (msgpack EXT) ~ -Buffer -> enum value kObjectTypeBuffer -Window -> enum value kObjectTypeWindow -Tabpage -> enum value kObjectTypeTabpage + Buffer -> enum value kObjectTypeBuffer + Window -> enum value kObjectTypeWindow + Tabpage -> enum value kObjectTypeTabpage An API method expecting one of these types may be passed an integer instead, although they are not interchangeable. For example, a Buffer may be passed as @@ -191,7 +214,7 @@ an integer, but not a Window or Tabpage. The most reliable way of determining the type codes for the special Nvim types is to inspect the `types` key of metadata dictionary returned by the -`vim_get_api_info` method at runtime. Here's an example JSON representation of +`vim_get_api_info` method at runtime. Here's a sample JSON representation of the `types` object: > "types": { @@ -206,55 +229,27 @@ the `types` object: } } < -Even for statically compiled clients, it's a good practice to avoid hardcoding -the type codes, because a client may be built against one Nvim version but connect -to another with different type codes. +Even for statically compiled clients it is good practice to avoid hardcoding +the type codes, because a client may be built against one Nvim version but +connect to another with different type codes. ============================================================================== -6. Wrapping methods *msgpack-rpc-wrap-methods* - -As mentioned before, clients should provide an API that hides msgpack-rpc -details from programmers, and the API metadata object contains information -that makes this task easier: - -- The "functions" key contains a list of metadata objects for individual - functions. -- Each function metadata object has type information about the return value - and parameters. These can be used for generating strongly-typed APIs in - static languages. -- Container types may be decorated with type/size constraints, e.g. - ArrayOf(Buffer) or ArrayOf(Integer, 2). This can be useful to generate even - more strongly-typed APIs. -- Methods that operate instances of Nvim's types are prefixed with the type - name in lower case, e.g. `buffer_get_line` represents the `get_line` method - of a Buffer instance. -- Global methods are prefixed with `vim`, e.g. `vim_get_buffers`. - -So, for an object-oriented language, a client library would have the classes -that represent Nvim's types, and the methods of each class could be defined -by inspecting the method name prefix. There could also be a singleton Vim -class with methods mapped to functions prefixed with `vim_` - -============================================================================== -7. Vimscript functions *msgpack-rpc-vim-functions* - -Four msgpack-rpc functions are available in Vimscript: - -1. |rpcstart()|: Similarly to |jobstart()|, this will spawn a co-process with - its standard handles connected to Nvim. The difference is that it's not - possible to process raw data to or from the process's stdin, stdout, or - stderr. This is because the job's stdin and stdout are used as a single - msgpack channel that is processed directly by Nvim. - -2. |rpcstop()|: Same as |jobstop()|, but operates on handles returned by - |rpcstart()|. - -3. |rpcrequest()|: Sends a msgpack-rpc request to the process. - -4. |rpcnotify()|: Sends a msgpack-rpc notification to the process. - -The last two functions may also be used with channels created from -connections to |$NVIM_LISTEN_ADDRESS|. +6. Vimscript functions *rpc-vim-functions* + +RPC functions are available in Vimscript: + + 1. |rpcstart()|: Similarly to |jobstart()|, this will spawn a co-process + with its standard handles connected to Nvim. The difference is that it's + not possible to process raw data to or from the process's stdin, stdout, + or stderr. This is because the job's stdin and stdout are used as + a single msgpack channel that is processed directly by Nvim. + 2. |rpcstop()|: Same as |jobstop()|, but operates on handles returned by + |rpcstart()|. + 3. |rpcrequest()|: Sends a msgpack-rpc request to the process. + 4. |rpcnotify()|: Sends a msgpack-rpc notification to the process. + +|rpcrequest()| and |rpcnotify()| can also be used with channels connected to +a nvim server. |v:servername| ============================================================================== vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/nvim.txt b/runtime/doc/nvim.txt index a7c512d1dc..904fb3c16c 100644 --- a/runtime/doc/nvim.txt +++ b/runtime/doc/nvim.txt @@ -1,24 +1,56 @@ -*nvim.txt* For Nvim. {Nvim} +*nvim.txt* {Nvim} - NVIM REFERENCE MANUAL *nvim* + NVIM REFERENCE MANUAL -Introduction to Nvim *nvim-intro* +Nvim *nvim* *nvim-intro* -This is an introduction for Vim users who are just getting started with Nvim. -It is not meant for Vim beginners. For a basic introduction to Vim, -see |help.txt|. +If you are new to Vim (and Nvim) see |help.txt| or type ":Tutor". +If you already use Vim (but not Nvim) see |nvim-from-vim| for a quickstart. -1. Transitioning from Vim |nvim-from-vim| -2. Differences from Vim |vim-differences| -3. Msgpack-RPC |msgpack-rpc| -4. Job control |job-control| -5. Python plugins |nvim-python| -6. Clipboard integration |nvim-clipboard| -7. Remote plugins |remote-plugin| -8. Provider infrastructure |nvim-provider| -9. Integrated terminal emulator |nvim-terminal-emulator| +Nvim is emphatically a fork of Vim, not a clone: compatibility with Vim is +maintained where possible. See |vim_diff.txt| for the complete reference of +differences from Vim. + +============================================================================== +Transitioning from Vim *nvim-from-vim* + +To start the transition, link your previous configuration so Nvim can use it: +> + mkdir -p ${XDG_CONFIG_HOME:=$HOME/.config} + ln -s ~/.vim $XDG_CONFIG_HOME/nvim + ln -s ~/.vimrc $XDG_CONFIG_HOME/nvim/init.vim +< +See |provider-python| and |provider-clipboard| for additional software you +might need to use some features. + +Your Vim configuration might not be entirely compatible with Nvim. For a +full list of differences between Vim and Nvim see |vim-differences|. + +The |'ttymouse'| option, for example, was removed from Nvim (mouse support +should work without it). If you use the same |vimrc| for Vim and Nvim, +consider guarding |'ttymouse'| in your configuration like so: +> + if !has('nvim') + set ttymouse=xterm2 + endif +< +Conversely, if you have Nvim specific configuration items, you could do +this: +> + if has('nvim') + tnoremap <Esc> <C-\><C-n> + endif +< +For a more granular approach use |exists()|: +> + if exists(':tnoremap') + tnoremap <Esc> <C-\><C-n> + endif +< +Now you should be able to explore Nvim more comfortably. Check |nvim-features| +for more information. ============================================================================== vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/nvim_clipboard.txt b/runtime/doc/nvim_clipboard.txt deleted file mode 100644 index 078382c7a7..0000000000 --- a/runtime/doc/nvim_clipboard.txt +++ /dev/null @@ -1,63 +0,0 @@ -*nvim_clipboard.txt* For Nvim. {Nvim} - - - NVIM REFERENCE MANUAL by Thiago de Arruda - - -Clipboard integration for Nvim *nvim-clipboard* - -1. Intro |nvim-clipboard-intro| -2. X11 selection mechanism |nvim-clipboard-x11| - -============================================================================== -1. Intro *nvim-clipboard-intro* - -Nvim has no direct connection to the system clipboard. Instead, it is -accessible through the |nvim-provider| infrastructure, which transparently -uses shell commands for communicating with the clipboard. - -Clipboard access is implicitly enabled if any of the following clipboard tools -is found in your `$PATH`. - -- xclip -- xsel (newer alternative to xclip) -- pbcopy/pbpaste (only for Mac OS X) -- lemonade (useful for SSH machine) - https://github.com/pocke/lemonade -- doitclient (another option for SSH setups from the maintainer of PuTTY) - http://www.chiark.greenend.org.uk/~sgtatham/doit/ - -The presence of a suitable clipboard tool implicitly enables the '+' and '*' -registers. - -If you want to ALWAYS use the clipboard for ALL operations (as opposed -to interacting with the '+' and/or '*' registers explicitly), set the -following option: -> - set clipboard+=unnamedplus -< -See 'clipboard' for details and more options. - -============================================================================== -2. X11 selection mechanism *nvim-clipboard-x11* *x11-selection* - -The clipboard providers for X11 store text in what is known as "selections". -Selections are "owned" by an application, so when the application is closed, -the selection text is lost. - -The contents of selections are held by the originating application (e.g., upon -a copy), and only passed on to another application when that other application -asks for them (e.g., upon a paste). - - *quoteplus* *quote+* - -There are three documented X11 selections: `PRIMARY`, `SECONDARY`, and `CLIPBOARD`. -`CLIPBOARD` is typically used in X11 applications for copy/paste operations -(`Ctrl-c`/`v`), while `PRIMARY` is used for the last selected text, which is -generally inserted with the middle mouse button. - -Nvim's X11 clipboard providers only utilize the `PRIMARY` and `CLIPBOARD` -selections, used for the '*' and '+' registers, respectively. - -============================================================================== - vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/nvim_from_vim.txt b/runtime/doc/nvim_from_vim.txt deleted file mode 100644 index 299eeb05f5..0000000000 --- a/runtime/doc/nvim_from_vim.txt +++ /dev/null @@ -1,50 +0,0 @@ -*nvim_from_vim.txt* For Nvim. {Nvim} - - - NVIM REFERENCE MANUAL - - -Transitioning from Vim *nvim-from-vim* - -Nvim is emphatically a fork of Vim, so compatibility to Vim should be pretty -good. - -To start the transition, link your previous configuration so Nvim can use -it: -> - mkdir -p ${XDG_CONFIG_HOME:=$HOME/.config} - ln -s ~/.vim $XDG_CONFIG_HOME/nvim - ln -s ~/.vimrc $XDG_CONFIG_HOME/nvim/init.vim -< -See |nvim-intro|, especially |nvim-python| and |nvim-clipboard|, for -additional software you might need to install to use all of Nvim's features. - -Your Vim configuration might not be entirely compatible with Nvim. For a -full list of differences between Vim and Nvim, see |vim-differences|. - -The |'ttymouse'| option, for example, was removed from Nvim (mouse support -should work without it). If you use the same |vimrc| for Vim and Nvim, -consider guarding |'ttymouse'| in your configuration like so: -> - if !has('nvim') - set ttymouse=xterm2 - endif -< -Conversely, if you have Nvim specific configuration items, you could do -this: -> - if has('nvim') - tnoremap <Esc> <C-\><C-n> - endif -< -For a more granular approach, use |exists()|: -> - if exists(':tnoremap') - tnoremap <Esc> <C-\><C-n> - endif -< -Now you should be able to explore Nvim more comfortably. Check |nvim| for more -information. - -============================================================================== - vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/nvim_provider.txt b/runtime/doc/nvim_provider.txt deleted file mode 100644 index 91cd5fbfc7..0000000000 --- a/runtime/doc/nvim_provider.txt +++ /dev/null @@ -1,76 +0,0 @@ -*nvim_provider.txt* For Nvim. {Nvim} - - - NVIM REFERENCE MANUAL by Thiago de Arruda - - -Nvim provider infrastructure *nvim-provider* - -First of all, this document is meant to be read by developers interested in -contributing to the refactoring effort. If you are a normal user or plugin -developer looking to learn about Nvim |msgpack-rpc| infrastructure for -implementing plugins in other programming languages, see |remote-plugin|. -For instructions on how to enable Python plugins, see |nvim-python|. For -clipboard, see |nvim-clipboard|. - -Instead of doing everything by itself, Nvim aims to simplify its own -maintenance by delegating as much work as possible to external systems. But -some Vim components are too tightly coupled and in some cases the refactoring -work necessary to swap in-house implementations by code that integrates to -other systems is too great. Nvim provider infrastructure is a facility that -aims to make this task simpler. - -To understand why the provider infrastructure is useful, let us consider two -examples of integration with external systems that are implemented in Vim and -are now decoupled from Nvim core as providers: - -The first example is clipboard integration: in the original Vim source code, -clipboard functions account for more than 1k lines of C source code (and that -is just on ui.c), all to perform two tasks that are now accomplished with -simple shell commands such as xclip or pbcopy/pbpaste. - -The other example is Python scripting support: Vim has three files dedicated to -embedding the Python interpreter: if_python.c, if_python3.c and if_py_both.h. -Together these files sum about 9.5k lines of C source code. On Nvim, Python -scripting is performed by an external host process that is running 2k sloc -Python program. - -In a perfect world, we would implement Python and clipboard integration in -pure vimscript and without touching the C code. Unfortunately we can't achieve -these goals without severely compromising backwards compatibility with Vim. -That's where providers come to the rescue. - -In essence, this infrastructure is a simple framework that simplifies the task -of calling vimscript from C code, making it simpler to rewrite C functions that -interact with external systems in pure vimscript. It is composed of two -functions in eval.c: - -- eval_call_provider(name, method, arguments): Call a provider(name) method - with arguments -- eval_has_provider(name): Checks if a provider is implemented - -What these functions do is simple: - -- eval_call_provider will call the provider#(name)#Call function passing in - the method and arguments. -- eval_has_provider will return true if the provider#(name)#Call function is - implemented, and is called by the "has" vimscript function to check if - features are available. - -The basic idea is that the provider#(name)#Call function should implement -integration with an external system, because calling shell commands and -|msgpack-rpc| clients (Nvim only) is easier to do in vimscript. - -Now, back to the Python example. Instead of modifying vimscript to allow for -the definition of lowercase functions and commands (for the |:python|, -|:pyfile|, and |:pydo| commands, and the |pyeval()| function), which would -break backwards compatibility with Vim, we implemented the -autoload/provider/python.vim script and the provider#python#Call function -that is only defined if an external Python host is started successfully. - -That works well with the `has('python')` expression (normally used by Python -plugins) because if the Python host isn't installed then the plugin will -"think" it is running in a Vim compiled without |+python| feature. - -============================================================================== - vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/nvim_python.txt b/runtime/doc/nvim_python.txt deleted file mode 100644 index a2fc968db4..0000000000 --- a/runtime/doc/nvim_python.txt +++ /dev/null @@ -1,95 +0,0 @@ -*nvim_python.txt* For Nvim. {Nvim} - - - NVIM REFERENCE MANUAL by Thiago de Arruda - - -Python plugins and scripting in Nvim *nvim-python* - -1. Introduction |nvim-python-intro| -2. Quickstart |nvim-python-quickstart| - -============================================================================== -1. Introduction *nvim-python-intro* - -Through external Python 2/3 interpreters connected via |msgpack-rpc|, Nvim -offers some support for the legacy |python-vim| and |python3| interfaces. - -Note: For now only the old Vim 7.3 API is supported. - -============================================================================== -2. Quickstart *nvim-python-quickstart* - -If you used a package manager to install Nvim, there's a good chance that -it also provides the `neovim` Python package. If it doesn't, follow these -steps to install the package with Python's package manager, `pip`. - -Note: Depending on your system, `pip` might refer to Python 2 or Python 3, - which is why the following instructions mention `pip2` or `pip3` - explicitly. If one of these is not available for you, maybe `pip` - is what you want. - -To use Vim Python 2/3 plugins with Nvim, do the following: - -- For Python 2 plugins, make sure an interpreter for Python 2.6 or 2.7 is - available in your `$PATH`, then install the `neovim` Python package systemwide: - > - $ sudo pip2 install neovim -< - or for the current user: -> - $ pip2 install --user neovim -< -- For Python 3 plugins, make sure an interpreter for Python 3.3 or above is - available in your `$PATH`, then install the `neovim` Python package systemwide: - > - $ sudo pip3 install neovim -< - or for the current user: -> - $ pip3 install --user neovim -< -Note: If you previously installed the package, get the latest version by - appending the `--upgrade` flag to the commands above. - -============================================================================== - *g:python_host_prog* - -To point Nvim to a specific Python 2 interpreter, set |g:python_host_prog|: -> - let g:python_host_prog = '/path/to/python' -< - *g:python3_host_prog* - -To point Nvim to a specific Python 3 interpreter, set |g:python3_host_prog|: -> - let g:python3_host_prog = '/path/to/python3' -< - *g:loaded_python_provider* - -To disable Python 2 interface, set `g:loaded_python_provider` to 1: -> - let g:loaded_python_provider = 1 -< - *g:loaded_python3_provider* - -To disable Python 3 interface, set `g:loaded_python3_provider` to 1: -> - let g:loaded_python3_provider = 1 -< - *g:python_host_skip_check* - -To disable Python 2 interpreter check, set `g:python_host_skip_check` to 1: -Note: If you disable Python 2 check, you must install neovim module properly. -> - let g:python_host_skip_check = 1 -< - *g:python3_host_skip_check* - -To disable Python 3 interpreter check, set `g:python3_host_skip_check` to 1: -Note: If you disable Python 3 check, you must install neovim module properly. -> - let g:python3_host_skip_check = 1 -< -============================================================================== - vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt index 6ef3aaebaa..8f7dc0dbf0 100644 --- a/runtime/doc/nvim_terminal_emulator.txt +++ b/runtime/doc/nvim_terminal_emulator.txt @@ -1,34 +1,31 @@ -*nvim_terminal_emulator.txt* For Nvim. {Nvim} +*terminal_emulator.txt* {Nvim} NVIM REFERENCE MANUAL by Thiago de Arruda -Nvim integrated terminal emulator *nvim-terminal-emulator* +Embedded terminal emulator *terminal-emulator* -1. Introduction |nvim-terminal-emulator-introduction| -2. Spawning |nvim-terminal-emulator-spawning| -3. Input |nvim-terminal-emulator-input| -4. Configuration |nvim-terminal-emulator-configuration| +1. Introduction |terminal-emulator-intro| +2. Spawning |terminal-emulator-spawning| +3. Input |terminal-emulator-input| +4. Configuration |terminal-emulator-configuration| +5. Status Variables |terminal-emulator-status| ============================================================================== -1. Introduction *nvim-terminal-emulator-introduction* +1. Introduction *terminal-emulator-intro* -One feature that distinguishes Nvim from Vim is that it implements a mostly -complete VT220/xterm-like terminal emulator. The terminal is presented to the -user as a special buffer type, one that is asynchronously updated to mirror -the virtual terminal display as data is received from the program connected -to it. For most purposes, terminal buffers behave a lot like normal buffers -with 'nomodifiable' set. +Nvim offers a mostly complete VT220/xterm terminal emulator. The terminal is +presented as a special buffer type, asynchronously updated to mirror the +virtual terminal display as data is received from the program connected to it. +For most purposes, terminal buffers behave a lot like normal buffers with +'nomodifiable' set. - -The implementation is powered by libvterm[1], a powerful abstract terminal -emulation library. - -[1]: http://www.leonerd.org.uk/code/libvterm/ +The implementation is powered by libvterm, a powerful abstract terminal +emulation library. http://www.leonerd.org.uk/code/libvterm/ ============================================================================== -2. Spawning *nvim-terminal-emulator-spawning* +2. Spawning *terminal-emulator-spawning* There are 3 ways to create a terminal buffer: @@ -37,16 +34,22 @@ There are 3 ways to create a terminal buffer: - By editing a file with a name matching `term://(.{-}//(\d+:)?)?\zs.*`. For example: > - :e term://bash - :vsp term://top + :edit term://bash + :vsplit term://top < + Note: The "term://" pattern is handled by a BufReadCmd handler, so the + |autocmd-nested| modifier is required to use it in an autocmd. > + autocmd VimEnter * nested split term://sh +< This is only mentioned for reference; you should use the |:terminal| + command instead. + When the terminal spawns the program, the buffer will start to mirror the terminal display and change its name to `term://$CWD//$PID:$COMMAND`. Note that |:mksession| will "save" the terminal buffers by restarting all programs when the session is restored. ============================================================================== -3. Input *nvim-terminal-emulator-input* +3. Input *terminal-emulator-input* Sending input is possible by entering terminal mode, which is achieved by pressing any key that would enter insert mode in a normal buffer (|i| or |a| @@ -90,7 +93,7 @@ Mouse input is also fully supported, and has the following behavior: the terminal wont lose focus and the hovered window will be scrolled. ============================================================================== -4. Configuration *nvim-terminal-emulator-configuration* +4. Configuration *terminal-emulator-configuration* Terminal buffers can be customized through the following global/buffer-local variables (set via the |TermOpen| autocmd): @@ -111,4 +114,25 @@ The terminal cursor can be highlighted via |hl-TermCursor| and |hl-TermCursorNC|. ============================================================================== +5. Status Variables *terminal-emulator-status* + +Terminal buffers maintain some information about the terminal in buffer-local +variables: + +- *b:term_title* The settable title of the terminal, typically displayed in + the window title or tab title of a graphical terminal emulator. Programs + running in the terminal can set this title via an escape sequence. +- *b:terminal_job_id* The nvim job ID of the job running in the terminal. See + |job-control| for more information. +- *b:terminal_job_pid* The PID of the top-level process running in the + terminal. + +These variables will have a value by the time the TermOpen autocmd runs, and +will continue to have a value for the lifetime of the terminal buffer, making +them suitable for use in 'statusline'. For example, to show the terminal title +as the status line: +> + :autocmd TermOpen * setlocal statusline=%{b:term_title} +< +============================================================================== vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 83ae96a651..e00f27f9f0 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 7.4. Last change: 2016 Jan 03 +*options.txt* For Vim version 7.4. Last change: 2016 Apr 12 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1172,8 +1172,7 @@ A jump table for the options with a short description can be found at |Q_op|. help help buffer (you are not supposed to set this manually) terminal terminal buffer, this is set automatically when a - terminal is created. See |nvim-terminal-emulator| for - more information. + terminal is created. |terminal-emulator| This option is used together with 'bufhidden' and 'swapfile' to specify special kinds of buffers. See |special-buffers|. @@ -1353,7 +1352,7 @@ A jump table for the options with a short description can be found at |Q_op|. used regardless of whether "unnamed" is in 'clipboard' or not. The clipboard register can always be explicitly accessed using the "* notation. Also see - |gui-clipboard|. + |clipboard|. *clipboard-unnamedplus* unnamedplus A variant of the "unnamed" flag which uses the @@ -1363,7 +1362,7 @@ A jump table for the options with a short description can be found at |Q_op|. register. When "unnamed" is also included to the option, yank and delete operations (but not put) will additionally copy the text into register - '*'. See |nvim-clipboard|. + '*'. See |clipboard|. *clipboard-autoselect* autoselect Works like the 'a' flag in 'guioptions': If present, @@ -1602,7 +1601,7 @@ A jump table for the options with a short description can be found at |Q_op|. line, the remaining space is filled in the normal manner. See 'preserveindent'. - *'cpoptions'* *'cpo'* + *'cpoptions'* *'cpo'* *cpo* 'cpoptions' 'cpo' string (Vim default: "aABceFs", Vi default: all flags) global @@ -2459,8 +2458,8 @@ A jump table for the options with a short description can be found at |Q_op|. file only, the option is not changed. When 'binary' is set, the value of 'fileformats' is not used. - Note that when Vim starts up with an empty buffer this option is not - used. Set 'fileformat' in your vimrc instead. + When Vim starts up with an empty buffer the first item is used. You + can overrule this by setting 'fileformat' in your .vimrc. For systems with a Dos-like <EOL> (<CR><NL>), when reading files that are ":source"ed and for vimrc files, automatic <EOL> detection may be @@ -2515,17 +2514,17 @@ A jump table for the options with a short description can be found at |Q_op|. item default Used for ~ stl:c ' ' or '^' statusline of the current window - stlnc:c ' ' or '-' statusline of the non-current windows + stlnc:c ' ' or '=' statusline of the non-current windows vert:c '|' vertical separators |:vsplit| fold:c '-' filling 'foldtext' diff:c '-' deleted lines of the 'diff' option Any one that is omitted will fall back to the default. For "stl" and - "stlnc" the space will be used when there is highlighting, '^' or '-' + "stlnc" the space will be used when there is highlighting, '^' or '=' otherwise. Example: > - :set fillchars=stl:^,stlnc:-,vert:\|,fold:-,diff:- + :set fillchars=stl:^,stlnc:=,vert:\|,fold:-,diff:- < This is similar to the default, except that these characters will also be used when there is highlighting. @@ -3328,8 +3327,6 @@ A jump table for the options with a short description can be found at |Q_op|. - no highlighting : use a highlight group The default is used for occasions that are not included. - If you want to change what the display modes do, see |dos-colors| - for an example. When using the ':' display mode, this must be followed by the name of a highlight group. A highlight group can be used to define any type of highlighting, including using color. See |:highlight| on how to @@ -3696,6 +3693,8 @@ A jump table for the options with a short description can be found at |Q_op|. '*', '"' and '|' (so that CTRL-] on a command finds the help for that command). When the 'lisp' option is on the '-' character is always included. + This option also influences syntax highlighting, unless the syntax + uses |:syn-iskeyword|. *'isprint'* *'isp'* 'isprint' 'isp' string (default: "@,161-255") @@ -4239,6 +4238,7 @@ A jump table for the options with a short description can be found at |Q_op|. written. A ":set nomodified" command also resets the original values to the current values and the 'modified' option will be reset. + Similarly for 'eol' and 'bomb'. This option is not set when a change is made to the buffer as the result of a BufNewFile, BufRead/BufReadPost, BufWritePost, FileAppendPost or VimLeave autocommand event. See |gzip-example| for @@ -4500,6 +4500,12 @@ A jump table for the options with a short description can be found at |Q_op|. This option cannot be set from a |modeline| or in the |sandbox|, for security reasons. + *'packpath'* *'pp'* +'packpath' 'pp' string (default: see 'runtimepath') + {not in Vi} + Directories used to find packages. See |packages|. + + *'paragraphs'* *'para'* 'paragraphs' 'para' string (default "IPLPPPQPP TPHPLIPpLpItpplpipbp") global @@ -4937,7 +4943,7 @@ A jump table for the options with a short description can be found at |Q_op|. $XDG_CONFIG_DIRS[1]/nvim, $XDG_CONFIG_DIRS[2]/nvim, … - $XDG_DATA_HOME/nvim, + $XDG_DATA_HOME/nvim/site, $XDG_DATA_DIRS[1]/nvim/site, $XDG_DATA_DIRS[2]/nvim/site, … @@ -4945,7 +4951,7 @@ A jump table for the options with a short description can be found at |Q_op|. … $XDG_DATA_DIRS[2]/nvim/site/after, $XDG_DATA_DIRS[1]/nvim/site/after, - $XDG_DATA_HOME/nvim/after, + $XDG_DATA_HOME/nvim/site/after, … $XDG_CONFIG_DIRS[2]/nvim/after, $XDG_CONFIG_DIRS[1]/nvim/after, @@ -5955,7 +5961,7 @@ A jump table for the options with a short description can be found at |Q_op|. The option consists of printf style '%' items interspersed with normal text. Each status line item is of the form: %-0{minwid}.{maxwid}{item} - All fields except the {item} is optional. A single percent sign can + All fields except the {item} are optional. A single percent sign can be given as "%%". Up to 80 items can be specified. *E541* When the option starts with "%!" then it is used as an expression, @@ -6068,7 +6074,8 @@ A jump table for the options with a short description can be found at |Q_op|. feature use `has('tablineat')`. < - Where to truncate line if too long. Default is at the start. No width fields allowed. - = - Separation point between left and right aligned items. + = - Separation point between alignment sections. Each section will + be separated by an equal number of spaces. No width fields allowed. # - Set highlight group. The name must follow and then a # again. Thus use %#HLname# for highlight group HLname. The same @@ -6461,6 +6468,7 @@ A jump table for the options with a short description can be found at |Q_op|. non-keyword characters (white space is preferred). Maximum line length is 510 bytes. To obtain a file to be used here, check out this ftp site: + [Sorry this link doesn't work anymore, do you know the right one?] ftp://ftp.ox.ac.uk/pub/wordlists/ First get the README file. To include a comma in a file name precede it with a backslash. Spaces after a comma are ignored, otherwise spaces are included in the file diff --git a/runtime/doc/os_win32.txt b/runtime/doc/os_win32.txt index 3c7ca4e36a..5dc276c9df 100644 --- a/runtime/doc/os_win32.txt +++ b/runtime/doc/os_win32.txt @@ -1,4 +1,4 @@ -*os_win32.txt* For Vim version 7.4. Last change: 2014 Sep 25 +*os_win32.txt* For Vim version 7.4. Last change: 2016 Mar 05 VIM REFERENCE MANUAL by George Reilly @@ -75,6 +75,31 @@ The directory of the Vim executable is appended to $PATH. This is mostly to make "!xxd" work, as it is in the Tools menu. And it also means that when executable() returns 1 the executable can actually be executed. +Quotes in file names *win32-quotes* + +Quotes inside a file name (or any other command line argument) can be escaped +with a backslash. E.g. > + vim -c "echo 'foo\"bar'" + +Alternatively use three quotes to get one: > + vim -c "echo 'foo"""bar'" + +The quotation rules are: + +1. A `"` starts quotation. +2. Another `"` or `""` ends quotation. If the quotation ends with `""`, a `"` + is produced at the end of the quoted string. + +Examples, with [] around an argument: + "foo" -> [foo] + "foo"" -> [foo"] + "foo"bar -> [foobar] + "foo" bar -> [foo], [bar] + "foo""bar -> [foo"bar] + "foo"" bar -> [foo"], [bar] + "foo"""bar" -> [foo"bar] + + ============================================================================== 3. Using the mouse *win32-mouse* diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt index 5897f756d8..0fe6106ec5 100644 --- a/runtime/doc/pattern.txt +++ b/runtime/doc/pattern.txt @@ -1,4 +1,4 @@ -*pattern.txt* For Vim version 7.4. Last change: 2016 Jan 03 +*pattern.txt* For Vim version 7.4. Last change: 2016 Apr 03 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1096,8 +1096,8 @@ x A single character, with no special meaning, matches itself '/', alphabetic, numeric, '_' or '~'. These items only work for 8-bit characters, except [:lower:] and [:upper:] also work for multi-byte characters when using the new - regexp engine. In the future these items may work for multi-byte - characters. + regexp engine. See |two-engines|. In the future these items may + work for multi-byte characters. */[[=* *[==]* - An equivalence class. This means that characters are matched that have almost the same meaning, e.g., when ignoring accents. This diff --git a/runtime/doc/pi_netrw.txt b/runtime/doc/pi_netrw.txt index 1705010ff2..2c240fe41f 100644 --- a/runtime/doc/pi_netrw.txt +++ b/runtime/doc/pi_netrw.txt @@ -1,4 +1,4 @@ -*pi_netrw.txt* For Vim version 7.4. Last change: 2015 Oct 31 +*pi_netrw.txt* For Vim version 7.4. Last change: 2016 Feb 16 ------------------------------------------------ NETRW REFERENCE MANUAL by Charles E. Campbell @@ -6,7 +6,7 @@ Author: Charles E. Campbell <NdrOchip@ScampbellPfamily.AbizM> (remove NOSPAM from Campbell's email first) -Copyright: Copyright (C) 1999-2015 Charles E Campbell *netrw-copyright* +Copyright: Copyright (C) 2016 Charles E Campbell *netrw-copyright* The VIM LICENSE applies to the files in this package, including netrw.vim, pi_netrw.txt, netrwFileHandlers.vim, netrwSettings.vim, and syntax/netrw.vim. Like anything else that's free, netrw.vim and its @@ -48,9 +48,10 @@ Copyright: Copyright (C) 1999-2015 Charles E Campbell *netrw-copyright* Introduction To Browsing............................|netrw-intro-browse| Quick Reference: Maps...............................|netrw-browse-maps| Quick Reference: Commands...........................|netrw-browse-cmds| + Banner Display......................................|netrw-I| Bookmarking A Directory.............................|netrw-mb| Browsing............................................|netrw-cr| - Squeezing the Current Tree-Listing Directory......|:netrw-s-cr| + Squeezing the Current Tree-Listing Directory........|netrw-s-cr| Browsing With A Horizontally Split Window...........|netrw-o| Browsing With A New Tab.............................|netrw-t| Browsing With A Vertically Split Window.............|netrw-v| @@ -75,11 +76,13 @@ Copyright: Copyright (C) 1999-2015 Charles E Campbell *netrw-copyright* Making The Browsing Directory The Current Directory.|netrw-c| Marking Files.......................................|netrw-mf| Unmarking Files.....................................|netrw-mF| + Marking Files By Location List......................|netrw-qL| Marking Files By QuickFix List......................|netrw-qF| Marking Files By Regular Expression.................|netrw-mr| Marked Files: Arbitrary Shell Command...............|netrw-mx| Marked Files: Arbitrary Shell Command, En Bloc......|netrw-mX| Marked Files: Arbitrary Vim Command.................|netrw-mv| + Marked Files: Argument List.........................|netrw-ma| |netrw-mA| Marked Files: Compression And Decompression.........|netrw-mz| Marked Files: Copying...............................|netrw-mc| Marked Files: Diff..................................|netrw-md| @@ -1111,6 +1114,7 @@ QUICK REFERENCE: MAPS *netrw-browse-maps* {{{2 qb List bookmarked directories and history |netrw-qb| qf Display information on file |netrw-qf| qF Mark files using a quickfix list |netrw-qF| + qL Mark files using a |location-list| |netrw-qL| r Reverse sorting order |netrw-r| R Rename the designated file(s)/directory(ies) |netrw-R| s Select sorting style: by name, time, or file size |netrw-s| @@ -1160,6 +1164,14 @@ QUICK REFERENCE: COMMANDS *netrw-explore-cmds* *netrw-browse-cmds* {{{2 :Texplore[!] [dir] Tab & Explore..........................|netrw-explore| :Vexplore[!] [dir] Vertical Split & Explore...............|netrw-explore| + +BANNER DISPLAY *netrw-I* + +One may toggle the banner display on and off by pressing "I". + +Also See: |g:netrw_banner| + + BOOKMARKING A DIRECTORY *netrw-mb* *netrw-bookmark* *netrw-bookmarks* {{{2 One may easily "bookmark" the currently browsed directory by using > @@ -1201,7 +1213,7 @@ Related Topics: |g:netrw_home| controls where .netrwbook is kept -BROWSING *netrw-cr* {{{2 +BROWSING *netrw-enter* *netrw-cr* {{{2 Browsing is simple: move the cursor onto a file or directory of interest. Hitting the <cr> (the return key) will select the file or directory. @@ -1242,11 +1254,21 @@ The price for such re-use is that when changes are made (such as new files are introduced into a directory), the listing may become out-of-date. One may always refresh directory listing buffers by pressing ctrl-L (see |netrw-ctrl-l|). - *:netrw-s-cr* - Squeezing the Current Tree-Listing Directory~ - When the tree listing style is enabled (see |netrw-i|) and one is using - gvim, then the <s-cr> mapping may be used to squeeze (close) the - directory currently containing the cursor. + + *netrw-s-cr* +Squeezing the Current Tree-Listing Directory~ + +When the tree listing style is enabled (see |netrw-i|) and one is using +gvim, then the <s-cr> mapping may be used to squeeze (close) the +directory currently containing the cursor. + +Otherwise, one may remap a key combination of one's own choice to get +this effect: > + + nmap <buffer> <silent> <nowait> YOURKEYCOMBO <Plug>NetrwTreeSqueeze +< +Put this line in $HOME/ftplugin/netrw/netrw.vim; it needs to be generated +for netrw buffers only. Related topics: |netrw-ctrl-r| |netrw-o| |netrw-p| @@ -1495,7 +1517,8 @@ One may also use visual mode (see |visual-start|) to select the text that the special handler will use. Normally gx uses expand("<cfile>") to pick up the text under the cursor; one may change what |expand()| uses via the |g:netrw_gx| variable. Alternatively, one may select the text to be used by -gx via first making a visual selection (see |visual-block|). +gx via first making a visual selection (see |visual-block|) or by changing +the |'isfname'| option (which is global, so netrw doesn't modify it). Associated setting variables: |g:netrw_gx| control how gx picks up the text under the cursor @@ -1713,8 +1736,9 @@ Also see: |g:netrw_alto| |g:netrw_altv| |g:netrw_winsize| EXPLORING WITH STARS AND PATTERNS {{{2 When Explore, Sexplore, Hexplore, or Vexplore are used with one of the -following four patterns Explore generates a list of files which satisfy -the request. > +following four patterns Explore generates a list of files which satisfy the +request for the local file system. These exploration patterns will not work +with remote file browsing. */filepat files in current directory which satisfy filepat **/filepat files in current directory or below which satisfy the @@ -2079,15 +2103,22 @@ Netrw provides several ways to mark files: :MF *.c < - * Note that :MF uses |<f-args>| to break the line - at spaces. + (Note that :MF uses |<f-args>| to break the line + at spaces) + + * Mark files using the |argument-list| (|netrw-mA|) + + * Mark files based upon a |location-list| (|netrw-qL|) * Mark files based upon the quickfix list (|netrw-qF|) + (|quickfix-error-lists|) The following netrw maps make use of marked files: |netrw-a| Hide marked files/directories |netrw-D| Delete marked files/directories + |netrw-ma| Move marked files' names to |arglist| + |netrw-mA| Move |arglist| filenames to marked file list |netrw-mb| Append marked files to bookmarks |netrw-mB| Delete marked files from bookmarks |netrw-mc| Copy marked files to target @@ -2146,8 +2177,14 @@ UNMARKING FILES *netrw-mF* {{{2 The "mF" command will unmark all files in the current buffer. One may also use mf (|netrw-mf|) on a specific, already marked, file to unmark just that file. +MARKING FILES BY LOCATION LIST *netrw-qL* {{{2 + (also see |netrw-mf|) + +One may convert |location-list|s into a marked file list using "qL". +You may then proceed with commands such as me (|netrw-me|) to edit them. -MARKING FILES BY QUICKFIX LIST *netrw-qF* {{{2 + +MARKING FILES BY QUICKFIX LIST *netrw-qF* {{{2 (also see |netrw-mf|) One may convert |quickfix-error-lists| into a marked file list using "qF". @@ -2223,6 +2260,16 @@ The command that will be run with this example: tar cf mynewtarball.tar 'file1' 'file2' ... +MARKED FILES: ARGUMENT LIST *netrw-ma* *netrw-mA* + (See |netrw-mf| and |netrw-mr| for how to mark files) + (uses the global marked-file list) + +Using ma, one moves filenames from the marked file list to the argument list. +Using mA, one moves filenames from the argument list to the marked file list. + +See Also: |netrw-qF| |argument-list| |:args| + + MARKED FILES: COMPRESSION AND DECOMPRESSION *netrw-mz* {{{2 (See |netrw-mf| and |netrw-mr| for how to mark files) (uses the local marked file list) @@ -2232,7 +2279,7 @@ If any marked files are decompressed, then "mz" will compress them using the command specified by |g:netrw_compress|; by default, that's "gzip". -For decompression, netrw provides a |Dictionary| of suffices and their +For decompression, netrw uses a |Dictionary| of suffices and their associated decompressing utilities; see |g:netrw_decompress|. Remember that one can mark multiple files by regular expression @@ -2287,7 +2334,7 @@ The command will ask for the requested pattern; one may then enter: > pattern < With /pattern/, editing will start with the first item on the |quickfix| list -that vimgrep sets up (see |:copen|, |:cnext|, |:cprevious|). The |:vimgrep| +that vimgrep sets up (see |:copen|, |:cnext|, |:cprevious|, |:cclose|). The |:vimgrep| command is in use, so without 'g' each line is added to quickfix list only once; with 'g' every match is included. @@ -2756,6 +2803,16 @@ your browsing preferences. (see also: |netrw-settings|) evaluation will be suppressed (see |'ballooneval'|) + *g:netrw_sizestyle* not defined: actual bytes (default) + ="b" : actual bytes (default) + ="h" : human-readable (ex. 5k, 4m, 3g) + uses 1000 base + ="H" : human-readable (ex. 5K, 4M, 3G) + uses 1024 base + The long listing (|netrw-i|) and query-file + maps (|netrw-qf|) will display file size + using the specified style. + *g:netrw_usetab* if this variable exists and is non-zero, then the <tab> map supporting shrinking/expanding a Lexplore or netrw window will be enabled. @@ -3024,14 +3081,14 @@ These will: Related: if you like this idea, you may also find :Lexplore (|netrw-:Lexplore|) or |g:netrw_chgwin| of interest -Also see: |g:netrw_chgwin| |netrw-P| |'previewwindow'| +Also see: |g:netrw_chgwin| |netrw-P| |'previewwindow'| |CTRL-W_z| |:pclose| PREVIOUS WINDOW *netrw-P* *netrw-prvwin* {{{2 -To edit a file or directory in the previously used (last accessed) window (see -:he |CTRL-W_p|), press a "P". If there's only one window, then the one window -will be horizontally split (by default). +To edit a file or directory under the cursor in the previously used (last +accessed) window (see :he |CTRL-W_p|), press a "P". If there's only one +window, then the one window will be horizontally split (by default). If there's more than one window, the previous window will be re-used on the selected file/directory. If the previous window's associated buffer @@ -3170,7 +3227,7 @@ only if your terminal supports differentiating <c-tab> from a plain * Else bring up a |:Lexplore| window If |g:netrw_usetab| exists or is zero, or if there is a pre-existing mapping -for <c-tab>, then the <tab> will not be mapped. One may map something other +for <c-tab>, then the <c-tab> will not be mapped. One may map something other than a <c-tab>, too: (but you'll still need to have had g:netrw_usetab set) > nmap <unique> (whatever) <Plug>NetrwShrink @@ -3637,13 +3694,13 @@ called netrw.vimrc with the following contents: > < Then run netrw as follows: > - vim -u netrw.vimrc --noplugins [some path here] + vim -u netrw.vimrc --noplugins -i NONE [some path here] < Perform whatever netrw commands you need to, and check that the problem is still present. This procedure sidesteps any issues due to personal .vimrc -settings and other plugins. If the problem does not appear, then you need -to determine what setting in your .vimrc is causing the conflict with netrw -or which plugin. +settings, .viminfo file, and other plugins. If the problem does not appear, +then you need to determine which setting in your .vimrc is causing the +conflict with netrw or which plugin(s) is/are involved. Step 3: If the problem still is present, then get a debugging trace from netrw: @@ -3698,6 +3755,37 @@ netrw: ============================================================================== 12. History *netrw-history* {{{1 + v155: Oct 29, 2015 * (Timur Fayzrakhmanov) reported that netrw's + mapping of ctrl-l was not allowing refresh of + other windows when it was done in a netrw + window. + Nov 05, 2015 * Improved s:TreeSqueezeDir() to use search() + instead of a loop + * NetrwBrowse() will return line to + w:netrw_bannercnt if cursor ended up in + banner + Nov 16, 2015 * Added a <Plug>NetrwTreeSqueeze (|netrw-s-cr|) + Nov 17, 2015 * Commented out imaps -- perhaps someone can + tell me how they're useful and should be + retained? + Nov 20, 2015 * Added |netrw-ma| and |netrw-mA| support + Nov 20, 2015 * gx (|netrw-gx|) on an url downloaded the + file in addition to simply bringing up the + url in a browser. Fixed. + Nov 23, 2015 * Added |g:netrw_sizestyle| support + Nov 27, 2015 * Inserted a lot of <c-u>s into various netrw + maps. + Jan 05, 2016 * |netrw-qL| implemented to mark files based + upon |location-list|s; similar to |netrw-qF|. + Jan 19, 2016 * using - call delete(directoryname,"d") - + instead of using g:netrw_localrmdir if + v7.4 + patch#1107 is available + Jan 28, 2016 * changed to using |winsaveview()| and + |winrestview()| + Jan 28, 2016 * s:NetrwTreePath() now does a save and + restore of view + Feb 08, 2016 * Fixed a tree-listing problem with remote + directories v154: Feb 26, 2015 * (Yuri Kanivetsky) reported a situation where a file was not treated properly as a file due to g:netrw_keepdir == 1 @@ -3858,7 +3946,7 @@ netrw: handling. * |:Lexplore| path: will be used to update a left-side netrw browsing directory. - Mar 12, 2014 * |:netrw-s-cr|: use <s-cr> to close + Mar 12, 2014 * |netrw-s-cr|: use <s-cr> to close tree directory implemented Mar 13, 2014 * (Tony Mechylynck) reported that using the browser with ftp on a directory, diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt new file mode 100644 index 0000000000..7380fb9346 --- /dev/null +++ b/runtime/doc/provider.txt @@ -0,0 +1,158 @@ +*provider.txt* {Nvim} + + + NVIM REFERENCE MANUAL by Thiago de Arruda + + +Providers *provider* + +Nvim delegates some features to dynamic "providers". + +============================================================================== +Python integration *provider-python* + +Nvim supports the Vim legacy |python-vim| and |python3| interfaces via +external Python interpreters connected via |RPC|, + +Note: Only the Vim 7.3 API is supported; bindeval (Vim 7.4) is not. + + +PYTHON QUICKSTART ~ + +If you used a package manager to install Nvim there's a good chance that +it also provides the `neovim` Python package. If it doesn't, follow these +steps to install the package with Python's package manager, `pip`. + +Note: Depending on your system, `pip` might refer to Python 2 or Python 3, + which is why the following instructions mention `pip2` or `pip3` + explicitly. If one of these is not available, try `pip`. + +To use Vim Python 2/3 plugins with Nvim: + +- For Python 2 plugins, make sure an interpreter for Python 2.6 or 2.7 is + available in your `$PATH`, then install the `neovim` Python package systemwide: > + $ sudo pip2 install --upgrade neovim +< + or for the current user: > + $ pip2 install --user --upgrade neovim +< +- For Python 3 plugins, make sure an interpreter for Python 3.3 or above is + available in your `$PATH`, then install the `neovim` Python package systemwide: > + $ sudo pip3 install --upgrade neovim +< + or for the current user: > + $ pip3 install --user --upgrade neovim +< +Note: The `--upgrade` flag ensures you have the latest version even if + a previous version was already installed. + +PYTHON PROVIDER CONFIGURATION ~ + *g:python_host_prog* +Set `g:python_host_prog` to point Nvim to a specific Python 2 interpreter: > + let g:python_host_prog = '/path/to/python' +< + *g:python3_host_prog* +Set `g:python3_host_prog` to point Nvim to a specific Python 3 interpreter: > + let g:python3_host_prog = '/path/to/python3' +< + *g:loaded_python_provider* +To disable Python 2 support: > + let g:loaded_python_provider = 1 +< + *g:loaded_python3_provider* +To disable Python 3 support: > + let g:loaded_python3_provider = 1 +< + *g:python_host_skip_check* +Set `g:python_host_skip_check` to disable the Python 2 interpreter check. +Note: This requires you to install the python-neovim module properly. > + let g:python_host_skip_check = 1 +< + *g:python3_host_skip_check* +Set `g:python3_host_skip_check` to disable the Python 3 interpreter check. +Note: This requires you to install the python3-neovim module properly. > + let g:python3_host_skip_check = 1 + + +TROUBLESHOOTING *python-trouble* + +If you have trouble with a plugin that uses the `neovim` Python client, use +the |:CheckHealth| command to diagnose your setup. + + *:CheckHealth* +:CheckHealth[!] Check your setup for common problems that may be keeping a + plugin from functioning correctly. Include the output of + this command in bug reports to help reduce the amount of + time it takes to address your issue. With "!" the output + will be placed in a new buffer which can make it easier to + save to a file or copy to the clipboard. + +============================================================================== +Ruby integration *provider-ruby* + +Nvim supports the Vim legacy |ruby-vim| interface via external Ruby +interpreters connected via |RPC|. + + +RUBY QUICKSTART ~ + +To use Vim Ruby plugins with Nvim, just install the latest `neovim` RubyGem: > + $ gem install neovim + + +RUBY PROVIDER CONFIGURATION ~ + *g:loaded_ruby_provider* +To disable Ruby support: > + let g:loaded_ruby_provider = 1 + + +============================================================================== +Clipboard integration *provider-clipboard* *clipboard* + +Nvim has no direct connection to the system clipboard. Instead it is +accessible through a |provider| which transparently uses shell commands for +communicating with the clipboard. + +Clipboard access is implicitly enabled if any of the following clipboard tools +are found in your `$PATH`. + + - xclip + - xsel (newer alternative to xclip) + - pbcopy/pbpaste (Mac OS X) + - lemonade (for SSH) https://github.com/pocke/lemonade + - doitclient (for SSH) http://www.chiark.greenend.org.uk/~sgtatham/doit/ + +The presence of a suitable clipboard tool implicitly enables the '+' and '*' +registers. + +If you want to ALWAYS use the clipboard for ALL operations (as opposed +to interacting with the '+' and/or '*' registers explicitly), set the +following option: +> + set clipboard+=unnamedplus +< +See 'clipboard' for details and more options. + +============================================================================== +X11 selection mechanism *clipboard-x11* *x11-selection* + +The clipboard providers for X11 store text in what is known as "selections". +Selections are "owned" by an application, so when the application is closed, +the selection text is lost. + +The contents of selections are held by the originating application (e.g., upon +a copy), and only passed on to another application when that other application +asks for them (e.g., upon a paste). + + *quoteplus* *quote+* + +There are three documented X11 selections: `PRIMARY`, `SECONDARY`, and `CLIPBOARD`. +`CLIPBOARD` is typically used in X11 applications for copy/paste operations +(`Ctrl-c`/`v`), while `PRIMARY` is used for the last selected text, which is +generally inserted with the middle mouse button. + +Nvim's X11 clipboard providers only utilize the `PRIMARY` and `CLIPBOARD` +selections, used for the '*' and '+' registers, respectively. + +============================================================================== + vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt index ff4fded0d9..3b54faf18e 100644 --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -1,4 +1,4 @@ -*quickfix.txt* For Vim version 7.4. Last change: 2015 Sep 08 +*quickfix.txt* For Vim version 7.4. Last change: 2016 Mar 19 VIM REFERENCE MANUAL by Bram Moolenaar @@ -49,6 +49,10 @@ The following quickfix commands can be used. The location list commands are similar to the quickfix commands, replacing the 'c' prefix in the quickfix command with 'l'. + *E924* +If the current window was closed by an |autocommand| while processing a +location list command, it will be aborted. + *:cc* :cc[!] [nr] Display error [nr]. If [nr] is omitted, the same error is displayed again. Without [!] this doesn't diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt index 8e40628e25..fcfecc02a1 100644 --- a/runtime/doc/quickref.txt +++ b/runtime/doc/quickref.txt @@ -1,4 +1,4 @@ -*quickref.txt* For Vim version 7.4. Last change: 2015 Nov 10 +*quickref.txt* For Vim version 7.4. Last change: 2016 Mar 30 VIM REFERENCE MANUAL by Bram Moolenaar @@ -794,6 +794,7 @@ Short explanation of each option: *option-list* 'omnifunc' 'ofu' function for filetype-specific completion 'opendevice' 'odev' allow reading/writing devices on MS-Windows 'operatorfunc' 'opfunc' function to be called for |g@| operator +'packpath' 'pp' list of directories used for packages 'paragraphs' 'para' nroff macros that separate paragraphs 'paste' allow pasting text 'pastetoggle' 'pt' key code that causes 'paste' to toggle diff --git a/runtime/doc/remote_plugin.txt b/runtime/doc/remote_plugin.txt index 139fcd83b9..d906096a86 100644 --- a/runtime/doc/remote_plugin.txt +++ b/runtime/doc/remote_plugin.txt @@ -16,8 +16,8 @@ Nvim support for remote plugins *remote-plugin* Extensibility is a primary goal of Nvim. Any programming language may be used to extend Nvim without changes to Nvim itself. This is achieved with remote -plugins, coprocesses that have a direct communication channel (via -|msgpack-rpc|) with the Nvim process. +plugins, coprocesses that have a direct communication channel (via |RPC|) with +the Nvim process. Even though these plugins run in separate processes they can call, be called, and receive events just as if the plugin's code were executed in the main @@ -33,9 +33,9 @@ check whether a plugin host is available for their chosen programming language. Plugin hosts are programs that provide a high-level environment for plugins, taking care of most boilerplate involved in defining commands, autocmds, and -functions that are implemented over |msgpack-rpc| connections. Hosts are -loaded only when one of their registered plugins require it, keeping Nvim's -startup as fast as possible, even if many plugins/hosts are installed. +functions that are implemented over |RPC| connections. Hosts are loaded only +when one of their registered plugins require it, keeping Nvim's startup as +fast as possible, even if many plugins/hosts are installed. ============================================================================== 3. Example *remote-plugin-example* diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index 343d3e62cf..e84bbe5439 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -1,4 +1,4 @@ -*repeat.txt* For Vim version 7.4. Last change: 2016 Jan 16 +*repeat.txt* For Vim version 7.4. Last change: 2016 Apr 05 VIM REFERENCE MANUAL by Bram Moolenaar @@ -8,12 +8,14 @@ Repeating commands, Vim scripts and debugging *repeating* Chapter 26 of the user manual introduces repeating |usr_26.txt|. -1. Single repeats |single-repeat| -2. Multiple repeats |multi-repeat| -3. Complex repeats |complex-repeat| -4. Using Vim scripts |using-scripts| -5. Debugging scripts |debug-scripts| -6. Profiling |profiling| +1. Single repeats |single-repeat| +2. Multiple repeats |multi-repeat| +3. Complex repeats |complex-repeat| +4. Using Vim scripts |using-scripts| +5. Using Vim packages |packages| +6. Creating Vim packages |package-create| +7. Debugging scripts |debug-scripts| +8. Profiling |profiling| ============================================================================== 1. Single repeats *single-repeat* @@ -68,8 +70,8 @@ examples. The global commands work by first scanning through the [range] lines and marking each line where a match occurs (for a multi-line pattern, only the start of the match matters). -In a second scan the [cmd] is executed for each marked line with its line -number prepended. For ":v" and ":g!" the command is executed for each not +In a second scan the [cmd] is executed for each marked line, as if the cursor +was in that line. For ":v" and ":g!" the command is executed for each not marked line. If a line is deleted its mark disappears. The default for [range] is the whole buffer (1,$). Use "CTRL-C" to interrupt the command. If an error message is given for a line, the command for that @@ -173,10 +175,12 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|. commands. *:ru* *:runtime* -:ru[ntime][!] {file} .. +:ru[ntime][!] [where] {file} .. Read Ex commands from {file} in each directory given - by 'runtimepath'. There is no error for non-existing - files. Example: > + by 'runtimepath' and/or 'packpath'. There is no error + for non-existing files. + + Example: > :runtime syntax/c.vim < There can be multiple {file} arguments, separated by @@ -190,6 +194,15 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|. When it is not included only the first found file is sourced. + When [where] is omitted only 'runtimepath' is used. + Other values: + START search under "start" in 'packpath' + OPT search under "opt" in 'packpath' + PACK search under "start" and "opt" in + 'packpath' + ALL first use 'runtimepath', then search + under "start" and "opt" in 'packpath' + When {file} contains wildcards it is expanded to all matching files. Example: > :runtime! plugin/*.vim @@ -203,6 +216,57 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|. When 'verbose' is two or higher, there is a message about each searched file. + *:pa* *:packadd* *E919* +:pa[ckadd][!] {name} Search for an optional plugin directory in 'packpath' + and source any plugin files found. The directory must + match: + pack/*/opt/{name} ~ + The directory is added to 'runtimepath' if it wasn't + there yet. + + Note that {name} is the directory name, not the name + of the .vim file. All the files matching the pattern + pack/*/opt/{name}/plugin/**/*.vim ~ + will be sourced. This allows for using subdirectories + below "plugin", just like with plugins in + 'runtimepath'. + + If the filetype detection was not enabled yet (this + is usually done with a "syntax enable" or "filetype + on" command in your .vimrc file), this will also look + for "{name}/ftdetect/*.vim" files. + + When the optional ! is added no plugin files or + ftdetect scripts are loaded, only the matching + directories are added to 'runtimepath'. This is + useful in your .vimrc. The plugins will then be + loaded during initialization, see |load-plugins|. + + Also see |pack-add|. + + *:packl* *:packloadall* +:packl[oadall][!] Load all packages in the "start" directory under each + entry in 'packpath'. + + First all the directories found are added to + 'runtimepath', then the plugins found in the + directories are sourced. This allows for a plugin to + depend on something of another plugin, e.g. an + "autoload" directory. See |packload-two-steps| for + how this can be useful. + + This is normally done automatically during startup, + after loading your .vimrc file. With this command it + can be done earlier. + + Packages will be loaded only once. After this command + it won't happen again. When the optional ! is added + this command will load packages even when done before. + + An error only causes sourcing the script where it + happens to be aborted, further plugins will be loaded. + See |packages|. + :scripte[ncoding] [encoding] *:scripte* *:scriptencoding* *E167* Specify the character encoding used in the script. The following lines will be converted from [encoding] @@ -373,7 +437,186 @@ Rationale: < Therefore the unusual leading backslash is used. ============================================================================== -5. Debugging scripts *debug-scripts* +5. Using Vim packages *packages* + +A Vim package is a directory that contains one or more plugins. The +advantages over normal plugins: +- A package can be downloaded as an archive and unpacked in its own directory. + Thus the files are not mixed with files of other plugins. That makes it + easy to update and remove. +- A package can be a git, mercurial, etc. repository. That makes it really + easy to update. +- A package can contain multiple plugins that depend on each other. +- A package can contain plugins that are automatically loaded on startup and + ones that are only loaded when needed with `:packadd`. + + +Using a package and loading automatically ~ + +Let's assume your Vim files are in the "~/.local/share/nvim/site" directory +and you want to add a package from a zip archive "/tmp/foopack.zip": + % mkdir -p ~/.local/share/nvim/site/pack/foo + % cd ~/.local/share/nvim/site/pack/foo + % unzip /tmp/foopack.zip + +The directory name "foo" is arbitrary, you can pick anything you like. + +You would now have these files under ~/.local/share/nvim/site: + pack/foo/README.txt + pack/foo/start/foobar/plugin/foo.vim + pack/foo/start/foobar/syntax/some.vim + pack/foo/opt/foodebug/plugin/debugger.vim + +When Vim starts up, after processing your .vimrc, it scans all directories in +'packpath' for plugins under the "pack/*/start" directory. First all those +directories are added to 'runtimepath'. Then all the plugins are loaded. +See |packload-two-steps| for how these two steps can be useful. + +In the example Vim will find "pack/foo/start/foobar/plugin/foo.vim" and adds +"~/.local/share/nvim/site/pack/foo/start/foobar" to 'runtimepath'. + +If the "foobar" plugin kicks in and sets the 'filetype' to "some", Vim will +find the syntax/some.vim file, because its directory is in 'runtimepath'. + +Vim will also load ftdetect files, if there are any. + +Note that the files under "pack/foo/opt" are not loaded automatically, only the +ones under "pack/foo/start". See |pack-add| below for how the "opt" directory +is used. + +Loading packages automatically will not happen if loading plugins is disabled, +see |load-plugins|. + +To load packages earlier, so that 'runtimepath' gets updated: > + :packloadall +This also works when loading plugins is disabled. The automatic loading will +only happen once. + + +Using a single plugin and loading it automatically ~ + +If you don't have a package but a single plugin, you need to create the extra +directory level: + % mkdir -p ~/.local/share/nvim/site/pack/foo/start/foobar + % cd ~/.local/share/nvim/site/pack/foo/start/foobar + % unzip /tmp/someplugin.zip + +You would now have these files: + pack/foo/start/foobar/plugin/foo.vim + pack/foo/start/foobar/syntax/some.vim + +From here it works like above. + + +Optional plugins ~ + *pack-add* +To load an optional plugin from a pack use the `:packadd` command: > + :packadd foodebug +This searches for "pack/*/opt/foodebug" in 'packpath' and will find +~/.local/share/nvim/site/pack/foo/opt/foodebug/plugin/debugger.vim and source +it. + +This could be done if some conditions are met. For example, depending on +whether Vim supports a feature or a dependency is missing. + +You can also load an optional plugin at startup, by putting this command in +your |.vimrc|: > + :packadd! foodebug +The extra "!" is so that the plugin isn't loaded with Vim was started with +|--noplugin|. + +It is perfectly normal for a package to only have files in the "opt" +directory. You then need to load each plugin when you want to use it. + + +Where to put what ~ + +Since color schemes, loaded with `:colorscheme`, are found below +"pack/*/start" and "pack/*/opt", you could put them anywhere. We recommend +you put them below "pack/*/opt", for example +".vim/pack/mycolors/opt/dark/colors/very_dark.vim". + +Filetype plugins should go under "pack/*/start", so that they are always +found. Unless you have more than one plugin for a file type and want to +select which one to load with `:packadd`. E.g. depending on the compiler +version: > + if foo_compiler_version > 34 + packadd foo_new + else + packadd foo_old + endif + +The "after" directory is most likely not useful in a package. It's not +disallowed though. + +============================================================================== +6. Creating Vim packages *package-create* + +This assumes you write one or more plugins that you distribute as a package. + +If you have two unrelated plugins you would use two packages, so that Vim +users can chose what they include or not. Or you can decide to use one +package with optional plugins, and tell the user to add the ones he wants with +`:packadd`. + +Decide how you want to distribute the package. You can create an archive or +you could use a repository. An archive can be used by more users, but is a +bit harder to update to a new version. A repository can usually be kept +up-to-date easily, but it requires a program like "git" to be available. +You can do both, github can automatically create an archive for a release. + +Your directory layout would be like this: + start/foobar/plugin/foo.vim " always loaded, defines commands + start/foobar/plugin/bar.vim " always loaded, defines commands + start/foobar/autoload/foo.vim " loaded when foo command used + start/foobar/doc/foo.txt " help for foo.vim + start/foobar/doc/tags " help tags + opt/fooextra/plugin/extra.vim " optional plugin, defines commands + opt/fooextra/autoload/extra.vim " loaded when extra command used + opt/fooextra/doc/extra.txt " help for extra.vim + opt/fooextra/doc/tags " help tags + +This allows for the user to do: > + mkdir ~/.local/share/nvim/site/pack/myfoobar + cd ~/.local/share/nvim/site/pack/myfoobar + git clone https://github.com/you/foobar.git + +Here "myfoobar" is a name that the user can choose, the only condition is that +it differs from other packages. + +In your documentation you explain what the plugins do, and tell the user how +to load the optional plugin: > + :packadd! fooextra + +You could add this packadd command in one of your plugins, to be executed when +the optional plugin is needed. + +Run the `:helptags` command to generate the doc/tags file. Including this +generated file in the package means that the user can drop the package in his +pack directory and the help command works right away. Don't forget to re-run +the command after changing the plugin help: > + :helptags path/start/foobar/doc + :helptags path/opt/fooextra/doc + + +Dependencies between plugins ~ + *packload-two-steps* +Suppose you have a two plugins that depend on the same functionality. You can +put the common functionality in an autoload directory, so that it will be +found automatically. Your package would have these files: + + pack/foo/start/one/plugin/one.vim > + call foolib#getit() +< pack/foo/start/two/plugin/two.vim > + call foolib#getit() +< pack/foo/start/lib/autoload/foolib.vim > + func foolib#getit() + +This works, because loading packages will first add all found directories to +'runtimepath' before sourcing the plugins. + +============================================================================== +7. Debugging scripts *debug-scripts* Besides the obvious messages that you can add to your scripts to find out what they are doing, Vim offers a debug mode. This allows you to step through a @@ -484,7 +727,7 @@ Additionally, these commands can be used: About the additional commands in debug mode: - There is no command-line completion for them, you get the completion for the normal Ex commands only. -- You can shorten them, up to a single character, unless more then one command +- You can shorten them, up to a single character, unless more than one command starts with the same letter. "f" stands for "finish", use "fr" for "frame". - Hitting <CR> will repeat the previous one. When doing another command, this is reset (because it's not clear what you want to repeat). @@ -597,7 +840,7 @@ OBSCURE user, don't use typeahead for debug commands. ============================================================================== -6. Profiling *profile* *profiling* +8. Profiling *profile* *profiling* Profiling means that Vim measures the time that is spent on executing functions and/or scripts. The |+profile| feature is required for this. diff --git a/runtime/doc/spell.txt b/runtime/doc/spell.txt index a767f6cbbf..0902d5d10f 100644 --- a/runtime/doc/spell.txt +++ b/runtime/doc/spell.txt @@ -1,4 +1,4 @@ -*spell.txt* For Vim version 7.4. Last change: 2016 Jan 08 +*spell.txt* VIM REFERENCE MANUAL by Bram Moolenaar @@ -11,10 +11,6 @@ Spell checking *spell* 3. Generating a spell file |spell-mkspell| 4. Spell file format |spell-file-format| -Note: There also is a vimspell plugin. If you have it you can do ":help -vimspell" to find about it. But you will probably want to get rid of the -plugin and use the 'spell' option instead, it works better. - ============================================================================== 1. Quick start *spell-quickstart* *E756* @@ -1633,4 +1629,111 @@ WORDCHARS (Hunspell) *spell-WORDCHARS* is no need to separate words before checking them (using a trie instead of a hashtable). +============================================================================== +5. Spell checker design *develop-spell* + +When spell checking was going to be added to Vim a survey was done over the +available spell checking libraries and programs. Unfortunately, the result +was that none of them provided sufficient capabilities to be used as the spell +checking engine in Vim, for various reasons: + +- Missing support for multi-byte encodings. At least UTF-8 must be supported, + so that more than one language can be used in the same file. + Doing on-the-fly conversion is not always possible (would require iconv + support). +- For the programs and libraries: Using them as-is would require installing + them separately from Vim. That's mostly not impossible, but a drawback. +- Performance: A few tests showed that it's possible to check spelling on the + fly (while redrawing), just like syntax highlighting. But the mechanisms + used by other code are much slower. Myspell uses a hashtable, for example. + The affix compression that most spell checkers use makes it slower too. +- For using an external program like aspell a communication mechanism would + have to be setup. That's complicated to do in a portable way (Unix-only + would be relatively simple, but that's not good enough). And performance + will become a problem (lots of process switching involved). +- Missing support for words with non-word characters, such as "Etten-Leur" and + "et al.", would require marking the pieces of them OK, lowering the + reliability. +- Missing support for regions or dialects. Makes it difficult to accept + all English words and highlight non-Canadian words differently. +- Missing support for rare words. Many words are correct but hardly ever used + and could be a misspelled often-used word. +- For making suggestions the speed is less important and requiring to install + another program or library would be acceptable. But the word lists probably + differ, the suggestions may be wrong words. + + +Spelling suggestions *develop-spell-suggestions* + +For making suggestions there are two basic mechanisms: +1. Try changing the bad word a little bit and check for a match with a good + word. Or go through the list of good words, change them a little bit and + check for a match with the bad word. The changes are deleting a character, + inserting a character, swapping two characters, etc. +2. Perform soundfolding on both the bad word and the good words and then find + matches, possibly with a few changes like with the first mechanism. + +The first is good for finding typing mistakes. After experimenting with +hashtables and looking at solutions from other spell checkers the conclusion +was that a trie (a kind of tree structure) is ideal for this. Both for +reducing memory use and being able to try sensible changes. For example, when +inserting a character only characters that lead to good words need to be +tried. Other mechanisms (with hashtables) need to try all possible letters at +every position in the word. Also, a hashtable has the requirement that word +boundaries are identified separately, while a trie does not require this. +That makes the mechanism a lot simpler. + +Soundfolding is useful when someone knows how the words sounds but doesn't +know how it is spelled. For example, the word "dictionary" might be written +as "daktonerie". The number of changes that the first method would need to +try is very big, it's hard to find the good word that way. After soundfolding +the words become "tktnr" and "tkxnry", these differ by only two letters. + +To find words by their soundfolded equivalent (soundalike word) we need a list +of all soundfolded words. A few experiments have been done to find out what +the best method is. Alternatives: +1. Do the sound folding on the fly when looking for suggestions. This means + walking through the trie of good words, soundfolding each word and + checking how different it is from the bad word. This is very efficient for + memory use, but takes a long time. On a fast PC it takes a couple of + seconds for English, which can be acceptable for interactive use. But for + some languages it takes more than ten seconds (e.g., German, Catalan), + which is unacceptable slow. For batch processing (automatic corrections) + it's too slow for all languages. +2. Use a trie for the soundfolded words, so that searching can be done just + like how it works without soundfolding. This requires remembering a list + of good words for each soundfolded word. This makes finding matches very + fast but requires quite a lot of memory, in the order of 1 to 10 Mbyte. + For some languages more than the original word list. +3. Like the second alternative, but reduce the amount of memory by using affix + compression and store only the soundfolded basic word. This is what Aspell + does. Disadvantage is that affixes need to be stripped from the bad word + before soundfolding it, which means that mistakes at the start and/or end + of the word will cause the mechanism to fail. Also, this becomes slow when + the bad word is quite different from the good word. + +The choice made is to use the second mechanism and use a separate file. This +way a user with sufficient memory can get very good suggestions while a user +who is short of memory or just wants the spell checking and no suggestions +doesn't use so much memory. + + +Word frequency + +For sorting suggestions it helps to know which words are common. In theory we +could store a word frequency with the word in the dictionary. However, this +requires storing a count per word. That degrades word tree compression a lot. +And maintaining the word frequency for all languages will be a heavy task. +Also, it would be nice to prefer words that are already in the text. This way +the words that appear in the specific text are preferred for suggestions. + +What has been implemented is to count words that have been seen during +displaying. A hashtable is used to quickly find the word count. The count is +initialized from words listed in COMMON items in the affix file, so that it +also works when starting a new file. + +This isn't ideal, because the longer Vim is running the higher the counts +become. But in practice it is a noticeable improvement over not using the word +count. + vim:tw=78:sw=4:ts=8:ft=help:norl: diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index 46efe1996a..236ed65f46 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -1,4 +1,4 @@ -*starting.txt* For Vim version 7.4. Last change: 2015 Jan 15 +*starting.txt* For Vim version 7.4. Last change: 2016 Apr 05 VIM REFERENCE MANUAL by Bram Moolenaar @@ -10,9 +10,10 @@ Starting Vim *starting* 2. Initialization |initialization| 3. $VIM and $VIMRUNTIME |$VIM| 4. Suspending |suspend| -5. Saving settings |save-settings| -6. Views and Sessions |views-sessions| -7. The ShaDa file |shada-file| +5. Exiting |exiting| +6. Saving settings |save-settings| +7. Views and Sessions |views-sessions| +8. The ShaDa file |shada-file| ============================================================================== 1. Vim arguments *vim-arguments* @@ -40,6 +41,7 @@ filename One or more file names. The first one will be the current nvim -- -filename < All arguments after the "--" will be interpreted as file names, no other options or "+command" argument can follow. + For behavior of quotes on MS-Windows, see |win32-quotes|. *--* - This argument can mean two things, depending on whether Ex @@ -349,6 +351,9 @@ argument. *-W* -W {scriptout} Like -w, but do not append, overwrite an existing file. + *--api-info* +--api-info Print msgpack-encoded |api-metadata| and exit. + ============================================================================== 2. Initialization *initialization* *startup* @@ -459,6 +464,11 @@ accordingly. Vim proceeds in this order: commands from the command line have not been executed yet. You can use "--cmd 'set noloadplugins'" |--cmd|. + Packages are loaded. These are plugins, as above, but found in the + "start" directory of each entry in 'packpath'. Every plugin directory + found is added in 'runtimepath' and then the plugins are sourced. See + |packages|. + 7. Set 'shellpipe' and 'shellredir' The 'shellpipe' and 'shellredir' options are set according to the value of the 'shell' option, unless they have been set before. @@ -494,8 +504,9 @@ accordingly. Vim proceeds in this order: 14. Execute startup commands If a "-t" flag was given to Vim, the tag is jumped to. The commands given with the |-c| and |+cmd| arguments are executed. - The starting flag is reset, has("vim_starting") will now return zero. If the 'insertmode' option is set, Insert mode is entered. + The starting flag is reset, has("vim_starting") will now return zero. + The |v:vim_did_enter| variable is set to 1. The |VimEnter| autocommands are executed. Some hints on using initializations: @@ -696,7 +707,20 @@ can't paste it in another application (since Vim is going to sleep an attempt to get the selection would make the program hang). ============================================================================== -5. Saving settings *save-settings* +5. Exiting *exiting* + +There are several ways to exit Vim: +- Close the last window with `:quit`. Only when there are no changes. +- Close the last window with `:quit!`. Also when there are changes. +- Close all windows with `:qall`. Only when there are no changes. +- Close all windows with `:qall!`. Also when there are changes. +- Use `:cquit`. Also when there are changes. + +When using `:cquit` or when there was an error message Vim exits with exit +code 1. Errors can be avoided by using `:silent!`. + +============================================================================== +6. Saving settings *save-settings* Mostly you will edit your vimrc files manually. This gives you the greatest flexibility. There are a few commands to generate a vimrc file automatically. @@ -753,7 +777,7 @@ these steps: You need to escape special characters, esp. spaces. ============================================================================== -6. Views and Sessions *views-sessions* +7. Views and Sessions *views-sessions* This is introduced in sections |21.4| and |21.5| of the user manual. @@ -897,7 +921,7 @@ To automatically save and restore views for *.c files: > au BufWinEnter *.c silent loadview ============================================================================== -7. The ShaDa file *shada* *shada-file* +8. The ShaDa file *shada* *shada-file* If you exit Vim and later start it again, you would normally lose a lot of information. The ShaDa file can be used to remember that information, which diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 81ba639dbe..491e5801c8 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -1,4 +1,4 @@ -*syntax.txt* For Vim version 7.4. Last change: 2015 Dec 19 +*syntax.txt* For Vim version 7.4. Last change: 2016 Apr 10 VIM REFERENCE MANUAL by Bram Moolenaar @@ -936,26 +936,27 @@ To disable them use ":unlet". Example: > :unlet c_comment_strings Variable Highlight ~ -c_gnu GNU gcc specific items -c_comment_strings strings and numbers inside a comment -c_space_errors trailing white space and spaces before a <Tab> -c_no_trail_space_error ... but no trailing spaces -c_no_tab_space_error ... but no spaces before a <Tab> -c_no_bracket_error don't highlight {}; inside [] as errors -c_no_curly_error don't highlight {}; inside [] and () as errors; +*c_gnu* GNU gcc specific items +*c_comment_strings* strings and numbers inside a comment +*c_space_errors* trailing white space and spaces before a <Tab> +*c_no_trail_space_error* ... but no trailing spaces +*c_no_tab_space_error* ... but no spaces before a <Tab> +*c_no_bracket_error* don't highlight {}; inside [] as errors +*c_no_curly_error* don't highlight {}; inside [] and () as errors; except { and } in first column -c_curly_error highlight a missing }; this forces syncing from the +*c_curly_error* highlight a missing }; this forces syncing from the start of the file, can be slow -c_no_ansi don't do standard ANSI types and constants -c_ansi_typedefs ... but do standard ANSI types -c_ansi_constants ... but do standard ANSI constants -c_no_utf don't highlight \u and \U in strings -c_syntax_for_h for *.h files use C syntax instead of C++ and use objc +*c_no_ansi* don't do standard ANSI types and constants +*c_ansi_typedefs* ... but do standard ANSI types +*c_ansi_constants* ... but do standard ANSI constants +*c_no_utf* don't highlight \u and \U in strings +*c_syntax_for_h* for *.h files use C syntax instead of C++ and use objc syntax instead of objcpp -c_no_if0 don't highlight "#if 0" blocks as comments -c_no_cformat don't highlight %-formats in strings -c_no_c99 don't highlight C99 standard items -c_no_c11 don't highlight C11 standard items +*c_no_if0* don't highlight "#if 0" blocks as comments +*c_no_cformat* don't highlight %-formats in strings +*c_no_c99* don't highlight C99 standard items +*c_no_c11* don't highlight C11 standard items +*c_no_bsd* don't highlight BSD specific types When 'foldmethod' is set to "syntax" then /* */ comments and { } blocks will become a fold. If you don't want comments to become a fold use: > @@ -2886,7 +2887,7 @@ You may wish to embed languages into sh. I'll give an example courtesy of Lorance Stinson on how to do this with awk as an example. Put the following file into $HOME/.config/nvim/after/syntax/sh/awkembed.vim: > - " AWK Embedding: {{{1 + " AWK Embedding: " ============== " Shamelessly ripped from aspperl.vim by Aaron Hope. if exists("b:current_syntax") @@ -3345,6 +3346,13 @@ Note that schemas are not actually limited to plain scalars, but this is the only difference between schemas defined in YAML specification and the only difference defined in the syntax file. + +ZSH *zsh.vim* *ft-zsh-syntax* + +The syntax script for zsh allows for syntax-based folding: > + + :let g:zsh_fold_enable = 1 + ============================================================================== 5. Defining a syntax *:syn-define* *E410* @@ -3422,6 +3430,32 @@ SPELL CHECKING *:syn-spell* To activate spell checking the 'spell' option must be set. +SYNTAX ISKEYWORD SETTING *:syn-iskeyword* + +:sy[ntax] iskeyword [clear | {option}] + This defines the keyword characters. It's like the 'iskeyword' option + for but only applies to syntax highlighting. + + clear: Syntax specific iskeyword setting is disabled and the + buffer-local 'iskeyword' setting is used. + {option} Set the syntax 'iskeyword' option to a new value. + + Example: > + :syntax iskeyword @,48-57,192-255,$,_ +< + This would set the syntax specific iskeyword option to include all + alphabetic characters, plus the numeric characters, all accented + characters and also includes the "_" and the "$". + + If no argument is given, the current value will be output. + + Setting this option influences what |/\k| matches in syntax patterns + and also determines where |:syn-keyword| will be checked for a new + match. + + It is recommended when writing syntax files, to use this command + to the correct value for the specific syntax language and not change + the 'iskeyword' option. DEFINING KEYWORDS *:syn-keyword* @@ -3453,6 +3487,7 @@ DEFINING KEYWORDS *:syn-keyword* isn't, the keyword will never be recognized. Multi-byte characters can also be used. These do not have to be in 'iskeyword'. + See |:syn-iskeyword| for defining syntax specific iskeyword settings. A keyword always has higher priority than a match or region, the keyword is used if more than one item matches. Keywords do not nest @@ -4484,9 +4519,9 @@ in their own color. :colo[rscheme] {name} Load color scheme {name}. This searches 'runtimepath' for the file "colors/{name}.vim". The first one that is found is loaded. - To see the name of the currently active color scheme: > - :colo -< The name is also stored in the g:colors_name variable. + Also searches all plugins in 'packpath', first below + "start" and then under "opt". + Doesn't work recursively, thus you can't use ":colorscheme" in a color scheme script. After the color scheme has been loaded the @@ -4992,6 +5027,9 @@ defaults back: > :syntax reset +It is a bit of a wrong name, since it does not reset any syntax items, it only +affects the highlighting. + This doesn't change the colors for the 'highlight' option. Note that the syntax colors that you set in your vimrc file will also be reset diff --git a/runtime/doc/usr_02.txt b/runtime/doc/usr_02.txt index 1c536c1eda..c10643940d 100644 --- a/runtime/doc/usr_02.txt +++ b/runtime/doc/usr_02.txt @@ -1,4 +1,4 @@ -*usr_02.txt* For Vim version 7.4. Last change: 2016 Jan 15 +*usr_02.txt* For Vim version 7.4. Last change: 2016 Jan 16 VIM USER MANUAL - by Bram Moolenaar @@ -543,38 +543,42 @@ Summary: *help-summary* > 8) Ex-commands always start with ":", so to go to the :s command help: > :help :s -9) Key combinations. They usually start with a single letter indicating - the mode for which they can be used. E.g.: > +9) Commands specifically for debugging start with ">". To go to to the help + for the "cont" debug command: > + :help >cont + +10) Key combinations. They usually start with a single letter indicating + the mode for which they can be used. E.g.: > :help i_CTRL-X -< takes you to the family of Ctrl-X commands for insert mode which can be - used to auto complete different things. Note, that certain keys will - always be written the same, e.g. Control will always be CTRL. - For normal mode commands there is no prefix and the topic is available at - :h CTRL-<Letter>. E.g. > +< takes you to the family of Ctrl-X commands for insert mode which can be + used to auto complete different things. Note, that certain keys will + always be written the same, e.g. Control will always be CTRL. + For normal mode commands there is no prefix and the topic is available at + :h CTRL-<Letter>. E.g. > :help CTRL-W -< In contrast > +< In contrast > :help c_CTRL-R -< will describe what the Ctrl-R does when entering commands in the Command - line and > +< will describe what the Ctrl-R does when entering commands in the Command + line and > :help v_Ctrl-A -< talks about incrementing numbers in visual mode and > +< talks about incrementing numbers in visual mode and > :help g_CTRL-A -< talks about the g<C-A> command (e.g. you have to press "g" then <Ctrl-A>). - Here the "g" stand for the normal command "g" which always expects a second - key before doing something similar to the commands starting with "z" +< talks about the g<C-A> command (e.g. you have to press "g" then <Ctrl-A>). + Here the "g" stand for the normal command "g" which always expects a second + key before doing something similar to the commands starting with "z" -10) Regexp items always start with /. So to get help for the "\+" quantifier +11) Regexp items always start with /. So to get help for the "\+" quantifier in Vim regexes: > :help /\+ -< If you need to know everything about regular expressions, start reading - at: > +< If you need to know everything about regular expressions, start reading + at: > :help pattern.txt -11) Registers always start with "quote". To find out about the special ":" +12) Registers always start with "quote". To find out about the special ":" register: > :help quote: -12) Vim Script (VimL) is available at > +13) Vim Script (VimL) is available at > :help eval.txt < Certain aspects of the language are available at :h expr-X where "X" is a single letter. E.g. > @@ -589,7 +593,7 @@ Summary: *help-summary* > < talks about the append VimL function rather than how to append text in the current buffer. -13) Mappings are talked about in the help page :h |map.txt|. Use > +14) Mappings are talked about in the help page :h |map.txt|. Use > :help mapmode-i < to find out about the |:imap| command. Also use :map-topic to find out about certain subtopics particular for mappings. e.g: > @@ -598,19 +602,19 @@ Summary: *help-summary* > :help map-bar < for how the '|' is handled in mappings. -14) Command definitions are talked about :h command-topic, so use > +15) Command definitions are talked about :h command-topic, so use > :help command-bar < to find out about the '!' argument for custom commands. -15) Window management commands always start with CTRL-W, so you find the +16) Window management commands always start with CTRL-W, so you find the corresponding help at :h CTRL-W_letter. E.g. > :help CTRL-W_p -< for moving the previous accessed window). You can also access > +< for moving the previous accessed window. You can also access > :help windows.txt < and read your way through if you are looking for window handling commands. -16) Use |:helpgrep| to search in all help pages (and also of any installed +17) Use |:helpgrep| to search in all help pages (and also of any installed plugins). See |:helpgrep| for how to use it. To search for a topic: > :helpgrep topic @@ -621,7 +625,7 @@ Summary: *help-summary* > :copen < Move around to the match you like and press Enter to jump to that help. -17) The user manual. This describes help topics for beginners in a rather +18) The user manual. This describes help topics for beginners in a rather friendly way. Start at |usr_toc.txt| to find the table of content (as you might have guessed): > :help usr_toc.txt @@ -634,31 +638,31 @@ Summary: *help-summary* > :help 10.1 < goes to chapter 10.1 in |usr_10.txt| and talks about recording macros. -18) Highlighting groups. Always start with hl-groupname. E.g. > +19) Highlighting groups. Always start with hl-groupname. E.g. > :help hl-WarningMsg < talks about the WarningMsg highlighting group. -19) Syntax highlighting is namespaced to :syn-topic e.g. > +20) Syntax highlighting is namespaced to :syn-topic e.g. > :help :syn-conceal < talks about the conceal argument for the :syn command. -20) Quickfix commands usually start with :c while location list commands +21) Quickfix commands usually start with :c while location list commands usually start with :l -21) Autocommand events can be found by their name: > +22) Autocommand events can be found by their name: > :help BufWinLeave < To see all possible events: > :help autocommands-events -22) Command-line switches always start with "-". So for the help of the -f +23) Command-line switches always start with "-". So for the help of the -f command switch of Vim use: > :help -f -23) Optional features always start with "+". To find out about the +24) Optional features always start with "+". To find out about the conceal feature use: > :help +conceal -24) Documentation for included filetype specific functionality is usually +25) Documentation for included filetype specific functionality is usually available in the form ft-<filetype>-<functionality>. So > :help ft-c-syntax < talks about the C syntax file and the option it provides. Sometimes, @@ -668,7 +672,7 @@ Summary: *help-summary* > :help ft-tex-plugin < are available. -25) Error and Warning codes can be looked up directly in the help. So > +26) Error and Warning codes can be looked up directly in the help. So > :help E297 < takes you exactly to the description of the swap error message and > :help W10 diff --git a/runtime/doc/usr_05.txt b/runtime/doc/usr_05.txt index 5aecf33557..f920fd4591 100644 --- a/runtime/doc/usr_05.txt +++ b/runtime/doc/usr_05.txt @@ -1,4 +1,4 @@ -*usr_05.txt* For Vim version 7.4. Last change: 2012 Nov 20 +*usr_05.txt* For Vim version 7.4. Last change: 2016 Mar 28 VIM USER MANUAL - by Bram Moolenaar @@ -12,10 +12,11 @@ Vim's capabilities. Or define your own macros. |05.1| The vimrc file |05.2| The example vimrc file explained |05.3| Simple mappings -|05.4| Adding a plugin -|05.5| Adding a help file -|05.6| The option window -|05.7| Often used options +|05.4| Adding a package +|05.5| Adding a plugin +|05.6| Adding a help file +|05.7| The option window +|05.8| Often used options Next chapter: |usr_06.txt| Using syntax highlighting Previous chapter: |usr_04.txt| Making small changes @@ -245,7 +246,47 @@ The ":map" command (with no arguments) lists your current mappings. At least the ones for Normal mode. More about mappings in section |40.1|. ============================================================================== -*05.4* Adding a plugin *add-plugin* *plugin* +*05.4* Adding a package *add-package* *vimball-install* + +A package is a set of files that you can add to Vim. There are two kinds of +packages: optional and automatically loaded on startup. + +The Vim distribution comes with a few packages that you can optionally use. +For example, the vimball plugin. This plugin supports creating and using +vimballs (self-installing Vim plugin archives). + +To start using the vimball plugin, add one line to your vimrc file: > + packadd vimball + +That's all! You can also type the command to try it out. Now you can find +help about this plugin: > + :help vimball + +This works, because when `:packadd` loaded the plugin it also added the +package directory in 'runtimepath', so that the help file can be found. The +tags for vimball's help are already created. If you need to generate the help +tags for a package, see the `:helptags` command. + +You can find packages on the Internet in various places. It usually comes as +an archive or as a repository. For an archive you can follow these steps: + 1. create the package directory: > + mkdir -p ~/.local/share/nvim/site/pack/fancy +< "fancy" can be any name of your liking. Use one that describes the + package. + 2. unpack the archive in that directory. This assumes the top + directory in the archive is "start": > + cd ~/.local/share/nvim/site/pack/fancy + unzip /tmp/fancy.zip +< If the archive layout is different make sure that you end up with a + path like this: + ~/.local/share/nvim/site/pack/fancy/start/fancytext/plugin/fancy.vim ~ + Here "fancytext" is the name of the package, it can be anything + else. + +More information about packages can be found here: |packages|. + +============================================================================== +*05.5* Adding a plugin *add-plugin* *plugin* Vim's functionality can be extended by adding plugins. A plugin is nothing more than a Vim script file that is loaded automatically when Vim starts. You @@ -299,10 +340,9 @@ Then copy the file to your plugin directory: Example for Unix (assuming you didn't have a plugin directory yet): > mkdir -p ~/.local/share/nvim/site/plugin - cp /usr/local/share/vim/vim60/macros/justify.vim ~/.local/share/nvim/site/plugin + cp /tmp/yourplugin.vim ~/.local/share/nvim/site/plugin -That's all! Now you can use the commands defined in this plugin to justify -text. +That's all! Now you can use the commands defined in this plugin. Instead of putting plugins directly into the plugin/ directory, you may better organize them by putting them into subdirectories under plugin/. @@ -384,7 +424,7 @@ Further reading: |new-filetype| How to detect a new file type. ============================================================================== -*05.5* Adding a help file *add-local-help* +*05.6* Adding a help file *add-local-help* If you are lucky, the plugin you installed also comes with a help file. We will explain how to install the help file, so that you can easily find help @@ -417,7 +457,7 @@ them through the tag. For writing a local help file, see |write-local-help|. ============================================================================== -*05.6* The option window +*05.7* The option window If you are looking for an option that does what you want, you can search in the help files here: |options|. Another way is by using this command: > @@ -456,7 +496,7 @@ border. This is what the 'scrolloff' option does, it specifies an offset from the window border where scrolling starts. ============================================================================== -*05.7* Often used options +*05.8* Often used options There are an awful lot of options. Most of them you will hardly ever use. Some of the more useful ones will be mentioned here. Don't forget you can diff --git a/runtime/doc/usr_25.txt b/runtime/doc/usr_25.txt index 23d76a8b0f..24420353dd 100644 --- a/runtime/doc/usr_25.txt +++ b/runtime/doc/usr_25.txt @@ -1,4 +1,4 @@ -*usr_25.txt* For Vim version 7.4. Last change: 2014 Oct 29 +*usr_25.txt* For Vim version 7.4. Last change: 2016 Mar 28 VIM USER MANUAL - by Bram Moolenaar @@ -196,12 +196,16 @@ Vim has no built-in way of justifying text. However, there is a neat macro package that does the job. To use this package, execute the following command: > - :runtime macros/justify.vim + :packadd justify + +Or put this line in your |vimrc|: > + + packadd! justify This Vim script file defines a new visual command "_j". To justify a block of text, highlight the text in Visual mode and then execute "_j". Look in the file for more explanations. To go there, do "gf" on this name: -$VIMRUNTIME/macros/justify.vim. +$VIMRUNTIME/pack/dist/opt/justify/plugin/justify.vim. An alternative is to filter the text through an external program. Example: > diff --git a/runtime/doc/usr_29.txt b/runtime/doc/usr_29.txt index e495aad06d..9eb66ce83c 100644 --- a/runtime/doc/usr_29.txt +++ b/runtime/doc/usr_29.txt @@ -1,4 +1,4 @@ -*usr_29.txt* For Vim version 7.4. Last change: 2008 Jun 28 +*usr_29.txt* For Vim version 7.4. Last change: 2016 Feb 27 VIM USER MANUAL - by Bram Moolenaar diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index fc8419a522..4d3ad49f1f 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -1,4 +1,4 @@ -*usr_41.txt* For Vim version 7.4. Last change: 2015 Nov 30 +*usr_41.txt* For Vim version 7.4. Last change: 2016 Apr 12 VIM USER MANUAL - by Bram Moolenaar @@ -768,6 +768,7 @@ Date and Time: *date-functions* *time-functions* strftime() convert time to a string reltime() get the current or elapsed time accurately reltimestr() convert reltime() result to a string + reltimefloat() convert reltime() result to a Float *buffer-functions* *window-functions* *arg-functions* Buffers, windows and the argument list: @@ -889,9 +890,14 @@ Mappings: *mapping-functions* wildmenumode() check if the wildmode is active Testing: *test-functions* - assert_equal() assert that two expressions values are equal + assert_equal() assert that two expressions values are equal + assert_notequal() assert that two expressions values are not equal + assert_match() assert that a pattern matches the value + assert_notmatch() assert that a pattern does not match the value assert_false() assert that an expression is false assert_true() assert that an expression is true + assert_exception() assert that a command throws an exception + assert_fails() assert that a function call fails Various: *various-functions* mode() get current editing mode @@ -2224,7 +2230,7 @@ This construct makes sure the function is only defined once: > :endif < -UNDO *undo_ftplugin* +UNDO *undo_indent* *undo_ftplugin* When the user does ":setfiletype xyz" the effect of the previous filetype should be undone. Set the b:undo_ftplugin variable to the commands that will @@ -2239,6 +2245,9 @@ global value. That is mostly the best way to reset the option value. This does require removing the "C" flag from 'cpoptions' to allow line continuation, as mentioned above |use-cpo-save|. +For undoing the effect of an indent script, the b:undo_indent variable should +be set accordingly. + FILE NAME diff --git a/runtime/doc/usr_toc.txt b/runtime/doc/usr_toc.txt index 77ea462a23..e021b806e3 100644 --- a/runtime/doc/usr_toc.txt +++ b/runtime/doc/usr_toc.txt @@ -1,4 +1,4 @@ -*usr_toc.txt* For Vim version 7.4. Last change: 2010 Jul 20 +*usr_toc.txt* For Vim version 7.4. Last change: 2016 Mar 25 VIM USER MANUAL - by Bram Moolenaar @@ -101,10 +101,11 @@ Read this from start to end to learn the essential commands. |05.1| The vimrc file |05.2| The example vimrc file explained |05.3| Simple mappings - |05.4| Adding a plugin - |05.5| Adding a help file - |05.6| The option window - |05.7| Often used options + |05.4| Adding a package + |05.5| Adding a plugin + |05.6| Adding a help file + |05.7| The option window + |05.8| Often used options |usr_06.txt| Using syntax highlighting |06.1| Switching it on diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index 293cfe6e00..eb813866da 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -1,4 +1,4 @@ -*various.txt* For Vim version 7.4. Last change: 2016 Jan 10 +*various.txt* For Vim version 7.4. Last change: 2016 Mar 20 VIM REFERENCE MANUAL by Bram Moolenaar @@ -220,7 +220,7 @@ g8 Print the hex values of the bytes used in the Like |:enew|, it will fail if the current buffer is modified, but can be forced with "!". See |termopen()| - and |nvim-terminal-emulator| for more information. + and |terminal-emulator|. To switch to terminal mode automatically: > @@ -319,8 +319,7 @@ N *+dialog_con* Support for |:confirm| with console dialog. N *+dialog_con_gui* Support for |:confirm| with GUI and console dialog. N *+digraphs* |digraphs| *E196* N *+eval* expression evaluation |eval.txt| -N *+ex_extra* Vim's extra Ex commands: |:center|, |:left|, - |:normal|, |:retab| and |:right| +N *+ex_extra* always on now, used to be for Vim's extra Ex commands N *+extra_search* |'hlsearch'| and |'incsearch'| options. B *+farsi* |farsi| language N *+file_in_path* |gf|, |CTRL-W_f| and |<cfile>| @@ -376,6 +375,7 @@ B *+termguicolors* 24-bit color in xterm-compatible terminals support N *+termresponse* support for |t_RV| and |v:termresponse| N *+textobjects* |text-objects| selection *+tgetent* non-Unix only: able to use external termcap +N *+timers* the |timer_start()| function N *+title* Setting the window 'title' and 'icon' N *+toolbar* |gui-toolbar| N *+user_commands* User-defined commands. |user-commands| @@ -416,8 +416,9 @@ m *+xpm_w32* Win32 GUI only: pixmap support |w32-xpm-support| To stop the messages and commands from being echoed to the screen, put the commands in a function and call it with ":silent call Function()". - An alternative is to use the 'verbosefile' option, - this can be used in combination with ":redir". + Alternatives are the 'verbosefile' option or + |capture()| function, these can be used in combination + with ":redir". :redi[r] >> {file} Redirect messages to file {file}. Append if {file} already exists. @@ -455,7 +456,7 @@ m *+xpm_w32* Win32 GUI only: pixmap support |w32-xpm-support| :redi[r] END End redirecting messages. - *:sil* *:silent* + *:sil* *:silent* *:silent!* :sil[ent][!] {command} Execute {command} silently. Normal messages will not be given or added to the message history. When [!] is added, error messages will also be diff --git a/runtime/doc/vi_diff.txt b/runtime/doc/vi_diff.txt index ec35694c9e..54ef8fecb2 100644 --- a/runtime/doc/vi_diff.txt +++ b/runtime/doc/vi_diff.txt @@ -1,4 +1,4 @@ -*vi_diff.txt* For Vim version 7.4. Last change: 2015 Nov 01 +*vi_diff.txt* For Vim version 7.4. Last change: 2016 Feb 12 VIM REFERENCE MANUAL by Bram Moolenaar diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 508712ca75..a5b1cbf9b1 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -12,8 +12,8 @@ these differences. 1. Configuration |nvim-configuration| 2. Defaults |nvim-defaults| -3. Changed features |nvim-features-changed| -4. New features |nvim-features-new| +3. New features |nvim-features| +4. Changed features |nvim-features-changed| 5. Missing legacy features |nvim-features-missing| 6. Removed features |nvim-features-removed| @@ -58,7 +58,62 @@ these differences. - 'wildmenu' is set by default ============================================================================== -3. Changed features *nvim-features-changed* +3. New Features *nvim-features* + + +MAJOR FEATURES ~ + +Embedded terminal emulator |terminal-emulator| +Shared data |shada| +RPC API |RPC| +Job control |job-control| +Remote plugins |remote-plugin| +Python plugins |provider-python| +Clipboard integration |provider-clipboard| +XDG support + + +OTHER FEATURES ~ + +|bracketed-paste-mode| is built-in and enabled by default. + +Meta (alt) chords are recognized (even in the terminal). + <M-1>, <M-2>, ... + <M-BS>, <M-Del>, <M-Ins>, ... + <M-/>, <M-\>, ... + <M-Space>, <M-Enter>, <M-=>, <M-->, <M-?>, <M-$>, ... + + Note: Meta chords are case-sensitive (<M-a> is distinguished from <M-A>). + +Some `CTRL-SHIFT-...` key chords are distinguished from `CTRL-...` variants +(even in the terminal). Specifically, the following are known to work: + <C-Tab>, <C-S-Tab> + <C-BS>, <C-S-BS> + <C-Enter>, <C-S-Enter> + +Options: + 'statusline' supports unlimited alignment sections + +Commands: + |:CheckHealth| + +Functions: + |capture()| + +Events: + |TabNew| + |TabNewEntered| + |TabClosed| + |TermOpen| + |TermClose| + +Highlight groups: + |hl-EndOfBuffer| + |hl-TermCursor| + |hl-TermCursorNC| + +============================================================================== +4. Changed features *nvim-features-changed* Nvim always builds with all features, in contrast to Vim which may have certain features removed/added at compile-time. This is like if Vim's "HUGE" @@ -68,7 +123,12 @@ build). If a Python interpreter is available on your `$PATH`, |:python| and |:python3| are always available and may be used simultaneously in separate plugins. The `neovim` pip package must be installed to use Python plugins in Nvim (see -|nvim-python|). +|provider-python|). + +|:!| and |system()| do not support "interactive" commands; use |:terminal| for +that instead. Terminal Vim supports interactive |:!| and |system()|, but gui +Vim does not. See ":help gui-pty" in Vim: + http://vimdoc.sourceforge.net/htmldoc/gui_x11.html#gui-pty |mkdir()| behaviour changed: 1. Assuming /tmp/foo does not exist and /tmp can be written to @@ -141,47 +201,13 @@ Additional differences: - ShaDa file keeps search direction (|v:searchforward|), viminfo does not. ============================================================================== -4. New Features *nvim-features-new* - -See |nvim-intro| for a list of Nvim's largest new features. - -|bracketed-paste-mode| is built-in and enabled by default. - -Meta (alt) chords are recognized (even in the terminal). - <M-1>, <M-2>, ... - <M-BS>, <M-Del>, <M-Ins>, ... - <M-/>, <M-\>, ... - <M-Space>, <M-Enter>, <M-=>, <M-->, <M-?>, <M-$>, ... - - Note: Meta chords are case-sensitive (<M-a> is distinguished from <M-A>). - -Some `CTRL-SHIFT-...` key chords are distinguished from `CTRL-...` variants -(even in the terminal). Specifically, the following are known to work: - <C-Tab>, <C-S-Tab> - <C-BS>, <C-S-BS> - <C-Enter>, <C-S-Enter> - -Events: - |TabNew| - |TabNewEntered| - |TabClosed| - |TermOpen| - |TermClose| - -Highlight groups: - |hl-EndOfBuffer| - |hl-TermCursor| - |hl-TermCursorNC| - -============================================================================== 5. Missing legacy features *nvim-features-missing* - *if_ruby* *if_lua* *if_perl* *if_mzscheme* *if_tcl* + *if_lua* *if_perl* *if_mzscheme* *if_tcl* These legacy Vim features may be implemented in the future, but they are not planned for the current milestone. - vim.bindeval() (new feature in Vim 7.4 Python interface) -- |if_ruby| - |if_lua| - |if_perl| - |if_mzscheme| diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt index 51b73223b6..d5c7db992e 100644 --- a/runtime/doc/windows.txt +++ b/runtime/doc/windows.txt @@ -1,4 +1,4 @@ -*windows.txt* For Vim version 7.4. Last change: 2015 Nov 14 +*windows.txt* For Vim version 7.4. Last change: 2016 Feb 01 VIM REFERENCE MANUAL by Bram Moolenaar @@ -707,8 +707,8 @@ can also get to them with the buffer list commands, like ":bnext". *:bufdo* :[range]bufdo[!] {cmd} Execute {cmd} in each buffer in the buffer list or if [range] is given only for buffers for which their - buffer name is in the [range]. It works like doing - this: > + buffer number is in the [range]. It works like doing + this: > :bfirst :{cmd} :bnext diff --git a/runtime/ftplugin/eiffel.vim b/runtime/ftplugin/eiffel.vim new file mode 100644 index 0000000000..216fdde162 --- /dev/null +++ b/runtime/ftplugin/eiffel.vim @@ -0,0 +1,96 @@ +" Vim filetype plugin +" Language: Eiffel +" Maintainer: Doug Kearns <dougkearns@gmail.com> +" Last Change: 2010 Aug 29 + +if (exists("b:did_ftplugin")) + finish +endif +let b:did_ftplugin = 1 + +let s:cpo_save = &cpo +set cpo&vim + +setlocal comments=:-- +setlocal commentstring=--\ %s + +setlocal formatoptions-=t formatoptions+=croql + +if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") + let b:browsefilter = "Eiffel Source Files (*.e)\t*.e\n" . + \ "Eiffel Control Files (*.ecf, *.ace, *.xace)\t*.ecf;*.ace;*.xace\n" . + \ "All Files (*.*)\t*.*\n" +endif + +if exists("loaded_matchit") && !exists("b:match_words") + let b:match_ignorecase = 0 + " Silly \%^ trick to match note at head of pair and in middle prevents + " 'g%' wrapping from 'note' to 'end' + let b:match_words = '\%^:' . + \ '\<\%(^note\|indexing\|class\|^obsolete\|inherit\|insert\|^create\|convert\|feature\|^invariant\)\>:' . + \ '^end\>,' . + \ '\<\%(do\|deferred\|external\|once\%(\s\+"\)\@!\|check\|debug\|if\|inspect\|from\|across\)\>:' . + \ '\%(\%(^\s\+\)\@<=\%(then\|until\|loop\)\|\%(then\|until\|loop\)\s\+[^ -]\|' . + \ '\<\%(ensure\%(\s\+then\)\=\|rescue\|_then\|elseif\|else\|when\|\s\@<=invariant\|_until\|_loop\|variant\|_as\|alias\)\>\):' . + \ '\s\@<=end\>' + let b:match_skip = 's:\<eiffel\%(Comment\|String\|Operator\)\>' + noremap [% <Nop> + noremap ]% <Nop> + vnoremap a% <Nop> +endif + +let b:undo_ftplugin = "setl fo< com< cms<" . + \ "| unlet! b:browsefilter b:match_ignorecase b:match_words b:match_skip" + +if !exists("g:no_plugin_maps") && !exists("g:no_eiffel_maps") + function! s:DoMotion(pattern, count, flags) abort + normal! m' + for i in range(a:count) + call search(a:pattern, a:flags) + endfor + endfunction + + let sections = '^\%(note\|indexing\|' . + \ '\%(\%(deferred\|expanded\|external\|frozen\)\s\+\)*class\|' . + \ 'obsolete\|inherit\|insert\|create\|convert\|feature\|' . + \ 'invariant\|end\)\>' + + nnoremap <silent> <buffer> ]] :<C-U>call <SID>DoMotion(sections, v:count1, 'W')<CR> + xnoremap <silent> <buffer> ]] :<C-U>exe "normal! gv"<Bar>call <SID>DoMotion(sections, v:count1, 'W')<CR> + nnoremap <silent> <buffer> [[ :<C-U>call <SID>DoMotion(sections, v:count1, 'Wb')<CR> + xnoremap <silent> <buffer> [[ :<C-U>exe "normal! gv"<Bar>call <SID>DoMotion(sections, v:count1, 'Wb')<CR> + + function! s:DoFeatureMotion(count, flags) + let view = winsaveview() + call cursor(1, 1) + let [features_start, _] = searchpos('^feature\>') + call search('^\s\+\a') " find the first feature + let spaces = indent(line('.')) + let [features_end, _] = searchpos('^\%(invariant\|note\|end\)\>') + call winrestview(view) + call s:DoMotion('\%>' . features_start . 'l\%<' . features_end . 'l^\s*\%' . (spaces + 1) . 'v\zs\a', a:count, a:flags) + endfunction + + nnoremap <silent> <buffer> ]m :<C-U>call <SID>DoFeatureMotion(v:count1, 'W')<CR> + xnoremap <silent> <buffer> ]m :<C-U>exe "normal! gv"<Bar>call <SID>DoFeatureMotion(v:count1, 'W')<CR> + nnoremap <silent> <buffer> [m :<C-U>call <SID>DoFeatureMotion(v:count1, 'Wb')<CR> + xnoremap <silent> <buffer> [m :<C-U>exe "normal! gv"<Bar>call <SID>DoFeatureMotion(v:count1, 'Wb')<CR> + + let comment_block_start = '^\%(\s\+--.*\n\)\@<!\s\+--' + let comment_block_end = '^\s\+--.*\n\%(\s\+--\)\@!' + + nnoremap <silent> <buffer> ]- :<C-U>call <SID>DoMotion(comment_block_start, 1, 'W')<CR> + xnoremap <silent> <buffer> ]- :<C-U>exe "normal! gv"<Bar>call <SID>DoMotion(comment_block_start, 1, 'W')<CR> + nnoremap <silent> <buffer> [- :<C-U>call <SID>DoMotion(comment_block_end, 1, 'Wb')<CR> + xnoremap <silent> <buffer> [- :<C-U>exe "normal! gv"<Bar>call <SID>DoMotion(comment_block_end, 1, 'Wb')<CR> + + let b:undo_ftplugin = b:undo_ftplugin . + \ "| silent! execute 'unmap <buffer> [[' | silent! execute 'unmap <buffer> ]]'" . + \ "| silent! execute 'unmap <buffer> [m' | silent! execute 'unmap <buffer> ]m'" . + \ "| silent! execute 'unmap <buffer> [-' | silent! execute 'unmap <buffer> ]-'" +endif + +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: nowrap sw=2 sts=2 ts=8 diff --git a/runtime/ftplugin/r.vim b/runtime/ftplugin/r.vim index 43b208b842..4ea3073922 100644 --- a/runtime/ftplugin/r.vim +++ b/runtime/ftplugin/r.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file " Language: R " Maintainer: Jakson Alves de Aquino <jalvesaq@gmail.com> -" Last Change: Sun Feb 23, 2014 04:07PM +" Homepage: https://github.com/jalvesaq/R-Vim-runtime +" Last Change: Tue Apr 07, 2015 04:38PM " Only do this when not yet done for this buffer if exists("b:did_ftplugin") diff --git a/runtime/ftplugin/rhelp.vim b/runtime/ftplugin/rhelp.vim index 9b72fb42f9..fdac38f3e9 100644 --- a/runtime/ftplugin/rhelp.vim +++ b/runtime/ftplugin/rhelp.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file " Language: R help file " Maintainer: Jakson Alves de Aquino <jalvesaq@gmail.com> -" Last Change: Wed Jul 09, 2014 06:23PM +" Homepage: https://github.com/jalvesaq/R-Vim-runtime +" Last Change: Tue Apr 07, 2015 04:37PM " Only do this when not yet done for this buffer if exists("b:did_ftplugin") diff --git a/runtime/ftplugin/rmd.vim b/runtime/ftplugin/rmd.vim index 55723ff396..ec64a07675 100644 --- a/runtime/ftplugin/rmd.vim +++ b/runtime/ftplugin/rmd.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file " Language: R help file " Maintainer: Jakson Alves de Aquino <jalvesaq@gmail.com> -" Last Change: Wed Jul 09, 2014 06:23PM +" Homepage: https://github.com/jalvesaq/R-Vim-runtime +" Last Change: Tue Apr 07, 2015 04:37PM " Original work by Alex Zvoleff (adjusted for rmd by Michel Kuhlmann) " Only do this when not yet done for this buffer diff --git a/runtime/ftplugin/rnoweb.vim b/runtime/ftplugin/rnoweb.vim index baf53d0108..e184399dcb 100644 --- a/runtime/ftplugin/rnoweb.vim +++ b/runtime/ftplugin/rnoweb.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file " Language: Rnoweb " Maintainer: Jakson Alves de Aquino <jalvesaq@gmail.com> -" Last Change: Wed Jul 09, 2014 06:23PM +" Homepage: https://github.com/jalvesaq/R-Vim-runtime +" Last Change: Tue Apr 07, 2015 04:37PM " Only do this when not yet done for this buffer if exists("b:did_ftplugin") diff --git a/runtime/ftplugin/rrst.vim b/runtime/ftplugin/rrst.vim index 8140169e61..ecfd6e87a1 100644 --- a/runtime/ftplugin/rrst.vim +++ b/runtime/ftplugin/rrst.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file " Language: reStructuredText documentation format with R code " Maintainer: Jakson Alves de Aquino <jalvesaq@gmail.com> -" Last Change: Wed Jul 09, 2014 06:23PM +" Homepage: https://github.com/jalvesaq/R-Vim-runtime +" Last Change: Tue Apr 07, 2015 04:38PM " Original work by Alex Zvoleff " Only do this when not yet done for this buffer diff --git a/runtime/indent/fortran.vim b/runtime/indent/fortran.vim index d492889fc7..e19a19fb1f 100644 --- a/runtime/indent/fortran.vim +++ b/runtime/indent/fortran.vim @@ -1,11 +1,11 @@ " Vim indent file " Language: Fortran 2008 (and older: Fortran 2003, 95, 90, and 77) -" Version: 0.42 -" Last Change: 2015 Nov. 30 +" Version: 0.44 +" Last Change: 2016 Jan. 26 " Maintainer: Ajit J. Thakkar <ajit@unb.ca>; <http://www2.unb.ca/~ajit/> " Usage: For instructions, do :help fortran-indent from Vim " Credits: -" Useful suggestions were made by: Albert Oliver Serra. +" Useful suggestions were made by: Albert Oliver Serra and Takuya Fujiwara. " Only load this indent file when no other was loaded. if exists("b:did_indent") @@ -92,10 +92,10 @@ function FortranGetIndent(lnum) "Indent do loops only if they are all guaranteed to be of do/end do type if exists("b:fortran_do_enddo") || exists("g:fortran_do_enddo") if prevstat =~? '^\s*\(\d\+\s\)\=\s*\(\a\w*\s*:\)\=\s*do\>' - let ind = ind + &sw + let ind = ind + shiftwidth() endif if getline(v:lnum) =~? '^\s*\(\d\+\s\)\=\s*end\s*do\>' - let ind = ind - &sw + let ind = ind - shiftwidth() endif endif @@ -105,14 +105,14 @@ function FortranGetIndent(lnum) \ ||prevstat=~? '^\s*\(type\|interface\|associate\|enum\)\>' \ ||prevstat=~?'^\s*\(\d\+\s\)\=\s*\(\a\w*\s*:\)\=\s*\(forall\|where\|block\)\>' \ ||prevstat=~? '^\s*\(\d\+\s\)\=\s*\(\a\w*\s*:\)\=\s*if\>' - let ind = ind + &sw + let ind = ind + shiftwidth() " Remove unwanted indent after logical and arithmetic ifs if prevstat =~? '\<if\>' && prevstat !~? '\<then\>' - let ind = ind - &sw + let ind = ind - shiftwidth() endif " Remove unwanted indent after type( statements if prevstat =~? '^\s*type\s*(' - let ind = ind - &sw + let ind = ind - shiftwidth() endif endif @@ -125,12 +125,12 @@ function FortranGetIndent(lnum) \ ||prevstat =~? '^\s*'.prefix.'subroutine\>' \ ||prevstat =~? '^\s*'.prefix.type.'function\>' \ ||prevstat =~? '^\s*'.type.prefix.'function\>' - let ind = ind + &sw + let ind = ind + shiftwidth() endif if getline(v:lnum) =~? '^\s*contains\>' \ ||getline(v:lnum)=~? '^\s*end\s*' \ .'\(function\|subroutine\|module\|program\)\>' - let ind = ind - &sw + let ind = ind - shiftwidth() endif endif @@ -141,23 +141,23 @@ function FortranGetIndent(lnum) \. '\(else\|else\s*if\|else\s*where\|case\|' \. 'end\s*\(if\|where\|select\|interface\|' \. 'type\|forall\|associate\|enum\|block\)\)\>' - let ind = ind - &sw + let ind = ind - shiftwidth() " Fix indent for case statement immediately after select if prevstat =~? '\<select\s\+\(case\|type\)\>' - let ind = ind + &sw + let ind = ind + shiftwidth() endif endif "First continuation line if prevstat =~ '&\s*$' && prev2stat !~ '&\s*$' - let ind = ind + &sw + let ind = ind + shiftwidth() endif if prevstat =~ '&\s*$' && prevstat =~ '\<else\s*if\>' - let ind = ind - &sw + let ind = ind - shiftwidth() endif "Line after last continuation line if prevstat !~ '&\s*$' && prev2stat =~ '&\s*$' && prevstat !~? '\<then\>' - let ind = ind - &sw + let ind = ind - shiftwidth() endif return ind diff --git a/runtime/indent/php.vim b/runtime/indent/php.vim index 1bffa7f195..07ecd8f141 100644 --- a/runtime/indent/php.vim +++ b/runtime/indent/php.vim @@ -3,8 +3,8 @@ " Author: John Wellesz <John.wellesz (AT) teaser (DOT) fr> " URL: http://www.2072productions.com/vim/indent/php.vim " Home: https://github.com/2072/PHP-Indenting-for-VIm -" Last Change: 2014 November 26th -" Version: 1.57 +" Last Change: 2015 September 8th +" Version: 1.60 " " " Type :help php-indent for available options @@ -50,16 +50,25 @@ let b:did_indent = 1 let g:php_sync_method = 0 +if exists('*shiftwidth') + function! s:sw() + return shiftwidth() + endfunction +else + function! s:sw() + return &shiftwidth + endfunction +endif if exists("PHP_default_indenting") - let b:PHP_default_indenting = PHP_default_indenting * &sw + let b:PHP_default_indenting = PHP_default_indenting * s:sw() else let b:PHP_default_indenting = 0 endif if exists("PHP_outdentSLComments") - let b:PHP_outdentSLComments = PHP_outdentSLComments * &sw + let b:PHP_outdentSLComments = PHP_outdentSLComments * s:sw() else let b:PHP_outdentSLComments = 0 endif @@ -124,7 +133,7 @@ endif if exists("*GetPhpIndent") call ResetPhpOptions() - finish " XXX -- comment this line for easy dev + finish endif @@ -135,7 +144,7 @@ let s:functionDecl = '\<function\>\%(\s\+'.s:PHP_validVariable.'\)\=\s*(.*' let s:endline= '\s*\%(//.*\|#.*\|/\*.*\*/\s*\)\=$' -let s:terminated = '\%(\%(;\%(\s*\%(?>\|}\)\)\=\|<<<''\=\a\w*''\=$\|^\s*}\|^\s*'.s:PHP_validVariable.':\)'.s:endline.'\)\|^[^''"`]*[''"`]$' +let s:terminated = '\%(\%(;\%(\s*\%(?>\|}\)\)\=\|<<<\s*[''"]\=\a\w*[''"]\=$\|^\s*}\|^\s*'.s:PHP_validVariable.':\)'.s:endline.'\)\|^[^''"`]*[''"`]$' let s:PHP_startindenttag = '<?\%(.*?>\)\@!\|<script[^>]*>\%(.*<\/script>\)\@!' @@ -200,7 +209,7 @@ function! GetLastRealCodeLNum(startline) " {{{ elseif lastline =~? '^\a\w*;\=$' && lastline !~? s:notPhpHereDoc - let tofind=substitute( lastline, '\(\a\w*\);\=', '<<<''\\=\1''\\=$', '') + let tofind=substitute( lastline, '\(\a\w*\);\=', '<<<\\s*[''"]\\=\1[''"]\\=$', '') while getline(lnum) !~? tofind && lnum > 1 let lnum = lnum - 1 endwhile @@ -314,7 +323,7 @@ function! FindTheSwitchIndent (lnum) " {{{ let test = GetLastRealCodeLNum(a:lnum - 1) if test <= 1 - return indent(1) - &sw * b:PHP_vintage_case_default_indent + return indent(1) - s:sw() * b:PHP_vintage_case_default_indent end while getline(test) =~ '^\s*}' && test > 1 @@ -328,7 +337,7 @@ function! FindTheSwitchIndent (lnum) " {{{ if getline(test) =~# '^\s*switch\>' return indent(test) elseif getline(test) =~# s:defaultORcase - return indent(test) - &sw * b:PHP_vintage_case_default_indent + return indent(test) - s:sw() * b:PHP_vintage_case_default_indent else return FindTheSwitchIndent(test) endif @@ -401,7 +410,7 @@ function! GetPhpIndent() endif if b:PHP_default_indenting - let b:PHP_default_indenting = g:PHP_default_indenting * &sw + let b:PHP_default_indenting = g:PHP_default_indenting * s:sw() endif let cline = getline(v:lnum) @@ -439,6 +448,7 @@ function! GetPhpIndent() if !b:InPHPcode_checked " {{{ One time check let b:InPHPcode_checked = 1 + let b:UserIsTypingComment = 0 let synname = "" if cline !~ '<?.*?>' @@ -447,8 +457,7 @@ function! GetPhpIndent() if synname!="" if synname == "SpecStringEntrails" - let b:InPHPcode = -1 " thumb down - let b:UserIsTypingComment = 0 + let b:InPHPcode = -1 let b:InPHPcode_tofind = "" elseif synname != "phpHereDoc" && synname != "phpHereDocDelimiter" let b:InPHPcode = 1 @@ -456,8 +465,7 @@ function! GetPhpIndent() if synname =~# '^php\%(Doc\)\?Comment' let b:UserIsTypingComment = 1 - else - let b:UserIsTypingComment = 0 + let b:InPHPcode_checked = 0 endif if synname =~? '^javaScript' @@ -466,18 +474,16 @@ function! GetPhpIndent() else let b:InPHPcode = 0 - let b:UserIsTypingComment = 0 let lnum = v:lnum - 1 - while getline(lnum) !~? '<<<''\=\a\w*''\=$' && lnum > 1 + while getline(lnum) !~? '<<<\s*[''"]\=\a\w*[''"]\=$' && lnum > 1 let lnum = lnum - 1 endwhile - let b:InPHPcode_tofind = substitute( getline(lnum), '^.*<<<''\=\(\a\w*\)''\=$', '^\\s*\1;\\=$', '') + let b:InPHPcode_tofind = substitute( getline(lnum), '^.*<<<\s*[''"]\=\(\a\w*\)[''"]\=$', '^\\s*\1;\\=$', '') endif else let b:InPHPcode = 0 - let b:UserIsTypingComment = 0 let b:InPHPcode_tofind = s:PHP_startindenttag endif endif "!b:InPHPcode_checked }}} @@ -537,9 +543,9 @@ function! GetPhpIndent() elseif last_line =~ '^[^''"`]\+[''"`]$' let b:InPHPcode = -1 let b:InPHPcode_tofind = substitute( last_line, '^.*\([''"`]\).*$', '^[^\1]*\1[;,]$', '') - elseif last_line =~? '<<<''\=\a\w*''\=$' + elseif last_line =~? '<<<\s*[''"]\=\a\w*[''"]\=$' let b:InPHPcode = 0 - let b:InPHPcode_tofind = substitute( last_line, '^.*<<<''\=\(\a\w*\)''\=$', '^\\s*\1;\\=$', '') + let b:InPHPcode_tofind = substitute( last_line, '^.*<<<\s*[''"]\=\(\a\w*\)[''"]\=$', '^\\s*\1;\\=$', '') elseif !UserIsEditing && cline =~ '^\s*/\*\%(.*\*/\)\@!' && getline(v:lnum + 1) !~ '^\s*\*' let b:InPHPcode = 0 @@ -660,7 +666,7 @@ function! GetPhpIndent() let b:PHP_CurrentIndentLevel = b:PHP_default_indenting return indent(FindTheIfOfAnElse(v:lnum, 1)) elseif cline =~# s:defaultORcase - return FindTheSwitchIndent(v:lnum) + &sw * b:PHP_vintage_case_default_indent + return FindTheSwitchIndent(v:lnum) + s:sw() * b:PHP_vintage_case_default_indent elseif cline =~ '^\s*)\=\s*{' let previous_line = last_line let last_line_num = lnum @@ -672,7 +678,7 @@ function! GetPhpIndent() let ind = indent(last_line_num) if b:PHP_BracesAtCodeLevel - let ind = ind + &sw + let ind = ind + s:sw() endif return ind @@ -683,7 +689,7 @@ function! GetPhpIndent() endwhile elseif last_line =~# unstated && cline !~ '^\s*);\='.endline - let ind = ind + &sw + let ind = ind + s:sw() return ind + addSpecial elseif (ind != b:PHP_default_indenting || last_line =~ '^[)\]]' ) && last_line =~ terminated @@ -782,7 +788,7 @@ function! GetPhpIndent() endif if !dontIndent && (!b:PHP_BracesAtCodeLevel || last_line !~# '^\s*{') - let ind = ind + &sw + let ind = ind + s:sw() endif if b:PHP_BracesAtCodeLevel || b:PHP_vintage_case_default_indent == 1 @@ -800,17 +806,17 @@ function! GetPhpIndent() endif elseif last_line =~ '^\s*'.s:blockstart - let ind = ind + &sw + let ind = ind + s:sw() elseif AntepenultimateLine =~ '{'.endline || AntepenultimateLine =~ terminated || AntepenultimateLine =~# s:defaultORcase - let ind = ind + &sw + let ind = ind + s:sw() endif endif if cline =~ '^\s*[)\]];\=' - let ind = ind - &sw + let ind = ind - s:sw() endif let b:PHP_CurrentIndentLevel = ind diff --git a/runtime/indent/r.vim b/runtime/indent/r.vim index 105f0cd7ad..01f3812ed2 100644 --- a/runtime/indent/r.vim +++ b/runtime/indent/r.vim @@ -1,7 +1,8 @@ " Vim indent file " Language: R " Author: Jakson Alves de Aquino <jalvesaq@gmail.com> -" Last Change: Thu Mar 26, 2015 05:36PM +" Homepage: https://github.com/jalvesaq/R-Vim-runtime +" Last Change: Thu Feb 18, 2016 06:32AM " Only load this indent file when no other was loaded. @@ -32,7 +33,7 @@ if ! exists("g:r_indent_ess_compatible") let g:r_indent_ess_compatible = 0 endif if ! exists("g:r_indent_op_pattern") - let g:r_indent_op_pattern = '\(+\|-\|\*\|/\|=\|\~\|%\)$' + let g:r_indent_op_pattern = '\(&\||\|+\|-\|\*\|/\|=\|\~\|%\|->\)\s*$' endif function s:RDelete_quotes(line) @@ -265,7 +266,7 @@ function GetRIndent() return 0 endif - if cline =~ '^\s*{' + if cline =~ '^\s*{' && s:Get_paren_balance(cline, '{', '}') > 0 if g:r_indent_ess_compatible && line =~ ')$' let nlnum = lnum let nline = line @@ -283,7 +284,7 @@ function GetRIndent() endif " line is an incomplete command: - if line =~ '\<\(if\|while\|for\|function\)\s*()$' || line =~ '\<else$' || line =~ '<-$' + if line =~ '\<\(if\|while\|for\|function\)\s*()$' || line =~ '\<else$' || line =~ '<-$' || line =~ '->$' return indent(lnum) + &sw endif @@ -344,7 +345,7 @@ function GetRIndent() endif let post_block = 0 - if line =~ '}$' + if line =~ '}$' && s:Get_paren_balance(line, '{', '}') < 0 let lnum = s:Get_matching_brace(lnum, '{', '}', 0) let line = SanitizeRLine(getline(lnum)) if lnum > 0 && line =~ '^\s*{' @@ -359,14 +360,14 @@ function GetRIndent() let olnum = s:Get_prev_line(lnum) let oline = getline(olnum) if olnum > 0 - if line =~ g:r_indent_op_pattern - if oline =~ g:r_indent_op_pattern + if line =~ g:r_indent_op_pattern && s:Get_paren_balance(line, "(", ")") == 0 + if oline =~ g:r_indent_op_pattern && s:Get_paren_balance(line, "(", ")") == 0 return indent(lnum) else return indent(lnum) + &sw endif else - if oline =~ g:r_indent_op_pattern + if oline =~ g:r_indent_op_pattern && s:Get_paren_balance(line, "(", ")") == 0 return indent(lnum) - &sw endif endif @@ -471,7 +472,6 @@ function GetRIndent() endif let ind = indent(lnum) - let pind = indent(plnum) if g:r_indent_align_args == 0 && pb != 0 let ind += pb * &sw @@ -483,6 +483,12 @@ function GetRIndent() return ind endif + if plnum > 0 + let pind = indent(plnum) + else + let pind = 0 + endif + if ind == pind || (ind == (pind + &sw) && pline =~ '{$' && ppost_else == 0) return ind endif diff --git a/runtime/indent/rhelp.vim b/runtime/indent/rhelp.vim index 3b37128b2c..9dc2031cb6 100644 --- a/runtime/indent/rhelp.vim +++ b/runtime/indent/rhelp.vim @@ -1,7 +1,8 @@ " Vim indent file " Language: R Documentation (Help), *.Rd " Author: Jakson Alves de Aquino <jalvesaq@gmail.com> -" Last Change: Thu Oct 16, 2014 07:07AM +" Homepage: https://github.com/jalvesaq/R-Vim-runtime +" Last Change: Tue Apr 07, 2015 04:38PM " Only load this indent file when no other was loaded. diff --git a/runtime/indent/rmd.vim b/runtime/indent/rmd.vim index 9a8a3cb719..88904405e8 100644 --- a/runtime/indent/rmd.vim +++ b/runtime/indent/rmd.vim @@ -1,7 +1,8 @@ " Vim indent file " Language: Rmd " Author: Jakson Alves de Aquino <jalvesaq@gmail.com> -" Last Change: Thu Jul 10, 2014 07:11PM +" Homepage: https://github.com/jalvesaq/R-Vim-runtime +" Last Change: Tue Apr 07, 2015 04:38PM " Only load this indent file when no other was loaded. diff --git a/runtime/indent/rnoweb.vim b/runtime/indent/rnoweb.vim index d0cad3d8d9..29fa5bc78f 100644 --- a/runtime/indent/rnoweb.vim +++ b/runtime/indent/rnoweb.vim @@ -1,7 +1,8 @@ " Vim indent file " Language: Rnoweb " Author: Jakson Alves de Aquino <jalvesaq@gmail.com> -" Last Change: Sun Mar 22, 2015 09:28AM +" Homepage: https://github.com/jalvesaq/R-Vim-runtime +" Last Change: Tue Apr 07, 2015 04:38PM " Only load this indent file when no other was loaded. diff --git a/runtime/indent/rrst.vim b/runtime/indent/rrst.vim index 8bfa8344ce..f3ee53e7fb 100644 --- a/runtime/indent/rrst.vim +++ b/runtime/indent/rrst.vim @@ -1,7 +1,8 @@ " Vim indent file " Language: Rrst " Author: Jakson Alves de Aquino <jalvesaq@gmail.com> -" Last Change: Wed Jul 09, 2014 07:33PM +" Homepage: https://github.com/jalvesaq/R-Vim-runtime +" Last Change: Tue Apr 07, 2015 04:38PM " Only load this indent file when no other was loaded. diff --git a/runtime/indent/sh.vim b/runtime/indent/sh.vim index 5bd8c77fab..d05bb3770f 100644 --- a/runtime/indent/sh.vim +++ b/runtime/indent/sh.vim @@ -3,7 +3,7 @@ " Maintainer: Christian Brabandt <cb@256bit.org> " Previous Maintainer: Peter Aronoff <telemachus@arpinum.org> " Original Author: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2015-12-15 +" Latest Revision: 2016-02-15 " License: Vim (see :h license) " Repository: https://github.com/chrisbra/vim-sh-indent @@ -12,14 +12,14 @@ if exists("b:did_indent") endif let b:did_indent = 1 -let b:undo_indent = 'setlocal indentexpr< indentkeys< smartindent<' - setlocal indentexpr=GetShIndent() setlocal indentkeys+=0=then,0=do,0=else,0=elif,0=fi,0=esac,0=done,0=end,),0=;;,0=;& setlocal indentkeys+=0=fin,0=fil,0=fip,0=fir,0=fix setlocal indentkeys-=:,0# setlocal nosmartindent +let b:undo_indent = 'setlocal indentexpr< indentkeys< smartindent<' + if exists("*GetShIndent") finish endif @@ -28,7 +28,7 @@ let s:cpo_save = &cpo set cpo&vim function s:buffer_shiftwidth() - return &shiftwidth + return shiftwidth() endfunction let s:sh_indent_defaults = { @@ -67,7 +67,7 @@ function! GetShIndent() if !s:is_case_ended(line) let ind += s:indent_value('case-statements') endif - elseif line =~ '^\s*\<\k\+\>\s*()\s*{' || line =~ '^\s*{' + elseif line =~ '^\s*\<\k\+\>\s*()\s*{' || line =~ '^\s*{' || line =~ '^\s*function\s*\w\S\+\s*\%(()\)\?\s*{' if line !~ '}\s*\%(#.*\)\=$' let ind += s:indent_value('default') endif diff --git a/runtime/indent/tex.vim b/runtime/indent/tex.vim index 7e3a351083..0150bb9623 100644 --- a/runtime/indent/tex.vim +++ b/runtime/indent/tex.vim @@ -2,10 +2,9 @@ " Language: LaTeX " Maintainer: YiChao Zhou <broken.zhou AT gmail.com> " Created: Sat, 16 Feb 2002 16:50:19 +0100 -" Last Change: 2012 Mar 18 19:19:50 -" Version: 0.7 -" Please email me if you found something we can do. Bug report and -" feature request is welcome. +" Version: 0.9.2 +" Please email me if you found something I can do. Comments, bug report and +" feature request are welcome. " Last Update: {{{ " 25th Sep 2002, by LH : @@ -41,7 +40,7 @@ " (*) Trust user when in "verbatim" and "lstlisting" " 2012/03/11 by Zhou Yichao <broken.zhou AT gmail.com> " (*) Modify "&" so that only indent when current line start with -" "&". +" "&". " 2012/03/12 by Zhou Yichao <broken.zhou AT gmail.com> " (*) Modify indentkeys. " 2012/03/18 by Zhou Yichao <broken.zhou AT gmail.com> @@ -49,6 +48,17 @@ " 2013/05/02 by Zhou Yichao <broken.zhou AT gmail.com> " (*) Fix problem about GetTeXIndent checker. Thank Albert Netymk " for reporting this. +" 2014/06/23 by Zhou Yichao <broken.zhou AT gmail.com> +" (*) Remove the feature g:tex_indent_and because it is buggy. +" (*) If there is not any obvious indentation hints, we do not +" alert our user's current indentation. +" (*) g:tex_indent_brace now only works if the open brace is the +" last character of that line. +" 2014/08/03 by Zhou Yichao <broken.zhou AT gmail.com> +" (*) Indent current line if last line has larger indentation +" 2014/08/09 by Zhou Yichao <broken.zhou AT gmail.com> +" (*) Add missing return value for s:GetEndIndentation(...) +" " }}} " Document: {{{ @@ -60,7 +70,17 @@ " * g:tex_indent_brace " " If this variable is unset or non-zero, it will use smartindent-like style -" for "{}" and "[]" +" for "{}" and "[]". Now this only works if the open brace is the last +" character of that line. +" +" % Example 1 +" \usetikzlibrary{ +" external +" } +" +" % Example 2 +" \tikzexternalize[ +" prefix=tikz] " " * g:tex_indent_items " @@ -98,14 +118,6 @@ " " A list of environment names. separated with '\|', where no indentation is " required. The default is 'document\|verbatim'. -" -" * g:tex_indent_and -" -" If this variable is unset or zero, vim will try to align the line with first -" "&". This is pretty useful when you use environment like table or align. -" Note that this feature need to search back some line, so vim may become -" a little slow. -" " }}} " Only define the function once @@ -126,8 +138,8 @@ endif if !exists("g:tex_indent_brace") let g:tex_indent_brace = 1 endif -if !exists("g:tex_indent_and") - let g:tex_indent_and = 1 +if !exists("g:tex_max_scan_line") + let g:tex_max_scan_line = 60 endif if g:tex_indent_items if !exists("g:tex_itemize_env") @@ -140,10 +152,6 @@ else let g:tex_items = '' endif -if !exists("g:tex_indent_paretheses") - let g:tex_indent_paretheses = 1 -endif - if !exists("g:tex_noindent_env") let g:tex_noindent_env = 'document\|verbatim\|lstlisting' endif "}}} @@ -160,6 +168,7 @@ let g:tex_items = '^\s*' . substitute(g:tex_items, '^\(\^\\s\*\)*', '', '') function! GetTeXIndent() " {{{ " Find a non-blank line above the current line. let lnum = prevnonblank(v:lnum - 1) + let cnum = v:lnum " Comment line is not what we need. while lnum != 0 && getline(lnum) =~ '^\s*%' @@ -171,8 +180,8 @@ function! GetTeXIndent() " {{{ return 0 endif - let line = substitute(getline(lnum), '%.*', ' ','g') " last line - let cline = substitute(getline(v:lnum), '%.*', ' ', 'g') " current line + let line = substitute(getline(lnum), '\s*%.*', '','g') " last line + let cline = substitute(getline(v:lnum), '\s*%.*', '', 'g') " current line " We are in verbatim, so do what our user what. if synIDattr(synID(v:lnum, indent(v:lnum), 1), "name") == "texZone" @@ -183,26 +192,12 @@ function! GetTeXIndent() " {{{ end endif - " You want to align with "&" - if g:tex_indent_and - " Align only when current line start with "&" - if line =~ '&.*\\\\' && cline =~ '^\s*&' - return indent(v:lnum) + stridx(line, "&") - stridx(cline, "&") - endif - - " set line & lnum to the line which doesn't contain "&" - while lnum != 0 && (stridx(line, "&") != -1 || line =~ '^\s*%') - let lnum = prevnonblank(lnum - 1) - let line = getline(lnum) - endwhile - endif - - if lnum == 0 return 0 endif let ind = indent(lnum) + let stay = 1 " New code for comment: retain the indent of current line if cline =~ '^\s*%' @@ -216,77 +211,197 @@ function! GetTeXIndent() " {{{ " ZYC modification : \end after \begin won't cause wrong indent anymore if line =~ '\\begin{.*}' && line !~ g:tex_noindent_env let ind = ind + &sw + let stay = 0 if g:tex_indent_items " Add another sw for item-environments if line =~ g:tex_itemize_env let ind = ind + &sw + let stay = 0 endif endif endif + if cline =~ '\\end{.*}' + let retn = s:GetEndIndentation(v:lnum) + if retn != -1 + return retn + endif + end " Subtract a 'shiftwidth' when an environment ends - if cline =~ '\\end{.*}' && cline !~ g:tex_noindent_env - + if cline =~ '\\end{.*}' + \ && cline !~ g:tex_noindent_env + \ && cline !~ '\\begin{.*}.*\\end{.*}' if g:tex_indent_items " Remove another sw for item-environments if cline =~ g:tex_itemize_env let ind = ind - &sw + let stay = 0 endif endif let ind = ind - &sw + let stay = 0 endif if g:tex_indent_brace - let sum1 = 0 - for i in range(0, strlen(line)-1) - if line[i] == "}" || line[i] == "]" || - \ strpart(line, i, 7) == '\right)' - let sum1 = max([0, sum1-1]) - endif - if line[i] == "{" || line[i] == "[" || - \ strpart(line, i, 6) == '\left(' - let sum1 += 1 - endif - endfor + let char = line[strlen(line)-1] + if char == '[' || char == '{' + let ind += &sw + let stay = 0 + endif - let sum2 = 0 - for i in reverse(range(0, strlen(cline)-1)) - if cline[i] == "{" || cline[i] == "[" || - \ strpart(cline, i, 6) == '\left(' - let sum2 = max([0, sum2-1]) - endif - if cline[i] == "}" || cline[i] == "]" || - \ strpart(cline, i, 7) == '\right)' - let sum2 += 1 + let cind = indent(v:lnum) + let char = cline[cind] + if (char == ']' || char == '}') && + \ s:CheckPairedIsLastCharacter(v:lnum, cind) + let ind -= &sw + let stay = 0 + endif + + for i in range(indent(lnum)+1, strlen(line)-1) + let char = line[i] + if char == ']' || char == '}' + if s:CheckPairedIsLastCharacter(lnum, i) + let ind -= &sw + let stay = 0 + endif endif endfor - - let ind += (sum1 - sum2) * &sw - endif - - if g:tex_indent_paretheses endif " Special treatment for 'item' " ---------------------------- if g:tex_indent_items - " '\item' or '\bibitem' itself: if cline =~ g:tex_items let ind = ind - &sw + let stay = 0 endif - " lines following to '\item' are intented once again: if line =~ g:tex_items let ind = ind + &sw + let stay = 0 + endif + endif + + if stay + " If there is no obvious indentation hint, we trust our user. + if empty(cline) + return ind + else + return max([indent(v:lnum), s:GetLastBeginIndentation(v:lnum)]) + endif + else + return ind + endif +endfunction "}}} + +function! s:GetLastBeginIndentation(lnum) " {{{ + let matchend = 1 + for lnum in range(a:lnum-1, max([a:lnum - g:tex_max_scan_line, 1]), -1) + let line = getline(lnum) + if line =~ '\\end{.*}' + let matchend += 1 + endif + if line =~ '\\begin{.*}' + let matchend -= 1 endif + if matchend == 0 + if line =~ g:tex_itemize_env + return indent(lnum) + 2 * &sw + endif + if line =~ g:tex_noindent_env + return indent(lnum) + endif + return indent(lnum) + &sw + endif + endfor + return -1 +endfunction + +function! s:GetEndIndentation(lnum) " {{{ + if getline(a:lnum) =~ '\\begin{.*}.*\\end{.*}' + return -1 + endif + + let min_indent = 100 + let matchend = 1 + for lnum in range(a:lnum-1, max([a:lnum-g:tex_max_scan_line, 1]), -1) + let line = getline(lnum) + if line =~ '\\end{.*}' + let matchend += 1 + endif + if line =~ '\\begin{.*}' + let matchend -= 1 + endif + if matchend == 0 + return indent(lnum) + endif + if !empty(line) + let min_indent = min([min_indent, indent(lnum)]) + endif + endfor + return min_indent - &sw +endfunction + +" Most of the code is from matchparen.vim +function! s:CheckPairedIsLastCharacter(lnum, col) "{{{ + " Get the character under the cursor and check if it's in 'matchpairs'. + let c_lnum = a:lnum + let c_col = a:col+1 + + + let c = getline(c_lnum)[c_col-1] + let plist = split(&matchpairs, '.\zs[:,]') + let i = index(plist, c) + if i < 0 + return 0 + endif + + " Figure out the arguments for searchpairpos(). + if i % 2 == 0 + let s_flags = 'nW' + let c2 = plist[i + 1] + else + let s_flags = 'nbW' + let c2 = c + let c = plist[i - 1] + endif + if c == '[' + let c = '\[' + let c2 = '\]' + endif + + " Find the match. When it was just before the cursor move it there for a + " moment. + let save_cursor = winsaveview() + call cursor(c_lnum, c_col) + + " When not in a string or comment ignore matches inside them. + " We match "escape" for special items, such as lispEscapeSpecial. + let s_skip ='synIDattr(synID(line("."), col("."), 0), "name") ' . + \ '=~? "string\\|character\\|singlequote\\|escape\\|comment"' + execute 'if' s_skip '| let s_skip = 0 | endif' + + let stopline = max([0, c_lnum - g:tex_max_scan_line]) + + " Limit the search time to 300 msec to avoid a hang on very long lines. + " This fails when a timeout is not supported. + try + let [m_lnum, m_col] = searchpairpos(c, '', c2, s_flags, s_skip, stopline, 100) + catch /E118/ + endtry + + call winrestview(save_cursor) + if m_lnum > 0 + let line = getline(m_lnum) + return strlen(line) == m_col endif - return ind + return 0 endfunction "}}} let &cpo = s:cpo_save diff --git a/runtime/indent/vim.vim b/runtime/indent/vim.vim index 7511325af4..31b76b8c0c 100644 --- a/runtime/indent/vim.vim +++ b/runtime/indent/vim.vim @@ -1,7 +1,7 @@ " Vim indent file " Language: Vim script " Maintainer: Bram Moolenaar <Bram@vim.org> -" Last Change: 2014 Dec 12 +" Last Change: 2016 Jan 24 " Only load this indent file when no other was loaded. if exists("b:did_indent") @@ -58,19 +58,19 @@ function GetVimIndentIntern() if exists("g:vim_indent_cont") let ind = ind + g:vim_indent_cont else - let ind = ind + &sw * 3 + let ind = ind + shiftwidth() * 3 endif elseif prev_text =~ '^\s*aug\%[roup]' && prev_text !~ '^\s*aug\%[roup]\s*!\=\s\+END' - let ind = ind + &sw + let ind = ind + shiftwidth() else " A line starting with :au does not increment/decrement indent. if prev_text !~ '^\s*au\%[tocmd]' let i = match(prev_text, '\(^\||\)\s*\(if\|wh\%[ile]\|for\|try\|cat\%[ch]\|fina\%[lly]\|fu\%[nction]\|el\%[seif]\)\>') if i >= 0 - let ind += &sw + let ind += shiftwidth() if strpart(prev_text, i, 1) == '|' && has('syntax_items') \ && synIDattr(synID(lnum, i, 1), "name") =~ '\(Comment\|String\)$' - let ind -= &sw + let ind -= shiftwidth() endif endif endif @@ -82,7 +82,7 @@ function GetVimIndentIntern() let i = match(prev_text, '[^\\]|\s*\(ene\@!\)') if i > 0 && prev_text !~ '^\s*au\%[tocmd]' if !has('syntax_items') || synIDattr(synID(lnum, i + 2, 1), "name") !~ '\(Comment\|String\)$' - let ind = ind - &sw + let ind = ind - shiftwidth() endif endif @@ -90,7 +90,7 @@ function GetVimIndentIntern() " Subtract a 'shiftwidth' on a :endif, :endwhile, :catch, :finally, :endtry, " :endfun, :else and :augroup END. if cur_text =~ '^\s*\(ene\@!\|cat\|fina\|el\|aug\%[roup]\s*!\=\s\+[eE][nN][dD]\)' - let ind = ind - &sw + let ind = ind - shiftwidth() endif return ind diff --git a/runtime/indent/zimbu.vim b/runtime/indent/zimbu.vim index 9565b10843..5451877ea7 100644 --- a/runtime/indent/zimbu.vim +++ b/runtime/indent/zimbu.vim @@ -1,7 +1,7 @@ " Vim indent file " Language: Zimbu " Maintainer: Bram Moolenaar <Bram@vim.org> -" Last Change: 2012 Sep 08 +" Last Change: 2016 Jan 25 " Only load this indent file when no other was loaded. if exists("b:did_indent") @@ -74,9 +74,9 @@ func GetZimbuIndent(lnum) \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" \ . " =~ '\\(Comment\\|String\\|Char\\)$'") if pp > 0 - return indent(prevLnum) + &sw + return indent(prevLnum) + shiftwidth() endif - return indent(prevLnum) + &sw * 2 + return indent(prevLnum) + shiftwidth() * 2 endif if plnumstart == p return indent(prevLnum) @@ -102,13 +102,13 @@ func GetZimbuIndent(lnum) endif if prevline =~ '^\s*\(IF\|\|ELSEIF\|ELSE\|GENERATE_IF\|\|GENERATE_ELSEIF\|GENERATE_ELSE\|WHILE\|REPEAT\|TRY\|CATCH\|FINALLY\|FOR\|DO\|SWITCH\|CASE\|DEFAULT\|FUNC\|VIRTUAL\|ABSTRACT\|DEFINE\|REPLACE\|FINAL\|PROC\|MAIN\|NEW\|ENUM\|CLASS\|INTERFACE\|BITS\|MODULE\|SHARED\)\>' - let plindent += &sw + let plindent += shiftwidth() endif if thisline =~ '^\s*\(}\|ELSEIF\>\|ELSE\>\|CATCH\|FINALLY\|GENERATE_ELSEIF\>\|GENERATE_ELSE\>\|UNTIL\>\)' - let plindent -= &sw + let plindent -= shiftwidth() endif if thisline =~ '^\s*\(CASE\>\|DEFAULT\>\)' && prevline !~ '^\s*SWITCH\>' - let plindent -= &sw + let plindent -= shiftwidth() endif " line up continued comment that started after some code diff --git a/runtime/optwin.vim b/runtime/optwin.vim index 68444dde01..bfcf4d5294 100644 --- a/runtime/optwin.vim +++ b/runtime/optwin.vim @@ -1,7 +1,7 @@ " These commands create the option window. " " Maintainer: Bram Moolenaar <Bram@vim.org> -" Last Change: 2015 Jul 22 +" Last Change: 2016 Mar 19 " If there already is an option window, jump to that one. if bufwinnr("option-window") > 0 @@ -228,6 +228,8 @@ else endif call append("$", "runtimepath\tlist of directories used for runtime files and plugins") call <SID>OptionG("rtp", &rtp) +call append("$", "packpath\tlist of directories used for plugin packages") +call <SID>OptionG("pp", &pp) call append("$", "helpfile\tname of the main help file") call <SID>OptionG("hf", &hf) diff --git a/runtime/autoload/vimball.vim b/runtime/pack/dist/opt/vimball/autoload/vimball.vim index 9a5a73c3c1..1af6b19c88 100644 --- a/runtime/autoload/vimball.vim +++ b/runtime/pack/dist/opt/vimball/autoload/vimball.vim @@ -1,9 +1,9 @@ " vimball.vim : construct a file containing both paths and files -" Author: Charles E. Campbell, Jr. -" Date: Jan 17, 2012 -" Version: 35 +" Author: Charles E. Campbell +" Date: Apr 11, 2016 +" Version: 37 " GetLatestVimScripts: 1502 1 :AutoInstall: vimball.vim -" Copyright: (c) 2004-2011 by Charles E. Campbell, Jr. +" Copyright: (c) 2004-2011 by Charles E. Campbell " The VIM LICENSE applies to Vimball.vim, and Vimball.txt " (see |copyright|) except use "Vimball" instead of "Vim". " No warranty, express or implied. @@ -14,7 +14,7 @@ if &cp || exists("g:loaded_vimball") finish endif -let g:loaded_vimball = "v35" +let g:loaded_vimball = "v37" if v:version < 702 echohl WarningMsg echo "***warning*** this version of vimball needs vim 7.2" @@ -142,7 +142,7 @@ fun! vimball#MkVimball(line1,line2,writelevel,...) range let lastline= line("$") + 1 if lastline == 2 && getline("$") == "" - call setline(1,'" Vimball Archiver by Charles E. Campbell, Jr., Ph.D.') + call setline(1,'" Vimball Archiver by Charles E. Campbell') call setline(2,'UseVimball') call setline(3,'finish') let lastline= line("$") + 1 @@ -179,7 +179,7 @@ fun! vimball#MkVimball(line1,line2,writelevel,...) range " remove the evidence setlocal nomod bh=wipe exe "tabn ".curtabnr - exe "tabc ".vbtabnr + exe "tabc! ".vbtabnr " restore options call vimball#RestoreSettings() @@ -280,7 +280,7 @@ fun! vimball#Vimball(really,...) " when AsNeeded/filename is filereadable or was present in VimballRecord if fname =~ '\<plugin/' let anfname= substitute(fname,'\<plugin/','AsNeeded/','') - if filereadable(anfname) || (exists("s:VBRstring") && s:VBRstring =~ anfname) + if filereadable(anfname) || (exists("s:VBRstring") && s:VBRstring =~# anfname) " call Decho("using anfname<".anfname."> instead of <".fname.">") let fname= anfname endif @@ -379,10 +379,10 @@ fun! vimball#Vimball(really,...) call s:RecordInFile(home) " restore events, delete tab and buffer - exe "tabn ".vbtabnr + exe "sil! tabn ".vbtabnr setlocal nomod bh=wipe - exe "tabn ".curtabnr - exe "tabc ".vbtabnr + exe "sil! tabn ".curtabnr + exe "sil! tabc! ".vbtabnr call vimball#RestoreSettings() call s:ChgDir(curdir) @@ -555,7 +555,7 @@ fun! vimball#ShowMesg(level,msg) set noruler noshowcmd redraw! - if &fo =~ '[ta]' + if &fo =~# '[ta]' echomsg "***vimball*** ".a:msg else if a:level == s:WARNING || a:level == s:USAGE @@ -715,7 +715,7 @@ fun! vimball#SaveSettings() " call Dfunc("SaveSettings()") let s:makeep = getpos("'a") let s:regakeep= @a - if exists("&acd") + if exists("+acd") let s:acdkeep = &acd endif let s:eikeep = &ei @@ -728,7 +728,7 @@ fun! vimball#SaveSettings() let s:vekeep = &ve let s:ffkeep = &l:ff let s:swfkeep = &l:swf - if exists("&acd") + if exists("+acd") setlocal ei=all ve=all noacd nofen noic report=999 nohid bt= ma lz pm= ff=unix noswf else setlocal ei=all ve=all nofen noic report=999 nohid bt= ma lz pm= ff=unix noswf @@ -743,7 +743,7 @@ endfun fun! vimball#RestoreSettings() " call Dfunc("RestoreSettings()") let @a = s:regakeep - if exists("&acd") + if exists("+acd") let &acd = s:acdkeep endif let &l:fen = s:fenkeep @@ -760,7 +760,7 @@ fun! vimball#RestoreSettings() " call Decho("restore mark-a: makeep=".string(makeep)) call setpos("'a",s:makeep) endif - if exists("&acd") + if exists("+acd") unlet s:acdkeep endif unlet s:regakeep s:eikeep s:fenkeep s:hidkeep s:ickeep s:repkeep s:vekeep s:makeep s:lzkeep s:pmkeep s:ffkeep diff --git a/runtime/doc/pi_vimball.txt b/runtime/pack/dist/opt/vimball/doc/vimball.txt index bbc74988ca..9965a216e4 100644 --- a/runtime/doc/pi_vimball.txt +++ b/runtime/pack/dist/opt/vimball/doc/vimball.txt @@ -1,4 +1,4 @@ -*pi_vimball.txt* For Vim version 7.4. Last change: 2012 Jan 17 +*vimball.txt* For Vim version 7.4. Last change: 2012 Jan 17 ---------------- Vimball Archiver diff --git a/runtime/pack/dist/opt/vimball/plugin/vimballPlugin.vim b/runtime/pack/dist/opt/vimball/plugin/vimballPlugin.vim new file mode 100644 index 0000000000..d7473a0296 --- /dev/null +++ b/runtime/pack/dist/opt/vimball/plugin/vimballPlugin.vim @@ -0,0 +1,43 @@ +" vimballPlugin : construct a file containing both paths and files +" Author: Charles E. Campbell +" Copyright: (c) 2004-2014 by Charles E. Campbell +" The VIM LICENSE applies to Vimball.vim, and Vimball.txt +" (see |copyright|) except use "Vimball" instead of "Vim". +" No warranty, express or implied. +" *** *** Use At-Your-Own-Risk! *** *** +" +" (Rom 2:1 WEB) Therefore you are without excuse, O man, whoever you are who +" judge. For in that which you judge another, you condemn yourself. For +" you who judge practice the same things. +" GetLatestVimScripts: 1502 1 :AutoInstall: vimball.vim + +" --------------------------------------------------------------------- +" Load Once: {{{1 +if &cp || exists("g:loaded_vimballPlugin") + finish +endif +let g:loaded_vimballPlugin = "v37" +let s:keepcpo = &cpo +set cpo&vim + +" ------------------------------------------------------------------------------ +" Public Interface: {{{1 +com! -range -complete=file -nargs=+ -bang MkVimball call vimball#MkVimball(<line1>,<line2>,<bang>0,<f-args>) +com! -nargs=? -complete=dir UseVimball call vimball#Vimball(1,<f-args>) +com! -nargs=0 VimballList call vimball#Vimball(0) +com! -nargs=* -complete=dir RmVimball call vimball#SaveSettings()|call vimball#RmVimball(<f-args>)|call vimball#RestoreSettings() +augroup Vimball + au! + au BufEnter *.vba,*.vba.gz,*.vba.bz2,*.vba.zip,*.vba.xz setlocal bt=nofile fmr=[[[,]]] fdm=marker|if &ff != 'unix'|setlocal ma ff=unix noma|endif|if line('$') > 1|call vimball#ShowMesg(0,"Source this file to extract it! (:so %)")|endif + au SourceCmd *.vba.gz,*.vba.bz2,*.vba.zip,*.vba.xz let s:origfile=expand("%")|if expand("%")!=expand("<afile>") | exe "1sp" fnameescape(expand("<afile>"))|endif|call vimball#Decompress(expand("<amatch>"))|so %|if s:origfile!=expand("<afile>")|close|endif + au SourceCmd *.vba if expand("%")!=expand("<afile>") | exe "1sp" fnameescape(expand("<afile>"))|call vimball#Vimball(1)|close|else|call vimball#Vimball(1)|endif + au BufEnter *.vmb,*.vmb.gz,*.vmb.bz2,*.vmb.zip,*.vmb.xz setlocal bt=nofile fmr=[[[,]]] fdm=marker|if &ff != 'unix'|setlocal ma ff=unix noma|endif|if line('$') > 1|call vimball#ShowMesg(0,"Source this file to extract it! (:so %)")|endif + au SourceCmd *.vmb.gz,*.vmb.bz2,*.vmb.zip,*.vmb.xz let s:origfile=expand("%")|if expand("%")!=expand("<afile>") | exe "1sp" fnameescape(expand("<afile>"))|endif|call vimball#Decompress(expand("<amatch>"))|so %|if s:origfile!=expand("<afile>")|close|endif + au SourceCmd *.vmb if expand("%")!=expand("<afile>") | exe "1sp" fnameescape(expand("<afile>"))|call vimball#Vimball(1)|close|else|call vimball#Vimball(1)|endif +augroup END + +" ===================================================================== +" Restoration And Modelines: {{{1 +" vim: fdm=marker +let &cpo= s:keepcpo +unlet s:keepcpo diff --git a/runtime/plugin/health.vim b/runtime/plugin/health.vim new file mode 100644 index 0000000000..db094a03a4 --- /dev/null +++ b/runtime/plugin/health.vim @@ -0,0 +1 @@ +command! -bang CheckHealth call health#check(<bang>0) diff --git a/runtime/plugin/matchparen.vim b/runtime/plugin/matchparen.vim index 873302efee..5db1f64c78 100644 --- a/runtime/plugin/matchparen.vim +++ b/runtime/plugin/matchparen.vim @@ -1,6 +1,6 @@ " Vim plugin for showing matching parens " Maintainer: Bram Moolenaar <Bram@vim.org> -" Last Change: 2015 Dec 31 +" Last Change: 2016 Feb 16 " Exit quickly when: " - this plugin was already loaded (or disabled) diff --git a/runtime/plugin/netrwPlugin.vim b/runtime/plugin/netrwPlugin.vim index 3776ac30f8..69902b1f19 100644 --- a/runtime/plugin/netrwPlugin.vim +++ b/runtime/plugin/netrwPlugin.vim @@ -1,6 +1,6 @@ " netrwPlugin.vim: Handles file transfer and remote directory listing across a network " PLUGIN SECTION -" Date: Nov 07, 2014 +" Date: Feb 08, 2016 " Maintainer: Charles E Campbell <NdrOchip@ScampbellPfamily.AbizM-NOSPAM> " GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim " Copyright: Copyright (C) 1999-2013 Charles E. Campbell {{{1 @@ -20,7 +20,7 @@ if &cp || exists("g:loaded_netrwPlugin") finish endif -let g:loaded_netrwPlugin = "v154" +let g:loaded_netrwPlugin = "v155" let s:keepcpo = &cpo set cpo&vim "DechoRemOn @@ -55,10 +55,10 @@ augroup Network augroup END " Commands: :Nread, :Nwrite, :NetUserPass {{{2 -com! -count=1 -nargs=* Nread call netrw#SavePosn()<bar>call netrw#NetRead(<count>,<f-args>)<bar>call netrw#RestorePosn() -com! -range=% -nargs=* Nwrite call netrw#SavePosn()<bar><line1>,<line2>call netrw#NetWrite(<f-args>)<bar>call netrw#RestorePosn() +com! -count=1 -nargs=* Nread let s:svpos= winsaveview()<bar>call netrw#NetRead(<count>,<f-args>)<bar>call winrestview(s:svpos) +com! -range=% -nargs=* Nwrite let s:svpos= winsaveview()<bar><line1>,<line2>call netrw#NetWrite(<f-args>)<bar>call winrestview(s:svpos) com! -nargs=* NetUserPass call NetUserPass(<f-args>) -com! -nargs=* Nsource call netrw#SavePosn()<bar>call netrw#NetSource(<f-args>)<bar>call netrw#RestorePosn() +com! -nargs=* Nsource let s:svpos= winsaveview()<bar>call netrw#NetSource(<f-args>)<bar>call winrestview(s:svpos) com! -nargs=? Ntree call netrw#SetTreetop(<q-args>) " Commands: :Explore, :Sexplore, Hexplore, Vexplore, Lexplore {{{2 diff --git a/runtime/plugin/vimballPlugin.vim b/runtime/plugin/vimballPlugin.vim deleted file mode 100644 index 59279774ca..0000000000 --- a/runtime/plugin/vimballPlugin.vim +++ /dev/null @@ -1,40 +0,0 @@ -" vimballPlugin : construct a file containing both paths and files -" Author: Charles E. Campbell, Jr. -" Copyright: (c) 2004-2010 by Charles E. Campbell, Jr. -" The VIM LICENSE applies to Vimball.vim, and Vimball.txt -" (see |copyright|) except use "Vimball" instead of "Vim". -" No warranty, express or implied. -" *** *** Use At-Your-Own-Risk! *** *** -" -" (Rom 2:1 WEB) Therefore you are without excuse, O man, whoever you are who -" judge. For in that which you judge another, you condemn yourself. For -" you who judge practice the same things. -" GetLatestVimScripts: 1502 1 :AutoInstall: vimball.vim - -" --------------------------------------------------------------------- -" Load Once: {{{1 -if &cp || exists("g:loaded_vimballPlugin") - finish -endif -let g:loaded_vimballPlugin = "v35" -let s:keepcpo = &cpo -set cpo&vim - -" ------------------------------------------------------------------------------ -" Public Interface: {{{1 -com! -ra -complete=file -na=+ -bang MkVimball call vimball#MkVimball(<line1>,<line2>,<bang>0,<f-args>) -com! -na=? -complete=dir UseVimball call vimball#Vimball(1,<f-args>) -com! -na=0 VimballList call vimball#Vimball(0) -com! -na=* -complete=dir RmVimball call vimball#SaveSettings()|call vimball#RmVimball(<f-args>)|call vimball#RestoreSettings() -au BufEnter *.vba,*.vba.gz,*.vba.bz2,*.vba.zip,*.vba.xz setlocal bt=nofile fmr=[[[,]]] fdm=marker|if &ff != 'unix'|setlocal ma ff=unix noma|endif|call vimball#ShowMesg(0,"Source this file to extract it! (:so %)") -au SourceCmd *.vba.gz,*.vba.bz2,*.vba.zip,*.vba.xz if expand("%")!=expand("<afile>") | exe "1sp" fnameescape(expand("<afile>"))|endif|call vimball#Decompress(expand("<amatch>"))|so %|if expand("%")!=expand("<afile>")|close|endif -au SourceCmd *.vba if expand("%")!=expand("<afile>") | exe "1sp" fnameescape(expand("<afile>"))|call vimball#Vimball(1)|close|else|call vimball#Vimball(1)|endif -au BufEnter *.vmb,*.vmb.gz,*.vmb.bz2,*.vmb.zip,*.vmb.xz setlocal bt=nofile fmr=[[[,]]] fdm=marker|if &ff != 'unix'|setlocal ma ff=unix noma|endif|call vimball#ShowMesg(0,"Source this file to extract it! (:so %)") -au SourceCmd *.vmb.gz,*.vmb.bz2,*.vmb.zip,*.vmb.xz if expand("%")!=expand("<afile>") | exe "1sp" fnameescape(expand("<afile>"))|endif|call vimball#Decompress(expand("<amatch>"))|so %|if expand("%")!=expand("<afile>")|close|endif -au SourceCmd *.vmb if expand("%")!=expand("<afile>") | exe "1sp" fnameescape(expand("<afile>"))|call vimball#Vimball(1)|close|else|call vimball#Vimball(1)|endif - -" ===================================================================== -" Restoration And Modelines: {{{1 -" vim: fdm=marker -let &cpo= s:keepcpo -unlet s:keepcpo diff --git a/runtime/syntax/c.vim b/runtime/syntax/c.vim index ac4909edba..3fe3256059 100644 --- a/runtime/syntax/c.vim +++ b/runtime/syntax/c.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: C " Maintainer: Bram Moolenaar <Bram@vim.org> -" Last Change: 2015 Mar 05 +" Last Change: 2016 Apr 10 " Quit when a (custom) syntax file was already loaded if exists("b:current_syntax") @@ -248,6 +248,10 @@ if !exists("c_no_c99") " ISO C99 syn keyword cType _Bool bool _Complex complex _Imaginary imaginary syn keyword cType int8_t int16_t int32_t int64_t syn keyword cType uint8_t uint16_t uint32_t uint64_t + if !exists("c_no_bsd") + " These are BSD specific. + syn keyword cType u_int8_t u_int16_t u_int32_t u_int64_t + endif syn keyword cType int_least8_t int_least16_t int_least32_t int_least64_t syn keyword cType uint_least8_t uint_least16_t uint_least32_t uint_least64_t syn keyword cType int_fast8_t int_fast16_t int_fast32_t int_fast64_t @@ -264,7 +268,7 @@ syn keyword cStorageClass static register auto volatile extern const if exists("c_gnu") syn keyword cStorageClass inline __attribute__ endif -if !exists("c_no_c99") +if !exists("c_no_c99") && s:ft !=# 'cpp' syn keyword cStorageClass inline restrict endif if !exists("c_no_c11") diff --git a/runtime/syntax/d.vim b/runtime/syntax/d.vim index 07a299fa55..8be9b9ff28 100644 --- a/runtime/syntax/d.vim +++ b/runtime/syntax/d.vim @@ -1,9 +1,9 @@ -" Vim syntax file for the D programming language (version 1.076 and 2.063). +" Vim syntax file for the D programming language (version 1.076 and 2.069). " " Language: D " Maintainer: Jesse Phillips <Jesse.K.Phillips+D@gmail.com> -" Last Change: 2013 October 5 -" Version: 0.26 +" Last Change: 2016 Feb 2 +" Version: 0.28 " " Contributors: " - Jason Mills: original Maintainer @@ -15,6 +15,7 @@ " - Steven N. Oliver " - Sohgo Takeuchi " - Robert Clipsham +" - Petar Kirov " " Please submit bugs/comments/suggestions to the github repo: " https://github.com/JesseKPhillips/d.vim @@ -114,17 +115,19 @@ syn keyword dTraitsIdentifier contained isIntegral isScalar isStaticArray syn keyword dTraitsIdentifier contained isUnsigned isVirtualFunction syn keyword dTraitsIdentifier contained isVirtualMethod isAbstractFunction syn keyword dTraitsIdentifier contained isFinalFunction isStaticFunction +syn keyword dTraitsIdentifier contained isOverrideFunction isTemplate syn keyword dTraitsIdentifier contained isRef isOut isLazy hasMember -syn keyword dTraitsIdentifier contained identifier getAttributes getMember -syn keyword dTraitsIdentifier contained getOverloads getProtection -syn keyword dTraitsIdentifier contained getVirtualFunctions -syn keyword dTraitsIdentifier contained getVirtualMethods parent -syn keyword dTraitsIdentifier contained classInstanceSize allMembers +syn keyword dTraitsIdentifier contained identifier getAliasThis +syn keyword dTraitsIdentifier contained getAttributes getFunctionAttributes getMember +syn keyword dTraitsIdentifier contained getOverloads getPointerBitmap getProtection +syn keyword dTraitsIdentifier contained getVirtualFunctions getVirtualIndex +syn keyword dTraitsIdentifier contained getVirtualMethods getUnitTests +syn keyword dTraitsIdentifier contained parent classInstanceSize allMembers syn keyword dTraitsIdentifier contained derivedMembers isSame compiles -syn keyword dPragmaIdentifier contained lib msg startaddress GNU_asm -syn keyword dExternIdentifier contained Windows Pascal Java System D +syn keyword dPragmaIdentifier contained inline lib mangle msg startaddress GNU_asm +syn keyword dExternIdentifier contained C C++ D Windows Pascal System Objective-C syn keyword dAttribute contained safe trusted system -syn keyword dAttribute contained property disable +syn keyword dAttribute contained property disable nogc syn keyword dVersionIdentifier contained DigitalMars GNU LDC SDC D_NET syn keyword dVersionIdentifier contained X86 X86_64 ARM PPC PPC64 IA64 MIPS MIPS64 Alpha syn keyword dVersionIdentifier contained SPARC SPARC64 S390 S390X HPPA HPPA64 SH SH64 @@ -134,7 +137,7 @@ syn keyword dVersionIdentifier contained Cygwin MinGW syn keyword dVersionIdentifier contained LittleEndian BigEndian syn keyword dVersionIdentifier contained D_InlineAsm_X86 D_InlineAsm_X86_64 syn keyword dVersionIdentifier contained D_Version2 D_Coverage D_Ddoc D_LP64 D_PIC -syn keyword dVersionIdentifier contained unittest none all +syn keyword dVersionIdentifier contained unittest assert none all syn cluster dComment contains=dNestedComment,dBlockComment,dLineComment @@ -168,10 +171,10 @@ syn match dExternal "\<extern\>" syn match dExtern "\<extern\s*([_a-zA-Z][_a-zA-Z0-9\+]*\>"he=s+6 contains=dExternIdentifier " Make import a region to prevent highlighting keywords -syn region dImport start="import\_s" end=";" contains=dExternal,@dComment +syn region dImport start="\<import\_s" end=";" contains=dExternal,@dComment " Make module a region to prevent highlighting keywords -syn region dImport start="module\_s" end=";" contains=dExternal,@dComment +syn region dImport start="\<module\_s" end=";" contains=dExternal,@dComment " dTokens is used by the token string highlighting syn cluster dTokens contains=dExternal,dConditional,dBranch,dRepeat,dBoolean @@ -246,13 +249,17 @@ syn match dUnicode "\\u\d\{4\}" " String. " -syn region dString start=+"+ end=+"[cwd]\=+ skip=+\\\\\|\\"+ contains=dEscSequence,@Spell +syn match dFormat display "%\(\d\+\$\)\=[-+' #0*]*\(\d*\|\*\|\*\d\+\$\)\(\.\(\d*\|\*\|\*\d\+\$\)\)\=\([hlL]\|ll\)\=\([bdiuoxXDOUfeEgGcCsSpn]\|\[\^\=.[^]]*\]\)" contained +syn match dFormat display "%%" contained + +syn region dString start=+"+ end=+"[cwd]\=+ skip=+\\\\\|\\"+ contains=dFormat,dEscSequence,@Spell syn region dRawString start=+`+ end=+`[cwd]\=+ contains=@Spell syn region dRawString start=+r"+ end=+"[cwd]\=+ contains=@Spell syn region dHexString start=+x"+ end=+"[cwd]\=+ contains=@Spell syn region dDelimString start=+q"\z(.\)+ end=+\z1"+ contains=@Spell syn region dHereString start=+q"\z(\I\i*\)\n+ end=+^\z1"+ contains=@Spell + " Nesting delimited string contents " syn region dNestParenString start=+(+ end=+)+ contained transparent contains=dNestParenString,@Spell @@ -276,8 +283,8 @@ syn cluster dTokens add=dString,dRawString,dHexString,dDelimString,dNestString " Token strings " -syn region dNestTokenString start=+{+ end=+}+ contained contains=dNestTokenString,@dTokens -syn region dTokenString matchgroup=dTokenStringBrack transparent start=+q{+ end=+}+ contains=dNestTokenString,@dTokens +syn region dNestTokenString start=+{+ end=+}+ contained contains=dNestTokenString,@dTokens,dFormat +syn region dTokenString matchgroup=dTokenStringBrack transparent start=+q{+ end=+}+ contains=dNestTokenString,@dTokens,dFormat syn cluster dTokens add=dTokenString @@ -357,6 +364,7 @@ hi def link dString String hi def link dHexString String hi def link dCharacter Character hi def link dEscSequence SpecialChar +hi def link dFormat SpecialChar hi def link dSpecialCharError Error hi def link dOctalError Error hi def link dOperator Operator diff --git a/runtime/syntax/dcl.vim b/runtime/syntax/dcl.vim index 37bf38fe11..b08adec31d 100644 --- a/runtime/syntax/dcl.vim +++ b/runtime/syntax/dcl.vim @@ -1,8 +1,8 @@ " Vim syntax file " Language: DCL (Digital Command Language - vms) " Maintainer: Charles E. Campbell <NdrOchipS@PcampbellAfamily.Mbiz> -" Last Change: Oct 23, 2014 -" Version: 7 +" Last Change: Jan 20, 2016 +" Version: 8 " URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_DCL " For version 5.x: Clear all syntax items @@ -13,10 +13,10 @@ elseif exists("b:current_syntax") finish endif -if version < 600 - set iskeyword=$,@,48-57,_ -else +if !has("patch-7.4.1141") setlocal iskeyword=$,@,48-57,_ +else + syn iskeyword $,@,48-57,_ endif syn case ignore diff --git a/runtime/syntax/fortran.vim b/runtime/syntax/fortran.vim index 26d063524e..b470e56f60 100644 --- a/runtime/syntax/fortran.vim +++ b/runtime/syntax/fortran.vim @@ -1,15 +1,16 @@ " Vim syntax file " Language: Fortran 2008 (and older: Fortran 2003, 95, 90, and 77) -" Version: 0.96 -" Last Change: 2015 Nov. 30 +" Version: 0.97 +" Last Change: 2016 Feb. 26 " Maintainer: Ajit J. Thakkar <ajit@unb.ca>; <http://www2.unb.ca/~ajit/> " Usage: For instructions, do :help fortran-syntax from Vim " Credits: -" Version 0.1 was based on the fortran 77 syntax file by Mario Eusebio and -" Preben Guldberg. Useful suggestions and contributions were made by: Andrej Panjkov, -" Bram Moolenaar, Thomas Olsen, Michael Sternberg, Christian Reile, +" Version 0.1 (April 2000) was based on the fortran 77 syntax file by Mario Eusebio and +" Preben Guldberg. Since then, useful suggestions and contributions have been made, +" in chronological order, by: +" Andrej Panjkov, Bram Moolenaar, Thomas Olsen, Michael Sternberg, Christian Reile, " Walter Dieudonné, Alexander Wagner, Roman Bertle, Charles Rendleman, -" Andrew Griffiths, Joe Krahn, Hendrik Merx, and Matt Thompson. +" Andrew Griffiths, Joe Krahn, Hendrik Merx, Matt Thompson, and Jan Hermann. if exists("b:current_syntax") finish @@ -407,7 +408,7 @@ if exists("fortran_fold") else syn region fortran77Loop transparent fold keepend start="\<do\s\+\z(\d\+\)" end="^\s*\z1\>" contains=ALLBUT,fortranUnitHeader,fortranStructure,fortranStorageClass,fortranType,fortranProgram,fortranModule,fortranSubroutine,fortranFunction,fortranBlockData syn region fortran90Loop transparent fold keepend extend start="\(\<end\s\+\)\@<!\<do\(\s\+\a\|\s*$\)" skip="^\s*[!#].*$" excludenl end="\<end\s*do\>" contains=ALLBUT,fortranUnitHeader,fortranStructure,fortranStorageClass,fortranType,fortranProgram,fortranModule,fortranSubroutine,fortranFunction,fortranBlockData - syn region fortranIfBlock transparent fold keepend extend start="\(\<e\(nd\|lse\)\s\+\)\@<!\<if\s*(.\+)\s*then\>" skip="^\s*[!#].*$" end="\<end\s*if\>" contains=ALLBUT,fortranUnitHeader,fortranStructure,fortranStorageClass,fortranType,fortranProgram,fortranModule,fortranSubroutine,fortranFunction,fortranBlockData + syn region fortranIfBlock transparent fold keepend extend start="\(\<e\(nd\|lse\)\s\+\)\@<!\<if\s*(\(.\|&\s*\n\)\+)\(\s\|&\s*\n\)*then\>" skip="^\s*[!#].*$" end="\<end\s*if\>" contains=ALLBUT,fortranUnitHeader,fortranStructure,fortranStorageClass,fortranType,fortranProgram,fortranModule,fortranSubroutine,fortranFunction,fortranBlockData syn region fortranCase transparent fold keepend extend start="\<select\s*case\>" skip="^\s*[!#].*$" end="\<end\s*select\>" contains=ALLBUT,fortranUnitHeader,fortranStructure,fortranStorageClass,fortranType,fortranProgram,fortranModule,fortranSubroutine,fortranFunction,fortranBlockData endif endif diff --git a/runtime/syntax/lisp.vim b/runtime/syntax/lisp.vim index 2528f4f9b1..f496398d50 100644 --- a/runtime/syntax/lisp.vim +++ b/runtime/syntax/lisp.vim @@ -1,8 +1,8 @@ " Vim syntax file " Language: Lisp " Maintainer: Charles E. Campbell <NdrOchipS@PcampbellAfamily.Mbiz> -" Last Change: Oct 06, 2014 -" Version: 23 +" Last Change: Jan 20, 2016 +" Version: 24 " URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_LISP " " Thanks to F Xavier Noria for a list of 978 Common Lisp symbols taken from HyperSpec @@ -16,8 +16,10 @@ endif if exists("g:lisp_isk") exe "setl isk=".g:lisp_isk -else +elseif !has("patch-7.4.1141") setl isk=38,42,43,45,47-58,60-62,64-90,97-122,_ +else + syn iskeyword 38,42,43,45,47-58,60-62,64-90,97-122,_ endif if exists("g:lispsyntax_ignorecase") || exists("g:lispsyntax_clisp") diff --git a/runtime/syntax/maple.vim b/runtime/syntax/maple.vim index 9c94643836..9a4db26dd8 100644 --- a/runtime/syntax/maple.vim +++ b/runtime/syntax/maple.vim @@ -1,8 +1,8 @@ " Vim syntax file " Language: Maple V (based on release 4) " Maintainer: Charles E. Campbell <NdrOchipS@PcampbellAfamily.Mbiz> -" Last Change: Oct 23, 2014 -" Version: 11 +" Last Change: Jan 20, 2016 +" Version: 12 " URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_MAPLE " " Package Function Selection: {{{1 @@ -30,10 +30,10 @@ elseif exists("b:current_syntax") endif " Iskeyword Effects: {{{1 -if version < 600 - set iskeyword=$,48-57,_,a-z,@-Z +if !has("patch-7.4.1141") + setl isk=$,48-57,_,a-z,@-Z else - setlocal iskeyword=$,48-57,_,a-z,@-Z + syn iskeyword $,48-57,_,a-z,@-Z endif " Package Selection: {{{1 diff --git a/runtime/syntax/messages.vim b/runtime/syntax/messages.vim index 4648e94c13..c22e4e8d0c 100644 --- a/runtime/syntax/messages.vim +++ b/runtime/syntax/messages.vim @@ -3,6 +3,7 @@ " Maintainer: Yakov Lerner <iler.ml@gmail.com> " Latest Revision: 2008-06-29 " Changes: 2008-06-29 support for RFC3339 tuimestamps James Vega +" 2016 Jan 19: messagesDate changed by Bram if exists("b:current_syntax") finish @@ -13,7 +14,7 @@ set cpo&vim syn match messagesBegin display '^' nextgroup=messagesDate,messagesDateRFC3339 -syn match messagesDate contained display '\a\a\a [ 0-9]\d *' +syn match messagesDate contained display '[[:lower:][:upper:]][[:lower:][:upper:]][[:lower:][:upper:]] [ 0-9]\d *' \ nextgroup=messagesHour syn match messagesHour contained display '\d\d:\d\d:\d\d\s*' diff --git a/runtime/syntax/mysql.vim b/runtime/syntax/mysql.vim index c01ecc192b..d7cf74710d 100644 --- a/runtime/syntax/mysql.vim +++ b/runtime/syntax/mysql.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: mysql " Maintainer: Kenneth J. Pronovici <pronovic@ieee.org> -" Last Change: $LastChangedDate: 2010-04-22 09:48:02 -0500 (Thu, 22 Apr 2010) $ +" Last Change: $LastChangedDate: 2016-04-11 10:31:04 -0500 (Mon, 11 Apr 2016) $ " Filenames: *.mysql " URL: ftp://cedar-solutions.com/software/mysql.vim " Note: The definitions below are taken from the mysql user manual as of April 2002, for version 3.23 @@ -18,7 +18,7 @@ endif syn case ignore " General keywords which don't fall into other categories -syn keyword mysqlKeyword action add after aggregate all alter as asc auto_increment avg avg_row_length +syn keyword mysqlKeyword action add after aggregate all alter as asc auto_increment avg_row_length syn keyword mysqlKeyword both by syn keyword mysqlKeyword cascade change character check checksum column columns comment constraint create cross syn keyword mysqlKeyword current_date current_time current_timestamp @@ -30,7 +30,7 @@ syn keyword mysqlKeyword global grant grants group syn keyword mysqlKeyword having heap high_priority hosts hour hour_minute hour_second syn keyword mysqlKeyword identified ignore index infile inner insert insert_id into isam syn keyword mysqlKeyword join -syn keyword mysqlKeyword key keys kill last_insert_id leading left limit lines load local lock logs long +syn keyword mysqlKeyword key keys kill last_insert_id leading left limit lines load local lock logs long syn keyword mysqlKeyword low_priority syn keyword mysqlKeyword match max_rows middleint min_rows minute minute_second modify month myisam syn keyword mysqlKeyword natural no @@ -64,6 +64,9 @@ syn match mysqlNumber "\<0x[abcdefABCDEF0-9]*\>" " User variables syn match mysqlVariable "@\a*[A-Za-z0-9]*\([._]*[A-Za-z0-9]\)*" +" Escaped column names +syn match mysqlEscaped "`[^`]*`" + " Comments (c-style, mysql-style and modified sql-style) syn region mysqlComment start="/\*" end="\*/" syn match mysqlComment "#.*" @@ -84,14 +87,14 @@ syn sync ccomment mysqlComment " The second problem is that some of these keywords are included in " function names. For instance, year() is part of the name of the " dayofyear() function, and the dec keyword (no parenthesis) is part of -" the name of the decode() function. +" the name of the decode() function. -syn keyword mysqlType tinyint smallint mediumint int integer bigint -syn keyword mysqlType date datetime time bit bool +syn keyword mysqlType tinyint smallint mediumint int integer bigint +syn keyword mysqlType date datetime time bit bool syn keyword mysqlType tinytext mediumtext longtext text syn keyword mysqlType tinyblob mediumblob longblob blob -syn region mysqlType start="float\W" end="."me=s-1 -syn region mysqlType start="float$" end="."me=s-1 +syn region mysqlType start="float\W" end="."me=s-1 +syn region mysqlType start="float$" end="."me=s-1 syn region mysqlType start="float(" end=")" contains=mysqlNumber,mysqlVariable syn region mysqlType start="double\W" end="."me=s-1 syn region mysqlType start="double$" end="."me=s-1 @@ -139,12 +142,12 @@ syn region mysqlFlow start="if(" end=")" contains=ALL " " I'm leery of just defining keywords for functions, since according to the MySQL manual: " -" Function names do not clash with table or column names. For example, ABS is a -" valid column name. The only restriction is that for a function call, no spaces -" are allowed between the function name and the `(' that follows it. +" Function names do not clash with table or column names. For example, ABS is a +" valid column name. The only restriction is that for a function call, no spaces +" are allowed between the function name and the `(' that follows it. " -" This means that if I want to highlight function names properly, I have to use a -" region to define them, not just a keyword. This will probably cause the syntax file +" This means that if I want to highlight function names properly, I have to use a +" region to define them, not just a keyword. This will probably cause the syntax file " to load more slowly, but at least it will be 'correct'. syn region mysqlFunction start="abs(" end=")" contains=ALL @@ -154,6 +157,7 @@ syn region mysqlFunction start="ascii(" end=")" contains=ALL syn region mysqlFunction start="asin(" end=")" contains=ALL syn region mysqlFunction start="atan(" end=")" contains=ALL syn region mysqlFunction start="atan2(" end=")" contains=ALL +syn region mysqlFunction start="avg(" end=")" contains=ALL syn region mysqlFunction start="benchmark(" end=")" contains=ALL syn region mysqlFunction start="bin(" end=")" contains=ALL syn region mysqlFunction start="bit_and(" end=")" contains=ALL diff --git a/runtime/syntax/python.vim b/runtime/syntax/python.vim index 78d35e4c15..2a0ea5de2b 100644 --- a/runtime/syntax/python.vim +++ b/runtime/syntax/python.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: Python " Maintainer: Zvezdan Petkovic <zpetkovic@acm.org> -" Last Change: 2015 Sep 15 +" Last Change: 2016 Feb 20 " Credits: Neil Schemenauer <nas@python.ca> " Dmitry Vasiliev " @@ -199,6 +199,8 @@ if !exists("python_no_builtin_highlight") syn keyword pythonBuiltin ascii bytes exec " non-essential built-in functions; Python 2 only syn keyword pythonBuiltin apply buffer coerce intern + " avoid highlighting attributes as builtins + syn match pythonAttribute /\.\h\w*/hs=s+1 contains=ALLBUT,pythonBuiltin transparent endif " From the 'Python Library Reference' class hierarchy at the bottom. diff --git a/runtime/syntax/r.vim b/runtime/syntax/r.vim index e48b6686cb..d96bf96acb 100644 --- a/runtime/syntax/r.vim +++ b/runtime/syntax/r.vim @@ -5,17 +5,21 @@ " Tom Payne <tom@tompayne.org> " Contributor: Johannes Ranke <jranke@uni-bremen.de> " Homepage: https://github.com/jalvesaq/R-Vim-runtime -" Last Change: Wed Oct 21, 2015 06:33AM +" Last Change: Thu Mar 10, 2016 12:26PM " Filenames: *.R *.r *.Rhistory *.Rt " " NOTE: The highlighting of R functions is defined in " runtime files created by a filetype plugin, if installed. " " CONFIGURATION: -" syntax folding can be turned on by +" Syntax folding can be turned on by " " let r_syntax_folding = 1 " +" ROxygen highlighting can be turned off by +" +" let r_hl_roxygen = 0 +" " Some lines of code were borrowed from Zhuojun Chen. if exists("b:current_syntax") @@ -24,9 +28,12 @@ endif setlocal iskeyword=@,48-57,_,. -if exists("g:r_syntax_folding") +if exists("g:r_syntax_folding") && g:r_syntax_folding setlocal foldmethod=syntax endif +if !exists("g:r_hl_roxygen") + let g:r_hl_roxygen = 1 +endif syn case match @@ -35,18 +42,20 @@ syn match rCommentTodo contained "\(BUG\|FIXME\|NOTE\|TODO\):" syn match rComment contains=@Spell,rCommentTodo,rOBlock "#.*" " Roxygen -syn region rOBlock start="^\s*\n#\{1,2}' " start="\%^#\{1,2}' " end="^\(#\{1,2}'\)\@!" contains=rOTitle,rOKeyword,rOExamples,@Spell keepend -syn region rOTitle start="^\s*\n#\{1,2}' " start="\%^#\{1,2}' " end="^\(#\{1,2}'\s*$\)\@=" contained contains=rOCommentKey -syn match rOCommentKey "#\{1,2}'" containedin=rOTitle contained - -syn region rOExamples start="^#\{1,2}' @examples.*"rs=e+1,hs=e+1 end="^\(#\{1,2}' @.*\)\@=" end="^\(#\{1,2}'\)\@!" contained contains=rOKeyword - -syn match rOKeyword contained "@\(param\|return\|name\|rdname\|examples\|example\|include\|docType\)" -syn match rOKeyword contained "@\(S3method\|TODO\|aliases\|alias\|assignee\|author\|callGraphDepth\|callGraph\)" -syn match rOKeyword contained "@\(callGraphPrimitives\|concept\|exportClass\|exportMethod\|exportPattern\|export\|formals\)" -syn match rOKeyword contained "@\(format\|importClassesFrom\|importFrom\|importMethodsFrom\|import\|keywords\|useDynLib\)" -syn match rOKeyword contained "@\(method\|noRd\|note\|references\|seealso\|setClass\|slot\|source\|title\|usage\)" -syn match rOKeyword contained "@\(family\|template\|templateVar\|description\|details\|inheritParams\|field\)" +if g:r_hl_roxygen + syn region rOBlock start="^\s*\n#\{1,2}' " start="\%^#\{1,2}' " end="^\(#\{1,2}'\)\@!" contains=rOTitle,rOKeyword,rOExamples,@Spell keepend + syn region rOTitle start="^\s*\n#\{1,2}' " start="\%^#\{1,2}' " end="^\(#\{1,2}'\s*$\)\@=" contained contains=rOCommentKey + syn match rOCommentKey "#\{1,2}'" containedin=rOTitle contained + + syn region rOExamples start="^#\{1,2}' @examples.*"rs=e+1,hs=e+1 end="^\(#\{1,2}' @.*\)\@=" end="^\(#\{1,2}'\)\@!" contained contains=rOKeyword + + syn match rOKeyword contained "@\(param\|return\|name\|rdname\|examples\|example\|include\|docType\)" + syn match rOKeyword contained "@\(S3method\|TODO\|aliases\|alias\|assignee\|author\|callGraphDepth\|callGraph\)" + syn match rOKeyword contained "@\(callGraphPrimitives\|concept\|exportClass\|exportMethod\|exportPattern\|export\|formals\)" + syn match rOKeyword contained "@\(format\|importClassesFrom\|importFrom\|importMethodsFrom\|import\|keywords\|useDynLib\)" + syn match rOKeyword contained "@\(method\|noRd\|note\|references\|seealso\|setClass\|slot\|source\|title\|usage\)" + syn match rOKeyword contained "@\(family\|template\|templateVar\|description\|details\|inheritParams\|field\)" +endif if &filetype == "rhelp" @@ -159,12 +168,13 @@ syn match rBraceError "[)}]" contained syn match rCurlyError "[)\]]" contained syn match rParenError "[\]}]" contained -" Source list of R functions produced by a filetype plugin (if installed) -if has("nvim") - " Nvim-R +if !exists("g:R_hi_fun") + let g:R_hi_fun = 1 +endif +if g:R_hi_fun + " Nvim-R: runtime R/functions.vim -else - " Vim-R-plugin + " Vim-R-plugin: runtime r-plugin/functions.vim endif @@ -235,11 +245,13 @@ hi def link rStatement Statement hi def link rString String hi def link rStrError Error hi def link rType Type -hi def link rOKeyword Title -hi def link rOBlock Comment -hi def link rOTitle Title -hi def link rOCommentKey Comment -hi def link rOExamples SpecialComment +if g:r_hl_roxygen + hi def link rOKeyword Title + hi def link rOBlock Comment + hi def link rOTitle Title + hi def link rOCommentKey Comment + hi def link rOExamples SpecialComment +endif let b:current_syntax="r" diff --git a/runtime/syntax/rhelp.vim b/runtime/syntax/rhelp.vim index 32c91add48..47c764e296 100644 --- a/runtime/syntax/rhelp.vim +++ b/runtime/syntax/rhelp.vim @@ -2,25 +2,21 @@ " Language: R Help File " Maintainer: Jakson Aquino <jalvesaq@gmail.com> " Former Maintainer: Johannes Ranke <jranke@uni-bremen.de> -" Last Change: Wed Jul 09, 2014 10:28PM +" Homepage: https://github.com/jalvesaq/R-Vim-runtime +" Last Change: Sat Feb 06, 2016 11:34AM " Remarks: - Includes R syntax highlighting in the appropriate " sections if an r.vim file is in the same directory or in the " default debian location. " - There is no Latex markup in equations " - Thanks to Will Gray for finding and fixing a bug -" - No support for \if, \ifelse and \out as I don't understand -" them and have no examples at hand (help welcome). -" - No support for \var tag within quoted string (dito) +" - No support for \var tag within quoted string " Version Clears: {{{1 -" For version 5.x: Clear all syntax items -" For version 6.x and 7.x: Quit when a syntax file was already loaded -if version < 600 - syntax clear -elseif exists("b:current_syntax") +if exists("b:current_syntax") finish endif +scriptencoding utf-8 setlocal iskeyword=@,48-57,_,. syn case match @@ -29,9 +25,11 @@ syn case match syn region rhelpIdentifier matchgroup=rhelpSection start="\\name{" end="}" syn region rhelpIdentifier matchgroup=rhelpSection start="\\alias{" end="}" syn region rhelpIdentifier matchgroup=rhelpSection start="\\pkg{" end="}" contains=rhelpLink +syn region rhelpIdentifier matchgroup=rhelpSection start="\\CRANpkg{" end="}" contains=rhelpLink syn region rhelpIdentifier matchgroup=rhelpSection start="\\method{" end="}" contained syn region rhelpIdentifier matchgroup=rhelpSection start="\\Rdversion{" end="}" + " Highlighting of R code using an existing r.vim syntax file if available {{{1 syn include @R syntax/r.vim @@ -69,76 +67,115 @@ syn match rhelpDelimiter "\\cr" syn match rhelpDelimiter "\\tab " " Keywords {{{1 -syn match rhelpKeyword "\\R" -syn match rhelpKeyword "\\ldots" +syn match rhelpKeyword "\\R\>" +syn match rhelpKeyword "\\ldots\>" +syn match rhelpKeyword "\\sspace\>" syn match rhelpKeyword "--" syn match rhelpKeyword "---" -syn match rhelpKeyword "<" -syn match rhelpKeyword ">" -syn match rhelpKeyword "\\ge" -syn match rhelpKeyword "\\le" -syn match rhelpKeyword "\\alpha" -syn match rhelpKeyword "\\beta" -syn match rhelpKeyword "\\gamma" -syn match rhelpKeyword "\\delta" -syn match rhelpKeyword "\\epsilon" -syn match rhelpKeyword "\\zeta" -syn match rhelpKeyword "\\eta" -syn match rhelpKeyword "\\theta" -syn match rhelpKeyword "\\iota" -syn match rhelpKeyword "\\kappa" -syn match rhelpKeyword "\\lambda" -syn match rhelpKeyword "\\mu" -syn match rhelpKeyword "\\nu" -syn match rhelpKeyword "\\xi" -syn match rhelpKeyword "\\omicron" -syn match rhelpKeyword "\\pi" -syn match rhelpKeyword "\\rho" -syn match rhelpKeyword "\\sigma" -syn match rhelpKeyword "\\tau" -syn match rhelpKeyword "\\upsilon" -syn match rhelpKeyword "\\phi" -syn match rhelpKeyword "\\chi" -syn match rhelpKeyword "\\psi" -syn match rhelpKeyword "\\omega" -syn match rhelpKeyword "\\Alpha" -syn match rhelpKeyword "\\Beta" -syn match rhelpKeyword "\\Gamma" -syn match rhelpKeyword "\\Delta" -syn match rhelpKeyword "\\Epsilon" -syn match rhelpKeyword "\\Zeta" -syn match rhelpKeyword "\\Eta" -syn match rhelpKeyword "\\Theta" -syn match rhelpKeyword "\\Iota" -syn match rhelpKeyword "\\Kappa" -syn match rhelpKeyword "\\Lambda" -syn match rhelpKeyword "\\Mu" -syn match rhelpKeyword "\\Nu" -syn match rhelpKeyword "\\Xi" -syn match rhelpKeyword "\\Omicron" -syn match rhelpKeyword "\\Pi" -syn match rhelpKeyword "\\Rho" -syn match rhelpKeyword "\\Sigma" -syn match rhelpKeyword "\\Tau" -syn match rhelpKeyword "\\Upsilon" -syn match rhelpKeyword "\\Phi" -syn match rhelpKeyword "\\Chi" -syn match rhelpKeyword "\\Psi" -syn match rhelpKeyword "\\Omega" -" Links {{{1 -syn region rhelpLink matchgroup=rhelpSection start="\\link{" end="}" contained keepend extend -syn region rhelpLink matchgroup=rhelpSection start="\\link\[.\{-}\]{" end="}" contained keepend extend -syn region rhelpLink matchgroup=rhelpSection start="\\linkS4class{" end="}" contained keepend extend +" Condition Keywords {{{2 +syn match rhelpKeyword "\\if\>" +syn match rhelpKeyword "\\ifelse\>" +syn match rhelpKeyword "\\out\>" +" Examples of usage: +" \ifelse{latex}{\eqn{p = 5 + 6 - 7 \times 8}}{\eqn{p = 5 + 6 - 7 * 8}} +" \ifelse{latex}{\out{$\alpha$}}{\ifelse{html}{\out{α}}{alpha}} -" Verbatim like {{{1 -if v:version > 703 - syn region rhelpVerbatim matchgroup=rhelpType start="\\samp{" skip='\\\@1<!{.\{-}\\\@1<!}' end="}" contains=rhelpSpecialChar,rhelpComment - syn region rhelpVerbatim matchgroup=rhelpType start="\\verb{" skip='\\\@1<!{.\{-}\\\@1<!}' end="}" contains=rhelpSpecialChar,rhelpComment +" Keywords and operators valid only if in math mode {{{2 +syn match rhelpMathOp "<" contained +syn match rhelpMathOp ">" contained +syn match rhelpMathOp "+" contained +syn match rhelpMathOp "-" contained +syn match rhelpMathOp "=" contained + +" Conceal function based on syntax/tex.vim {{{2 +if exists("g:tex_conceal") + let s:tex_conceal = g:tex_conceal else - syn region rhelpVerbatim matchgroup=rhelpType start="\\samp{" skip='\\\@<!{.\{-}\\\@<!}' end="}" contains=rhelpSpecialChar,rhelpComment - syn region rhelpVerbatim matchgroup=rhelpType start="\\verb{" skip='\\\@<!{.\{-}\\\@<!}' end="}" contains=rhelpSpecialChar,rhelpComment + let s:tex_conceal = 'gm' endif +function s:HideSymbol(pat, cchar, hide) + if a:hide + exe "syn match rhelpMathSymb '" . a:pat . "' contained conceal cchar=" . a:cchar + else + exe "syn match rhelpMathSymb '" . a:pat . "' contained" + endif +endfunction + +" Math symbols {{{2 +if s:tex_conceal =~ 'm' + let s:hd = 1 +else + let s:hd = 0 +endif +call s:HideSymbol('\\infty\>', '∞', s:hd) +call s:HideSymbol('\\ge\>', '≥', s:hd) +call s:HideSymbol('\\le\>', '≤', s:hd) +call s:HideSymbol('\\prod\>', 'âˆ', s:hd) +call s:HideSymbol('\\sum\>', '∑', s:hd) +syn match rhelpMathSymb "\\sqrt\>" contained + +" Greek letters {{{2 +if s:tex_conceal =~ 'g' + let s:hd = 1 +else + let s:hd = 0 +endif +call s:HideSymbol('\\alpha\>', 'α', s:hd) +call s:HideSymbol('\\beta\>', 'β', s:hd) +call s:HideSymbol('\\gamma\>', 'γ', s:hd) +call s:HideSymbol('\\delta\>', 'δ', s:hd) +call s:HideSymbol('\\epsilon\>', 'ϵ', s:hd) +call s:HideSymbol('\\zeta\>', 'ζ', s:hd) +call s:HideSymbol('\\eta\>', 'η', s:hd) +call s:HideSymbol('\\theta\>', 'θ', s:hd) +call s:HideSymbol('\\iota\>', 'ι', s:hd) +call s:HideSymbol('\\kappa\>', 'κ', s:hd) +call s:HideSymbol('\\lambda\>', 'λ', s:hd) +call s:HideSymbol('\\mu\>', 'μ', s:hd) +call s:HideSymbol('\\nu\>', 'ν', s:hd) +call s:HideSymbol('\\xi\>', 'ξ', s:hd) +call s:HideSymbol('\\pi\>', 'Ï€', s:hd) +call s:HideSymbol('\\rho\>', 'Ï', s:hd) +call s:HideSymbol('\\sigma\>', 'σ', s:hd) +call s:HideSymbol('\\tau\>', 'Ï„', s:hd) +call s:HideSymbol('\\upsilon\>', 'Ï…', s:hd) +call s:HideSymbol('\\phi\>', 'Ï•', s:hd) +call s:HideSymbol('\\chi\>', 'χ', s:hd) +call s:HideSymbol('\\psi\>', 'ψ', s:hd) +call s:HideSymbol('\\omega\>', 'ω', s:hd) +call s:HideSymbol('\\Gamma\>', 'Γ', s:hd) +call s:HideSymbol('\\Delta\>', 'Δ', s:hd) +call s:HideSymbol('\\Theta\>', 'Θ', s:hd) +call s:HideSymbol('\\Lambda\>', 'Λ', s:hd) +call s:HideSymbol('\\Xi\>', 'Ξ', s:hd) +call s:HideSymbol('\\Pi\>', 'Î ', s:hd) +call s:HideSymbol('\\Sigma\>', 'Σ', s:hd) +call s:HideSymbol('\\Upsilon\>', 'Î¥', s:hd) +call s:HideSymbol('\\Phi\>', 'Φ', s:hd) +call s:HideSymbol('\\Psi\>', 'Ψ', s:hd) +call s:HideSymbol('\\Omega\>', 'Ω', s:hd) +delfunction s:HideSymbol +" Note: The letters 'omicron', 'Alpha', 'Beta', 'Epsilon', 'Zeta', 'Eta', +" 'Iota', 'Kappa', 'Mu', 'Nu', 'Omicron', 'Rho', 'Tau' and 'Chi' are listed +" at src/library/tools/R/Rd2txt.R because they are valid in HTML, although +" they do not make valid LaTeX code (e.g. Α versus \Alpha). + +" Links {{{1 +syn region rhelpLink matchgroup=rhelpType start="\\link{" end="}" contained keepend extend +syn region rhelpLink matchgroup=rhelpType start="\\link\[.\{-}\]{" end="}" contained keepend extend +syn region rhelpLink matchgroup=rhelpType start="\\linkS4class{" end="}" contained keepend extend +syn region rhelpLink matchgroup=rhelpType start="\\url{" end="}" contained keepend extend +syn region rhelpLink matchgroup=rhelpType start="\\href{" end="}" contained keepend extend +syn region rhelpLink matchgroup=rhelpType start="\\figure{" end="}" contained keepend extend + +" Verbatim like {{{1 +syn region rhelpVerbatim matchgroup=rhelpType start="\\samp{" skip='\\\@1<!{.\{-}\\\@1<!}' end="}" contains=rhelpSpecialChar,rhelpComment +syn region rhelpVerbatim matchgroup=rhelpType start="\\verb{" skip='\\\@1<!{.\{-}\\\@1<!}' end="}" contains=rhelpSpecialChar,rhelpComment + +" Equation {{{1 +syn region rhelpEquation matchgroup=rhelpType start="\\eqn{" skip='\\\@1<!{.\{-}\\\@1<!}' end="}" contains=rhelpMathSymb,rhelpMathOp,rhelpRegion contained keepend extend +syn region rhelpEquation matchgroup=rhelpType start="\\deqn{" skip='\\\@1<!{.\{-}\\\@1<!}' end="}" contains=rhelpMathSymb,rhelpMathOp,rhelpRegion contained keepend extend " Type Styles {{{1 syn match rhelpType "\\emph\>" @@ -148,12 +185,9 @@ syn match rhelpType "\\sQuote\>" syn match rhelpType "\\dQuote\>" syn match rhelpType "\\preformatted\>" syn match rhelpType "\\kbd\>" -syn match rhelpType "\\eqn\>" -syn match rhelpType "\\deqn\>" syn match rhelpType "\\file\>" syn match rhelpType "\\email\>" -syn match rhelpType "\\url\>" -syn match rhelpType "\\href\>" +syn match rhelpType "\\enc\>" syn match rhelpType "\\var\>" syn match rhelpType "\\env\>" syn match rhelpType "\\option\>" @@ -163,6 +197,7 @@ syn match rhelpType "\\renewcommand\>" syn match rhelpType "\\dfn\>" syn match rhelpType "\\cite\>" syn match rhelpType "\\acronym\>" +syn match rhelpType "\\doi\>" " rhelp sections {{{1 syn match rhelpSection "\\encoding\>" @@ -202,9 +237,9 @@ syn match rhelpDelimiter "{\|\[\|(\|)\|\]\|}" syn match rhelpComment /%.*$/ " Error {{{1 -syn region rhelpRegion matchgroup=Delimiter start=/(/ matchgroup=Delimiter end=/)/ contains=@Spell,rhelpCodeSpecial,rhelpComment,rhelpDelimiter,rhelpDots,rhelpFreesec,rhelpFreesubsec,rhelpIdentifier,rhelpKeyword,rhelpLink,rhelpPreProc,rhelpRComment,rhelpRcode,rhelpRegion,rhelpS4method,rhelpSection,rhelpSexpr,rhelpSpecialChar,rhelpString,rhelpType,rhelpVerbatim -syn region rhelpRegion matchgroup=Delimiter start=/{/ matchgroup=Delimiter end=/}/ contains=@Spell,rhelpCodeSpecial,rhelpComment,rhelpDelimiter,rhelpDots,rhelpFreesec,rhelpFreesubsec,rhelpIdentifier,rhelpKeyword,rhelpLink,rhelpPreProc,rhelpRComment,rhelpRcode,rhelpRegion,rhelpS4method,rhelpSection,rhelpSexpr,rhelpSpecialChar,rhelpString,rhelpType,rhelpVerbatim -syn region rhelpRegion matchgroup=Delimiter start=/\[/ matchgroup=Delimiter end=/]/ contains=@Spell,rhelpCodeSpecial,rhelpComment,rhelpDelimiter,rhelpDots,rhelpFreesec,rhelpFreesubsec,rhelpIdentifier,rhelpKeyword,rhelpLink,rhelpPreProc,rhelpRComment,rhelpRcode,rhelpRegion,rhelpS4method,rhelpSection,rhelpSexpr,rhelpSpecialChar,rhelpString,rhelpType,rhelpVerbatim +syn region rhelpRegion matchgroup=Delimiter start=/(/ matchgroup=Delimiter end=/)/ contains=@Spell,rhelpCodeSpecial,rhelpComment,rhelpDelimiter,rhelpDots,rhelpFreesec,rhelpFreesubsec,rhelpIdentifier,rhelpKeyword,rhelpLink,rhelpPreProc,rhelpRComment,rhelpRcode,rhelpRegion,rhelpS4method,rhelpSection,rhelpSexpr,rhelpSpecialChar,rhelpString,rhelpType,rhelpVerbatim,rhelpEquation +syn region rhelpRegion matchgroup=Delimiter start=/{/ matchgroup=Delimiter end=/}/ contains=@Spell,rhelpCodeSpecial,rhelpComment,rhelpDelimiter,rhelpDots,rhelpFreesec,rhelpFreesubsec,rhelpIdentifier,rhelpKeyword,rhelpLink,rhelpPreProc,rhelpRComment,rhelpRcode,rhelpRegion,rhelpS4method,rhelpSection,rhelpSexpr,rhelpSpecialChar,rhelpString,rhelpType,rhelpVerbatim,rhelpEquation +syn region rhelpRegion matchgroup=Delimiter start=/\[/ matchgroup=Delimiter end=/]/ contains=@Spell,rhelpCodeSpecial,rhelpComment,rhelpDelimiter,rhelpDots,rhelpFreesec,rhelpFreesubsec,rhelpIdentifier,rhelpKeyword,rhelpLink,rhelpPreProc,rhelpRComment,rhelpRcode,rhelpRegion,rhelpS4method,rhelpSection,rhelpSexpr,rhelpSpecialChar,rhelpString,rhelpType,rhelpVerbatim,rhelpEquation syn match rhelpError /[)\]}]/ syn match rhelpBraceError /[)}]/ contained syn match rhelpCurlyError /[)\]]/ contained @@ -213,36 +248,27 @@ syn match rhelpParenError /[\]}]/ contained syntax sync match rhelpSyncRcode grouphere rhelpRcode "\\examples{" " Define the default highlighting {{{1 -" For version 5.7 and earlier: only when not done already -" For version 5.8 and later: only when an item doesn't have highlighting yet -if version >= 508 || !exists("did_rhelp_syntax_inits") - if version < 508 - let did_rhelp_syntax_inits = 1 - command -nargs=+ HiLink hi link <args> - else - command -nargs=+ HiLink hi def link <args> - endif - HiLink rhelpVerbatim String - HiLink rhelpDelimiter Delimiter - HiLink rhelpIdentifier Identifier - HiLink rhelpString String - HiLink rhelpCodeSpecial Special - HiLink rhelpKeyword Keyword - HiLink rhelpDots Keyword - HiLink rhelpLink Underlined - HiLink rhelpType Type - HiLink rhelpSection PreCondit - HiLink rhelpError Error - HiLink rhelpBraceError Error - HiLink rhelpCurlyError Error - HiLink rhelpParenError Error - HiLink rhelpPreProc PreProc - HiLink rhelpDelimiter Delimiter - HiLink rhelpComment Comment - HiLink rhelpRComment Comment - HiLink rhelpSpecialChar SpecialChar - delcommand HiLink -endif +hi def link rhelpVerbatim String +hi def link rhelpDelimiter Delimiter +hi def link rhelpIdentifier Identifier +hi def link rhelpString String +hi def link rhelpCodeSpecial Special +hi def link rhelpKeyword Keyword +hi def link rhelpDots Keyword +hi def link rhelpLink Underlined +hi def link rhelpType Type +hi def link rhelpSection PreCondit +hi def link rhelpError Error +hi def link rhelpBraceError Error +hi def link rhelpCurlyError Error +hi def link rhelpParenError Error +hi def link rhelpPreProc PreProc +hi def link rhelpDelimiter Delimiter +hi def link rhelpComment Comment +hi def link rhelpRComment Comment +hi def link rhelpSpecialChar SpecialChar +hi def link rhelpMathSymb Special +hi def link rhelpMathOp Operator let b:current_syntax = "rhelp" diff --git a/runtime/syntax/rmd.vim b/runtime/syntax/rmd.vim index 6f1b847453..4cde7441d3 100644 --- a/runtime/syntax/rmd.vim +++ b/runtime/syntax/rmd.vim @@ -1,15 +1,13 @@ " markdown Text with R statements " Language: markdown with R code chunks -" Last Change: Wed Jul 09, 2014 10:29PM +" Homepage: https://github.com/jalvesaq/R-Vim-runtime +" Last Change: Sat Feb 06, 2016 06:45AM " " CONFIGURATION: " To highlight chunk headers as R code, put in your vimrc: " let rmd_syn_hl_chunk = 1 -" for portability -if version < 600 - syntax clear -elseif exists("b:current_syntax") +if exists("b:current_syntax") finish endif @@ -58,6 +56,8 @@ if rmdIsPandoc == 0 if exists("b:current_syntax") unlet b:current_syntax endif + " Extend cluster + syn cluster texMathZoneGroup add=rmdrInline " Inline syntax match rmdLaTeXInlDelim "\$" syntax match rmdLaTeXInlDelim "\\\$" diff --git a/runtime/syntax/rnoweb.vim b/runtime/syntax/rnoweb.vim index 7d42395b5c..665acc53e2 100644 --- a/runtime/syntax/rnoweb.vim +++ b/runtime/syntax/rnoweb.vim @@ -1,20 +1,14 @@ " Vim syntax file " Language: R noweb Files " Maintainer: Johannes Ranke <jranke@uni-bremen.de> -" Last Change: 2009 May 05 -" Version: 0.9 -" SVN: $Id: rnoweb.vim 84 2009-05-03 19:52:47Z ranke $ +" Last Change: Sat Feb 06, 2016 06:47AM +" Version: 0.9.1 " Remarks: - This file is inspired by the proposal of -" Fernando Henrique Ferraz Pereira da Rosa <feferraz@ime.usp.br> -" http://www.ime.usp.br/~feferraz/en/sweavevim.html +" Fernando Henrique Ferraz Pereira da Rosa <feferraz@ime.usp.br> +" http://www.ime.usp.br/~feferraz/en/sweavevim.html " -" Version Clears: {{{1 -" For version 5.x: Clear all syntax items -" For version 6.x and 7.x: Quit when a syntax file was already loaded -if version < 600 - syntax clear -elseif exists("b:current_syntax") +if exists("b:current_syntax") finish endif @@ -26,21 +20,22 @@ unlet b:current_syntax syn cluster texMatchGroup add=@rnoweb syn cluster texMathMatchGroup add=rnowebSexpr +syn cluster texMathZoneGroup add=rnowebSexpr syn cluster texEnvGroup add=@rnoweb syn cluster texFoldGroup add=@rnoweb -syn cluster texDocGroup add=@rnoweb -syn cluster texPartGroup add=@rnoweb -syn cluster texChapterGroup add=@rnoweb -syn cluster texSectionGroup add=@rnoweb -syn cluster texSubSectionGroup add=@rnoweb -syn cluster texSubSubSectionGroup add=@rnoweb -syn cluster texParaGroup add=@rnoweb +syn cluster texDocGroup add=@rnoweb +syn cluster texPartGroup add=@rnoweb +syn cluster texChapterGroup add=@rnoweb +syn cluster texSectionGroup add=@rnoweb +syn cluster texSubSectionGroup add=@rnoweb +syn cluster texSubSubSectionGroup add=@rnoweb +syn cluster texParaGroup add=@rnoweb " Highlighting of R code using an existing r.vim syntax file if available {{{1 syn include @rnowebR syntax/r.vim syn region rnowebChunk matchgroup=rnowebDelimiter start="^<<.*>>=" matchgroup=rnowebDelimiter end="^@" contains=@rnowebR,rnowebChunkReference,rnowebChunk fold keepend syn match rnowebChunkReference "^<<.*>>$" contained -syn region rnowebSexpr matchgroup=Delimiter start="\\Sexpr{" matchgroup=Delimiter end="}" contains=@rnowebR +syn region rnowebSexpr matchgroup=Delimiter start="\\Sexpr{" matchgroup=Delimiter end="}" contains=@rnowebR contained " Sweave options command {{{1 syn region rnowebSweaveopts matchgroup=Delimiter start="\\SweaveOpts{" matchgroup=Delimiter end="}" diff --git a/runtime/syntax/rrst.vim b/runtime/syntax/rrst.vim index 4667b3a2c1..24d3844df0 100644 --- a/runtime/syntax/rrst.vim +++ b/runtime/syntax/rrst.vim @@ -1,16 +1,14 @@ " reStructured Text with R statements " Language: reST with R code chunks " Maintainer: Alex Zvoleff, azvoleff@mail.sdsu.edu -" Last Change: Wed Jul 09, 2014 10:29PM +" Homepage: https://github.com/jalvesaq/R-Vim-runtime +" Last Change: Sat Feb 06, 2016 06:45AM " " CONFIGURATION: " To highlight chunk headers as R code, put in your vimrc: " let rrst_syn_hl_chunk = 1 -" for portability -if version < 600 - syntax clear -elseif exists("b:current_syntax") +if exists("b:current_syntax") finish endif diff --git a/runtime/syntax/sh.vim b/runtime/syntax/sh.vim index 909ead81f1..6ef5bf0d16 100644 --- a/runtime/syntax/sh.vim +++ b/runtime/syntax/sh.vim @@ -2,8 +2,8 @@ " Language: shell (sh) Korn shell (ksh) bash (sh) " Maintainer: Charles E. Campbell <NdrOchipS@PcampbellAfamily.Mbiz> " Previous Maintainer: Lennart Schultz <Lennart.Schultz@ecmwf.int> -" Last Change: Dec 11, 2015 -" Version: 143 +" Last Change: Apr 11, 2016 +" Version: 147 " URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_SH " For options and settings, please use: :help ft-sh-syntax " This file includes many ideas from Eric Brunet (eric.brunet@ens.fr) @@ -85,6 +85,11 @@ if g:sh_fold_enabled && &fdm == "manual" setl fdm=syntax endif +" set up the syntax-highlighting iskeyword +if has("patch-7.4.1141") + exe "syn iskeyword ".&iskeyword.",-" +endif + " Set up folding commands for shell {{{1 " ================================= if s:sh_fold_functions @@ -180,7 +185,7 @@ endif " Options: {{{1 " ==================== -syn match shOption "\s\zs[-+][-_a-zA-Z0-9#]\+" +syn match shOption "\s\zs[-+][-_a-zA-Z#@]\+" syn match shOption "\s\zs--[^ \t$`'"|);]\+" " File Redirection Highlighted As Operators: {{{1 @@ -312,7 +317,8 @@ syn match shColon '^\s*\zs:' " String And Character Constants: {{{1 "================================ -syn match shNumber "-\=\<\d\+\>#\=" +syn match shNumber "\<\d\+\>#\=" +syn match shNumber "-\=\.\=\d\+\>#\=" syn match shCtrlSeq "\\\d\d\d\|\\[abcfnrtv0]" contained if exists("b:is_bash") syn match shSpecial "\\\o\o\o\|\\x\x\x\|\\c[^"]\|\\[abefnrtv]" contained @@ -533,13 +539,20 @@ endif " Synchronization: {{{1 " ================ -if !exists("sh_minlines") - let sh_minlines = 200 +if !exists("g:sh_minlines") + let s:sh_minlines = 200 +else + let s:sh_minlines= g:sh_minlines endif -if !exists("sh_maxlines") - let sh_maxlines = 2 * sh_minlines +if !exists("g:sh_maxlines") + let s:sh_maxlines = 2*s:sh_minlines + if s:sh_maxlines < 25 + let s:sh_maxlines= 25 + endif +else + let s:sh_maxlines= g:sh_maxlines endif -exec "syn sync minlines=" . sh_minlines . " maxlines=" . sh_maxlines +exec "syn sync minlines=" . s:sh_minlines . " maxlines=" . s:sh_maxlines syn sync match shCaseEsacSync grouphere shCaseEsac "\<case\>" syn sync match shCaseEsacSync groupthere shCaseEsac "\<esac\>" syn sync match shDoSync grouphere shDo "\<do\>" diff --git a/runtime/syntax/sshconfig.vim b/runtime/syntax/sshconfig.vim index ef2ca07976..44b3c67a96 100644 --- a/runtime/syntax/sshconfig.vim +++ b/runtime/syntax/sshconfig.vim @@ -4,8 +4,8 @@ " Maintainer: Dominik Fischer <d dot f dot fischer at web dot de> " Contributor: Leonard Ehrenfried <leonard.ehrenfried@web.de> " Contributor: Karsten Hopp <karsten@redhat.com> -" Last Change: 2016 Jan 15 -" SSH Version: 7.1 +" Last Change: 2016 Mar 1 +" SSH Version: 7.2 " " Setup @@ -40,26 +40,57 @@ syn keyword sshconfigYesNo yes no ask syn keyword sshconfigYesNo any auto syn keyword sshconfigYesNo force autoask none -syn keyword sshconfigCipher 3des blowfish -syn keyword sshconfigCiphers aes128-cbc 3des-cbc blowfish blowfish-cbc cast128-cbc -syn keyword sshconfigCiphers aes192-cbc aes256-cbc aes128-ctr aes192-ctr aes256-ctr -syn keyword sshconfigCiphers arcfour arcfour128 arcfour256 cast128-cbc +syn keyword sshconfigCipher 3des blowfish -syn keyword sshconfigMAC hmac-md5 hmac-sha1 hmac-ripemd160 hmac-sha1-96 -syn keyword sshconfigMAC hmac-md5-96 -syn keyword sshconfigMAC hmac-sha2-256 hmac-sha2-256-96 hmac-sha2-512 -syn keyword sshconfigMAC hmac-sha2-512-96 +syn keyword sshconfigCiphers 3des-cbc +syn keyword sshconfigCiphers blowfish-cbc +syn keyword sshconfigCiphers cast128-cbc +syn keyword sshconfigCiphers arcfour +syn keyword sshconfigCiphers arcfour128 +syn keyword sshconfigCiphers arcfour256 +syn keyword sshconfigCiphers aes128-cbc +syn keyword sshconfigCiphers aes192-cbc +syn keyword sshconfigCiphers aes256-cbc +syn match sshconfigCiphers "\<rijndael-cbc@lysator\.liu.se\>" +syn keyword sshconfigCiphers aes128-ctr +syn keyword sshconfigCiphers aes192-ctr +syn keyword sshconfigCiphers aes256-ctr +syn match sshconfigCiphers "\<aes128-gcm@openssh\.com\>" +syn match sshconfigCiphers "\<aes256-gcm@openssh\.com\>" +syn match sshconfigCiphers "\<chacha20-poly1305@openssh\.com\>" + +syn keyword sshconfigMAC hmac-sha1 +syn keyword sshconfigMAC mac-sha1-96 +syn keyword sshconfigMAC mac-sha2-256 +syn keyword sshconfigMAC mac-sha2-512 +syn keyword sshconfigMAC mac-md5 +syn keyword sshconfigMAC mac-md5-96 +syn keyword sshconfigMAC mac-ripemd160 +syn match sshconfigMAC "\<hmac-ripemd160@openssh\.com\>" syn match sshconfigMAC "\<umac-64@openssh\.com\>" +syn match sshconfigMAC "\<umac-128@openssh\.com\>" +syn match sshconfigMAC "\<hmac-sha1-etm@openssh\.com\>" +syn match sshconfigMAC "\<hmac-sha1-96-etm@openssh\.com\>" +syn match sshconfigMAC "\<hmac-sha2-256-etm@openssh\.com\>" +syn match sshconfigMAC "\<hmac-sha2-512-etm@openssh\.com\>" +syn match sshconfigMAC "\<hmac-md5-etm@openssh\.com\>" +syn match sshconfigMAC "\<hmac-md5-96-etm@openssh\.com\>" +syn match sshconfigMAC "\<hmac-ripemd160-etm@openssh\.com\>" +syn match sshconfigMAC "\<umac-64-etm@openssh\.com\>" +syn match sshconfigMAC "\<umac-128-etm@openssh\.com\>" -syn keyword sshconfigHostKeyAlg ssh-rsa ssh-dss -syn match sshconfigHostKeyAlg "\<ecdsa-sha2-nistp256-cert-v01@openssh\.com\>" -syn match sshconfigHostKeyAlg "\<ecdsa-sha2-nistp384-cert-v01@openssh\.com\>" -syn match sshconfigHostKeyAlg "\<ecdsa-sha2-nistp521-cert-v01@openssh\.com\>" -syn match sshconfigHostKeyAlg "\<ssh-rsa-cert-v01@openssh\.com\>" -syn match sshconfigHostKeyAlg "\<ssh-dss-cert-v01@openssh\.com\>" -syn match sshconfigHostKeyAlg "\<ssh-rsa-cert-v00@openssh\.com\>" -syn match sshconfigHostKeyAlg "\<ssh-dss-cert-v00@openssh\.com\>" -syn keyword sshconfigHostKeyAlg ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 +syn keyword sshconfigHostKeyAlgo ssh-ed25519 +syn match sshconfigHostKeyAlgo "\<ssh-ed25519-cert-v01@openssh\.com\>" +syn keyword sshconfigHostKeyAlgo ssh-rsa +syn keyword sshconfigHostKeyAlgo ssh-dss +syn keyword sshconfigHostKeyAlgo ecdsa-sha2-nistp256 +syn keyword sshconfigHostKeyAlgo ecdsa-sha2-nistp384 +syn keyword sshconfigHostKeyAlgo ecdsa-sha2-nistp521 +syn match sshconfigHostKeyAlgo "\<ssh-rsa-cert-v01@openssh\.com\>" +syn match sshconfigHostKeyAlgo "\<ssh-dss-cert-v01@openssh\.com\>" +syn match sshconfigHostKeyAlgo "\<ecdsa-sha2-nistp256-cert-v01@openssh\.com\>" +syn match sshconfigHostKeyAlgo "\<ecdsa-sha2-nistp384-cert-v01@openssh\.com\>" +syn match sshconfigHostKeyAlgo "\<ecdsa-sha2-nistp521-cert-v01@openssh\.com\>" syn keyword sshconfigPreferredAuth hostbased publickey password gssapi-with-mic syn keyword sshconfigPreferredAuth keyboard-interactive @@ -78,11 +109,14 @@ syn match sshconfigIPQoS "cs[0-7]" syn keyword sshconfigIPQoS ef lowdelay throughput reliability syn keyword sshconfigKbdInteractive bsdauth pam skey -syn keyword sshconfigKexAlgo ecdh-sha2-nistp256 ecdh-sha2-nistp384 ecdh-sha2-nistp521 -syn keyword sshconfigKexAlgo diffie-hellman-group-exchange-sha256 -syn keyword sshconfigKexAlgo diffie-hellman-group-exchange-sha1 -syn keyword sshconfigKexAlgo diffie-hellman-group14-sha1 -syn keyword sshconfigKexAlgo diffie-hellman-group1-sha1 +syn keyword sshconfigKexAlgo diffie-hellman-group1-sha1 +syn keyword sshconfigKexAlgo diffie-hellman-group14-sha1 +syn keyword sshconfigKexAlgo diffie-hellman-group-exchange-sha1 +syn keyword sshconfigKexAlgo diffie-hellman-group-exchange-sha256 +syn keyword sshconfigKexAlgo ecdh-sha2-nistp256 +syn keyword sshconfigKexAlgo ecdh-sha2-nistp384 +syn keyword sshconfigKexAlgo ecdh-sha2-nistp521 +syn match sshconfigKexAlgo "\<curve25519-sha256@libssh\.org\>" syn keyword sshconfigTunnel point-to-point ethernet @@ -111,6 +145,7 @@ syn keyword sshconfigKeyword CanonicalDomains syn keyword sshconfigKeyword CanonicalizeFallbackLocal syn keyword sshconfigKeyword CanonicalizeHostname syn keyword sshconfigKeyword CanonicalizeMaxDots +syn keyword sshconfigKeyword CertificateFile syn keyword sshconfigKeyword ChallengeResponseAuthentication syn keyword sshconfigKeyword CheckHostIP syn keyword sshconfigKeyword Cipher @@ -212,7 +247,7 @@ if version >= 508 || !exists("did_sshconfig_syntax_inits") HiLink sshconfigCipher sshconfigEnum HiLink sshconfigCiphers sshconfigEnum HiLink sshconfigMAC sshconfigEnum - HiLink sshconfigHostKeyAlg sshconfigEnum + HiLink sshconfigHostKeyAlgo sshconfigEnum HiLink sshconfigLogLevel sshconfigEnum HiLink sshconfigSysLogFacility sshconfigEnum HiLink sshconfigAddressFamily sshconfigEnum diff --git a/runtime/syntax/sshdconfig.vim b/runtime/syntax/sshdconfig.vim index 4203047d2c..6b7b98d893 100644 --- a/runtime/syntax/sshdconfig.vim +++ b/runtime/syntax/sshdconfig.vim @@ -6,8 +6,8 @@ " Contributor: Leonard Ehrenfried <leonard.ehrenfried@web.de> " Contributor: Karsten Hopp <karsten@redhat.com> " Originally: 2009-07-09 -" Last Change: 2016 Jan 12 -" SSH Version: 7.1 +" Last Change: 2016 Mar 1 +" SSH Version: 7.2 " " Setup @@ -47,15 +47,55 @@ syn keyword sshdconfigTcpForwarding local remote syn keyword sshdconfigRootLogin prohibit-password without-password forced-commands-only -syn keyword sshdconfigCipher aes128-cbc 3des-cbc blowfish-cbc cast128-cbc -syn keyword sshdconfigCipher aes192-cbc aes256-cbc aes128-ctr aes192-ctr aes256-ctr -syn keyword sshdconfigCipher arcfour arcfour128 arcfour256 cast128-cbc - -syn keyword sshdconfigMAC hmac-md5 hmac-sha1 hmac-ripemd160 hmac-sha1-96 -syn keyword sshdconfigMAC hmac-md5-96 -syn keyword sshdconfigMAC hmac-sha2-256 hmac-sha256-96 hmac-sha2-512 -syn keyword sshdconfigMAC hmac-sha2-512-96 +syn keyword sshdconfigCiphers 3des-cbc +syn keyword sshdconfigCiphers blowfish-cbc +syn keyword sshdconfigCiphers cast128-cbc +syn keyword sshdconfigCiphers arcfour +syn keyword sshdconfigCiphers arcfour128 +syn keyword sshdconfigCiphers arcfour256 +syn keyword sshdconfigCiphers aes128-cbc +syn keyword sshdconfigCiphers aes192-cbc +syn keyword sshdconfigCiphers aes256-cbc +syn match sshdconfigCiphers "\<rijndael-cbc@lysator\.liu.se\>" +syn keyword sshdconfigCiphers aes128-ctr +syn keyword sshdconfigCiphers aes192-ctr +syn keyword sshdconfigCiphers aes256-ctr +syn match sshdconfigCiphers "\<aes128-gcm@openssh\.com\>" +syn match sshdconfigCiphers "\<aes256-gcm@openssh\.com\>" +syn match sshdconfigCiphers "\<chacha20-poly1305@openssh\.com\>" + +syn keyword sshdconfigMAC hmac-sha1 +syn keyword sshdconfigMAC mac-sha1-96 +syn keyword sshdconfigMAC mac-sha2-256 +syn keyword sshdconfigMAC mac-sha2-512 +syn keyword sshdconfigMAC mac-md5 +syn keyword sshdconfigMAC mac-md5-96 +syn keyword sshdconfigMAC mac-ripemd160 +syn match sshdconfigMAC "\<hmac-ripemd160@openssh\.com\>" syn match sshdconfigMAC "\<umac-64@openssh\.com\>" +syn match sshdconfigMAC "\<umac-128@openssh\.com\>" +syn match sshdconfigMAC "\<hmac-sha1-etm@openssh\.com\>" +syn match sshdconfigMAC "\<hmac-sha1-96-etm@openssh\.com\>" +syn match sshdconfigMAC "\<hmac-sha2-256-etm@openssh\.com\>" +syn match sshdconfigMAC "\<hmac-sha2-512-etm@openssh\.com\>" +syn match sshdconfigMAC "\<hmac-md5-etm@openssh\.com\>" +syn match sshdconfigMAC "\<hmac-md5-96-etm@openssh\.com\>" +syn match sshdconfigMAC "\<hmac-ripemd160-etm@openssh\.com\>" +syn match sshdconfigMAC "\<umac-64-etm@openssh\.com\>" +syn match sshdconfigMAC "\<umac-128-etm@openssh\.com\>" + +syn keyword sshdconfigHostKeyAlgo ssh-ed25519 +syn match sshdconfigHostKeyAlgo "\<ssh-ed25519-cert-v01@openssh\.com\>" +syn keyword sshdconfigHostKeyAlgo ssh-rsa +syn keyword sshdconfigHostKeyAlgo ssh-dss +syn keyword sshdconfigHostKeyAlgo ecdsa-sha2-nistp256 +syn keyword sshdconfigHostKeyAlgo ecdsa-sha2-nistp384 +syn keyword sshdconfigHostKeyAlgo ecdsa-sha2-nistp521 +syn match sshdconfigHostKeyAlgo "\<ssh-rsa-cert-v01@openssh\.com\>" +syn match sshdconfigHostKeyAlgo "\<ssh-dss-cert-v01@openssh\.com\>" +syn match sshdconfigHostKeyAlgo "\<ecdsa-sha2-nistp256-cert-v01@openssh\.com\>" +syn match sshdconfigHostKeyAlgo "\<ecdsa-sha2-nistp384-cert-v01@openssh\.com\>" +syn match sshdconfigHostKeyAlgo "\<ecdsa-sha2-nistp521-cert-v01@openssh\.com\>" syn keyword sshdconfigRootLogin prohibit-password without-password forced-commands-only @@ -73,11 +113,14 @@ syn match sshdconfigIPQoS "af4[123]" syn match sshdconfigIPQoS "cs[0-7]" syn keyword sshdconfigIPQoS ef lowdelay throughput reliability -syn keyword sshdconfigKexAlgo ecdh-sha2-nistp256 ecdh-sha2-nistp384 ecdh-sha2-nistp521 -syn keyword sshdconfigKexAlgo diffie-hellman-group-exchange-sha256 -syn keyword sshdconfigKexAlgo diffie-hellman-group-exchange-sha1 -syn keyword sshdconfigKexAlgo diffie-hellman-group14-sha1 -syn keyword sshdconfigKexAlgo diffie-hellman-group1-sha1 +syn keyword sshdconfigKexAlgo diffie-hellman-group1-sha1 +syn keyword sshdconfigKexAlgo diffie-hellman-group14-sha1 +syn keyword sshdconfigKexAlgo diffie-hellman-group-exchange-sha1 +syn keyword sshdconfigKexAlgo diffie-hellman-group-exchange-sha256 +syn keyword sshdconfigKexAlgo ecdh-sha2-nistp256 +syn keyword sshdconfigKexAlgo ecdh-sha2-nistp384 +syn keyword sshdconfigKexAlgo ecdh-sha2-nistp521 +syn match sshdconfigKexAlgo "\<curve25519-sha256@libssh\.org\>" syn keyword sshdconfigTunnel point-to-point ethernet @@ -215,8 +258,9 @@ if version >= 508 || !exists("did_sshdconfig_syntax_inits") HiLink sshdconfigPrivilegeSeparation sshdconfigEnum HiLink sshdconfigTcpForwarding sshdconfigEnum HiLink sshdconfigRootLogin sshdconfigEnum - HiLink sshdconfigCipher sshdconfigEnum + HiLink sshdconfigCiphers sshdconfigEnum HiLink sshdconfigMAC sshdconfigEnum + HiLink sshdconfigHostKeyAlgo sshdconfigEnum HiLink sshdconfigRootLogin sshdconfigEnum HiLink sshdconfigLogLevel sshdconfigEnum HiLink sshdconfigSysLogFacility sshdconfigEnum diff --git a/runtime/syntax/tex.vim b/runtime/syntax/tex.vim index d31e14bed0..d6d5dd81ee 100644 --- a/runtime/syntax/tex.vim +++ b/runtime/syntax/tex.vim @@ -1,8 +1,8 @@ " Vim syntax file " Language: TeX " Maintainer: Charles E. Campbell <NdrchipO@ScampbellPfamily.AbizM> -" Last Change: Oct 20, 2015 -" Version: 90 +" Last Change: Apr 11, 2016 +" Version: 94 " URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_TEX " " Notes: {{{1 @@ -83,10 +83,14 @@ else let s:tex_conceal= g:tex_conceal endif if !exists("g:tex_superscripts") - let g:tex_superscripts= "[0-9a-zA-W.,:;+-<>/()=]" + let s:tex_superscripts= "[0-9a-zA-W.,:;+-<>/()=]" +else + let s:tex_superscripts= g:tex_superscripts endif if !exists("g:tex_subscripts") - let g:tex_subscripts= "[0-9aehijklmnoprstuvx,+-/().]" + let s:tex_subscripts= "[0-9aehijklmnoprstuvx,+-/().]" +else + let s:tex_subscripts= g:tex_subscripts endif " Determine whether or not to use "*.sty" mode {{{1 @@ -129,8 +133,10 @@ endif " g:tex_isk if exists("g:tex_isk") exe "setlocal isk=".g:tex_isk +elseif !has("patch-7.4.1141") + setl isk=48-57,a-z,A-Z,192-255 else - setlocal isk=48-57,a-z,A-Z,192-255 + syn iskeyword 48-57,a-z,A-Z,192-255 endif if b:tex_stylish setlocal isk+=@-@ @@ -198,7 +204,7 @@ if !exists("g:tex_no_math") endif " Try to flag {} and () mismatches: {{{1 -if s:tex_fast =~ 'm' +if s:tex_fast =~# 'm' if !s:tex_no_error syn region texMatcher matchgroup=Delimiter start="{" skip="\\\\\|\\[{}]" end="}" transparent contains=@texMatchGroup,texError syn region texMatcher matchgroup=Delimiter start="\[" end="]" transparent contains=@texMatchGroup,texError,@NoSpell @@ -215,7 +221,7 @@ endif if !s:tex_no_error syn match texError "[}\])]" endif -if s:tex_fast =~ 'M' +if s:tex_fast =~# 'M' if !exists("g:tex_no_math") if !s:tex_no_error syn match texMathError "}" contained @@ -258,14 +264,14 @@ syn match texLigature "\\\([ijolL]\|ae\|oe\|ss\|AA\|AE\|OE\)$" " \begin{}/\end{} section markers: {{{1 syn match texBeginEnd "\\begin\>\|\\end\>" nextgroup=texBeginEndName -if s:tex_fast =~ 'm' +if s:tex_fast =~# 'm' syn region texBeginEndName matchgroup=Delimiter start="{" end="}" contained nextgroup=texBeginEndModifier contains=texComment syn region texBeginEndModifier matchgroup=Delimiter start="\[" end="]" contained contains=texComment,@NoSpell endif " \documentclass, \documentstyle, \usepackage: {{{1 syn match texDocType "\\documentclass\>\|\\documentstyle\>\|\\usepackage\>" nextgroup=texBeginEndName,texDocTypeArgs -if s:tex_fast =~ 'm' +if s:tex_fast =~# 'm' syn region texDocTypeArgs matchgroup=Delimiter start="\[" end="]" contained nextgroup=texBeginEndName contains=texComment,@NoSpell endif @@ -279,7 +285,7 @@ syn match texInput "\\input\s\+[a-zA-Z/.0-9_^]\+"hs=s+7 contains=texStatemen syn match texInputFile "\\include\(graphics\|list\)\=\(\[.\{-}\]\)\=\s*{.\{-}}" contains=texStatement,texInputCurlies,texInputFileOpt syn match texInputFile "\\\(epsfig\|input\|usepackage\)\s*\(\[.*\]\)\={.\{-}}" contains=texStatement,texInputCurlies,texInputFileOpt syn match texInputCurlies "[{}]" contained -if s:tex_fast =~ 'm' +if s:tex_fast =~# 'm' syn region texInputFileOpt matchgroup=Delimiter start="\[" end="\]" contained contains=texComment endif @@ -294,7 +300,7 @@ syn match texTypeStyle "\\sc\>" syn match texTypeStyle "\\tt\>" " Type Styles: attributes, commands, families, etc (LaTeX2E): {{{1 -if s:tex_conceal !~ 'b' +if s:tex_conceal !~# 'b' syn match texTypeStyle "\\textbf\>" syn match texTypeStyle "\\textit\>" endif @@ -347,7 +353,7 @@ syn match texSpaceCode "\\\(math\|cat\|del\|lc\|sf\|uc\)code`"me=e-1 nextgroup= syn match texSpaceCodeChar "`\\\=.\(\^.\)\==\(\d\|\"\x\{1,6}\|`.\)" contained " Sections, subsections, etc: {{{1 -if s:tex_fast =~ 'p' +if s:tex_fast =~# 'p' if !s:tex_nospell TexFold syn region texDocZone matchgroup=texSection start='\\begin\s*{\s*document\s*}' end='\\end\s*{\s*document\s*}' contains=@texFoldGroup,@texDocGroup,@Spell TexFold syn region texPartZone matchgroup=texSection start='\\part\>' end='\ze\s*\\\%(part\>\|end\s*{\s*document\s*}\)' contains=@texFoldGroup,@texPartGroup,@Spell @@ -374,8 +380,8 @@ if s:tex_fast =~ 'p' endif " particular support for bold and italic {{{1 -if s:tex_fast =~ 'b' - if s:tex_conceal =~ 'b' +if s:tex_fast =~# 'b' + if s:tex_conceal =~# 'b' if !exists("g:tex_nospell") || !g:tex_nospell syn region texBoldStyle matchgroup=texTypeStyle start="\\textbf\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texBoldGroup,@Spell syn region texBoldItalStyle matchgroup=texTypeStyle start="\\textit\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texItalGroup,@Spell @@ -412,7 +418,7 @@ if !exists("g:tex_no_math") let foldcmd= "" endif exe "syn cluster texMathZones add=".grpname - if s:tex_fast =~ 'M' + if s:tex_fast =~# 'M' exe 'syn region '.grpname.' start='."'".'\\begin\s*{\s*'.a:mathzone.'\s*}'."'".' end='."'".'\\end\s*{\s*'.a:mathzone.'\s*}'."'".' keepend contains=@texMathZoneGroup'.foldcmd exe 'syn sync match '.syncname.' grouphere '.grpname.' "\\begin\s*{\s*'.a:mathzone.'\*\s*}"' exe 'syn sync match '.syncname.' grouphere '.grpname.' "\\begin\s*{\s*'.a:mathzone.'\*\s*}"' @@ -422,7 +428,7 @@ if !exists("g:tex_no_math") let grpname = "texMathZone".a:sfx.'S' let syncname = "texSyncMathZone".a:sfx.'S' exe "syn cluster texMathZones add=".grpname - if s:tex_fast =~ 'M' + if s:tex_fast =~# 'M' exe 'syn region '.grpname.' start='."'".'\\begin\s*{\s*'.a:mathzone.'\*\s*}'."'".' end='."'".'\\end\s*{\s*'.a:mathzone.'\*\s*}'."'".' keepend contains=@texMathZoneGroup'.foldcmd exe 'syn sync match '.syncname.' grouphere '.grpname.' "\\begin\s*{\s*'.a:mathzone.'\*\s*}"' exe 'syn sync match '.syncname.' grouphere '.grpname.' "\\begin\s*{\s*'.a:mathzone.'\*\s*}"' @@ -446,8 +452,8 @@ if !exists("g:tex_no_math") call TexNewMathZone("L","xxalignat",0) " Inline Math Zones: {{{2 - if s:tex_fast =~ 'M' - if has("conceal") && &enc == 'utf-8' && s:tex_conceal =~ 'd' + if s:tex_fast =~# 'M' + if has("conceal") && &enc == 'utf-8' && s:tex_conceal =~# 'd' syn region texMathZoneV matchgroup=Delimiter start="\\(" matchgroup=Delimiter end="\\)\|%stopzone\>" keepend concealends contains=@texMathZoneGroup syn region texMathZoneW matchgroup=Delimiter start="\\\[" matchgroup=Delimiter end="\\]\|%stopzone\>" keepend concealends contains=@texMathZoneGroup syn region texMathZoneX matchgroup=Delimiter start="\$" skip="\\\\\|\\\$" matchgroup=Delimiter end="\$" end="%stopzone\>" concealends contains=@texMathZoneGroup @@ -464,7 +470,7 @@ if !exists("g:tex_no_math") syn match texMathOper "[_^=]" contained " Text Inside Math Zones: {{{2 - if s:tex_fast =~ 'M' + if s:tex_fast =~# 'M' if !exists("g:tex_nospell") || !g:tex_nospell syn region texMathText matchgroup=texStatement start='\\\(\(inter\)\=text\|mbox\)\s*{' end='}' contains=@texFoldGroup,@Spell else @@ -474,7 +480,7 @@ if !exists("g:tex_no_math") " \left..something.. and \right..something.. support: {{{2 syn match texMathDelimBad contained "\S" - if has("conceal") && &enc == 'utf-8' && s:tex_conceal =~ 'm' + if has("conceal") && &enc == 'utf-8' && s:tex_conceal =~# 'm' syn match texMathDelim contained "\\left\\{\>" skipwhite nextgroup=texMathDelimSet1,texMathDelimSet2,texMathDelimBad contains=texMathSymbol cchar={ syn match texMathDelim contained "\\right\\}\>" skipwhite nextgroup=texMathDelimSet1,texMathDelimSet2,texMathDelimBad contains=texMathSymbol cchar=} let s:texMathDelimList=[ @@ -539,7 +545,7 @@ if !exists("g:tex_no_math") syn match texOnlyMath "[_^]" endif syn match texSpecialChar "\^\^[0-9a-f]\{2}\|\^\^\S" -if s:tex_conceal !~ 'S' +if s:tex_conceal !~# 'S' syn match texSpecialChar '\\glq\>' contained conceal cchar=‚ syn match texSpecialChar '\\grq\>' contained conceal cchar=‘ syn match texSpecialChar '\\glqq\>' contained conceal cchar=„ @@ -566,13 +572,13 @@ else " allows syntax-folding of 2 or more contiguous comment lines " single-line comments are not folded syn match texComment "%.*$" contains=@texCommentGroup - if s:tex_fast =~ 'c' + if s:tex_fast =~# 'c' TexFold syn region texComment start="^\zs\s*%.*\_s*%" skip="^\s*%" end='^\ze\s*[^%]' contains=@texCommentGroup TexFold syn region texNoSpell contained matchgroup=texComment start="%\s*nospell\s*{" end="%\s*nospell\s*}" contains=@texFoldGroup,@NoSpell endif else syn match texComment "%.*$" contains=@texCommentGroup - if s:tex_fast =~ 'c' + if s:tex_fast =~# 'c' syn region texNoSpell contained matchgroup=texComment start="%\s*nospell\s*{" end="%\s*nospell\s*}" contains=@texFoldGroup,@NoSpell endif endif @@ -581,7 +587,7 @@ endif " Separate lines used for verb` and verb# so that the end conditions {{{1 " will appropriately terminate. " If g:tex_verbspell exists, then verbatim texZones will permit spellchecking there. -if s:tex_fast =~ 'v' +if s:tex_fast =~# 'v' if exists("g:tex_verbspell") && g:tex_verbspell syn region texZone start="\\begin{[vV]erbatim}" end="\\end{[vV]erbatim}\|%stopzone\>" contains=@Spell " listings package: @@ -612,7 +618,7 @@ if s:tex_fast =~ 'v' endif " Tex Reference Zones: {{{1 -if s:tex_fast =~ 'r' +if s:tex_fast =~# 'r' syn region texZone matchgroup=texStatement start="@samp{" end="}\|%stopzone\>" contains=@texRefGroup syn region texRefZone matchgroup=texStatement start="\\nocite{" end="}\|%stopzone\>" contains=@texRefGroup syn region texRefZone matchgroup=texStatement start="\\bibliography{" end="}\|%stopzone\>" contains=@texRefGroup @@ -626,13 +632,13 @@ syn match texRefZone '\\cite\%([tp]\*\=\)\=' nextgroup=texRefOption,texCite " Handle newcommand, newenvironment : {{{1 syn match texNewCmd "\\newcommand\>" nextgroup=texCmdName skipwhite skipnl -if s:tex_fast =~ 'V' +if s:tex_fast =~# 'V' syn region texCmdName contained matchgroup=Delimiter start="{"rs=s+1 end="}" nextgroup=texCmdArgs,texCmdBody skipwhite skipnl syn region texCmdArgs contained matchgroup=Delimiter start="\["rs=s+1 end="]" nextgroup=texCmdBody skipwhite skipnl syn region texCmdBody contained matchgroup=Delimiter start="{"rs=s+1 skip="\\\\\|\\[{}]" matchgroup=Delimiter end="}" contains=@texCmdGroup endif syn match texNewEnv "\\newenvironment\>" nextgroup=texEnvName skipwhite skipnl -if s:tex_fast =~ 'V' +if s:tex_fast =~# 'V' syn region texEnvName contained matchgroup=Delimiter start="{"rs=s+1 end="}" nextgroup=texEnvBgn skipwhite skipnl syn region texEnvBgn contained matchgroup=Delimiter start="{"rs=s+1 end="}" nextgroup=texEnvEnd skipwhite skipnl contains=@texEnvGroup syn region texEnvEnd contained matchgroup=Delimiter start="{"rs=s+1 end="}" skipwhite skipnl contains=@texEnvGroup @@ -658,11 +664,11 @@ syn match texString "\(``\|''\|,,\)" " makeatletter -- makeatother sections if !s:tex_no_error - if s:tex_fast =~ 'S' + if s:tex_fast =~# 'S' syn region texStyle matchgroup=texStatement start='\\makeatletter' end='\\makeatother' contains=@texStyleGroup contained endif syn match texStyleStatement "\\[a-zA-Z@]\+" contained - if s:tex_fast =~ 'S' + if s:tex_fast =~# 'S' syn region texStyleMatcher matchgroup=Delimiter start="{" skip="\\\\\|\\[{}]" end="}" contains=@texStyleGroup,texError contained syn region texStyleMatcher matchgroup=Delimiter start="\[" end="]" contains=@texStyleGroup,texError contained endif @@ -673,7 +679,7 @@ if has("conceal") && &enc == 'utf-8' " Math Symbols {{{2 " (many of these symbols were contributed by Björn Winckler) - if s:tex_conceal =~ 'm' + if s:tex_conceal =~# 'm' let s:texMathList=[ \ ['|' , '‖'], \ ['aleph' , 'ℵ'], @@ -954,7 +960,7 @@ if has("conceal") && &enc == 'utf-8' " \ ['uminus' , 'X'] " \ ['uplus' , 'X'] for texmath in s:texMathList - if texmath[0] =~ '\w$' + if texmath[0] =~# '\w$' exe "syn match texMathSymbol '\\\\".texmath[0]."\\>' contained conceal cchar=".texmath[1] else exe "syn match texMathSymbol '\\\\".texmath[0]."' contained conceal cchar=".texmath[1] @@ -993,7 +999,7 @@ if has("conceal") && &enc == 'utf-8' endif " Greek {{{2 - if s:tex_conceal =~ 'g' + if s:tex_conceal =~# 'g' fun! s:Greek(group,pat,cchar) exe 'syn match '.a:group." '".a:pat."' contained conceal cchar=".a:cchar endfun @@ -1040,14 +1046,14 @@ if has("conceal") && &enc == 'utf-8' endif " Superscripts/Subscripts {{{2 - if s:tex_conceal =~ 's' - if s:tex_fast =~ 's' + if s:tex_conceal =~# 's' + if s:tex_fast =~# 's' syn region texSuperscript matchgroup=Delimiter start='\^{' skip="\\\\\|\\[{}]" end='}' contained concealends contains=texSpecialChar,texSuperscripts,texStatement,texSubscript,texSuperscript,texMathMatcher syn region texSubscript matchgroup=Delimiter start='_{' skip="\\\\\|\\[{}]" end='}' contained concealends contains=texSpecialChar,texSubscripts,texStatement,texSubscript,texSuperscript,texMathMatcher endif " s:SuperSub: fun! s:SuperSub(group,leader,pat,cchar) - if a:pat =~ '^\\' || (a:leader == '\^' && a:pat =~ g:tex_superscripts) || (a:leader == '_' && a:pat =~ g:tex_subscripts) + if a:pat =~# '^\\' || (a:leader == '\^' && a:pat =~# s:tex_superscripts) || (a:leader == '_' && a:pat =~# s:tex_subscripts) " call Decho("SuperSub: group<".a:group."> leader<".a:leader."> pat<".a:pat."> cchar<".a:cchar.">") exe 'syn match '.a:group." '".a:leader.a:pat."' contained conceal cchar=".a:cchar exe 'syn match '.a:group."s '".a:pat ."' contained conceal cchar=".a:cchar.' nextgroup='.a:group.'s' @@ -1152,7 +1158,7 @@ if has("conceal") && &enc == 'utf-8' endif " Accented characters: {{{2 - if s:tex_conceal =~ 'a' + if s:tex_conceal =~# 'a' if b:tex_stylish syn match texAccent "\\[bcdvuH][^a-zA-Z@]"me=e-1 syn match texLigature "\\\([ijolL]\|ae\|oe\|ss\|AA\|AE\|OE\)[^a-zA-Z@]"me=e-1 @@ -1167,7 +1173,7 @@ if has("conceal") && &enc == 'utf-8' let i= i + 1 continue endif - if accent =~ '\a' + if accent =~# '\a' exe "syn match texAccent '".'\\'.accent.'\(\s*{'.a:chr.'}\|\s\+'.a:chr.'\)'."' conceal cchar=".a:{i} else exe "syn match texAccent '".'\\'.accent.'\s*\({'.a:chr.'}\|'.a:chr.'\)'."' conceal cchar=".a:{i} diff --git a/runtime/syntax/vhdl.vim b/runtime/syntax/vhdl.vim index 916bd9635d..32503823ee 100644 --- a/runtime/syntax/vhdl.vim +++ b/runtime/syntax/vhdl.vim @@ -1,14 +1,10 @@ " Vim syntax file -" Language: VHDL -" Maintainer: Daniel Kho <daniel.kho@tauhop.com> +" Language: VHDL [VHSIC (Very High Speed Integrated Circuit) Hardware Description Language] +" Maintainer: Daniel Kho <daniel.kho@tauhop.com> " Previous Maintainer: Czo <Olivier.Sirol@lip6.fr> -" Credits: Stephan Hegel <stephan.hegel@snc.siemens.com.cn> -" Last Changed: 2015 Dec 4 by Daniel Kho +" Credits: Stephan Hegel <stephan.hegel@snc.siemens.com.cn> +" Last Changed: 2016 Mar 05 by Daniel Kho -" VHSIC (Very High Speed Integrated Circuit) Hardware Description Language - -" For version 5.x: Clear all syntax items -" For version 6.x: Quit when a syntax file was already loaded if version < 600 syntax clear elseif exists("b:current_syntax") @@ -56,17 +52,40 @@ syn keyword vhdlStatement note warning error failure syn match vhdlStatement "\<\(if\|else\)\>" syn match vhdlError "\<else\s\+if\>" -" Predefined VHDL types -syn keyword vhdlType bit bit_vector -syn keyword vhdlType character boolean integer real time -syn keyword vhdlType boolean_vector integer_vector real_vector time_vector -syn keyword vhdlType string severity_level -" Predefined standard ieee VHDL types -syn keyword vhdlType positive natural signed unsigned -syn keyword vhdlType unresolved_signed unresolved_unsigned u_signed u_unsigned -syn keyword vhdlType line text -syn keyword vhdlType std_logic std_logic_vector -syn keyword vhdlType std_ulogic std_ulogic_vector +" Types and type qualifiers +" Predefined standard VHDL types +syn match vhdlType "\<bit\>\'\=" +syn match vhdlType "\<boolean\>\'\=" +syn match vhdlType "\<natural\>\'\=" +syn match vhdlType "\<positive\>\'\=" +syn match vhdlType "\<integer\>\'\=" +syn match vhdlType "\<real\>\'\=" +syn match vhdlType "\<time\>\'\=" + +syn match vhdlType "\<bit_vector\>\'\=" +syn match vhdlType "\<boolean_vector\>\'\=" +syn match vhdlType "\<integer_vector\>\'\=" +syn match vhdlType "\<real_vector\>\'\=" +syn match vhdlType "\<time_vector\>\'\=" + +syn match vhdlType "\<character\>\'\=" +syn match vhdlType "\<string\>\'\=" +"syn keyword vhdlType severity_level +syn keyword vhdlType line +syn keyword vhdlType text + +" Predefined standard IEEE VHDL types +syn match vhdlType "\<std_ulogic\>\'\=" +syn match vhdlType "\<std_logic\>\'\=" +syn match vhdlType "\<std_ulogic_vector\>\'\=" +syn match vhdlType "\<std_logic_vector\>\'\=" +syn match vhdlType "\<unresolved_signed\>\'\=" +syn match vhdlType "\<unresolved_unsigned\>\'\=" +syn match vhdlType "\<u_signed\>\'\=" +syn match vhdlType "\<u_unsigned\>\'\=" +syn match vhdlType "\<signed\>\'\=" +syn match vhdlType "\<unsigned\>\'\=" + " array attributes syn match vhdlAttribute "\'high" @@ -191,15 +210,23 @@ syn case ignore syn region vhdlComment start="/\*" end="\*/" contains=vhdlTodo,vhdlFixme,@Spell syn match vhdlComment "\(^\|\s\)--.*" contains=vhdlTodo,vhdlFixme,@Spell +" Standard IEEE P1076.6 preprocessor directives (metacomments). +syn match vhdlPreProc "/\*\s*rtl_synthesis\s\+\(on\|off\)\s*\*/" +syn match vhdlPreProc "\(^\|\s\)--\s*rtl_synthesis\s\+\(on\|off\)\s*" +syn match vhdlPreProc "/\*\s*rtl_syn\s\+\(on\|off\)\s*\*/" +syn match vhdlPreProc "\(^\|\s\)--\s*rtl_syn\s\+\(on\|off\)\s*" + " Industry-standard directives. These are not standard VHDL, but are commonly " used in the industry. syn match vhdlPreProc "/\*\s*synthesis\s\+translate_\(on\|off\)\s*\*/" "syn match vhdlPreProc "/\*\s*simulation\s\+translate_\(on\|off\)\s*\*/" +syn match vhdlPreProc "/\*\s*pragma\s\+translate_\(on\|off\)\s*\*/" syn match vhdlPreProc "/\*\s*pragma\s\+synthesis_\(on\|off\)\s*\*/" syn match vhdlPreProc "/\*\s*synopsys\s\+translate_\(on\|off\)\s*\*/" syn match vhdlPreProc "\(^\|\s\)--\s*synthesis\s\+translate_\(on\|off\)\s*" "syn match vhdlPreProc "\(^\|\s\)--\s*simulation\s\+translate_\(on\|off\)\s*" +syn match vhdlPreProc "\(^\|\s\)--\s*pragma\s\+translate_\(on\|off\)\s*" syn match vhdlPreProc "\(^\|\s\)--\s*pragma\s\+synthesis_\(on\|off\)\s*" syn match vhdlPreProc "\(^\|\s\)--\s*synopsys\s\+translate_\(on\|off\)\s*" @@ -216,24 +243,24 @@ if version >= 508 || !exists("did_vhdl_syntax_inits") else command -nargs=+ HiLink hi def link <args> endif - - HiLink vhdlSpecial Special - HiLink vhdlStatement Statement - HiLink vhdlCharacter Character - HiLink vhdlString String - HiLink vhdlVector Number - HiLink vhdlBoolean Number - HiLink vhdlTodo Todo - HiLink vhdlFixme Fixme - HiLink vhdlComment Comment - HiLink vhdlNumber Number - HiLink vhdlTime Number - HiLink vhdlType Type - HiLink vhdlOperator Operator - HiLink vhdlError Error - HiLink vhdlAttribute Special - HiLink vhdlPreProc PreProc - + + HiLink vhdlSpecial Special + HiLink vhdlStatement Statement + HiLink vhdlCharacter Character + HiLink vhdlString String + HiLink vhdlVector Number + HiLink vhdlBoolean Number + HiLink vhdlTodo Todo + HiLink vhdlFixme Fixme + HiLink vhdlComment Comment + HiLink vhdlNumber Number + HiLink vhdlTime Number + HiLink vhdlType Type + HiLink vhdlOperator Operator + HiLink vhdlError Error + HiLink vhdlAttribute Special + HiLink vhdlPreProc PreProc + delcommand HiLink endif diff --git a/runtime/syntax/zsh.vim b/runtime/syntax/zsh.vim index 162577669f..0d385a35d0 100644 --- a/runtime/syntax/zsh.vim +++ b/runtime/syntax/zsh.vim @@ -2,7 +2,7 @@ " Language: Zsh shell script " Maintainer: Christian Brabandt <cb@256bit.org> " Previous Maintainer: Nikolai Weibull <now@bitwi.se> -" Latest Revision: 2015-12-25 +" Latest Revision: 2016-02-15 " License: Vim (see :h license) " Repository: https://github.com/chrisbra/vim-zsh @@ -13,19 +13,29 @@ endif let s:cpo_save = &cpo set cpo&vim -setlocal iskeyword+=- +if v:version > 704 || (v:version == 704 && has("patch1142")) + syn iskeyword @,48-57,_,192-255,#,- +else + setlocal iskeyword+=- +endif +if get(g:, 'zsh_fold_enable', 0) + setlocal foldmethod=syntax +endif syn keyword zshTodo contained TODO FIXME XXX NOTE syn region zshComment oneline start='\%(^\|\s*\)#' end='$' - \ contains=zshTodo,@Spell + \ contains=zshTodo,@Spell fold + +syn region zshComment start='^\s*#' end='^\%(\s*#\)\@!' + \ contains=zshTodo,@Spell fold syn match zshPreProc '^\%1l#\%(!\|compdef\|autoload\).*$' syn match zshQuoted '\\.' syn region zshString matchgroup=zshStringDelimiter start=+"+ end=+"+ - \ contains=zshQuoted,@zshDerefs,@zshSubst -syn region zshString matchgroup=zshStringDelimiter start=+'+ end=+'+ + \ contains=zshQuoted,@zshDerefs,@zshSubst fold +syn region zshString matchgroup=zshStringDelimiter start=+'+ end=+'+ fold " XXX: This should probably be more precise, but Zsh seems a bit confused about it itself syn region zshPOSIXString matchgroup=zshStringDelimiter start=+\$'+ \ end=+'+ contains=zshQuoted @@ -45,7 +55,7 @@ syn keyword zshException always syn keyword zshKeyword function nextgroup=zshKSHFunction skipwhite -syn match zshKSHFunction contained '\k\+' +syn match zshKSHFunction contained '\w\S\+' syn match zshFunction '^\s*\k\+\ze\s*()' syn match zshOperator '||\|&&\|;\|&!\=' @@ -307,19 +317,21 @@ syn match zshNumber '[+-]\=\d\+\.\d\+\>' " TODO: $[...] is the same as $((...)), so add that as well. syn cluster zshSubst contains=zshSubst,zshOldSubst,zshMathSubst syn region zshSubst matchgroup=zshSubstDelim transparent - \ start='\$(' skip='\\)' end=')' contains=TOP -syn region zshParentheses transparent start='(' skip='\\)' end=')' + \ start='\$(' skip='\\)' end=')' contains=TOP fold +syn region zshParentheses transparent start='(' skip='\\)' end=')' fold syn region zshMathSubst matchgroup=zshSubstDelim transparent \ start='\$((' skip='\\)' \ matchgroup=zshSubstDelim end='))' \ contains=zshParentheses,@zshSubst,zshNumber, - \ @zshDerefs,zshString keepend + \ @zshDerefs,zshString keepend fold syn region zshBrackets contained transparent start='{' skip='\\}' - \ end='}' + \ end='}' fold +syn region zshBrackets transparent start='{' skip='\\}' + \ end='}' contains=TOP fold syn region zshSubst matchgroup=zshSubstDelim start='\${' skip='\\}' - \ end='}' contains=@zshSubst,zshBrackets,zshQuoted,zshString + \ end='}' contains=@zshSubst,zshBrackets,zshQuoted,zshString fold syn region zshOldSubst matchgroup=zshSubstDelim start=+`+ skip=+\\`+ - \ end=+`+ contains=TOP,zshOldSubst + \ end=+`+ contains=TOP,zshOldSubst fold syn sync minlines=50 maxlines=90 syn sync match zshHereDocSync grouphere NONE '<<-\=\s*\%(\\\=\S\+\|\(["']\)\S\+\1\)' diff --git a/scripts/msgpack-gen.lua b/scripts/msgpack-gen.lua index 190af636dc..2da3c174f9 100644 --- a/scripts/msgpack-gen.lua +++ b/scripts/msgpack-gen.lua @@ -45,7 +45,7 @@ grammar = Ct((c_proto + c_comment + c_preproc + ws) ^ 1) assert(#arg >= 1) functions = {} --- names of all headers relative to the source root(for inclusion in the +-- names of all headers relative to the source root (for inclusion in the -- generated file) headers = {} -- output file(dispatch function + metadata serialized with msgpack) @@ -64,24 +64,22 @@ for i = 1, #arg - 1 do local tmp = grammar:match(input:read('*all')) for i = 1, #tmp do local fn = tmp[i] - if fn.noexport then - goto continue - end - functions[#functions + 1] = tmp[i] - if #fn.parameters ~= 0 and fn.parameters[1][2] == 'channel_id' then - -- this function should receive the channel id - fn.receives_channel_id = true - -- remove the parameter since it won't be passed by the api client - table.remove(fn.parameters, 1) - end - if #fn.parameters ~= 0 and fn.parameters[#fn.parameters][1] == 'error' then - -- function can fail if the last parameter type is 'Error' - fn.can_fail = true - -- remove the error parameter, msgpack has it's own special field - -- for specifying errors - fn.parameters[#fn.parameters] = nil + if not fn.noexport then + functions[#functions + 1] = tmp[i] + if #fn.parameters ~= 0 and fn.parameters[1][2] == 'channel_id' then + -- this function should receive the channel id + fn.receives_channel_id = true + -- remove the parameter since it won't be passed by the api client + table.remove(fn.parameters, 1) + end + if #fn.parameters ~= 0 and fn.parameters[#fn.parameters][1] == 'error' then + -- function can fail if the last parameter type is 'Error' + fn.can_fail = true + -- remove the error parameter, msgpack has it's own special field + -- for specifying errors + fn.parameters[#fn.parameters] = nil + end end - ::continue:: end input:close() end diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh index 7a0001769a..3997bd52b1 100755 --- a/scripts/vim-patch.sh +++ b/scripts/vim-patch.sh @@ -92,7 +92,7 @@ commit_message() { find_git_remote() { git remote -v \ - | awk '$2 ~ /github.com[:/]neovim\/neovim/ && $3 == "(fetch)" {print $1}' + | awk '$2 ~ /github.com[:\/]neovim\/neovim/ && $3 == "(fetch)" {print $1; exit}' } assign_commit_details() { @@ -137,7 +137,7 @@ get_vim_patch() { # Patch surgery: preprocess the patch. # - transform src/ paths to src/nvim/ local vim_full - vim_full="$(git show -1 --pretty=medium "${vim_commit}" \ + vim_full="$(git --no-pager show --color=never -1 --pretty=medium "${vim_commit}" \ | LC_ALL=C sed -e 's/\( [ab]\/src\)/\1\/nvim/g')" local neovim_branch="${BRANCH_PREFIX}${vim_version}" @@ -290,7 +290,7 @@ list_vim_patches() { is_missing="$(sed -n '/static int included_patches/,/}/p' "${NEOVIM_SOURCE_DIR}/src/nvim/version.c" | grep -x -e "[[:space:]]*//[[:space:]]${patch_number} NA.*" -e "[[:space:]]*${patch_number}," >/dev/null && echo "false" || echo "true")" vim_commit="${vim_tag#v}" - if (cd "${VIM_SOURCE_DIR}" && git show --name-only "v${vim_commit}" 2>/dev/null) | grep -q ^runtime; then + if (cd "${VIM_SOURCE_DIR}" && git --no-pager show --color=never --name-only "v${vim_commit}" 2>/dev/null) | grep -q ^runtime; then vim_commit="${vim_commit} (+runtime)" fi else diff --git a/.asan-blacklist b/src/.asan-blacklist index 63558170b3..63558170b3 100644 --- a/.asan-blacklist +++ b/src/.asan-blacklist diff --git a/.valgrind.supp b/src/.valgrind.supp index 8b630fcaaf..8b630fcaaf 100644 --- a/.valgrind.supp +++ b/src/.valgrind.supp diff --git a/Doxyfile b/src/Doxyfile index de31c8355f..de31c8355f 100644 --- a/Doxyfile +++ b/src/Doxyfile diff --git a/clint.py b/src/clint.py index c19ba4b7ae..efc5f18378 100755 --- a/clint.py +++ b/src/clint.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# vim: set fileencoding=utf-8 # # Copyright (c) 2009 Google Inc. All rights reserved. # @@ -217,6 +218,8 @@ _ERROR_CATEGORIES = [ 'whitespace/semicolon', 'whitespace/tab', 'whitespace/todo', + 'whitespace/line_continuation', + 'whitespace/cast', ] # The default state of the category filter. This is overrided by the --filter= @@ -2499,6 +2502,28 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error): 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'(?<!\bkvec_t)' + 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. diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index ab6f69f66c..d80add2835 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -1,6 +1,3 @@ -include(CheckLibraryExists) -include(CheckCCompilerFlag) - option(USE_GCOV "Enable gcov support" OFF) if(NOT CLANG_TSAN) @@ -78,6 +75,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}) @@ -95,7 +95,6 @@ set(CONV_SOURCES mbyte.c memline.c message.c - ops.c regexp.c screen.c search.c @@ -269,7 +268,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..5fb95a163f 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 @@ -41,6 +41,12 @@ typedef bool Boolean; typedef int64_t Integer; typedef double Float; +/// Maximum value of an Integer +#define API_INTEGER_MAX INT64_MAX + +/// Minimum value of an Integer +#define API_INTEGER_MIN INT64_MIN + typedef struct { char *data; size_t size; 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.c b/src/nvim/api/private/helpers.c index db3e499427..c88bf2127a 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -17,6 +17,13 @@ #include "nvim/map.h" #include "nvim/option.h" #include "nvim/option_defs.h" +#include "nvim/eval/typval_encode.h" +#include "nvim/lib/kvec.h" + +/// Helper structure for vim_to_object +typedef struct { + kvec_t(Object) stack; ///< Object stack. +} EncodedData; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/helpers.c.generated.h" @@ -310,6 +317,179 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) } } +#define TYPVAL_ENCODE_ALLOW_SPECIALS false + +#define TYPVAL_ENCODE_CONV_NIL() \ + kv_push(edata->stack, NIL) + +#define TYPVAL_ENCODE_CONV_BOOL(num) \ + kv_push(edata->stack, BOOLEAN_OBJ((Boolean)(num))) + +#define TYPVAL_ENCODE_CONV_NUMBER(num) \ + kv_push(edata->stack, INTEGER_OBJ((Integer)(num))) + +#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER TYPVAL_ENCODE_CONV_NUMBER + +#define TYPVAL_ENCODE_CONV_FLOAT(flt) \ + kv_push(edata->stack, FLOATING_OBJ((Float)(flt))) + +#define TYPVAL_ENCODE_CONV_STRING(str, len) \ + do { \ + const size_t len_ = (size_t)(len); \ + const char *const str_ = (const char *)(str); \ + assert(len_ == 0 || str_ != NULL); \ + kv_push(edata->stack, STRING_OBJ(((String) { \ + .data = xmemdupz((len_?str_:""), len_), \ + .size = len_ \ + }))); \ + } while (0) + +#define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING + +#define TYPVAL_ENCODE_CONV_EXT_STRING(str, len, type) \ + TYPVAL_ENCODE_CONV_NIL() + +#define TYPVAL_ENCODE_CONV_FUNC(fun) \ + TYPVAL_ENCODE_CONV_NIL() + +#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \ + kv_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 }))) + +#define TYPVAL_ENCODE_CONV_EMPTY_DICT() \ + kv_push(edata->stack, \ + DICTIONARY_OBJ(((Dictionary) { .capacity = 0, .size = 0 }))) + +static inline void typval_encode_list_start(EncodedData *const edata, + const size_t len) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL +{ + const Object obj = OBJECT_INIT; + kv_push(edata->stack, ARRAY_OBJ(((Array) { + .capacity = len, + .size = 0, + .items = xmalloc(len * sizeof(*obj.data.array.items)), + }))); +} + +#define TYPVAL_ENCODE_CONV_LIST_START(len) \ + typval_encode_list_start(edata, (size_t)(len)) + +static inline void typval_encode_between_list_items(EncodedData *const edata) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL +{ + Object item = kv_pop(edata->stack); + Object *const list = &kv_last(edata->stack); + assert(list->type == kObjectTypeArray); + assert(list->data.array.size < list->data.array.capacity); + list->data.array.items[list->data.array.size++] = item; +} + +#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS() \ + typval_encode_between_list_items(edata) + +static inline void typval_encode_list_end(EncodedData *const edata) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL +{ + typval_encode_between_list_items(edata); +#ifndef NDEBUG + const Object *const list = &kv_last(edata->stack); + assert(list->data.array.size == list->data.array.capacity); +#endif +} + +#define TYPVAL_ENCODE_CONV_LIST_END() \ + typval_encode_list_end(edata) + +static inline void typval_encode_dict_start(EncodedData *const edata, + const size_t len) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL +{ + const Object obj = OBJECT_INIT; + kv_push(edata->stack, DICTIONARY_OBJ(((Dictionary) { + .capacity = len, + .size = 0, + .items = xmalloc(len * sizeof(*obj.data.dictionary.items)), + }))); +} + +#define TYPVAL_ENCODE_CONV_DICT_START(len) \ + typval_encode_dict_start(edata, (size_t)(len)) + +#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(label, kv_pair) + +static inline void typval_encode_after_key(EncodedData *const edata) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL +{ + Object key = kv_pop(edata->stack); + Object *const dict = &kv_last(edata->stack); + assert(dict->type == kObjectTypeDictionary); + assert(dict->data.dictionary.size < dict->data.dictionary.capacity); + if (key.type == kObjectTypeString) { + dict->data.dictionary.items[dict->data.dictionary.size].key + = key.data.string; + } else { + api_free_object(key); + dict->data.dictionary.items[dict->data.dictionary.size].key + = STATIC_CSTR_TO_STRING("__INVALID_KEY__"); + } +} + +#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY() \ + typval_encode_after_key(edata) + +static inline void typval_encode_between_dict_items(EncodedData *const edata) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL +{ + Object val = kv_pop(edata->stack); + Object *const dict = &kv_last(edata->stack); + assert(dict->type == kObjectTypeDictionary); + assert(dict->data.dictionary.size < dict->data.dictionary.capacity); + dict->data.dictionary.items[dict->data.dictionary.size++].value = val; +} + +#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS() \ + typval_encode_between_dict_items(edata) + +static inline void typval_encode_dict_end(EncodedData *const edata) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL +{ + typval_encode_between_dict_items(edata); +#ifndef NDEBUG + const Object *const dict = &kv_last(edata->stack); + assert(dict->data.dictionary.size == dict->data.dictionary.capacity); +#endif +} + +#define TYPVAL_ENCODE_CONV_DICT_END() \ + typval_encode_dict_end(edata) + +#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ + TYPVAL_ENCODE_CONV_NIL() + +TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, object, EncodedData *const, edata) + +#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 + /// Convert a vim object to an `Object` instance, recursively expanding /// Arrays/Dictionaries. /// @@ -317,13 +497,12 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) /// @return The converted value Object vim_to_object(typval_T *obj) { - Object rv; - // We use a lookup table to break out of cyclic references - PMap(ptr_t) *lookup = pmap_new(ptr_t)(); - rv = vim_to_object_rec(obj, lookup); - // Free the table - pmap_free(ptr_t)(lookup); - return rv; + EncodedData edata = { .stack = KV_INITIAL_VALUE }; + encode_vim_to_object(&edata, obj, "vim_to_object argument"); + Object ret = kv_A(edata.stack, 0); + assert(kv_size(edata.stack) == 1); + kv_destroy(edata.stack); + return ret; } buf_T *find_buffer_by_handle(Buffer buffer, Error *err) @@ -633,131 +812,6 @@ Object copy_object(Object obj) } } -/// Recursion helper for the `vim_to_object`. This uses a pointer table -/// to avoid infinite recursion due to cyclic references -/// -/// @param obj The source object -/// @param lookup Lookup table containing pointers to all processed objects -/// @return The converted value -static Object vim_to_object_rec(typval_T *obj, PMap(ptr_t) *lookup) -{ - Object rv = OBJECT_INIT; - - if (obj->v_type == VAR_LIST || obj->v_type == VAR_DICT) { - // Container object, add it to the lookup table - if (pmap_has(ptr_t)(lookup, obj)) { - // It's already present, meaning we alredy processed it so just return - // nil instead. - return rv; - } - pmap_put(ptr_t)(lookup, obj, NULL); - } - - switch (obj->v_type) { - case VAR_SPECIAL: - switch (obj->vval.v_special) { - case kSpecialVarTrue: - case kSpecialVarFalse: { - rv.type = kObjectTypeBoolean; - rv.data.boolean = (obj->vval.v_special == kSpecialVarTrue); - break; - } - case kSpecialVarNull: { - rv.type = kObjectTypeNil; - break; - } - } - break; - - case VAR_STRING: - rv.type = kObjectTypeString; - rv.data.string = cstr_to_string((char *) obj->vval.v_string); - break; - - case VAR_NUMBER: - rv.type = kObjectTypeInteger; - rv.data.integer = obj->vval.v_number; - break; - - case VAR_FLOAT: - rv.type = kObjectTypeFloat; - rv.data.floating = obj->vval.v_float; - break; - - case VAR_LIST: - { - list_T *list = obj->vval.v_list; - listitem_T *item; - - if (list != NULL) { - rv.type = kObjectTypeArray; - assert(list->lv_len >= 0); - rv.data.array.size = (size_t)list->lv_len; - rv.data.array.items = xmalloc(rv.data.array.size * sizeof(Object)); - - uint32_t i = 0; - for (item = list->lv_first; item != NULL; item = item->li_next) { - rv.data.array.items[i] = vim_to_object_rec(&item->li_tv, lookup); - i++; - } - } - } - break; - - case VAR_DICT: - { - dict_T *dict = obj->vval.v_dict; - hashtab_T *ht; - uint64_t todo; - hashitem_T *hi; - dictitem_T *di; - - if (dict != NULL) { - ht = &obj->vval.v_dict->dv_hashtab; - todo = ht->ht_used; - rv.type = kObjectTypeDictionary; - - // Count items - rv.data.dictionary.size = 0; - for (hi = ht->ht_array; todo > 0; ++hi) { - if (!HASHITEM_EMPTY(hi)) { - todo--; - rv.data.dictionary.size++; - } - } - - rv.data.dictionary.items = - xmalloc(rv.data.dictionary.size * sizeof(KeyValuePair)); - todo = ht->ht_used; - uint32_t i = 0; - - // Convert all - for (hi = ht->ht_array; todo > 0; ++hi) { - if (!HASHITEM_EMPTY(hi)) { - di = dict_lookup(hi); - // Convert key - rv.data.dictionary.items[i].key = - cstr_to_string((char *) hi->hi_key); - // Convert value - rv.data.dictionary.items[i].value = - vim_to_object_rec(&di->di_tv, lookup); - todo--; - i++; - } - } - } - } - break; - - case VAR_UNKNOWN: - case VAR_FUNC: - break; - } - - return rv; -} - - static void set_option_value_for(char *key, int numval, char *stringval, diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index a0f14ac7a4..a946e35149 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -8,69 +8,70 @@ #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 FLOATING_OBJ(f) ((Object) { \ + .type = kObjectTypeFloat, \ + .data.floating = f }) + +#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}) +/// Create a new String instance, putting data in allocated memory +/// +/// @param[in] s String to work with. Must be a string literal. +#define STATIC_CSTR_TO_STRING(s) ((String){ \ + .data = xmemdupz(s, sizeof(s) - 1), \ + .size = sizeof(s) - 1 }) + // Helpers used by the generated msgpack-rpc api wrappers #define api_init_boolean #define api_init_integer diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 46d72b847d..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 @@ -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..438a85dd5d 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1249,6 +1249,10 @@ void enter_buffer(buf_T *buf) /* mark cursor position as being invalid */ curwin->w_valid = 0; + if (buf->terminal) { + terminal_resize(buf->terminal, curwin->w_width, curwin->w_height); + } + /* Make sure the buffer is loaded. */ if (curbuf->b_ml.ml_mfp == NULL) { /* need to load the file */ /* If there is no filetype, allow for detecting one. Esp. useful for @@ -1534,6 +1538,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 +2853,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 +2897,7 @@ int build_stl_str_hl( Normal, Empty, Group, - Middle, + Separate, Highlight, TabPage, ClickFunc, @@ -2993,14 +2998,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 +3844,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++; + } + } + + // 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++; + } + } - // Adjust the offset of any items after the middle - for (item_idx++; item_idx < itemcnt; item_idx++) - item[item_idx].start += maxwidth - width; + int standard_spaces = (maxwidth - width) / num_separators; + int final_spaces = (maxwidth - width) - + standard_spaces * (num_separators - 1); - width = maxwidth; - break; + 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 +4981,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..22ca0fb0cc 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -43,20 +43,29 @@ static bool chartab_initialized = false; #define GET_CHARTAB(buf, c) \ ((buf)->b_chartab[(unsigned)(c) >> 6] & (1ull << ((c) & 0x3f))) -/// Fill chartab[]. Also fills curbuf->b_chartab[] with flags for keyword +// Table used below, see init_chartab() for an explanation +static char_u g_chartab[256]; + +// Flags for g_chartab[]. +#define CT_CELL_MASK 0x07 ///< mask: nr of display cells (1, 2 or 4) +#define CT_PRINT_CHAR 0x10 ///< flag: set for printable chars +#define CT_ID_CHAR 0x20 ///< flag: set for ID chars +#define CT_FNAME_CHAR 0x40 ///< flag: set for file name chars + +/// Fill g_chartab[]. Also fills curbuf->b_chartab[] with flags for keyword /// characters for current buffer. /// /// Depends on the option settings 'iskeyword', 'isident', 'isfname', /// 'isprint' and 'encoding'. /// -/// The index in chartab[] depends on 'encoding': +/// The index in g_chartab[] depends on 'encoding': /// - For non-multi-byte index with the byte (same as the character). /// - For DBCS index with the first byte. /// - For UTF-8 index with the character (when first byte is up to 0x80 it is /// the same as the character, if the first byte is 0x80 and above it depends /// on further bytes). /// -/// The contents of chartab[]: +/// The contents of g_chartab[]: /// - The lower two bits, masked by CT_CELL_MASK, give the number of display /// cells the character occupies (1 or 2). Not valid for UTF-8 above 0x80. /// - CT_PRINT_CHAR bit is set when the character is printable (no need to @@ -94,32 +103,32 @@ int buf_init_chartab(buf_T *buf, int global) c = 0; while (c < ' ') { - chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2; + g_chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2; } while (c <= '~') { - chartab[c++] = 1 + CT_PRINT_CHAR; + g_chartab[c++] = 1 + CT_PRINT_CHAR; } if (p_altkeymap) { while (c < YE) { - chartab[c++] = 1 + CT_PRINT_CHAR; + g_chartab[c++] = 1 + CT_PRINT_CHAR; } } while (c < 256) { if (enc_utf8 && (c >= 0xa0)) { // UTF-8: bytes 0xa0 - 0xff are printable (latin1) - chartab[c++] = CT_PRINT_CHAR + 1; + g_chartab[c++] = CT_PRINT_CHAR + 1; } else if ((enc_dbcs == DBCS_JPNU) && (c == 0x8e)) { // euc-jp characters starting with 0x8e are single width - chartab[c++] = CT_PRINT_CHAR + 1; + g_chartab[c++] = CT_PRINT_CHAR + 1; } else if ((enc_dbcs != 0) && (MB_BYTE2LEN(c) == 2)) { // other double-byte chars can be printable AND double-width - chartab[c++] = CT_PRINT_CHAR + 2; + g_chartab[c++] = CT_PRINT_CHAR + 2; } else { // the rest is unprintable by default - chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2; + g_chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2; } } @@ -128,7 +137,7 @@ int buf_init_chartab(buf_T *buf, int global) if (((enc_dbcs != 0) && (MB_BYTE2LEN(c) > 1)) || ((enc_dbcs == DBCS_JPNU) && (c == 0x8e)) || (enc_utf8 && (c >= 0xa0))) { - chartab[c] |= CT_FNAME_CHAR; + g_chartab[c] |= CT_FNAME_CHAR; } } } @@ -231,9 +240,9 @@ int buf_init_chartab(buf_T *buf, int global) if (i == 0) { // (re)set ID flag if (tilde) { - chartab[c] &= (uint8_t)~CT_ID_CHAR; + g_chartab[c] &= (uint8_t)~CT_ID_CHAR; } else { - chartab[c] |= CT_ID_CHAR; + g_chartab[c] |= CT_ID_CHAR; } } else if (i == 1) { // (re)set printable @@ -244,20 +253,20 @@ int buf_init_chartab(buf_T *buf, int global) || (p_altkeymap && (F_isalpha(c) || F_isdigit(c)))) && !(enc_dbcs && (MB_BYTE2LEN(c) == 2))) { if (tilde) { - chartab[c] = (uint8_t)((chartab[c] & ~CT_CELL_MASK) - + ((dy_flags & DY_UHEX) ? 4 : 2)); - chartab[c] &= (uint8_t)~CT_PRINT_CHAR; + g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK) + + ((dy_flags & DY_UHEX) ? 4 : 2)); + g_chartab[c] &= (uint8_t)~CT_PRINT_CHAR; } else { - chartab[c] = (uint8_t)((chartab[c] & ~CT_CELL_MASK) + 1); - chartab[c] |= CT_PRINT_CHAR; + g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK) + 1); + g_chartab[c] |= CT_PRINT_CHAR; } } } else if (i == 2) { // (re)set fname flag if (tilde) { - chartab[c] &= (uint8_t)~CT_FNAME_CHAR; + g_chartab[c] &= (uint8_t)~CT_FNAME_CHAR; } else { - chartab[c] |= CT_FNAME_CHAR; + g_chartab[c] |= CT_FNAME_CHAR; } } else { // i == 3 // (re)set keyword flag @@ -492,9 +501,9 @@ char_u* str_foldcase(char_u *str, int orglen, char_u *buf, int buflen) return buf; } -// Catch 22: chartab[] can't be initialized before the options are +// Catch 22: g_chartab[] can't be initialized before the options are // initialized, and initializing options may cause transchar() to be called! -// When chartab_initialized == false don't use chartab[]. +// When chartab_initialized == false don't use g_chartab[]. // Does NOT work for multi-byte characters, c must be <= 255. // Also doesn't work for the first byte of a multi-byte, "c" must be a // character! @@ -633,7 +642,7 @@ int byte2cells(int b) if (enc_utf8 && (b >= 0x80)) { return 0; } - return chartab[b] & CT_CELL_MASK; + return g_chartab[b] & CT_CELL_MASK; } /// Return number of display cells occupied by character "c". @@ -665,7 +674,7 @@ int char2cells(int c) return 2; } } - return chartab[c & 0xff] & CT_CELL_MASK; + return g_chartab[c & 0xff] & CT_CELL_MASK; } /// Return number of display cells occupied by character at "*p". @@ -682,7 +691,7 @@ int ptr2cells(char_u *p) } // For DBCS we can tell the cell count from the first byte. - return chartab[*p] & CT_CELL_MASK; + return g_chartab[*p] & CT_CELL_MASK; } /// Return the number of character cells string "s" will take on the screen, @@ -806,7 +815,7 @@ unsigned int win_linetabsize(win_T *wp, char_u *line, colnr_T len) bool vim_isIDc(int c) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - return c > 0 && c < 0x100 && (chartab[c] & CT_ID_CHAR); + return c > 0 && c < 0x100 && (g_chartab[c] & CT_ID_CHAR); } /// Check that "c" is a keyword character: @@ -878,7 +887,7 @@ bool vim_iswordp_buf(char_u *p, buf_T *buf) bool vim_isfilec(int c) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - return c >= 0x100 || (c > 0 && (chartab[c] & CT_FNAME_CHAR)); + return c >= 0x100 || (c > 0 && (g_chartab[c] & CT_FNAME_CHAR)); } /// Check that "c" is a valid file-name character or a wildcard character @@ -906,7 +915,7 @@ bool vim_isprintc(int c) if (enc_utf8 && (c >= 0x100)) { return utf_printable(c); } - return c >= 0x100 || (c > 0 && (chartab[c] & CT_PRINT_CHAR)); + return c >= 0x100 || (c > 0 && (g_chartab[c] & CT_PRINT_CHAR)); } /// Strict version of vim_isprintc(c), don't return true if "c" is the head @@ -925,7 +934,7 @@ bool vim_isprintc_strict(int c) if (enc_utf8 && (c >= 0x100)) { return utf_printable(c); } - return c >= 0x100 || (c > 0 && (chartab[c] & CT_PRINT_CHAR)); + return c >= 0x100 || (c > 0 && (g_chartab[c] & CT_PRINT_CHAR)); } /// like chartabsize(), but also check for line breaks on the screen @@ -1247,7 +1256,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, if (enc_utf8 && (c >= 0x80)) { incr = utf_ptr2cells(ptr); } else { - incr = CHARSIZE(c); + incr = g_chartab[c] & CT_CELL_MASK; } // If a double-cell char doesn't fit at the end of a line @@ -1261,7 +1270,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, head = 1; } } else { - incr = CHARSIZE(c); + incr = g_chartab[c] & CT_CELL_MASK; } } @@ -1582,7 +1591,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 +1622,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/charset.h b/src/nvim/charset.h index 995ad123ae..78d6f2a76c 100644 --- a/src/nvim/charset.h +++ b/src/nvim/charset.h @@ -1,14 +1,6 @@ #ifndef NVIM_CHARSET_H #define NVIM_CHARSET_H -/* - * Flags for chartab[]. - */ -#define CT_CELL_MASK 0x07 /* mask: nr of display cells (1, 2 or 4) */ -#define CT_PRINT_CHAR 0x10 /* flag: set for printable chars */ -#define CT_ID_CHAR 0x20 /* flag: set for ID chars */ -#define CT_FNAME_CHAR 0x40 /* flag: set for file name chars */ - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "charset.h.generated.h" #endif diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index 9525024c1b..aad145b3e5 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -1757,12 +1757,12 @@ char_u* keymap_init(void) vim_snprintf(buf, buflen, "keymap/%s_%s.vim", curbuf->b_p_keymap, p_enc); - if (source_runtime((char_u *)buf, FALSE) == FAIL) { + if (source_runtime((char_u *)buf, 0) == FAIL) { // try finding "keymap/'keymap'.vim" in 'runtimepath' vim_snprintf(buf, buflen, "keymap/%s.vim", curbuf->b_p_keymap); - if (source_runtime((char_u *)buf, FALSE) == FAIL) { + if (source_runtime((char_u *)buf, 0) == FAIL) { xfree(buf); return (char_u *)N_("E544: Keymap file not found"); } 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 420a712e3e..47d44b148a 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" @@ -90,6 +91,7 @@ #include "nvim/os/input.h" #include "nvim/event/loop.h" #include "nvim/lib/queue.h" +#include "nvim/eval/typval_encode.h" #define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */ @@ -433,6 +435,7 @@ typedef struct { TimeWatcher tw; int timer_id; int repeat_count; + long timeout; bool stopped; ufunc_T *callback; } timer_T; @@ -507,6 +510,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 +1893,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 +2981,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 +2999,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 +6686,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 }, @@ -6700,6 +6715,7 @@ static struct fst { { "byteidx", 2, 2, f_byteidx }, { "byteidxcomp", 2, 2, f_byteidxcomp }, { "call", 2, 3, f_call }, + { "capture", 1, 1, f_capture }, { "ceil", 1, 1, f_ceil }, { "changenr", 0, 0, f_changenr }, { "char2nr", 1, 2, f_char2nr }, @@ -7454,6 +7470,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 +7554,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; } } @@ -7659,7 +7668,8 @@ static void f_assert_exception(typval_T *argvars, typval_T *rettv) ga_concat(&ga, (char_u *)"v:exception is not set"); assert_error(&ga); ga_clear(&ga); - } else if (strstr((char *)vimvars[VV_EXCEPTION].vv_str, error) == NULL) { + } else if (error != NULL + && strstr((char *)vimvars[VV_EXCEPTION].vv_str, error) == NULL) { prepare_assert_error(&ga); fill_assert_error(&ga, &argvars[1], NULL, &argvars[0], &vimvars[VV_EXCEPTION].vv_tv); @@ -8077,6 +8087,38 @@ static void f_call(typval_T *argvars, typval_T *rettv) (void)func_call(func, &argvars[1], selfdict, rettv); } +// "capture(command)" function +static void f_capture(typval_T *argvars, typval_T *rettv) +{ + int save_msg_silent = msg_silent; + garray_T *save_capture_ga = capture_ga; + + if (check_secure()) { + return; + } + + garray_T capture_local; + capture_ga = &capture_local; + ga_init(capture_ga, (int)sizeof(char), 80); + + msg_silent++; + if (argvars[0].v_type != VAR_LIST) { + do_cmdline_cmd((char *)get_tv_string(&argvars[0])); + } else if (argvars[0].vval.v_list != NULL) { + for (listitem_T *li = argvars[0].vval.v_list->lv_first; + li != NULL; li = li->li_next) { + do_cmdline_cmd((char *)get_tv_string(&li->li_tv)); + } + } + msg_silent = save_msg_silent; + + ga_append(capture_ga, NUL); + rettv->v_type = VAR_STRING; + rettv->vval.v_string = capture_ga->ga_data; + + capture_ga = save_capture_ga; +} + /* * "ceil({float})" function */ @@ -9887,7 +9929,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. @@ -9916,26 +9958,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.")); @@ -9944,16 +9987,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; @@ -9988,6 +10029,9 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv) } } break; + case kCdScopeInvalid: + // We should never get here + assert(false); } if (from) { @@ -10459,9 +10503,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); @@ -10714,6 +10782,7 @@ static void f_has(typval_T *argvars, typval_T *rettv) "mouse", "multi_byte", "multi_lang", + "packages", "path_extra", "persistent_undo", "postscript", @@ -10835,7 +10904,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. @@ -10860,25 +10929,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.")); @@ -10887,16 +10957,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; @@ -10917,6 +10985,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); } } @@ -11726,8 +11797,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; @@ -11737,7 +11821,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) { @@ -11812,7 +11896,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. @@ -11890,7 +11974,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); @@ -14891,7 +14975,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) @@ -14902,7 +14987,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; } @@ -15078,13 +15164,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 /* @@ -15104,14 +15195,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); @@ -15122,7 +15213,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; @@ -15131,7 +15222,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; @@ -15139,12 +15230,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); @@ -15185,9 +15278,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; @@ -15197,19 +15291,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 @@ -15242,6 +15339,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 { @@ -15252,61 +15355,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; } } @@ -15322,19 +15434,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; @@ -15350,21 +15463,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; @@ -15383,6 +15499,9 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) xfree(ptrs); } + +theend: + sortinfo = old_sortinfo; } /// "sort"({list})" function @@ -16419,8 +16538,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; @@ -16428,7 +16560,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"); @@ -16443,11 +16575,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]; @@ -16514,6 +16641,9 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv) } if (dict_find(dict, (char_u *)"repeat", -1) != NULL) { repeat = get_dict_number(dict, (char_u *)"repeat"); + if (repeat == 0) { + repeat = 1; + } } } @@ -16531,11 +16661,12 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv) timer = xmalloc(sizeof *timer); timer->stopped = false; timer->repeat_count = repeat; + timer->timeout = timeout; 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, @@ -16568,7 +16699,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) { @@ -16585,6 +16716,14 @@ static void timer_due_cb(TimeWatcher *tw, void *data) call_user_func(timer->callback, ARRAY_SIZE(argv), argv, &rettv, curwin->w_cursor.lnum, curwin->w_cursor.lnum, NULL); clear_tv(&rettv); + + if (!timer->stopped && timer->timeout == 0) { + // special case: timeout=0 means the callback will be + // invoked again on the next event loop tick. + // we don't use uv_idle_t to not spin the event loop + // when the main loop is blocked. + time_watcher_start(&timer->tw, timer_due_cb, 0, 0); + } } static void timer_stop(timer_T *timer) @@ -16608,6 +16747,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 */ @@ -17707,7 +17854,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) { @@ -17723,7 +17871,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++; @@ -17737,7 +17886,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) { @@ -18014,45 +18164,147 @@ void free_tv(typval_T *varp) } } -/* - * Free the memory for a variable value and set the value to NULL or 0. - */ +#define TYPVAL_ENCODE_ALLOW_SPECIALS false + +#define TYPVAL_ENCODE_CONV_NIL() \ + do { \ + tv->vval.v_special = kSpecialVarFalse; \ + tv->v_lock = VAR_UNLOCKED; \ + } while (0) + +#define TYPVAL_ENCODE_CONV_BOOL(ignored) \ + TYPVAL_ENCODE_CONV_NIL() + +#define TYPVAL_ENCODE_CONV_NUMBER(ignored) \ + do { \ + (void)ignored; \ + tv->vval.v_number = 0; \ + tv->v_lock = VAR_UNLOCKED; \ + } while (0) + +#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(ignored) \ + assert(false) + +#define TYPVAL_ENCODE_CONV_FLOAT(ignored) \ + do { \ + tv->vval.v_float = 0; \ + tv->v_lock = VAR_UNLOCKED; \ + } while (0) + +#define TYPVAL_ENCODE_CONV_STRING(str, ignored) \ + do { \ + xfree(str); \ + tv->vval.v_string = NULL; \ + tv->v_lock = VAR_UNLOCKED; \ + } while (0) + +#define TYPVAL_ENCODE_CONV_STR_STRING(ignored1, ignored2) + +#define TYPVAL_ENCODE_CONV_EXT_STRING(ignored1, ignored2, ignored3) + +#define TYPVAL_ENCODE_CONV_FUNC(fun) \ + do { \ + func_unref(fun); \ + if (fun != empty_string) { \ + xfree(fun); \ + } \ + tv->vval.v_string = NULL; \ + tv->v_lock = VAR_UNLOCKED; \ + } while (0) + +#define TYPVAL_ENCODE_CONV_EMPTY_LIST() \ + do { \ + list_unref(tv->vval.v_list); \ + tv->vval.v_list = NULL; \ + tv->v_lock = VAR_UNLOCKED; \ + } while (0) + +#define TYPVAL_ENCODE_CONV_EMPTY_DICT() \ + do { \ + dict_unref(tv->vval.v_dict); \ + tv->vval.v_dict = NULL; \ + tv->v_lock = VAR_UNLOCKED; \ + } while (0) + +#define TYPVAL_ENCODE_CONV_LIST_START(ignored) \ + do { \ + if (tv->vval.v_list->lv_refcount > 1) { \ + tv->vval.v_list->lv_refcount--; \ + tv->vval.v_list = NULL; \ + tv->v_lock = VAR_UNLOCKED; \ + return OK; \ + } \ + } while (0) + +#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS() + +#define TYPVAL_ENCODE_CONV_LIST_END() \ + do { \ + typval_T *const cur_tv = cur_mpsv->tv; \ + assert(cur_tv->v_type == VAR_LIST); \ + list_unref(cur_tv->vval.v_list); \ + cur_tv->vval.v_list = NULL; \ + cur_tv->v_lock = VAR_UNLOCKED; \ + } while (0) + +#define TYPVAL_ENCODE_CONV_DICT_START(ignored) \ + do { \ + if (tv->vval.v_dict->dv_refcount > 1) { \ + tv->vval.v_dict->dv_refcount--; \ + tv->vval.v_dict = NULL; \ + tv->v_lock = VAR_UNLOCKED; \ + return OK; \ + } \ + } while (0) + +#define TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK(ignored1, ignored2) + +#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY() + +#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS() + +#define TYPVAL_ENCODE_CONV_DICT_END() \ + do { \ + typval_T *const cur_tv = cur_mpsv->tv; \ + assert(cur_tv->v_type == VAR_DICT); \ + dict_unref(cur_tv->vval.v_dict); \ + cur_tv->vval.v_dict = NULL; \ + cur_tv->v_lock = VAR_UNLOCKED; \ + } while (0) + +#define TYPVAL_ENCODE_CONV_RECURSE(ignored1, ignored2) + +TYPVAL_ENCODE_DEFINE_CONV_FUNCTIONS(static, nothing, void *, ignored) + +#undef TYPVAL_ENCODE_ALLOW_SPECIALS +#undef TYPVAL_ENCODE_CONV_NIL +#undef TYPVAL_ENCODE_CONV_BOOL +#undef TYPVAL_ENCODE_CONV_NUMBER +#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER +#undef TYPVAL_ENCODE_CONV_FLOAT +#undef TYPVAL_ENCODE_CONV_STRING +#undef TYPVAL_ENCODE_CONV_STR_STRING +#undef TYPVAL_ENCODE_CONV_EXT_STRING +#undef TYPVAL_ENCODE_CONV_FUNC +#undef TYPVAL_ENCODE_CONV_EMPTY_LIST +#undef TYPVAL_ENCODE_CONV_EMPTY_DICT +#undef TYPVAL_ENCODE_CONV_LIST_START +#undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS +#undef TYPVAL_ENCODE_CONV_LIST_END +#undef TYPVAL_ENCODE_CONV_DICT_START +#undef TYPVAL_ENCODE_CONV_SPECIAL_DICT_KEY_CHECK +#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY +#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS +#undef TYPVAL_ENCODE_CONV_DICT_END +#undef TYPVAL_ENCODE_CONV_RECURSE + +/// Free memory for a variable value and set the value to NULL or 0 +/// +/// @param[in,out] varp Value to free. void clear_tv(typval_T *varp) { - if (varp != NULL) { - switch (varp->v_type) { - case VAR_FUNC: - func_unref(varp->vval.v_string); - if (varp->vval.v_string != empty_string) { - xfree(varp->vval.v_string); - } - varp->vval.v_string = NULL; - break; - case VAR_STRING: - xfree(varp->vval.v_string); - varp->vval.v_string = NULL; - break; - case VAR_LIST: - list_unref(varp->vval.v_list); - varp->vval.v_list = NULL; - break; - case VAR_DICT: - dict_unref(varp->vval.v_dict); - varp->vval.v_dict = NULL; - break; - case VAR_NUMBER: - varp->vval.v_number = 0; - break; - case VAR_FLOAT: - varp->vval.v_float = 0.0; - break; - case VAR_SPECIAL: - varp->vval.v_special = kSpecialVarFalse; - break; - case VAR_UNKNOWN: - break; - } - varp->v_lock = 0; + if (varp != NULL && varp->v_type != VAR_UNKNOWN) { + encode_vim_to_nothing(varp, varp, "clear_tv argument"); } } @@ -19917,11 +20169,15 @@ theend: */ static int eval_fname_script(char_u *p) { - if (p[0] == '<' && (STRNICMP(p + 1, "SID>", 4) == 0 - || STRNICMP(p + 1, "SNR>", 4) == 0)) + // Use mb_stricmp() because in Turkish comparing the "I" may not work with + // the standard library function. + if (p[0] == '<' && (mb_strnicmp(p + 1, (char_u *)"SID>", 4) == 0 + || mb_strnicmp(p + 1, (char_u *)"SNR>", 4) == 0)) { return 5; - if (p[0] == 's' && p[1] == ':') + } + if (p[0] == 's' && p[1] == ':') { return 2; + } return 0; } @@ -20246,9 +20502,10 @@ script_autoload ( tofree = NULL; } - /* Try loading the package from $VIMRUNTIME/autoload/<name>.vim */ - if (source_runtime(scriptname, FALSE) == OK) - ret = TRUE; + // Try loading the package from $VIMRUNTIME/autoload/<name>.vim + if (source_runtime(scriptname, 0) == OK) { + ret = true; + } } xfree(tofree); @@ -21704,7 +21961,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; @@ -21712,11 +21970,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; @@ -21728,6 +21986,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; } @@ -21814,7 +22073,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 @@ -22076,17 +22335,19 @@ 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; + static int has_clipboard = -1; + static int has_python = -1; + static int has_python3 = -1; + static int has_ruby = -1; if (!strcmp(name, "clipboard")) { check_provider(clipboard); @@ -22097,14 +22358,16 @@ bool eval_has_provider(char *name) } else if (!strcmp(name, "python")) { check_provider(python); return has_python; + } else if (!strcmp(name, "ruby")) { + check_provider(ruby); + return has_ruby; } 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..670437ceda 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, key) -#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 */ \ @@ -761,15 +379,14 @@ encode_vim_to_##name##_error_ret: \ } \ vim_snprintf(ebuf, ARRAY_SIZE(ebuf), "{E724@%zu}", backref); \ ga_concat(gap, &ebuf[0]); \ - 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 +413,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 */ \ @@ -808,30 +425,29 @@ DEFINE_VIML_CONV_FUNCTIONS(, echo, garray_T *const, gap) EMSG(_("E724: unable to correctly dump variable " \ "with self-referencing container")); \ } \ - 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 +635,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) @@ -1044,9 +660,8 @@ static inline int convert_to_json_string(garray_T *const gap, /// Check whether given key can be used in json_encode() /// /// @param[in] tv Key to check. -static inline bool check_json_key(const typval_T *const tv) +bool encode_check_json_key(const typval_T *const tv) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE - FUNC_ATTR_ALWAYS_INLINE { if (tv->v_type == VAR_STRING) { return true; @@ -1080,38 +695,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, key) \ do { \ - if (!check_json_key(&kv_pair->lv_first->li_tv)) { \ + if (!encode_check_json_key(&key)) { \ 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 +796,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 +807,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 +818,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 +829,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 +861,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, key) -#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..98fa7b26c6 --- /dev/null +++ b/src/nvim/eval/typval_encode.h @@ -0,0 +1,570 @@ +/// @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 key typval_T key to check. + +/// @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. + typval_T *tv; ///< Currently converted typval_T. + 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_withinit_t(MPConvStackVal, 8) MPConvStack; + +// Defines for MPConvStack +#define _mp_size kv_size +#define _mp_init kvi_init +#define _mp_destroy kvi_destroy +#define _mp_push kvi_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. +/// @param conv_type Type of the conversion, @see MPConvStackValType. +#define _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val, copyID_attr, conv_type) \ + do { \ + if ((val)->copyID_attr == copyID) { \ + TYPVAL_ENCODE_CONV_RECURSE((val), conv_type); \ + return OK; \ + } \ + (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 name Name of the target converter. +/// @param firstargtype Type of the first argument. It will be used to return +/// the results. +/// @param firstargname Name of the first argument. +#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, \ + .tv = tv, \ + .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) { \ + .tv = tv, \ + .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) { \ + .tv = tv, \ + .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) { \ + .tv = tv, \ + .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->lv_first->li_tv); \ + 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/eval_defs.h b/src/nvim/eval_defs.h index 8ffc0c98ce..d5c9b2c1ec 100644 --- a/src/nvim/eval_defs.h +++ b/src/nvim/eval_defs.h @@ -155,6 +155,10 @@ typedef struct list_stack_S { /// Convert a hashitem key pointer to a dictitem pointer #define HIKEY2DI(p) ((dictitem_T *)(p - offsetof(dictitem_T, di_key))) +/// Convert a hashitem value pointer to a dictitem pointer +#define HIVAL2DI(p) \ + ((dictitem_T *)(((char *)p) - offsetof(dictitem_T, di_tv))) + /// Convert a hashitem pointer to a dictitem pointer #define HI2DI(hi) HIKEY2DI((hi)->hi_key) 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 3c8c08e235..317e40e43a 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; @@ -332,9 +332,61 @@ static void process_close(Process *proc) } } +/// Flush output stream. +/// +/// @param proc Process, for which an output stream should be flushed. +/// @param stream Stream to flush. +static void flush_stream(Process *proc, Stream *stream) + FUNC_ATTR_NONNULL_ARG(1) +{ + if (!stream || stream->closed) { + return; + } + + // Maximal remaining data size of terminated process is system + // buffer size. + // Also helps with a child process that keeps the output streams open. If it + // keeps sending data, we only accept as much data as the system buffer size. + // Otherwise this would block cleanup/teardown. + int system_buffer_size = 0; + int err = uv_recv_buffer_size((uv_handle_t *)&stream->uv.pipe, + &system_buffer_size); + if (err) { + system_buffer_size = (int)rbuffer_capacity(stream->buffer); + } + + size_t max_bytes = stream->num_bytes + (size_t)system_buffer_size; + + // Read remaining data. + while (!stream->closed && stream->num_bytes < max_bytes) { + // Remember number of bytes before polling + size_t num_bytes = stream->num_bytes; + + // Poll for data and process the generated events. + loop_poll_events(proc->loop, 0); + if (proc->events) { + queue_process_events(proc->events); + } + + // Stream can be closed if it is empty. + if (num_bytes == stream->num_bytes) { + if (stream->read_cb) { + // Stream callback could miss EOF handling if a child keeps the stream + // open. + stream->read_cb(stream, stream->buffer, 0, stream->data, true); + } + break; + } + } +} + static void process_close_handles(void **argv) { Process *proc = argv[0]; + + flush_stream(proc, proc->out); + flush_stream(proc, proc->err); + process_close_streams(proc); process_close(proc); } @@ -349,11 +401,12 @@ static void on_process_exit(Process *proc) uv_timer_stop(&loop->children_kill_timer); } - // Process handles are closed in the next event loop tick. This is done to - // give libuv more time to read data from the OS after the process exits(If - // process_close_streams is called with data still in the OS buffer, we lose - // it) - CREATE_EVENT(proc->events, process_close_handles, 1, proc); + // Process has terminated, but there could still be data to be read from the + // OS. We are still in the libuv loop, so we cannot call code that polls for + // more data directly. Instead delay the reading after the libuv loop by + // queueing process_close_handles() as an event. + Queue *queue = proc->events ? proc->events : loop->events; + CREATE_EVENT(queue, process_close_handles, 1, proc); } static void on_process_stream_close(Stream *stream, void *data) 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/event/rstream.c b/src/nvim/event/rstream.c index 9f3fbc25ff..a520143064 100644 --- a/src/nvim/event/rstream.c +++ b/src/nvim/event/rstream.c @@ -100,6 +100,10 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf) { Stream *stream = uvstream->data; + if (cnt > 0) { + stream->num_bytes += (size_t)cnt; + } + if (cnt <= 0) { if (cnt != UV_ENOBUFS // cnt == 0 means libuv asked for a buffer and decided it wasn't needed: @@ -185,10 +189,6 @@ static void read_event(void **argv) static void invoke_read_cb(Stream *stream, size_t count, bool eof) { - if (stream->closed) { - return; - } - // Don't let the stream be closed before the event is processed. stream->pending_reqs++; diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c index 93cc592683..cdaf40849b 100644 --- a/src/nvim/event/socket.c +++ b/src/nvim/event/socket.c @@ -103,7 +103,7 @@ int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb) // Libuv converts ENOENT to EACCES for Windows compatibility, but if // the parent directory does not exist, ENOENT would be more accurate. *path_tail((char_u *)watcher->addr) = NUL; - if (!os_file_exists((char_u *)watcher->addr)) { + if (!os_path_exists((char_u *)watcher->addr)) { result = -ENOENT; } } diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c index 71582ab357..33404158cf 100644 --- a/src/nvim/event/stream.c +++ b/src/nvim/event/stream.c @@ -71,6 +71,7 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream, stream->closed = false; stream->buffer = NULL; stream->events = NULL; + stream->num_bytes = 0; } void stream_close(Stream *stream, stream_close_cb on_stream_close) diff --git a/src/nvim/event/stream.h b/src/nvim/event/stream.h index c6baac0db7..ad4e24775b 100644 --- a/src/nvim/event/stream.h +++ b/src/nvim/event/stream.h @@ -49,6 +49,7 @@ struct stream { size_t curmem; size_t maxmem; size_t pending_reqs; + size_t num_bytes; void *data, *internal_data; bool closed; Queue *events; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 86f1a16216..da64533708 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -1745,14 +1745,14 @@ check_overwrite ( * write to other file or b_flags set or not writing the whole file: * overwriting only allowed with '!' */ - if ( (other - || (buf->b_flags & BF_NOTEDITED) - || ((buf->b_flags & BF_NEW) - && vim_strchr(p_cpo, CPO_OVERNEW) == NULL) - || (buf->b_flags & BF_READERR)) - && !p_wa - && !bt_nofile(buf) - && os_file_exists(ffname)) { + if ((other + || (buf->b_flags & BF_NOTEDITED) + || ((buf->b_flags & BF_NEW) + && vim_strchr(p_cpo, CPO_OVERNEW) == NULL) + || (buf->b_flags & BF_READERR)) + && !p_wa + && !bt_nofile(buf) + && os_path_exists(ffname)) { if (!eap->forceit && !eap->append) { #ifdef UNIX // It is possible to open a directory on Unix. @@ -1795,7 +1795,7 @@ check_overwrite ( } swapname = makeswapname(fname, ffname, curbuf, dir); xfree(dir); - if (os_file_exists(swapname)) { + if (os_path_exists(swapname)) { if (p_confirm || cmdmod.confirm) { char_u buff[DIALOG_MSG_SIZE]; @@ -1909,7 +1909,7 @@ static int check_readonly(int *forceit, buf_T *buf) /* Handle a file being readonly when the 'readonly' option is set or when * the file exists and permissions are read-only. */ if (!*forceit && (buf->b_p_ro - || (os_file_exists(buf->b_ffname) + || (os_path_exists(buf->b_ffname) && !os_file_is_writable((char *)buf->b_ffname)))) { if ((p_confirm || cmdmod.confirm) && buf->b_fname != NULL) { char_u buff[DIALOG_MSG_SIZE]; @@ -4796,122 +4796,15 @@ void ex_viusage(exarg_T *eap) } -/* - * ":helptags" - */ -void ex_helptags(exarg_T *eap) -{ - garray_T ga; - int len; - char_u lang[2]; - expand_T xpc; - char_u *dirname; - char_u ext[5]; - char_u fname[8]; - int filecount; - char_u **files; - int add_help_tags = FALSE; - - /* Check for ":helptags ++t {dir}". */ - if (STRNCMP(eap->arg, "++t", 3) == 0 && ascii_iswhite(eap->arg[3])) { - add_help_tags = TRUE; - eap->arg = skipwhite(eap->arg + 3); - } - - ExpandInit(&xpc); - xpc.xp_context = EXPAND_DIRECTORIES; - dirname = ExpandOne(&xpc, eap->arg, NULL, - WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE); - if (dirname == NULL || !os_isdir(dirname)) { - EMSG2(_("E150: Not a directory: %s"), eap->arg); - xfree(dirname); - return; - } - - /* Get a list of all files in the help directory and in subdirectories. */ - STRCPY(NameBuff, dirname); - add_pathsep((char *)NameBuff); - STRCAT(NameBuff, "**"); - - // Note: We cannot just do `&NameBuff` because it is a statically sized array - // so `NameBuff == &NameBuff` according to C semantics. - char_u *buff_list[1] = {NameBuff}; - if (gen_expand_wildcards(1, buff_list, &filecount, &files, - EW_FILE|EW_SILENT) == FAIL - || filecount == 0) { - EMSG2("E151: No match: %s", NameBuff); - xfree(dirname); - return; - } - - /* Go over all files in the directory to find out what languages are - * present. */ - ga_init(&ga, 1, 10); - for (int i = 0; i < filecount; ++i) { - len = (int)STRLEN(files[i]); - if (len <= 4) { - continue; - } - if (STRICMP(files[i] + len - 4, ".txt") == 0) { - /* ".txt" -> language "en" */ - lang[0] = 'e'; - lang[1] = 'n'; - } else if (files[i][len - 4] == '.' - && ASCII_ISALPHA(files[i][len - 3]) - && ASCII_ISALPHA(files[i][len - 2]) - && TOLOWER_ASC(files[i][len - 1]) == 'x') { - /* ".abx" -> language "ab" */ - lang[0] = TOLOWER_ASC(files[i][len - 3]); - lang[1] = TOLOWER_ASC(files[i][len - 2]); - } else - continue; - - int j; - /* Did we find this language already? */ - for (j = 0; j < ga.ga_len; j += 2) - if (STRNCMP(lang, ((char_u *)ga.ga_data) + j, 2) == 0) - break; - if (j == ga.ga_len) { - /* New language, add it. */ - ga_grow(&ga, 2); - ((char_u *)ga.ga_data)[ga.ga_len++] = lang[0]; - ((char_u *)ga.ga_data)[ga.ga_len++] = lang[1]; - } - } - - /* - * Loop over the found languages to generate a tags file for each one. - */ - for (int j = 0; j < ga.ga_len; j += 2) { - STRCPY(fname, "tags-xx"); - fname[5] = ((char_u *)ga.ga_data)[j]; - fname[6] = ((char_u *)ga.ga_data)[j + 1]; - if (fname[5] == 'e' && fname[6] == 'n') { - /* English is an exception: use ".txt" and "tags". */ - fname[4] = NUL; - STRCPY(ext, ".txt"); - } else { - /* Language "ab" uses ".abx" and "tags-ab". */ - STRCPY(ext, ".xxx"); - ext[1] = fname[5]; - ext[2] = fname[6]; - } - helptags_one(dirname, ext, fname, add_help_tags); - } - - ga_clear(&ga); - FreeWild(filecount, files); - - xfree(dirname); -} - -static void -helptags_one ( - char_u *dir, /* doc directory */ - char_u *ext, /* suffix, ".txt", ".itx", ".frx", etc. */ - char_u *tagfname, /* "tags" for English, "tags-fr" for French. */ - int add_help_tags /* add "help-tags" tag */ -) +/// Generate tags in one help directory +/// +/// @param dir Path to the doc directory +/// @param ext Suffix of the help files (".txt", ".itx", ".frx", etc.) +/// @param tagname Name of the tags file ("tags" for English, "tags-fr" for +/// French) +/// @param add_help_tags Whether to add the "help-tags" tag +static void helptags_one(char_u *dir, char_u *ext, char_u *tagfname, + bool add_help_tags) { FILE *fd_tags; FILE *fd; @@ -5111,6 +5004,132 @@ helptags_one ( fclose(fd_tags); /* there is no check for an error... */ } +/// Generate tags in one help directory, taking care of translations. +static void do_helptags(char_u *dirname, bool add_help_tags) +{ + int len; + garray_T ga; + char_u lang[2]; + char_u ext[5]; + char_u fname[8]; + int filecount; + char_u **files; + + // Get a list of all files in the help directory and in subdirectories. + STRCPY(NameBuff, dirname); + add_pathsep((char *)NameBuff); + STRCAT(NameBuff, "**"); + + // Note: We cannot just do `&NameBuff` because it is a statically sized array + // so `NameBuff == &NameBuff` according to C semantics. + char_u *buff_list[1] = {NameBuff}; + if (gen_expand_wildcards(1, buff_list, &filecount, &files, + EW_FILE|EW_SILENT) == FAIL + || filecount == 0) { + EMSG2("E151: No match: %s", NameBuff); + xfree(dirname); + return; + } + + /* Go over all files in the directory to find out what languages are + * present. */ + int j; + ga_init(&ga, 1, 10); + for (int i = 0; i < filecount; i++) { + len = (int)STRLEN(files[i]); + if (len <= 4) { + continue; + } + if (STRICMP(files[i] + len - 4, ".txt") == 0) { + /* ".txt" -> language "en" */ + lang[0] = 'e'; + lang[1] = 'n'; + } else if (files[i][len - 4] == '.' + && ASCII_ISALPHA(files[i][len - 3]) + && ASCII_ISALPHA(files[i][len - 2]) + && TOLOWER_ASC(files[i][len - 1]) == 'x') { + /* ".abx" -> language "ab" */ + lang[0] = TOLOWER_ASC(files[i][len - 3]); + lang[1] = TOLOWER_ASC(files[i][len - 2]); + } else + continue; + + // Did we find this language already? + for (j = 0; j < ga.ga_len; j += 2) { + if (STRNCMP(lang, ((char_u *)ga.ga_data) + j, 2) == 0) { + break; + } + } + if (j == ga.ga_len) { + // New language, add it. + ga_grow(&ga, 2); + ((char_u *)ga.ga_data)[ga.ga_len++] = lang[0]; + ((char_u *)ga.ga_data)[ga.ga_len++] = lang[1]; + } + } + + /* + * Loop over the found languages to generate a tags file for each one. + */ + for (j = 0; j < ga.ga_len; j += 2) { + STRCPY(fname, "tags-xx"); + fname[5] = ((char_u *)ga.ga_data)[j]; + fname[6] = ((char_u *)ga.ga_data)[j + 1]; + if (fname[5] == 'e' && fname[6] == 'n') { + /* English is an exception: use ".txt" and "tags". */ + fname[4] = NUL; + STRCPY(ext, ".txt"); + } else { + /* Language "ab" uses ".abx" and "tags-ab". */ + STRCPY(ext, ".xxx"); + ext[1] = fname[5]; + ext[2] = fname[6]; + } + helptags_one(dirname, ext, fname, add_help_tags); + } + + ga_clear(&ga); + FreeWild(filecount, files); +} + + static void +helptags_cb(char_u *fname, void *cookie) +{ + do_helptags(fname, *(bool *)cookie); +} + +/* + * ":helptags" + */ +void ex_helptags(exarg_T *eap) +{ + expand_T xpc; + char_u *dirname; + bool add_help_tags = false; + + /* Check for ":helptags ++t {dir}". */ + if (STRNCMP(eap->arg, "++t", 3) == 0 && ascii_iswhite(eap->arg[3])) { + add_help_tags = true; + eap->arg = skipwhite(eap->arg + 3); + } + + if (STRCMP(eap->arg, "ALL") == 0) { + do_in_path(p_rtp, (char_u *)"doc", DIP_ALL + DIP_DIR, + helptags_cb, &add_help_tags); + } else { + ExpandInit(&xpc); + xpc.xp_context = EXPAND_DIRECTORIES; + dirname = ExpandOne(&xpc, eap->arg, NULL, + WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE); + if (dirname == NULL || !os_isdir(dirname)) { + EMSG2(_("E150: Not a directory: %s"), eap->arg); + } else { + do_helptags(dirname, add_help_tags); + } + xfree(dirname); + } +} + struct sign { sign_T *sn_next; /* next sign in list */ diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 04fd88cc8d..3f5d9b3244 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', }, @@ -1849,6 +1849,18 @@ return { func='ex_print', }, { + command='packadd', + flags=bit.bor(BANG, FILE1, NEEDARG, TRLBAR, SBOXOK, CMDWIN), + addr_type=ADDR_LINES, + func='ex_packadd', + }, + { + command='packloadall', + flags=bit.bor(BANG, TRLBAR, SBOXOK, CMDWIN), + addr_type=ADDR_LINES, + func='ex_packloadall', + }, + { command='pclose', flags=bit.bor(BANG, TRLBAR), addr_type=ADDR_LINES, @@ -2158,19 +2170,19 @@ return { command='ruby', flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), addr_type=ADDR_LINES, - func='ex_script_ni', + func='ex_ruby', }, { command='rubydo', flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN), addr_type=ADDR_LINES, - func='ex_ni', + func='ex_rubydo', }, { command='rubyfile', flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN), addr_type=ADDR_LINES, - func='ex_ni', + func='ex_rubyfile', }, { command='rviminfo', diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 5fe6209a0a..6d24ba91f2 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -1,6 +1,6 @@ -/* - * ex_cmds2.c: some more functions for command line commands - */ +/// @file ex_cmds2.c +/// +/// Some more functions for command line commands #include <assert.h> #include <inttypes.h> @@ -50,15 +50,15 @@ #include "nvim/api/private/defs.h" -/* Growarray to store info about already sourced scripts. - * Also store the dev/ino, so that we don't have to stat() each - * script when going through the list. */ +/// Growarray to store info about already sourced scripts. +/// Also store the dev/ino, so that we don't have to stat() each +/// script when going through the list. typedef struct scriptitem_S { char_u *sn_name; bool file_id_valid; FileID file_id; bool sn_prof_on; ///< true when script is/was profiled - int sn_pr_force; ///< forceit: profile functions in this script + bool sn_pr_force; ///< forceit: profile functions in this script proftime_T sn_pr_child; ///< time set when going into first child int sn_pr_nest; ///< nesting for sn_pr_child // profiling the script as a whole @@ -76,29 +76,27 @@ typedef struct scriptitem_S { int sn_prl_execed; ///< line being timed was executed } scriptitem_T; -static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL}; +static garray_T script_items = { 0, 0, sizeof(scriptitem_T), 4, NULL }; #define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1]) -/* Struct used in sn_prl_ga for every line of a script. */ +// Struct used in sn_prl_ga for every line of a script. typedef struct sn_prl_S { int snp_count; ///< nr of times line was executed proftime_T sn_prl_total; ///< time spent in a line + children proftime_T sn_prl_self; ///< time spent in a line itself } sn_prl_T; -/* - * Structure used to store info for each sourced file. - * It is shared between do_source() and getsourceline(). - * This is required, because it needs to be handed to do_cmdline() and - * sourcing can be done recursively. - */ +/// Structure used to store info for each sourced file. +/// It is shared between do_source() and getsourceline(). +/// This is required, because it needs to be handed to do_cmdline() and +/// sourcing can be done recursively. struct source_cookie { FILE *fp; ///< opened file for sourcing char_u *nextline; ///< if not NULL: line that was read ahead int finished; ///< ":finish" used #if defined(USE_CRNL) int fileformat; ///< EOL_UNKNOWN, EOL_UNIX or EOL_DOS - int error; ///< TRUE if LF found after CR-LF + bool error; ///< true if LF found after CR-LF #endif linenr_T breakpoint; ///< next line with breakpoint or zero char_u *fname; ///< name of sourced file @@ -113,13 +111,11 @@ struct source_cookie { # include "ex_cmds2.c.generated.h" #endif -static int debug_greedy = FALSE; /* batch mode debugging: don't save - and restore typeahead. */ +/// batch mode debugging: don't save and restore typeahead. +static bool debug_greedy = false; -/* - * do_debug(): Debug mode. - * Repeatedly get Ex commands, until told to continue normal execution. - */ +/// Debug mode. Repeatedly get Ex commands, until told to continue normal +/// execution. void do_debug(char_u *cmd) { int save_msg_scroll = msg_scroll; @@ -130,7 +126,7 @@ void do_debug(char_u *cmd) int save_emsg_silent = emsg_silent; int save_redir_off = redir_off; tasave_T typeaheadbuf; - int typeahead_saved = FALSE; + bool typeahead_saved = false; int save_ignore_script = 0; int save_ex_normal_busy; int n; @@ -150,43 +146,44 @@ void do_debug(char_u *cmd) #define CMD_DOWN 10 - ++RedrawingDisabled; /* don't redisplay the window */ - ++no_wait_return; /* don't wait for return */ - did_emsg = FALSE; /* don't use error from debugged stuff */ - cmd_silent = FALSE; /* display commands */ - msg_silent = FALSE; /* display messages */ - emsg_silent = FALSE; /* display error messages */ - redir_off = TRUE; /* don't redirect debug commands */ + RedrawingDisabled++; // don't redisplay the window + no_wait_return++; // don't wait for return + did_emsg = false; // don't use error from debugged stuff + cmd_silent = false; // display commands + msg_silent = false; // display messages + emsg_silent = false; // display error messages + redir_off = true; // don't redirect debug commands State = NORMAL; - if (!debug_did_msg) + if (!debug_did_msg) { MSG(_("Entering Debug mode. Type \"cont\" to continue.")); - if (sourcing_name != NULL) + } + if (sourcing_name != NULL) { msg(sourcing_name); - if (sourcing_lnum != 0) + } + if (sourcing_lnum != 0) { smsg(_("line %" PRId64 ": %s"), (int64_t)sourcing_lnum, cmd); - else + } else { smsg(_("cmd: %s"), cmd); + } - /* - * Repeat getting a command and executing it. - */ + // Repeat getting a command and executing it. for (;; ) { - msg_scroll = TRUE; - need_wait_return = FALSE; - /* Save the current typeahead buffer and replace it with an empty one. - * This makes sure we get input from the user here and don't interfere - * with the commands being executed. Reset "ex_normal_busy" to avoid - * the side effects of using ":normal". Save the stuff buffer and make - * it empty. Set ignore_script to avoid reading from script input. */ + msg_scroll = true; + need_wait_return = false; + // Save the current typeahead buffer and replace it with an empty one. + // This makes sure we get input from the user here and don't interfere + // with the commands being executed. Reset "ex_normal_busy" to avoid + // the side effects of using ":normal". Save the stuff buffer and make + // it empty. Set ignore_script to avoid reading from script input. save_ex_normal_busy = ex_normal_busy; ex_normal_busy = 0; if (!debug_greedy) { save_typeahead(&typeaheadbuf); - typeahead_saved = TRUE; + typeahead_saved = true; save_ignore_script = ignore_script; - ignore_script = TRUE; + ignore_script = true; } xfree(cmdline); @@ -201,9 +198,9 @@ void do_debug(char_u *cmd) cmdline_row = msg_row; msg_starthere(); if (cmdline != NULL) { - /* If this is a debug command, set "last_cmd". - * If not, reset "last_cmd". - * For a blank line use previous command. */ + // If this is a debug command, set "last_cmd". + // If not, reset "last_cmd". + // For a blank line use previous command. p = skipwhite(cmdline); if (*p != NUL) { switch (*p) { @@ -255,11 +252,11 @@ void do_debug(char_u *cmd) default: last_cmd = 0; } if (last_cmd != 0) { - /* Check that the tail matches. */ - ++p; + // Check that the tail matches. + p++; while (*p != NUL && *p == *tail) { - ++p; - ++tail; + p++; + tail++; } if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME) { last_cmd = 0; @@ -268,8 +265,7 @@ void do_debug(char_u *cmd) } if (last_cmd != 0) { - /* Execute debug command: decided where to break next and - * return. */ + // Execute debug command: decided where to break next and return. switch (last_cmd) { case CMD_CONT: debug_break_level = -1; @@ -284,13 +280,13 @@ void do_debug(char_u *cmd) debug_break_level = ex_nesting_level - 1; break; case CMD_QUIT: - got_int = TRUE; + got_int = true; debug_break_level = -1; break; case CMD_INTERRUPT: - got_int = TRUE; + got_int = true; debug_break_level = 9999; - /* Do not repeat ">interrupt" cmd, continue stepping. */ + // Do not repeat ">interrupt" cmd, continue stepping. last_cmd = CMD_STEP; break; case CMD_BACKTRACE: @@ -318,21 +314,21 @@ void do_debug(char_u *cmd) break; } - /* don't debug this command */ + // don't debug this command n = debug_break_level; debug_break_level = -1; (void)do_cmdline(cmdline, getexline, NULL, - DOCMD_VERBOSE|DOCMD_EXCRESET); + DOCMD_VERBOSE|DOCMD_EXCRESET); debug_break_level = n; } lines_left = (int)(Rows - 1); } xfree(cmdline); - --RedrawingDisabled; - --no_wait_return; + RedrawingDisabled--; + no_wait_return--; redraw_all_later(NOT_VALID); - need_wait_return = FALSE; + need_wait_return = false; msg_scroll = save_msg_scroll; lines_left = (int)(Rows - 1); State = save_State; @@ -342,9 +338,8 @@ void do_debug(char_u *cmd) emsg_silent = save_emsg_silent; redir_off = save_redir_off; - /* Only print the message again when typing a command before coming back - * here. */ - debug_did_msg = TRUE; + // Only print the message again when typing a command before coming back here. + debug_did_msg = true; } static int get_maxbacktrace_level(void) @@ -419,9 +414,8 @@ static void do_showbacktrace(char_u *cmd) } } -/* - * ":debug". - */ + +/// ":debug". void ex_debug(exarg_T *eap) { int debug_break_level_save = debug_break_level; @@ -434,88 +428,81 @@ void ex_debug(exarg_T *eap) static char_u *debug_breakpoint_name = NULL; static linenr_T debug_breakpoint_lnum; -/* - * When debugging or a breakpoint is set on a skipped command, no debug prompt - * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and - * debug_skipped_name is then set to the source name in the breakpoint case. If - * a skipped command decides itself that a debug prompt should be displayed, it - * can do so by calling dbg_check_skipped(). - */ +/// When debugging or a breakpoint is set on a skipped command, no debug prompt +/// is shown by do_one_cmd(). This situation is indicated by debug_skipped, and +/// debug_skipped_name is then set to the source name in the breakpoint case. If +/// a skipped command decides itself that a debug prompt should be displayed, it +/// can do so by calling dbg_check_skipped(). static int debug_skipped; static char_u *debug_skipped_name; -/* - * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is - * at or below the break level. But only when the line is actually - * executed. Return TRUE and set breakpoint_name for skipped commands that - * decide to execute something themselves. - * Called from do_one_cmd() before executing a command. - */ +/// Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is +/// at or below the break level. But only when the line is actually +/// executed. Return true and set breakpoint_name for skipped commands that +/// decide to execute something themselves. +/// Called from do_one_cmd() before executing a command. void dbg_check_breakpoint(exarg_T *eap) { char_u *p; - debug_skipped = FALSE; + debug_skipped = false; if (debug_breakpoint_name != NULL) { if (!eap->skip) { - /* replace K_SNR with "<SNR>" */ + // replace K_SNR with "<SNR>" if (debug_breakpoint_name[0] == K_SPECIAL && debug_breakpoint_name[1] == KS_EXTRA - && debug_breakpoint_name[2] == (int)KE_SNR) + && debug_breakpoint_name[2] == (int)KE_SNR) { p = (char_u *)"<SNR>"; - else + } else { p = (char_u *)""; + } smsg(_("Breakpoint in \"%s%s\" line %" PRId64), - p, - debug_breakpoint_name + (*p == NUL ? 0 : 3), - (int64_t)debug_breakpoint_lnum); + p, + debug_breakpoint_name + (*p == NUL ? 0 : 3), + (int64_t)debug_breakpoint_lnum); debug_breakpoint_name = NULL; do_debug(eap->cmd); } else { - debug_skipped = TRUE; + debug_skipped = true; debug_skipped_name = debug_breakpoint_name; debug_breakpoint_name = NULL; } } else if (ex_nesting_level <= debug_break_level) { - if (!eap->skip) + if (!eap->skip) { do_debug(eap->cmd); - else { - debug_skipped = TRUE; + } else { + debug_skipped = true; debug_skipped_name = NULL; } } } -/* - * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was - * set. Return TRUE when the debug mode is entered this time. - */ -int dbg_check_skipped(exarg_T *eap) +/// Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was +/// set. +/// +/// @return true when the debug mode is entered this time. +bool dbg_check_skipped(exarg_T *eap) { int prev_got_int; if (debug_skipped) { - /* - * Save the value of got_int and reset it. We don't want a previous - * interruption cause flushing the input buffer. - */ + // Save the value of got_int and reset it. We don't want a previous + // interruption cause flushing the input buffer. prev_got_int = got_int; - got_int = FALSE; + got_int = false; debug_breakpoint_name = debug_skipped_name; - /* eap->skip is TRUE */ - eap->skip = FALSE; + // eap->skip is true + eap->skip = false; dbg_check_breakpoint(eap); - eap->skip = TRUE; + eap->skip = true; got_int |= prev_got_int; - return TRUE; + return true; } - return FALSE; + return false; } -/* - * The list of breakpoints: dbg_breakp. - * This is a grow-array of structs. - */ +/// The list of breakpoints: dbg_breakp. +/// This is a grow-array of structs. struct debuggy { int dbg_nr; ///< breakpoint number int dbg_type; ///< DBG_FUNC or DBG_FILE @@ -525,33 +512,30 @@ struct debuggy { int dbg_forceit; ///< ! used }; -static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL}; +static garray_T dbg_breakp = { 0, 0, sizeof(struct debuggy), 4, NULL }; #define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx]) #define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx]) -static int last_breakp = 0; /* nr of last defined breakpoint */ +static int last_breakp = 0; // nr of last defined breakpoint -/* Profiling uses file and func names similar to breakpoints. */ -static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL}; +// Profiling uses file and func names similar to breakpoints. +static garray_T prof_ga = { 0, 0, sizeof(struct debuggy), 4, NULL }; #define DBG_FUNC 1 #define DBG_FILE 2 -/* - * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them - * in the entry just after the last one in dbg_breakp. Note that "dbg_name" - * is allocated. - * Returns FAIL for failure. - */ -static int -dbg_parsearg ( - char_u *arg, - garray_T *gap /* either &dbg_breakp or &prof_ga */ -) +/// Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them +/// in the entry just after the last one in dbg_breakp. Note that "dbg_name" +/// is allocated. +/// Returns FAIL for failure. +/// +/// @param arg +/// @param gap either &dbg_breakp or &prof_ga +static int dbg_parsearg(char_u *arg, garray_T *gap) { char_u *p = arg; char_u *q; struct debuggy *bp; - int here = FALSE; + bool here = false; ga_grow(gap, 1); @@ -568,7 +552,7 @@ dbg_parsearg ( return FAIL; } bp->dbg_type = DBG_FILE; - here = TRUE; + here = true; } else { EMSG2(_(e_invarg2), p); return FAIL; @@ -585,7 +569,7 @@ dbg_parsearg ( bp->dbg_lnum = 0; } - /* Find the function or file name. Don't accept a function name with (). */ + // Find the function or file name. Don't accept a function name with (). if ((!here && *p == NUL) || (here && *p != NUL) || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL)) { @@ -593,36 +577,38 @@ dbg_parsearg ( return FAIL; } - if (bp->dbg_type == DBG_FUNC) + if (bp->dbg_type == DBG_FUNC) { bp->dbg_name = vim_strsave(p); - else if (here) + } else if (here) { bp->dbg_name = vim_strsave(curbuf->b_ffname); - else { - /* Expand the file name in the same way as do_source(). This means - * doing it twice, so that $DIR/file gets expanded when $DIR is - * "~/dir". */ + } else { + // Expand the file name in the same way as do_source(). This means + // doing it twice, so that $DIR/file gets expanded when $DIR is + // "~/dir". q = expand_env_save(p); - if (q == NULL) + if (q == NULL) { return FAIL; + } p = expand_env_save(q); xfree(q); - if (p == NULL) + if (p == NULL) { return FAIL; + } if (*p != '*') { bp->dbg_name = (char_u *)fix_fname((char *)p); xfree(p); - } else + } else { bp->dbg_name = p; + } } - if (bp->dbg_name == NULL) + if (bp->dbg_name == NULL) { return FAIL; + } return OK; } -/* - * ":breakadd". - */ +/// ":breakadd". void ex_breakadd(exarg_T *eap) { struct debuggy *bp; @@ -630,52 +616,51 @@ void ex_breakadd(exarg_T *eap) garray_T *gap; gap = &dbg_breakp; - if (eap->cmdidx == CMD_profile) + if (eap->cmdidx == CMD_profile) { gap = &prof_ga; + } if (dbg_parsearg(eap->arg, gap) == OK) { bp = &DEBUGGY(gap, gap->ga_len); bp->dbg_forceit = eap->forceit; - pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE); + pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, false); if (pat != NULL) { bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING); xfree(pat); } - if (pat == NULL || bp->dbg_prog == NULL) + if (pat == NULL || bp->dbg_prog == NULL) { xfree(bp->dbg_name); - else { - if (bp->dbg_lnum == 0) /* default line number is 1 */ + } else { + if (bp->dbg_lnum == 0) { // default line number is 1 bp->dbg_lnum = 1; + } if (eap->cmdidx != CMD_profile) { DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp; - ++debug_tick; + debug_tick++; } - ++gap->ga_len; + gap->ga_len++; } } } -/* - * ":debuggreedy". - */ +/// ":debuggreedy". void ex_debuggreedy(exarg_T *eap) { - if (eap->addr_count == 0 || eap->line2 != 0) - debug_greedy = TRUE; - else - debug_greedy = FALSE; + if (eap->addr_count == 0 || eap->line2 != 0) { + debug_greedy = true; + } else { + debug_greedy = false; + } } -/* - * ":breakdel" and ":profdel". - */ +/// ":breakdel" and ":profdel". void ex_breakdel(exarg_T *eap) { struct debuggy *bp, *bpi; int nr; int todel = -1; - int del_all = FALSE; + bool del_all = false; linenr_T best_lnum = 0; garray_T *gap; @@ -687,7 +672,7 @@ void ex_breakdel(exarg_T *eap) if (ascii_isdigit(*eap->arg)) { // ":breakdel {nr}" nr = atoi((char *)eap->arg); - for (int i = 0; i < gap->ga_len; ++i) { + for (int i = 0; i < gap->ga_len; i++) { if (DEBUGGY(gap, i).dbg_nr == nr) { todel = i; break; @@ -695,13 +680,14 @@ void ex_breakdel(exarg_T *eap) } } else if (*eap->arg == '*') { todel = 0; - del_all = TRUE; + del_all = true; } else { - /* ":breakdel {func|file} [lnum] {name}" */ - if (dbg_parsearg(eap->arg, gap) == FAIL) + // ":breakdel {func|file} [lnum] {name}" + if (dbg_parsearg(eap->arg, gap) == FAIL) { return; + } bp = &DEBUGGY(gap, gap->ga_len); - for (int i = 0; i < gap->ga_len; ++i) { + for (int i = 0; i < gap->ga_len; i++) { bpi = &DEBUGGY(gap, i); if (bp->dbg_type == bpi->dbg_type && STRCMP(bp->dbg_name, bpi->dbg_name) == 0 @@ -716,90 +702,85 @@ void ex_breakdel(exarg_T *eap) xfree(bp->dbg_name); } - if (todel < 0) + if (todel < 0) { EMSG2(_("E161: Breakpoint not found: %s"), eap->arg); - else { + } else { while (!GA_EMPTY(gap)) { xfree(DEBUGGY(gap, todel).dbg_name); vim_regfree(DEBUGGY(gap, todel).dbg_prog); - --gap->ga_len; - if (todel < gap->ga_len) + gap->ga_len--; + if (todel < gap->ga_len) { memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1), (size_t)(gap->ga_len - todel) * sizeof(struct debuggy)); + } if (eap->cmdidx == CMD_breakdel) { - ++debug_tick; + debug_tick++; } if (!del_all) { break; } } - /* If all breakpoints were removed clear the array. */ - if (GA_EMPTY(gap)) + // If all breakpoints were removed clear the array. + if (GA_EMPTY(gap)) { ga_clear(gap); + } } } -/* - * ":breaklist". - */ +/// ":breaklist". void ex_breaklist(exarg_T *eap) { struct debuggy *bp; - if (GA_EMPTY(&dbg_breakp)) + if (GA_EMPTY(&dbg_breakp)) { MSG(_("No breakpoints defined")); - else - for (int i = 0; i < dbg_breakp.ga_len; ++i) { + } else { + for (int i = 0; i < dbg_breakp.ga_len; i++) { bp = &BREAKP(i); - if (bp->dbg_type == DBG_FILE) - home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE); + if (bp->dbg_type == DBG_FILE) { + home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, true); + } smsg(_("%3d %s %s line %" PRId64), - bp->dbg_nr, - bp->dbg_type == DBG_FUNC ? "func" : "file", - bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff, - (int64_t)bp->dbg_lnum); - } -} - -/* - * Find a breakpoint for a function or sourced file. - * Returns line number at which to break; zero when no matching breakpoint. - */ -linenr_T -dbg_find_breakpoint ( - int file, /* TRUE for a file, FALSE for a function */ - char_u *fname, /* file or function name */ - linenr_T after /* after this line number */ + bp->dbg_nr, + bp->dbg_type == DBG_FUNC ? "func" : "file", + bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff, + (int64_t)bp->dbg_lnum); + } + } +} + +/// Find a breakpoint for a function or sourced file. +/// Returns line number at which to break; zero when no matching breakpoint. +linenr_T +dbg_find_breakpoint( + bool file, // true for a file, false for a function + char_u *fname, // file or function name + linenr_T after // after this line number ) { return debuggy_find(file, fname, after, &dbg_breakp, NULL); } -/* - * Return TRUE if profiling is on for a function or sourced file. - */ -int -has_profiling ( - int file, /* TRUE for a file, FALSE for a function */ - char_u *fname, /* file or function name */ - int *fp /* return: forceit */ -) +/// @param file true for a file, false for a function +/// @param fname file or function name +/// @param fp[out] forceit +/// +/// @returns true if profiling is on for a function or sourced file. +bool has_profiling(bool file, char_u *fname, bool *fp) { return debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp) != (linenr_T)0; } -/* - * Common code for dbg_find_breakpoint() and has_profiling(). - */ -static linenr_T -debuggy_find ( - int file, /* TRUE for a file, FALSE for a function */ - char_u *fname, /* file or function name */ - linenr_T after, /* after this line number */ - garray_T *gap, /* either &dbg_breakp or &prof_ga */ - int *fp /* if not NULL: return forceit */ +/// Common code for dbg_find_breakpoint() and has_profiling(). +static linenr_T +debuggy_find( + bool file, // true for a file, false for a function + char_u *fname, // file or function name + linenr_T after, // after this line number + garray_T *gap, // either &dbg_breakp or &prof_ga + bool *fp // if not NULL: return forceit ) { struct debuggy *bp; @@ -807,59 +788,57 @@ debuggy_find ( char_u *name = fname; int prev_got_int; - /* Return quickly when there are no breakpoints. */ - if (GA_EMPTY(gap)) + // Return quickly when there are no breakpoints. + if (GA_EMPTY(gap)) { return (linenr_T)0; + } - /* Replace K_SNR in function name with "<SNR>". */ + // Replace K_SNR in function name with "<SNR>". if (!file && fname[0] == K_SPECIAL) { name = xmalloc(STRLEN(fname) + 3); STRCPY(name, "<SNR>"); STRCPY(name + 5, fname + 3); } - for (int i = 0; i < gap->ga_len; ++i) { - /* Skip entries that are not useful or are for a line that is beyond - * an already found breakpoint. */ + for (int i = 0; i < gap->ga_len; i++) { + // Skip entries that are not useful or are for a line that is beyond + // an already found breakpoint. bp = &DEBUGGY(gap, i); - if (((bp->dbg_type == DBG_FILE) == file - && (gap == &prof_ga - || (bp->dbg_lnum > after - && (lnum == 0 || bp->dbg_lnum < lnum))))) { + if ((bp->dbg_type == DBG_FILE) == file + && (gap == &prof_ga + || (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))) { // Save the value of got_int and reset it. We don't want a // previous interruption cancel matching, only hitting CTRL-C // while matching should abort it. prev_got_int = got_int; - got_int = FALSE; + got_int = false; if (vim_regexec_prog(&bp->dbg_prog, false, name, (colnr_T)0)) { lnum = bp->dbg_lnum; - if (fp != NULL) + if (fp != NULL) { *fp = bp->dbg_forceit; + } } got_int |= prev_got_int; } } - if (name != fname) + if (name != fname) { xfree(name); + } return lnum; } -/* - * Called when a breakpoint was encountered. - */ +/// Called when a breakpoint was encountered. void dbg_breakpoint(char_u *name, linenr_T lnum) { - /* We need to check if this line is actually executed in do_one_cmd() */ + // We need to check if this line is actually executed in do_one_cmd() debug_breakpoint_name = name; debug_breakpoint_lnum = lnum; } static char_u *profile_fname = NULL; -/* - * ":profile cmd args" - */ +/// ":profile cmd args" void ex_profile(exarg_T *eap) { static proftime_T pause_time; @@ -885,8 +864,9 @@ void ex_profile(exarg_T *eap) set_vim_var_nr(VV_PROFILING, 0L); profile_reset(); } else if (STRCMP(eap->arg, "pause") == 0) { - if (do_profiling == PROF_YES) + if (do_profiling == PROF_YES) { pause_time = profile_start(); + } do_profiling = PROF_PAUSED; } else if (STRCMP(eap->arg, "continue") == 0) { if (do_profiling == PROF_PAUSED) { @@ -897,7 +877,7 @@ void ex_profile(exarg_T *eap) } else if (STRCMP(eap->arg, "dump") == 0) { profile_dump(); } else { - /* The rest is similar to ":breakadd". */ + // The rest is similar to ":breakadd". ex_breakadd(eap); } } @@ -917,6 +897,21 @@ void ex_pydo(exarg_T *eap) script_host_do_range("python", eap); } +void ex_ruby(exarg_T *eap) +{ + script_host_execute("ruby", eap); +} + +void ex_rubyfile(exarg_T *eap) +{ + script_host_execute_file("ruby", eap); +} + +void ex_rubydo(exarg_T *eap) +{ + script_host_do_range("ruby", eap); +} + void ex_python3(exarg_T *eap) { script_host_execute("python3", eap); @@ -932,7 +927,7 @@ void ex_pydo3(exarg_T *eap) script_host_do_range("python3", eap); } -/* Command line expansion for :profile. */ +// Command line expansion for :profile. static enum { PEXP_SUBCMD, ///< expand :profile sub-commands PEXP_FUNC ///< expand :profile func {funcname} @@ -949,36 +944,33 @@ static char *pexpand_cmds[] = { NULL }; -/* - * Function given to ExpandGeneric() to obtain the profile command - * specific expansion. - */ +/// Function given to ExpandGeneric() to obtain the profile command +/// specific expansion. char_u *get_profile_name(expand_T *xp, int idx) { switch (pexpand_what) { case PEXP_SUBCMD: return (char_u *)pexpand_cmds[idx]; - /* case PEXP_FUNC: TODO */ + // case PEXP_FUNC: TODO default: return NULL; } } -/* - * Handle command line completion for :profile command. - */ +/// Handle command line completion for :profile command. void set_context_in_profile_cmd(expand_T *xp, char_u *arg) { char_u *end_subcmd; - /* Default: expand subcommands. */ + // Default: expand subcommands. xp->xp_context = EXPAND_PROFILE; pexpand_what = PEXP_SUBCMD; xp->xp_pattern = arg; end_subcmd = skiptowhite(arg); - if (*end_subcmd == NUL) + if (*end_subcmd == NUL) { return; + } if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0) { xp->xp_context = EXPAND_FILES; @@ -986,22 +978,20 @@ void set_context_in_profile_cmd(expand_T *xp, char_u *arg) return; } - /* TODO: expand function names after "func" */ + // TODO(tarruda): expand function names after "func" xp->xp_context = EXPAND_NOTHING; } -/* - * Dump the profiling info. - */ +/// Dump the profiling info. void profile_dump(void) { FILE *fd; if (profile_fname != NULL) { fd = mch_fopen((char *)profile_fname, "w"); - if (fd == NULL) + if (fd == NULL) { EMSG2(_(e_notopen), profile_fname); - else { + } else { script_dump_profile(fd); func_dump_profile(fd); fclose(fd); @@ -1017,7 +1007,7 @@ static void profile_reset(void) scriptitem_T *si = &SCRIPT_ITEM(id); if (si->sn_prof_on) { si->sn_prof_on = false; - si->sn_pr_force = 0; + si->sn_pr_force = false; si->sn_pr_child = profile_zero(); si->sn_pr_nest = 0; si->sn_pr_count = 0; @@ -1077,26 +1067,23 @@ static void profile_init(scriptitem_T *si) si->sn_pr_nest = 0; } -/* - * save time when starting to invoke another script or function. - */ +/// save time when starting to invoke another script or function. void script_prof_save( - proftime_T *tm /* place to store wait time */ - ) + proftime_T *tm // place to store wait time +) { scriptitem_T *si; if (current_SID > 0 && current_SID <= script_items.ga_len) { si = &SCRIPT_ITEM(current_SID); - if (si->sn_prof_on && si->sn_pr_nest++ == 0) + if (si->sn_prof_on && si->sn_pr_nest++ == 0) { si->sn_pr_child = profile_start(); + } } *tm = profile_get_wait(); } -/* - * Count time spent in children after invoking another script or function. - */ +/// Count time spent in children after invoking another script or function. void script_prof_restore(proftime_T *tm) { scriptitem_T *si; @@ -1115,62 +1102,60 @@ void script_prof_restore(proftime_T *tm) static proftime_T inchar_time; -/* - * Called when starting to wait for the user to type a character. - */ +/// Called when starting to wait for the user to type a character. void prof_inchar_enter(void) { inchar_time = profile_start(); } -/* - * Called when finished waiting for the user to type a character. - */ +/// Called when finished waiting for the user to type a character. void prof_inchar_exit(void) { inchar_time = profile_end(inchar_time); profile_set_wait(profile_add(profile_get_wait(), inchar_time)); } -/* - * Dump the profiling results for all scripts in file "fd". - */ +/// Dump the profiling results for all scripts in file "fd". static void script_dump_profile(FILE *fd) { scriptitem_T *si; FILE *sfd; sn_prl_T *pp; - for (int id = 1; id <= script_items.ga_len; ++id) { + for (int id = 1; id <= script_items.ga_len; id++) { si = &SCRIPT_ITEM(id); if (si->sn_prof_on) { fprintf(fd, "SCRIPT %s\n", si->sn_name); - if (si->sn_pr_count == 1) + if (si->sn_pr_count == 1) { fprintf(fd, "Sourced 1 time\n"); - else + } else { fprintf(fd, "Sourced %d times\n", si->sn_pr_count); + } fprintf(fd, "Total time: %s\n", profile_msg(si->sn_pr_total)); fprintf(fd, " Self time: %s\n", profile_msg(si->sn_pr_self)); fprintf(fd, "\n"); fprintf(fd, "count total (s) self (s)\n"); sfd = mch_fopen((char *)si->sn_name, "r"); - if (sfd == NULL) + if (sfd == NULL) { fprintf(fd, "Cannot open file!\n"); - else { - for (int i = 0; i < si->sn_prl_ga.ga_len; ++i) { - if (vim_fgets(IObuff, IOSIZE, sfd)) + } else { + for (int i = 0; i < si->sn_prl_ga.ga_len; i++) { + if (vim_fgets(IObuff, IOSIZE, sfd)) { break; + } pp = &PRL_ITEM(si, i); if (pp->snp_count > 0) { fprintf(fd, "%5d ", pp->snp_count); - if (profile_equal(pp->sn_prl_total, pp->sn_prl_self)) + if (profile_equal(pp->sn_prl_total, pp->sn_prl_self)) { fprintf(fd, " "); - else + } else { fprintf(fd, "%s ", profile_msg(pp->sn_prl_total)); + } fprintf(fd, "%s ", profile_msg(pp->sn_prl_self)); - } else + } else { fprintf(fd, " "); + } fprintf(fd, "%s", IObuff); } fclose(sfd); @@ -1180,44 +1165,41 @@ static void script_dump_profile(FILE *fd) } } -/* - * Return TRUE when a function defined in the current script should be - * profiled. - */ -int prof_def_func(void) +/// Return true when a function defined in the current script should be +/// profiled. +bool prof_def_func(void) { - if (current_SID > 0) + if (current_SID > 0) { return SCRIPT_ITEM(current_SID).sn_pr_force; - return FALSE; + } + return false; } -/* - * If 'autowrite' option set, try to write the file. - * Careful: autocommands may make "buf" invalid! - * - * return FAIL for failure, OK otherwise - */ +/// If 'autowrite' option set, try to write the file. +/// Careful: autocommands may make "buf" invalid! +/// +/// @return FAIL for failure, OK otherwise int autowrite(buf_T *buf, int forceit) { int r; if (!(p_aw || p_awa) || !p_write - /* never autowrite a "nofile" or "nowrite" buffer */ + // never autowrite a "nofile" or "nowrite" buffer || bt_dontwrite(buf) - || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL) + || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL) { return FAIL; + } r = buf_write_all(buf, forceit); - /* Writing may succeed but the buffer still changed, e.g., when there is a - * conversion error. We do want to return FAIL then. */ - if (buf_valid(buf) && bufIsChanged(buf)) + // Writing may succeed but the buffer still changed, e.g., when there is a + // conversion error. We do want to return FAIL then. + if (buf_valid(buf) && bufIsChanged(buf)) { r = FAIL; + } return r; } -/* - * flush all buffers, except the ones that are readonly - */ +/// flush all buffers, except the ones that are readonly void autowrite_all(void) { if (!(p_aw || p_awa) || !p_write) { @@ -1226,123 +1208,125 @@ void autowrite_all(void) FOR_ALL_BUFFERS(buf) { if (bufIsChanged(buf) && !buf->b_p_ro) { - (void)buf_write_all(buf, FALSE); - /* an autocommand may have deleted the buffer */ - if (!buf_valid(buf)) + (void)buf_write_all(buf, false); + // an autocommand may have deleted the buffer + if (!buf_valid(buf)) { buf = firstbuf; + } } } } -/* - * Return TRUE if buffer was changed and cannot be abandoned. - * For flags use the CCGD_ values. - */ -int check_changed(buf_T *buf, int flags) +/// Return true if buffer was changed and cannot be abandoned. +/// For flags use the CCGD_ values. +bool check_changed(buf_T *buf, int flags) { int forceit = (flags & CCGD_FORCEIT); - if ( !forceit - && bufIsChanged(buf) - && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1) - && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL)) { + if (!forceit + && bufIsChanged(buf) + && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1) + && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL)) { if ((p_confirm || cmdmod.confirm) && p_write) { int count = 0; - if (flags & CCGD_ALLBUF) + if (flags & CCGD_ALLBUF) { FOR_ALL_BUFFERS(buf2) { if (bufIsChanged(buf2) && (buf2->b_ffname != NULL)) { - ++count; + count++; } } - if (!buf_valid(buf)) - /* Autocommand deleted buffer, oops! It's not changed now. */ - return FALSE; + } + if (!buf_valid(buf)) { + // Autocommand deleted buffer, oops! It's not changed now. + return false; + } dialog_changed(buf, count > 1); - if (!buf_valid(buf)) - /* Autocommand deleted buffer, oops! It's not changed now. */ - return FALSE; + if (!buf_valid(buf)) { + // Autocommand deleted buffer, oops! It's not changed now. + return false; + } return bufIsChanged(buf); } - if (flags & CCGD_EXCMD) + if (flags & CCGD_EXCMD) { EMSG(_(e_nowrtmsg)); - else + } else { EMSG(_(e_nowrtmsg_nobang)); - return TRUE; + } + return true; } - return FALSE; + return false; } -/* - * Ask the user what to do when abandoning a changed buffer. - * Must check 'write' option first! - */ -void -dialog_changed ( - buf_T *buf, - int checkall /* may abandon all changed buffers */ -) +/// Ask the user what to do when abandoning a changed buffer. +/// Must check 'write' option first! +/// +/// @param buf +/// @param checkall may abandon all changed buffers +void dialog_changed(buf_T *buf, int checkall) { char_u buff[DIALOG_MSG_SIZE]; int ret; exarg_T ea; dialog_msg(buff, _("Save changes to \"%s\"?"), - (buf->b_fname != NULL) ? - buf->b_fname : (char_u *)_("Untitled")); - if (checkall) + (buf->b_fname != NULL) ? + buf->b_fname : (char_u *)_("Untitled")); + if (checkall) { ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1); - else + } else { ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1); + } - /* Init ea pseudo-structure, this is needed for the check_overwrite() - * function. */ - ea.append = ea.forceit = FALSE; + // Init ea pseudo-structure, this is needed for the check_overwrite() + // function. + ea.append = ea.forceit = false; if (ret == VIM_YES) { - if (buf->b_fname != NULL && check_overwrite(&ea, buf, - buf->b_fname, buf->b_ffname, FALSE) == OK) - /* didn't hit Cancel */ - (void)buf_write_all(buf, FALSE); + if (buf->b_fname != NULL + && check_overwrite(&ea, + buf, + buf->b_fname, + buf->b_ffname, + false) == OK) { + // didn't hit Cancel + (void)buf_write_all(buf, false); + } } else if (ret == VIM_NO) { - unchanged(buf, TRUE); + unchanged(buf, true); } else if (ret == VIM_ALL) { - /* - * Write all modified files that can be written. - * Skip readonly buffers, these need to be confirmed - * individually. - */ + // Write all modified files that can be written. + // Skip readonly buffers, these need to be confirmed + // individually. FOR_ALL_BUFFERS(buf2) { if (bufIsChanged(buf2) - && (buf2->b_ffname != NULL - ) + && (buf2->b_ffname != NULL) && !buf2->b_p_ro) { - if (buf2->b_fname != NULL && check_overwrite(&ea, buf2, - buf2->b_fname, buf2->b_ffname, FALSE) == OK) - /* didn't hit Cancel */ - (void)buf_write_all(buf2, FALSE); - /* an autocommand may have deleted the buffer */ - if (!buf_valid(buf2)) + if (buf2->b_fname != NULL + && check_overwrite(&ea, buf2, buf2->b_fname, + buf2->b_ffname, false) == OK) { + // didn't hit Cancel + (void)buf_write_all(buf2, false); + } + // an autocommand may have deleted the buffer + if (!buf_valid(buf2)) { buf2 = firstbuf; + } } } } else if (ret == VIM_DISCARDALL) { - /* - * mark all buffers as unchanged - */ + // mark all buffers as unchanged FOR_ALL_BUFFERS(buf2) { - unchanged(buf2, TRUE); + unchanged(buf2, true); } } } -/* - * Return TRUE if the buffer "buf" can be abandoned, either by making it - * hidden, autowriting it or unloading it. - */ -int can_abandon(buf_T *buf, int forceit) +/// Return true if the buffer "buf" can be abandoned, either by making it +/// hidden, autowriting it or unloading it. +bool can_abandon(buf_T *buf, int forceit) { return P_HID(buf) || !bufIsChanged(buf) @@ -1352,16 +1336,16 @@ int can_abandon(buf_T *buf, int forceit) } -/* - * Add a buffer number to "bufnrs", unless it's already there. - */ +/// Add a buffer number to "bufnrs", unless it's already there. static void add_bufnum(int *bufnrs, int *bufnump, int nr) { int i; - for (i = 0; i < *bufnump; ++i) - if (bufnrs[i] == nr) + for (i = 0; i < *bufnump; i++) { + if (bufnrs[i] == nr) { return; + } + } bufnrs[*bufnump] = nr; *bufnump = *bufnump + 1; } @@ -1375,7 +1359,7 @@ static void add_bufnum(int *bufnrs, int *bufnump, int nr) /// @param[in] unload specifies whether to unload, instead of hide, the buffer. /// /// @returns true if any buffer is changed and cannot be abandoned -int check_changed_any(bool hidden, bool unload) +bool check_changed_any(bool hidden, bool unload) { bool ret = false; int save; @@ -1385,7 +1369,7 @@ int check_changed_any(bool hidden, bool unload) int *bufnrs; FOR_ALL_BUFFERS(buf) { - ++bufcount; + bufcount++; } if (bufcount == 0) { @@ -1394,16 +1378,16 @@ int check_changed_any(bool hidden, bool unload) bufnrs = xmalloc(sizeof(*bufnrs) * bufcount); - /* curbuf */ + // curbuf bufnrs[bufnum++] = curbuf->b_fnum; - /* buf in curtab */ + // buf in curtab FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_buffer != curbuf) { add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum); } } - /* buf in other tab */ + // buf in other tab FOR_ALL_TABS(tp) { if (tp != curtab) { FOR_ALL_WINDOWS_IN_TAB(wp, tp) { @@ -1412,59 +1396,60 @@ int check_changed_any(bool hidden, bool unload) } } - /* any other buf */ + // any other buf FOR_ALL_BUFFERS(buf) { add_bufnum(bufnrs, &bufnum, buf->b_fnum); } buf_T *buf = NULL; - for (i = 0; i < bufnum; ++i) { + for (i = 0; i < bufnum; i++) { buf = buflist_findnr(bufnrs[i]); - if (buf == NULL) + if (buf == NULL) { continue; + } if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf)) { - /* Try auto-writing the buffer. If this fails but the buffer no - * longer exists it's not changed, that's OK. */ + // Try auto-writing the buffer. If this fails but the buffer no + // longer exists it's not changed, that's OK. if (check_changed(buf, (p_awa ? CCGD_AW : 0) - | CCGD_MULTWIN - | CCGD_ALLBUF) && buf_valid(buf)) - break; /* didn't save - still changes */ + | CCGD_MULTWIN + | CCGD_ALLBUF) && buf_valid(buf)) { + break; // didn't save - still changes + } } } - if (i >= bufnum) + if (i >= bufnum) { goto theend; + } - ret = TRUE; - exiting = FALSE; - /* - * When ":confirm" used, don't give an error message. - */ + ret = true; + exiting = false; + // When ":confirm" used, don't give an error message. if (!(p_confirm || cmdmod.confirm)) { - /* There must be a wait_return for this message, do_buffer() - * may cause a redraw. But wait_return() is a no-op when vgetc() - * is busy (Quit used from window menu), then make sure we don't - * cause a scroll up. */ + // There must be a wait_return for this message, do_buffer() + // may cause a redraw. But wait_return() is a no-op when vgetc() + // is busy (Quit used from window menu), then make sure we don't + // cause a scroll up. if (vgetc_busy > 0) { msg_row = cmdline_row; msg_col = 0; - msg_didout = FALSE; + msg_didout = false; } if (EMSG2(_("E162: No write since last change for buffer \"%s\""), - buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname)) { + buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname)) { save = no_wait_return; - no_wait_return = FALSE; - wait_return(FALSE); + no_wait_return = false; + wait_return(false); no_wait_return = save; } } - /* Try to find a window that contains the buffer. */ + // Try to find a window that contains the buffer. if (buf != curbuf) { FOR_ALL_TAB_WINDOWS(tp, wp) { if (wp->w_buffer == buf) { goto_tabpage_win(tp, wp); - /* Paranoia: did autocms wipe out the buffer with changes? */ + // Paranoia: did autocmds wipe out the buffer with changes? if (!buf_valid(buf)) { goto theend; } @@ -1484,10 +1469,8 @@ theend: return ret; } -/* - * return FAIL if there is no file name, OK if there is one - * give error message for FAIL - */ +/// Return FAIL if there is no file name, OK if there is one. +/// Give error message for FAIL. int check_fname(void) { if (curbuf->b_ffname == NULL) { @@ -1497,19 +1480,17 @@ int check_fname(void) return OK; } -/* - * flush the contents of a buffer, unless it has no file name - * - * return FAIL for failure, OK otherwise - */ +/// Flush the contents of a buffer, unless it has no file name. +/// +/// @return FAIL for failure, OK otherwise int buf_write_all(buf_T *buf, int forceit) { int retval; buf_T *old_curbuf = curbuf; retval = (buf_write(buf, buf->b_ffname, buf->b_fname, - (linenr_T)1, buf->b_ml.ml_line_count, NULL, - FALSE, forceit, TRUE, FALSE)); + (linenr_T)1, buf->b_ml.ml_line_count, NULL, + false, forceit, true, false)); if (curbuf != old_curbuf) { msg_source(hl_attr(HLF_W)); MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)")); @@ -1517,37 +1498,35 @@ int buf_write_all(buf_T *buf, int forceit) return retval; } -/* - * Code to handle the argument list. - */ +/// Code to handle the argument list. #define AL_SET 1 #define AL_ADD 2 #define AL_DEL 3 -/* - * Isolate one argument, taking backticks. - * Changes the argument in-place, puts a NUL after it. Backticks remain. - * Return a pointer to the start of the next argument. - */ +/// Isolate one argument, taking backticks. +/// Changes the argument in-place, puts a NUL after it. Backticks remain. +/// Return a pointer to the start of the next argument. static char_u *do_one_arg(char_u *str) { char_u *p; - int inbacktick; + bool inbacktick; - inbacktick = FALSE; - for (p = str; *str; ++str) { - /* When the backslash is used for escaping the special meaning of a - * character we need to keep it until wildcard expansion. */ + inbacktick = false; + for (p = str; *str; str++) { + // When the backslash is used for escaping the special meaning of a + // character we need to keep it until wildcard expansion. if (rem_backslash(str)) { *p++ = *str++; *p++ = *str; } else { - /* An item ends at a space not in backticks */ - if (!inbacktick && ascii_isspace(*str)) + // An item ends at a space not in backticks + if (!inbacktick && ascii_isspace(*str)) { break; - if (*str == '`') - inbacktick ^= TRUE; + } + if (*str == '`') { + inbacktick ^= true; + } *p++ = *str; } } @@ -1557,26 +1536,23 @@ static char_u *do_one_arg(char_u *str) return str; } -/* - * Separate the arguments in "str" and return a list of pointers in the - * growarray "gap". - */ +/// Separate the arguments in "str" and return a list of pointers in the +/// growarray "gap". void get_arglist(garray_T *gap, char_u *str) { ga_init(gap, (int)sizeof(char_u *), 20); while (*str != NUL) { GA_APPEND(char_u *, gap, str); - /* Isolate one argument, change it in-place, put a NUL after it. */ + // Isolate one argument, change it in-place, put a NUL after it. str = do_one_arg(str); } } -/* - * Parse a list of arguments (file names), expand them and return in - * "fnames[fcountp]". When "wig" is true, removes files matching 'wildignore'. - * Return FAIL or OK. - */ +/// Parse a list of arguments (file names), expand them and return in +/// "fnames[fcountp]". When "wig" is true, removes files matching 'wildignore'. +/// +/// @return FAIL or OK. int get_arglist_exp(char_u *str, int *fcountp, char_u ***fnamesp, bool wig) { garray_T ga; @@ -1584,31 +1560,29 @@ int get_arglist_exp(char_u *str, int *fcountp, char_u ***fnamesp, bool wig) get_arglist(&ga, str); - if (wig) + if (wig) { i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data, - fcountp, fnamesp, EW_FILE|EW_NOTFOUND); - else + fcountp, fnamesp, EW_FILE|EW_NOTFOUND); + } else { i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data, - fcountp, fnamesp, EW_FILE|EW_NOTFOUND); + fcountp, fnamesp, EW_FILE|EW_NOTFOUND); + } ga_clear(&ga); return i; } -/* - * "what" == AL_SET: Redefine the argument list to 'str'. - * "what" == AL_ADD: add files in 'str' to the argument list after "after". - * "what" == AL_DEL: remove files in 'str' from the argument list. - * - * Return FAIL for failure, OK otherwise. - */ -static int -do_arglist ( - char_u *str, - int what, - int after /* 0 means before first one */ -) +/// @param str +/// @param what +/// AL_SET: Redefine the argument list to 'str'. +/// AL_ADD: add files in 'str' to the argument list after "after". +/// AL_DEL: remove files in 'str' from the argument list. +/// @param after +/// 0 means before first one +/// +/// @return FAIL for failure, OK otherwise. +static int do_arglist(char_u *str, int what, int after) { garray_T new_ga; int exp_count; @@ -1616,54 +1590,63 @@ 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) { regmatch_T regmatch; - int didone; - - /* - * Delete the items: use each item as a regexp and find a match in the - * argument list. - */ - regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */ - for (int i = 0; i < new_ga.ga_len && !got_int; ++i) { + bool didone; + + // Delete the items: use each item as a regexp and find a match in the + // argument list. + regmatch.rm_ic = p_fic; // ignore case when 'fileignorecase' is set + for (int i = 0; i < new_ga.ga_len && !got_int; i++) { p = ((char_u **)new_ga.ga_data)[i]; - p = file_pat_to_reg_pat(p, NULL, NULL, FALSE); - if (p == NULL) + p = file_pat_to_reg_pat(p, NULL, NULL, false); + if (p == NULL) { break; + } regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0); if (regmatch.regprog == NULL) { xfree(p); break; } - didone = FALSE; - for (match = 0; match < ARGCOUNT; ++match) + didone = false; + for (match = 0; match < ARGCOUNT; match++) { if (vim_regexec(®match, alist_name(&ARGLIST[match]), - (colnr_T)0)) { - didone = TRUE; + (colnr_T)0)) { + didone = true; xfree(ARGLIST[match].ae_fname); memmove(ARGLIST + match, ARGLIST + match + 1, (size_t)(ARGCOUNT - match - 1) * sizeof(aentry_T)); - --ALIST(curwin)->al_ga.ga_len; - if (curwin->w_arg_idx > match) - --curwin->w_arg_idx; - --match; + ALIST(curwin)->al_ga.ga_len--; + if (curwin->w_arg_idx > match) { + curwin->w_arg_idx--; + } + match--; } + } vim_regfree(regmatch.regprog); xfree(p); - if (!didone) + if (!didone) { EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]); + } } ga_clear(&new_ga); } else { int i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data, - &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND); + &exp_count, &exp_files, + EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND); ga_clear(&new_ga); if (i == FAIL || exp_count == 0) { EMSG(_(e_nomatch)); @@ -1673,8 +1656,9 @@ do_arglist ( if (what == AL_ADD) { (void)alist_add_list(exp_count, exp_files, after); xfree(exp_files); - } else /* what == AL_SET */ - alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0); + } else { // what == AL_SET + alist_set(ALIST(curwin), exp_count, exp_files, false, NULL, 0); + } } alist_check_arg_idx(); @@ -1682,9 +1666,7 @@ do_arglist ( return OK; } -/* - * Check the validity of the arg_idx for each other window. - */ +/// Check the validity of the arg_idx for each other window. static void alist_check_arg_idx(void) { FOR_ALL_TAB_WINDOWS(tp, win) { @@ -1694,136 +1676,123 @@ static void alist_check_arg_idx(void) } } -/* - * Return TRUE if window "win" is editing the file at the current argument - * index. - */ -static int editing_arg_idx(win_T *win) +/// Return true if window "win" is editing the file at the current argument +/// index. +static bool editing_arg_idx(win_T *win) { return !(win->w_arg_idx >= WARGCOUNT(win) || (win->w_buffer->b_fnum != WARGLIST(win)[win->w_arg_idx].ae_fnum && (win->w_buffer->b_ffname == NULL || !(path_full_compare( - alist_name(&WARGLIST(win)[win->w_arg_idx]), - win->w_buffer->b_ffname, TRUE) & kEqualFiles)))); + alist_name(&WARGLIST(win)[win->w_arg_idx]), + win->w_buffer->b_ffname, true) & kEqualFiles)))); } -/* - * Check if window "win" is editing the w_arg_idx file in its argument list. - */ +/// Check if window "win" is editing the w_arg_idx file in its argument list. void check_arg_idx(win_T *win) { if (WARGCOUNT(win) > 1 && !editing_arg_idx(win)) { - /* We are not editing the current entry in the argument list. - * Set "arg_had_last" if we are editing the last one. */ - win->w_arg_idx_invalid = TRUE; + // We are not editing the current entry in the argument list. + // Set "arg_had_last" if we are editing the last one. + win->w_arg_idx_invalid = true; if (win->w_arg_idx != WARGCOUNT(win) - 1 - && arg_had_last == FALSE + && arg_had_last == false && ALIST(win) == &global_alist && GARGCOUNT > 0 && win->w_arg_idx < GARGCOUNT && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum || (win->w_buffer->b_ffname != NULL && (path_full_compare(alist_name(&GARGLIST[GARGCOUNT - 1]), - win->w_buffer->b_ffname, TRUE) & kEqualFiles)))) - arg_had_last = TRUE; + win->w_buffer->b_ffname, true) + & kEqualFiles)))) { + arg_had_last = true; + } } else { - /* We are editing the current entry in the argument list. - * Set "arg_had_last" if it's also the last one */ - win->w_arg_idx_invalid = FALSE; + // We are editing the current entry in the argument list. + // Set "arg_had_last" if it's also the last one + win->w_arg_idx_invalid = false; if (win->w_arg_idx == WARGCOUNT(win) - 1 - && win->w_alist == &global_alist - ) - arg_had_last = TRUE; + && win->w_alist == &global_alist) { + arg_had_last = true; + } } } -/* - * ":args", ":argslocal" and ":argsglobal". - */ +/// ":args", ":argslocal" and ":argsglobal". void ex_args(exarg_T *eap) { if (eap->cmdidx != CMD_args) { alist_unlink(ALIST(curwin)); - if (eap->cmdidx == CMD_argglobal) + if (eap->cmdidx == CMD_argglobal) { ALIST(curwin) = &global_alist; - else /* eap->cmdidx == CMD_arglocal */ + } else { // eap->cmdidx == CMD_arglocal alist_new(); + } } if (!ends_excmd(*eap->arg)) { - /* - * ":args file ..": define new argument list, handle like ":next" - * Also for ":argslocal file .." and ":argsglobal file ..". - */ + // ":args file ..": define new argument list, handle like ":next" + // Also for ":argslocal file .." and ":argsglobal file ..". ex_next(eap); - } else if (eap->cmdidx == CMD_args) { - /* - * ":args": list arguments. - */ + } else if (eap->cmdidx == CMD_args) { + // ":args": list arguments. if (ARGCOUNT > 0) { - /* Overwrite the command, for a short list there is no scrolling - * required and no wait_return(). */ - gotocmdline(TRUE); - for (int i = 0; i < ARGCOUNT; ++i) { - if (i == curwin->w_arg_idx) + // Overwrite the command, for a short list there is no scrolling + // required and no wait_return(). + gotocmdline(true); + for (int i = 0; i < ARGCOUNT; i++) { + if (i == curwin->w_arg_idx) { msg_putchar('['); + } msg_outtrans(alist_name(&ARGLIST[i])); - if (i == curwin->w_arg_idx) + if (i == curwin->w_arg_idx) { msg_putchar(']'); + } msg_putchar(' '); } } } else if (eap->cmdidx == CMD_arglocal) { garray_T *gap = &curwin->w_alist->al_ga; - /* - * ":argslocal": make a local copy of the global argument list. - */ + // ":argslocal": make a local copy of the global argument list. ga_grow(gap, GARGCOUNT); - for (int i = 0; i < GARGCOUNT; ++i) + for (int i = 0; i < GARGCOUNT; i++) { if (GARGLIST[i].ae_fname != NULL) { AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname = vim_strsave(GARGLIST[i].ae_fname); AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum = GARGLIST[i].ae_fnum; - ++gap->ga_len; + gap->ga_len++; } + } } } -/* - * ":previous", ":sprevious", ":Next" and ":sNext". - */ +/// ":previous", ":sprevious", ":Next" and ":sNext". void ex_previous(exarg_T *eap) { - /* If past the last one already, go to the last one. */ - if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT) + // If past the last one already, go to the last one. + if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT) { do_argfile(eap, ARGCOUNT - 1); - else + } else { do_argfile(eap, curwin->w_arg_idx - (int)eap->line2); + } } -/* - * ":rewind", ":first", ":sfirst" and ":srewind". - */ +/// ":rewind", ":first", ":sfirst" and ":srewind". void ex_rewind(exarg_T *eap) { do_argfile(eap, 0); } -/* - * ":last" and ":slast". - */ +/// ":last" and ":slast". void ex_last(exarg_T *eap) { do_argfile(eap, ARGCOUNT - 1); } -/* - * ":argument" and ":sargument". - */ +/// ":argument" and ":sargument". void ex_argument(exarg_T *eap) { int i; @@ -1836,9 +1805,7 @@ void ex_argument(exarg_T *eap) do_argfile(eap, i); } -/* - * Edit file "argn" of the argument lists. - */ +/// Edit file "argn" of the argument lists. void do_argfile(exarg_T *eap, int argn) { int other; @@ -1846,26 +1813,26 @@ void do_argfile(exarg_T *eap, int argn) int old_arg_idx = curwin->w_arg_idx; if (argn < 0 || argn >= ARGCOUNT) { - if (ARGCOUNT <= 1) + if (ARGCOUNT <= 1) { EMSG(_("E163: There is only one file to edit")); - else if (argn < 0) + } else if (argn < 0) { EMSG(_("E164: Cannot go before first file")); - else + } else { EMSG(_("E165: Cannot go beyond last file")); + } } else { setpcmark(); - /* split window or create new tab page first */ + // split window or create new tab page first if (*eap->cmd == 's' || cmdmod.tab != 0) { - if (win_split(0, 0) == FAIL) + if (win_split(0, 0) == FAIL) { return; + } RESET_BINDING(curwin); } else { - /* - * if 'hidden' set, only check for changed file when re-editing - * the same buffer - */ - other = TRUE; + // if 'hidden' set, only check for changed file when re-editing + // the same buffer + other = true; if (P_HID(curbuf)) { p = (char_u *)fix_fname((char *)alist_name(&ARGLIST[argn])); other = otherfile(p); @@ -1873,101 +1840,97 @@ void do_argfile(exarg_T *eap, int argn) } if ((!P_HID(curbuf) || !other) && check_changed(curbuf, CCGD_AW - | (other ? 0 : CCGD_MULTWIN) - | (eap->forceit ? CCGD_FORCEIT : 0) - | CCGD_EXCMD)) + | (other ? 0 : CCGD_MULTWIN) + | (eap->forceit ? CCGD_FORCEIT : 0) + | CCGD_EXCMD)) { return; + } } curwin->w_arg_idx = argn; if (argn == ARGCOUNT - 1 - && curwin->w_alist == &global_alist - ) - arg_had_last = TRUE; + && curwin->w_alist == &global_alist) { + arg_had_last = true; + } - /* Edit the file; always use the last known line number. - * When it fails (e.g. Abort for already edited file) restore the - * argument index. */ + // Edit the file; always use the last known line number. + // When it fails (e.g. Abort for already edited file) restore the + // argument index. if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL, - eap, ECMD_LAST, - (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0) - + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL) + eap, ECMD_LAST, + (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0) + + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL) { curwin->w_arg_idx = old_arg_idx; - /* like Vi: set the mark where the cursor is in the file. */ - else if (eap->cmdidx != CMD_argdo) + } else if (eap->cmdidx != CMD_argdo) { + // like Vi: set the mark where the cursor is in the file. setmark('\''); + } } } -/* - * ":next", and commands that behave like it. - */ +/// ":next", and commands that behave like it. void ex_next(exarg_T *eap) { int i; - /* - * check for changed buffer now, if this fails the argument list is not - * redefined. - */ - if ( P_HID(curbuf) - || eap->cmdidx == CMD_snext - || !check_changed(curbuf, CCGD_AW - | (eap->forceit ? CCGD_FORCEIT : 0) - | CCGD_EXCMD)) { - if (*eap->arg != NUL) { /* redefine file list */ - if (do_arglist(eap->arg, AL_SET, 0) == FAIL) + // check for changed buffer now, if this fails the argument list is not + // redefined. + if (P_HID(curbuf) + || eap->cmdidx == CMD_snext + || !check_changed(curbuf, CCGD_AW + | (eap->forceit ? CCGD_FORCEIT : 0) + | CCGD_EXCMD)) { + if (*eap->arg != NUL) { // redefine file list + if (do_arglist(eap->arg, AL_SET, 0) == FAIL) { return; + } i = 0; - } else + } else { i = curwin->w_arg_idx + (int)eap->line2; + } do_argfile(eap, i); } } -/* - * ":argedit" - */ +/// ":argedit" void ex_argedit(exarg_T *eap) { int fnum; int i; char_u *s; - /* Add the argument to the buffer list and get the buffer number. */ + // Add the argument to the buffer list and get the buffer number. fnum = buflist_add(eap->arg, BLN_LISTED); - /* Check if this argument is already in the argument list. */ - for (i = 0; i < ARGCOUNT; ++i) - if (ARGLIST[i].ae_fnum == fnum) + // Check if this argument is already in the argument list. + for (i = 0; i < ARGCOUNT; i++) { + if (ARGLIST[i].ae_fnum == fnum) { break; + } + } if (i == ARGCOUNT) { - /* Can't find it, add it to the argument list. */ + // Can't find it, add it to the argument list. s = vim_strsave(eap->arg); - i = alist_add_list(1, &s, - eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1); + int after = eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1; + i = alist_add_list(1, &s, after); curwin->w_arg_idx = i; } alist_check_arg_idx(); - /* Edit the argument. */ + // Edit the argument. do_argfile(eap, i); } -/* - * ":argadd" - */ +/// ":argadd" void ex_argadd(exarg_T *eap) { do_arglist(eap->arg, AL_ADD, - eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1); + eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1); maketitle(); } -/* - * ":argdelete" - */ +/// ":argdelete" void ex_argdelete(exarg_T *eap) { if (eap->addr_count > 0) { @@ -1979,7 +1942,7 @@ void ex_argdelete(exarg_T *eap) if (*eap->arg != NUL || n <= 0) { EMSG(_(e_invarg)); } else { - for (linenr_T i = eap->line1; i <= eap->line2; ++i) { + for (linenr_T i = eap->line1; i <= eap->line2; i++) { xfree(ARGLIST[i - 1].ae_fname); } memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2, @@ -1990,17 +1953,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; @@ -2010,10 +1977,11 @@ void ex_listdo(exarg_T *eap) char_u *save_ei = NULL; char_u *p_shm_save; - if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo) - /* Don't do syntax HL autocommands. Skipping the syntax file is a - * great speed improvement. */ + if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo) { + // Don't do syntax HL autocommands. Skipping the syntax file is a + // great speed improvement. save_ei = au_event_disable(",Syntax"); + } start_global_changes(); @@ -2021,36 +1989,36 @@ void ex_listdo(exarg_T *eap) || eap->cmdidx == CMD_tabdo || P_HID(curbuf) || !check_changed(curbuf, CCGD_AW - | (eap->forceit ? CCGD_FORCEIT : 0) - | CCGD_EXCMD)) { + | (eap->forceit ? CCGD_FORCEIT : 0) + | CCGD_EXCMD)) { i = 0; - /* start at the eap->line1 argument/window/buffer */ + // start at the eap->line1 argument/window/buffer wp = firstwin; tp = first_tabpage; switch (eap->cmdidx) { - case CMD_windo: - for (; wp != NULL && i + 1 < eap->line1; wp = wp->w_next) { - i++; - } - break; - case CMD_tabdo: - for (; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next) { - i++; - } - break; - case CMD_argdo: - i = (int)eap->line1 - 1; - break; - default: - break; + case CMD_windo: + for (; wp != NULL && i + 1 < eap->line1; wp = wp->w_next) { + i++; + } + break; + case CMD_tabdo: + for (; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next) { + i++; + } + break; + case CMD_argdo: + i = (int)eap->line1 - 1; + break; + default: + break; } 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) { @@ -2082,64 +2050,71 @@ void ex_listdo(exarg_T *eap) } else { setpcmark(); } - listcmd_busy = TRUE; /* avoids setting pcmark below */ + listcmd_busy = true; // avoids setting pcmark below while (!got_int && buf != NULL) { if (eap->cmdidx == CMD_argdo) { - /* go to argument "i" */ - if (i == ARGCOUNT) + // go to argument "i" + if (i == ARGCOUNT) { break; - /* Don't call do_argfile() when already there, it will try - * reloading the file. */ + } + // Don't call do_argfile() when already there, it will try + // reloading the file. if (curwin->w_arg_idx != i || !editing_arg_idx(curwin)) { - /* Clear 'shm' to avoid that the file message overwrites - * any output from the command. */ + // Clear 'shm' to avoid that the file message overwrites + // any output from the command. p_shm_save = vim_strsave(p_shm); set_option_value((char_u *)"shm", 0L, (char_u *)"", 0); do_argfile(eap, i); set_option_value((char_u *)"shm", 0L, p_shm_save, 0); xfree(p_shm_save); } - if (curwin->w_arg_idx != i) + if (curwin->w_arg_idx != i) { break; + } } else if (eap->cmdidx == CMD_windo) { - /* go to window "wp" */ - if (!win_valid(wp)) + // go to window "wp" + if (!win_valid(wp)) { break; + } assert(wp); win_goto(wp); - if (curwin != wp) - break; /* something must be wrong */ + if (curwin != wp) { + break; // something must be wrong + } wp = curwin->w_next; } else if (eap->cmdidx == CMD_tabdo) { - /* go to window "tp" */ - if (!valid_tabpage(tp)) + // go to window "tp" + if (!valid_tabpage(tp)) { break; + } assert(tp); - goto_tabpage_tp(tp, TRUE, TRUE); + goto_tabpage_tp(tp, true, true); tp = tp->tp_next; } else if (eap->cmdidx == CMD_bufdo) { - /* Remember the number of the next listed buffer, in case - * ":bwipe" is used or autocommands do something strange. */ + // Remember the number of the next listed buffer, in case + // ":bwipe" is used or autocommands do something strange. next_fnum = -1; - for (buf_T *buf = curbuf->b_next; buf != NULL; buf = buf->b_next) + for (buf_T *buf = curbuf->b_next; buf != NULL; buf = buf->b_next) { if (buf->b_p_bl) { next_fnum = buf->b_fnum; break; } + } } - ++i; - /* execute the command */ + i++; + // execute the command do_cmdline(eap->arg, eap->getline, eap->cookie, - DOCMD_VERBOSE + DOCMD_NOWAIT); + DOCMD_VERBOSE + DOCMD_NOWAIT); if (eap->cmdidx == CMD_bufdo) { - /* Done? */ - if (next_fnum < 0 || next_fnum > eap->line2) + // Done? + if (next_fnum < 0 || next_fnum > eap->line2) { break; + } - /* Check if the buffer still exists. */ + // Check if the buffer still exists. bool buf_still_exists = false; FOR_ALL_BUFFERS(bp) { if (bp->b_fnum == next_fnum) { @@ -2151,8 +2126,8 @@ void ex_listdo(exarg_T *eap) break; } - /* Go to the next buffer. Clear 'shm' to avoid that the file - * message overwrites any output from the command. */ + // Go to the next buffer. Clear 'shm' to avoid that the file + // message overwrites any output from the command. p_shm_save = vim_strsave(p_shm); set_option_value((char_u *)"shm", 0L, (char_u *)"", 0); goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum); @@ -2178,15 +2153,16 @@ void ex_listdo(exarg_T *eap) // If jumping to the next quickfix entry fails, quit here. if (qf_get_cur_idx(eap) == qf_idx) { - break; + break; } } if (eap->cmdidx == CMD_windo) { - validate_cursor(); /* cursor may have moved */ - /* required when 'scrollbind' has been set */ - if (curwin->w_p_scb) - do_check_scrollbind(TRUE); + validate_cursor(); // cursor may have moved + // required when 'scrollbind' has been set + if (curwin->w_p_scb) { + do_check_scrollbind(true); + } } if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo) { if (i + 1 > eap->line2) { @@ -2197,54 +2173,53 @@ void ex_listdo(exarg_T *eap) break; } } - listcmd_busy = FALSE; + listcmd_busy = false; } if (save_ei != NULL) { au_event_restore(save_ei); apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, - curbuf->b_fname, TRUE, curbuf); + curbuf->b_fname, true, curbuf); } end_global_changes(); } -/* - * Add files[count] to the arglist of the current window after arg "after". - * The file names in files[count] must have been allocated and are taken over. - * Files[] itself is not taken over. - * Returns index of first added argument. - */ -static int -alist_add_list ( - int count, - char_u **files, - int after /* where to add: 0 = before first one */ -) +/// Add files[count] to the arglist of the current window after arg "after". +/// The file names in files[count] must have been allocated and are taken over. +/// Files[] itself is not taken over. +/// +/// @param after: where to add: 0 = before first one +/// +/// @return index of first added argument +static int alist_add_list(int count, char_u **files, int after) { + int old_argcount = ARGCOUNT; ga_grow(&ALIST(curwin)->al_ga, count); { - if (after < 0) + if (after < 0) { after = 0; - if (after > ARGCOUNT) + } + if (after > ARGCOUNT) { after = ARGCOUNT; - if (after < ARGCOUNT) + } + if (after < ARGCOUNT) { memmove(&(ARGLIST[after + count]), &(ARGLIST[after]), (size_t)(ARGCOUNT - after) * sizeof(aentry_T)); - for (int i = 0; i < count; ++i) { + } + for (int i = 0; i < count; i++) { ARGLIST[after + i].ae_fname = files[i]; 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; } } -/* - * ":compiler[!] {name}" - */ +/// ":compiler[!] {name}" void ex_compiler(exarg_T *eap) { char_u *buf; @@ -2252,134 +2227,148 @@ void ex_compiler(exarg_T *eap) char_u *p; if (*eap->arg == NUL) { - /* List all compiler scripts. */ - do_cmdline_cmd("echo globpath(&rtp, 'compiler/*.vim')"); - /* ) keep the indenter happy... */ + // List all compiler scripts. + do_cmdline_cmd("echo globpath(&rtp, 'compiler/*.vim')"); // NOLINT } else { - buf = xmalloc(STRLEN(eap->arg) + 14); + size_t bufsize = STRLEN(eap->arg) + 14; + buf = xmalloc(bufsize); if (eap->forceit) { - /* ":compiler! {name}" sets global options */ + // ":compiler! {name}" sets global options do_cmdline_cmd("command -nargs=* CompilerSet set <args>"); } else { - /* ":compiler! {name}" sets local options. - * To remain backwards compatible "current_compiler" is always - * used. A user's compiler plugin may set it, the distributed - * plugin will then skip the settings. Afterwards set - * "b:current_compiler" and restore "current_compiler". - * Explicitly prepend "g:" to make it work in a function. */ + // ":compiler! {name}" sets local options. + // To remain backwards compatible "current_compiler" is always + // used. A user's compiler plugin may set it, the distributed + // plugin will then skip the settings. Afterwards set + // "b:current_compiler" and restore "current_compiler". + // Explicitly prepend "g:" to make it work in a function. old_cur_comp = get_var_value((char_u *)"g:current_compiler"); - if (old_cur_comp != NULL) + if (old_cur_comp != NULL) { old_cur_comp = vim_strsave(old_cur_comp); + } do_cmdline_cmd("command -nargs=* CompilerSet setlocal <args>"); } - do_unlet((char_u *)"g:current_compiler", TRUE); - do_unlet((char_u *)"b:current_compiler", TRUE); + do_unlet((char_u *)"g:current_compiler", true); + do_unlet((char_u *)"b:current_compiler", true); - sprintf((char *)buf, "compiler/%s.vim", eap->arg); - if (source_runtime(buf, TRUE) == FAIL) + snprintf((char *)buf, bufsize, "compiler/%s.vim", eap->arg); + if (source_runtime(buf, DIP_ALL) == FAIL) { EMSG2(_("E666: compiler not supported: %s"), eap->arg); + } xfree(buf); do_cmdline_cmd(":delcommand CompilerSet"); - /* Set "b:current_compiler" from "current_compiler". */ + // Set "b:current_compiler" from "current_compiler". p = get_var_value((char_u *)"g:current_compiler"); - if (p != NULL) + if (p != NULL) { set_internal_string_var((char_u *)"b:current_compiler", p); + } - /* Restore "current_compiler" for ":compiler {name}". */ + // Restore "current_compiler" for ":compiler {name}". if (!eap->forceit) { if (old_cur_comp != NULL) { set_internal_string_var((char_u *)"g:current_compiler", - old_cur_comp); + old_cur_comp); xfree(old_cur_comp); - } else - do_unlet((char_u *)"g:current_compiler", TRUE); + } else { + do_unlet((char_u *)"g:current_compiler", true); + } } } } -/* - * ":runtime {name}" - */ +/// ":runtime [what] {name}" void ex_runtime(exarg_T *eap) { - source_runtime(eap->arg, eap->forceit); + char_u *arg = eap->arg; + char_u *p = skiptowhite(arg); + ptrdiff_t len = p - arg; + int flags = eap->forceit ? DIP_ALL : 0; + + if (STRNCMP(arg, "START", len) == 0) { + flags += DIP_START + DIP_NORTP; + arg = skipwhite(arg + len); + } else if (STRNCMP(arg, "OPT", len) == 0) { + flags += DIP_OPT + DIP_NORTP; + arg = skipwhite(arg + len); + } else if (STRNCMP(arg, "PACK", len) == 0) { + flags += DIP_START + DIP_OPT + DIP_NORTP; + arg = skipwhite(arg + len); + } else if (STRNCMP(arg, "ALL", len) == 0) { + flags += DIP_START + DIP_OPT; + arg = skipwhite(arg + len); + } + + source_runtime(arg, flags); } static void source_callback(char_u *fname, void *cookie) { - (void)do_source(fname, FALSE, DOSO_NONE); + (void)do_source(fname, false, DOSO_NONE); } -/* - * Source the file "name" from all directories in 'runtimepath'. - * "name" can contain wildcards. - * When "all" is TRUE, source all files, otherwise only the first one. - * return FAIL when no file could be sourced, OK otherwise. - */ -int source_runtime(char_u *name, int all) +/// Source the file "name" from all directories in 'runtimepath'. +/// "name" can contain wildcards. +/// When "flags" has DIP_ALL: source all files, otherwise only the first one. +/// +/// return FAIL when no file could be sourced, OK otherwise. +int source_runtime(char_u *name, int flags) { - return do_in_runtimepath(name, all, source_callback, NULL); + return do_in_runtimepath(name, flags, source_callback, NULL); } -/* - * Find "name" in 'runtimepath'. When found, invoke the callback function for - * it: callback(fname, "cookie") - * When "all" is TRUE repeat for all matches, otherwise only the first one is - * used. - * Returns OK when at least one match found, FAIL otherwise. - * - * If "name" is NULL calls callback for each entry in runtimepath. Cookie is - * passed by reference in this case, setting it to NULL indicates that callback - * has done its job. - */ -int do_in_runtimepath(char_u *name, int all, DoInRuntimepathCB callback, - void *cookie) +/// Find the file "name" in all directories in "path" and invoke +/// "callback(fname, cookie)". +/// "name" can contain wildcards. +/// When "flags" has DIP_ALL: source all files, otherwise only the first one. +/// When "flags" has DIP_DIR: find directories instead of files. +/// When "flags" has DIP_ERR: give an error message if there is no match. +/// +/// return FAIL when no file could be sourced, OK otherwise. +int do_in_path(char_u *path, char_u *name, int flags, + DoInRuntimepathCB callback, void *cookie) { - char_u *rtp; - char_u *np; - char_u *buf; - char_u *rtp_copy; char_u *tail; int num_files; char_u **files; int i; - int did_one = FALSE; + bool did_one = false; - /* Make a copy of 'runtimepath'. Invoking the callback may change the - * value. */ - rtp_copy = vim_strsave(p_rtp); - buf = xmallocz(MAXPATHL); + // Make a copy of 'runtimepath'. Invoking the callback may change the + // value. + char_u *rtp_copy = vim_strsave(path); + char_u *buf = xmallocz(MAXPATHL); { if (p_verbose > 1 && name != NULL) { verbose_enter(); smsg(_("Searching for \"%s\" in \"%s\""), - (char *)name, (char *)p_rtp); + (char *)name, (char *)path); verbose_leave(); } - /* Loop over all entries in 'runtimepath'. */ - rtp = rtp_copy; - while (*rtp != NUL && (all || !did_one)) { - /* Copy the path from 'runtimepath' to buf[]. */ + // Loop over all entries in 'runtimepath'. + char_u *rtp = rtp_copy; + while (*rtp != NUL && ((flags & DIP_ALL) || !did_one)) { + // Copy the path from 'runtimepath' to buf[]. copy_option_part(&rtp, buf, MAXPATHL, ","); if (name == NULL) { - (*callback)(buf, (void *) &cookie); - if (!did_one) + (*callback)(buf, (void *)&cookie); + if (!did_one) { did_one = (cookie == NULL); + } } else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL) { add_pathsep((char *)buf); tail = buf + STRLEN(buf); - /* Loop over all patterns in "name" */ - np = name; - while (*np != NUL && (all || !did_one)) { - /* Append the pattern from "name" to buf[]. */ + // Loop over all patterns in "name" + char_u *np = name; + while (*np != NUL && ((flags & DIP_ALL) || !did_one)) { + // Append the pattern from "name" to buf[]. assert(MAXPATHL >= (tail - buf)); copy_option_part(&np, tail, (size_t)(MAXPATHL - (tail - buf)), - "\t "); + "\t "); if (p_verbose > 2) { verbose_enter(); @@ -2387,14 +2376,16 @@ int do_in_runtimepath(char_u *name, int all, DoInRuntimepathCB callback, verbose_leave(); } - /* Expand wildcards, invoke the callback for each match. */ + // Expand wildcards, invoke the callback for each match. if (gen_expand_wildcards(1, &buf, &num_files, &files, - EW_FILE) == OK) { - for (i = 0; i < num_files; ++i) { + (flags & DIP_DIR) ? EW_DIR + : EW_FILE) == OK) { + for (i = 0; i < num_files; i++) { (*callback)(files[i], cookie); - did_one = TRUE; - if (!all) + did_one = true; + if (!(flags & DIP_ALL)) { break; + } } FreeWild(num_files, files); } @@ -2404,27 +2395,235 @@ int do_in_runtimepath(char_u *name, int all, DoInRuntimepathCB callback, } xfree(buf); xfree(rtp_copy); - if (p_verbose > 0 && !did_one && name != NULL) { - verbose_enter(); - smsg(_("not found in 'runtimepath': \"%s\""), name); - verbose_leave(); + if (!did_one && name != NULL) { + char *basepath = path == p_rtp ? "runtimepath" : "packpath"; + + if (flags & DIP_ERR) { + EMSG3(_(e_dirnotf), basepath, name); + } else if (p_verbose > 0) { + verbose_enter(); + smsg(_("not found in '%s': \"%s\""), basepath, name); + verbose_leave(); + } } return did_one ? OK : FAIL; } -/* - * ":options" - */ +/// Find "name" in 'runtimepath'. When found, invoke the callback function for +/// it: callback(fname, "cookie") +/// When "flags" has DIP_ALL repeat for all matches, otherwise only the first +/// one is used. +/// Returns OK when at least one match found, FAIL otherwise. +/// If "name" is NULL calls callback for each entry in runtimepath. Cookie is +/// passed by reference in this case, setting it to NULL indicates that callback +/// has done its job. +int do_in_runtimepath(char_u *name, int flags, DoInRuntimepathCB callback, + void *cookie) +{ + int done = FAIL; + + if ((flags & DIP_NORTP) == 0) { + done = do_in_path(p_rtp, name, flags, callback, cookie); + } + + if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START)) { + char *start_dir = "pack/*/start/*/%s"; // NOLINT + size_t len = STRLEN(start_dir) + STRLEN(name); + char_u *s = xmallocz(len); + + vim_snprintf((char *)s, len, start_dir, name); + done = do_in_path(p_pp, s, flags, callback, cookie); + + xfree(s); + } + + if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT)) { + char *opt_dir = "pack/*/opt/*/%s"; // NOLINT + size_t len = STRLEN(opt_dir) + STRLEN(name); + char_u *s = xmallocz(len); + + vim_snprintf((char *)s, len, opt_dir, name); + done = do_in_path(p_pp, s, flags, callback, cookie); + + xfree(s); + } + + return done; +} + +// Expand wildcards in "pat" and invoke do_source() for each match. +static void source_all_matches(char_u *pat) +{ + int num_files; + char_u **files; + + if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK) { + for (int i = 0; i < num_files; i++) { + (void)do_source(files[i], false, DOSO_NONE); + } + FreeWild(num_files, files); + } +} + +// used for "cookie" of add_pack_plugin() +static int APP_ADD_DIR; +static int APP_LOAD; +static int APP_BOTH; + +static void add_pack_plugin(char_u *fname, void *cookie) +{ + char_u *p4, *p3, *p2, *p1, *p; + char_u *new_rtp; + char_u *ffname = (char_u *)fix_fname((char *)fname); + + if (ffname == NULL) { + return; + } + + if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL) { + // directory is not yet in 'runtimepath', add it + p4 = p3 = p2 = p1 = get_past_head(ffname); + for (p = p1; *p; mb_ptr_adv(p)) { + if (vim_ispathsep_nocolon(*p)) { + p4 = p3; p3 = p2; p2 = p1; p1 = p; + } + } + + // now we have: + // rtp/pack/name/start/name + // p4 p3 p2 p1 + // + // find the part up to "pack" in 'runtimepath' + char_u c = *p4; + *p4 = NUL; + + // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences + size_t fname_len = STRLEN(ffname); + char_u *insp = p_rtp; + for (;;) { + if (vim_fnamencmp(insp, ffname, fname_len) == 0) { + break; + } + insp = vim_strchr(insp, ','); + if (insp == NULL) { + break; + } + insp++; + } + + if (insp == NULL) { + // not found, append at the end + insp = p_rtp + STRLEN(p_rtp); + } else { + // append after the matching directory. + insp += STRLEN(ffname); + while (*insp != NUL && *insp != ',') { + insp++; + } + } + *p4 = c; + + // check if rtp/pack/name/start/name/after exists + char *afterdir = concat_fnames((char *)ffname, "after", true); + size_t afterlen = 0; + if (os_isdir((char_u *)afterdir)) { + afterlen = STRLEN(afterdir) + 1; // add one for comma + } + + size_t oldlen = STRLEN(p_rtp); + size_t addlen = STRLEN(ffname) + 1; // add one for comma + new_rtp = try_malloc(oldlen + addlen + afterlen + 1); // add one for NUL + if (new_rtp == NULL) { + goto theend; + } + uintptr_t keep = (uintptr_t)(insp - p_rtp); + memmove(new_rtp, p_rtp, keep); + new_rtp[keep] = ','; + memmove(new_rtp + keep + 1, ffname, addlen); + if (p_rtp[keep] != NUL) { + memmove(new_rtp + keep + addlen, p_rtp + keep, + oldlen - keep + 1); + } + if (afterlen > 0) { + STRCAT(new_rtp, ","); + STRCAT(new_rtp, afterdir); + } + set_option_value((char_u *)"rtp", 0L, new_rtp, 0); + xfree(new_rtp); + xfree(afterdir); + } + + if (cookie != &APP_ADD_DIR) { + static const char *plugpat = "%s/plugin/*.vim"; // NOLINT + static const char *ftpat = "%s/ftdetect/*.vim"; // NOLINT + + size_t len = STRLEN(ffname) + STRLEN(ftpat); + char_u *pat = try_malloc(len + 1); + if (pat == NULL) { + goto theend; + } + vim_snprintf((char *)pat, len, plugpat, ffname); + source_all_matches(pat); + + char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes"); + + // If runtime/filetype.vim wasn't loaded yet, the scripts will be + // found when it loads. + if (eval_to_number(cmd) > 0) { + do_cmdline_cmd("augroup filetypedetect"); + vim_snprintf((char *)pat, len, ftpat, ffname); + source_all_matches(pat); + do_cmdline_cmd("augroup END"); + } + xfree(cmd); + xfree(pat); + } + +theend: + xfree(ffname); +} + +static bool did_source_packages = false; + +// ":packloadall" +// Find plugins in the package directories and source them. +void ex_packloadall(exarg_T *eap) +{ + if (!did_source_packages || (eap != NULL && eap->forceit)) { + did_source_packages = true; + + // First do a round to add all directories to 'runtimepath', then load + // the plugins. This allows for plugins to use an autoload directory + // of another plugin. + do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT + add_pack_plugin, &APP_ADD_DIR); + do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT + add_pack_plugin, &APP_LOAD); + } +} + +/// ":packadd[!] {name}" +void ex_packadd(exarg_T *eap) +{ + static const char *plugpat = "pack/*/opt/%s"; // NOLINT + + size_t len = STRLEN(plugpat) + STRLEN(eap->arg); + char *pat = (char *)xmallocz(len); + vim_snprintf(pat, len, plugpat, eap->arg); + do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + DIP_ERR, add_pack_plugin, + eap->forceit ? &APP_ADD_DIR : &APP_BOTH); + xfree(pat); +} + +/// ":options" void ex_options(exarg_T *eap) { cmd_source((char_u *)SYS_OPTWIN_FILE, NULL); } -/* - * ":source {fname}" - */ +/// ":source {fname}" void ex_source(exarg_T *eap) { cmd_source(eap->arg, eap); @@ -2432,96 +2631,82 @@ void ex_source(exarg_T *eap) static void cmd_source(char_u *fname, exarg_T *eap) { - if (*fname == NUL) + if (*fname == NUL) { EMSG(_(e_argreq)); - - else if (eap != NULL && eap->forceit) - /* ":source!": read Normal mode commands - * Need to execute the commands directly. This is required at least - * for: - * - ":g" command busy - * - after ":argdo", ":windo" or ":bufdo" - * - another command follows - * - inside a loop - */ + } else if (eap != NULL && eap->forceit) { + // ":source!": read Normal mode commands + // Need to execute the commands directly. This is required at least + // for: + // - ":g" command busy + // - after ":argdo", ":windo" or ":bufdo" + // - another command follows + // - inside a loop openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL - || eap->cstack->cs_idx >= 0 - ); + || eap->cstack->cs_idx >= 0); - /* ":source" read ex commands */ - else if (do_source(fname, FALSE, DOSO_NONE) == FAIL) + // ":source" read ex commands + } else if (do_source(fname, false, DOSO_NONE) == FAIL) { EMSG2(_(e_notopen), fname); + } } -/* - * ":source" and associated commands. - */ - -/* - * Return the address holding the next breakpoint line for a source cookie. - */ +/// ":source" and associated commands. +/// +/// @return address holding the next breakpoint line for a source cookie linenr_T *source_breakpoint(void *cookie) { return &((struct source_cookie *)cookie)->breakpoint; } -/* - * Return the address holding the debug tick for a source cookie. - */ +/// Return the address holding the debug tick for a source cookie. int *source_dbg_tick(void *cookie) { return &((struct source_cookie *)cookie)->dbg_tick; } -/* - * Return the nesting level for a source cookie. - */ +/// Return the nesting level for a source cookie. 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 -/* - * do_source: Read the file "fname" and execute its lines as EX commands. - * - * This function may be called recursively! - * - * return FAIL if file could not be opened, OK otherwise - */ -int -do_source ( - char_u *fname, - int check_other, /* check for .vimrc and _vimrc */ - int is_vimrc /* DOSO_ value */ -) +/// Read the file "fname" and execute its lines as EX commands. +/// +/// This function may be called recursively! +/// +/// @param fname +/// @param check_other check for .vimrc and _vimrc +/// @param is_vimrc DOSO_ value +/// +/// @return FAIL if file could not be opened, OK otherwise +int do_source(char_u *fname, int check_other, int is_vimrc) { struct source_cookie cookie; char_u *save_sourcing_name; @@ -2538,125 +2723,113 @@ do_source ( proftime_T wait_start; p = expand_env_save(fname); - if (p == NULL) + if (p == NULL) { return retval; + } fname_exp = (char_u *)fix_fname((char *)p); xfree(p); - if (fname_exp == NULL) + if (fname_exp == NULL) { return retval; + } if (os_isdir(fname_exp)) { smsg(_("Cannot source a directory: \"%s\""), fname); goto theend; } - /* Apply SourceCmd autocommands, they should get the file and source it. */ + // Apply SourceCmd autocommands, they should get the file and source it. if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL) && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp, - FALSE, curbuf)) { + false, curbuf)) { retval = aborting() ? FAIL : OK; goto theend; } - /* Apply SourcePre autocommands, they may get the file. */ - apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf); + // 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, - * and ".exrc" by "_exrc" or vice versa. - */ + // Try again, replacing file name ".vimrc" by "_vimrc" or vice versa, + // and ".exrc" by "_exrc" or vice versa. 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 } } if (cookie.fp == NULL) { if (p_verbose > 0) { verbose_enter(); - if (sourcing_name == NULL) + if (sourcing_name == NULL) { smsg(_("could not source \"%s\""), fname); - else + } else { smsg(_("line %" PRId64 ": could not source \"%s\""), - (int64_t)sourcing_lnum, fname); + (int64_t)sourcing_lnum, fname); + } verbose_leave(); } goto theend; } - /* - * The file exists. - * - In verbose mode, give a message. - * - For a vimrc file, may want to call vimrc_found(). - */ + // The file exists. + // - In verbose mode, give a message. + // - For a vimrc file, may want to call vimrc_found(). if (p_verbose > 1) { verbose_enter(); - if (sourcing_name == NULL) + if (sourcing_name == NULL) { smsg(_("sourcing \"%s\""), fname); - else + } else { smsg(_("line %" PRId64 ": sourcing \"%s\""), - (int64_t)sourcing_lnum, fname); + (int64_t)sourcing_lnum, fname); + } verbose_leave(); } - if (is_vimrc == DOSO_VIMRC) + if (is_vimrc == DOSO_VIMRC) { vimrc_found(fname_exp, (char_u *)"MYVIMRC"); - else if (is_vimrc == DOSO_GVIMRC) + } else if (is_vimrc == DOSO_GVIMRC) { vimrc_found(fname_exp, (char_u *)"MYGVIMRC"); + } #ifdef USE_CRNL - /* If no automatic file format: Set default to CR-NL. */ - if (*p_ffs == NUL) + // If no automatic file format: Set default to CR-NL. + if (*p_ffs == NUL) { cookie.fileformat = EOL_DOS; - else + } else { cookie.fileformat = EOL_UNKNOWN; - cookie.error = FALSE; + } + cookie.error = false; #endif cookie.nextline = NULL; - cookie.finished = FALSE; + cookie.finished = false; - /* - * Check if this script has a breakpoint. - */ - cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0); + // Check if this script has a breakpoint. + cookie.breakpoint = dbg_find_breakpoint(true, fname_exp, (linenr_T)0); cookie.fname = fname_exp; cookie.dbg_tick = debug_tick; cookie.level = ex_nesting_level; - /* - * Keep the sourcing name/lnum, for recursive calls. - */ + // Keep the sourcing name/lnum, for recursive calls. save_sourcing_name = sourcing_name; sourcing_name = fname_exp; save_sourcing_lnum = sourcing_lnum; sourcing_lnum = 0; - cookie.conv.vc_type = CONV_NONE; /* no conversion */ + cookie.conv.vc_type = CONV_NONE; // no conversion - /* Read the first line so we can check for a UTF-8 BOM. */ + // Read the first line so we can check for a UTF-8 BOM. firstline = getsourceline(0, (void *)&cookie, 0); if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef && firstline[1] == 0xbb && firstline[2] == 0xbf) { - /* Found BOM; setup conversion, skip over BOM and recode the line. */ + // Found BOM; setup conversion, skip over BOM and recode the line. convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc); p = string_convert(&cookie.conv, firstline + 3, NULL); - if (p == NULL) + if (p == NULL) { p = vim_strsave(firstline + 3); + } xfree(firstline); firstline = p; } @@ -2671,22 +2844,21 @@ do_source ( } const int l_do_profiling = do_profiling; - if (l_do_profiling == PROF_YES) - prof_child_enter(&wait_start); /* entering a child now */ + if (l_do_profiling == PROF_YES) { + prof_child_enter(&wait_start); // entering a child now + } - /* Don't use local function variables, if called from a function. - * Also starts profiling timer for nested script. */ + // Don't use local function variables, if called from a function. + // Also starts profiling timer for nested script. save_funccalp = save_funccal(); - /* - * Check if this script was sourced before to finds its SID. - * If it's new, generate a new SID. - */ + // Check if this script was sourced before to finds its SID. + // If it's new, generate a new SID. save_current_SID = current_SID; FileID file_id; bool file_id_ok = os_fileid((char *)fname_exp, &file_id); assert(script_items.ga_len >= 0); - for (current_SID = script_items.ga_len; current_SID > 0; --current_SID) { + for (current_SID = script_items.ga_len; current_SID > 0; current_SID--) { si = &SCRIPT_ITEM(current_SID); // Compare dev/ino when possible, it catches symbolic links. // Also compare file names, the inode may change when the file was edited. @@ -2701,7 +2873,7 @@ do_source ( current_SID = ++last_current_SID; ga_grow(&script_items, (int)(current_SID - script_items.ga_len)); while (script_items.ga_len < current_SID) { - ++script_items.ga_len; + script_items.ga_len++; SCRIPT_ITEM(script_items.ga_len).sn_name = NULL; SCRIPT_ITEM(script_items.ga_len).sn_prof_on = false; } @@ -2715,53 +2887,53 @@ do_source ( si->file_id_valid = false; } - /* Allocate the local script variables to use for this script. */ + // Allocate the local script variables to use for this script. new_script_vars(current_SID); } if (l_do_profiling == PROF_YES) { - int forceit; + bool forceit; - /* Check if we do profiling for this script. */ + // Check if we do profiling for this script. if (!si->sn_prof_on && has_profiling(true, si->sn_name, &forceit)) { profile_init(si); si->sn_pr_force = forceit; } if (si->sn_prof_on) { - ++si->sn_pr_count; + si->sn_pr_count++; si->sn_pr_start = profile_start(); si->sn_pr_children = profile_zero(); } } - /* - * Call do_cmdline, which will call getsourceline() to get the lines. - */ + // Call do_cmdline, which will call getsourceline() to get the lines. do_cmdline(firstline, getsourceline, (void *)&cookie, - DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT); + DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT); retval = OK; if (l_do_profiling == PROF_YES) { - /* Get "si" again, "script_items" may have been reallocated. */ + // Get "si" again, "script_items" may have been reallocated. si = &SCRIPT_ITEM(current_SID); if (si->sn_prof_on) { si->sn_pr_start = profile_end(si->sn_pr_start); si->sn_pr_start = profile_sub_wait(wait_start, si->sn_pr_start); si->sn_pr_total = profile_add(si->sn_pr_total, si->sn_pr_start); si->sn_pr_self = profile_self(si->sn_pr_self, si->sn_pr_start, - si->sn_pr_children); + si->sn_pr_children); } } - if (got_int) + if (got_int) { EMSG(_(e_interr)); + } sourcing_name = save_sourcing_name; sourcing_lnum = save_sourcing_lnum; if (p_verbose > 1) { verbose_enter(); smsg(_("finished sourcing %s"), fname); - if (sourcing_name != NULL) + if (sourcing_name != NULL) { smsg(_("continuing in %s"), sourcing_name); + } verbose_leave(); } @@ -2771,18 +2943,18 @@ do_source ( time_pop(rel_time); } - /* - * After a "finish" in debug mode, need to break at first command of next - * sourced file. - */ + // After a "finish" in debug mode, need to break at first command of next + // sourced file. if (save_debug_break_level > ex_nesting_level - && debug_break_level == ex_nesting_level) - ++debug_break_level; + && debug_break_level == ex_nesting_level) { + debug_break_level++; + } current_SID = save_current_SID; restore_funccal(save_funccalp); - if (l_do_profiling == PROF_YES) - prof_child_exit(&wait_start); /* leaving a child now */ + if (l_do_profiling == PROF_YES) { + prof_child_exit(&wait_start); // leaving a child now + } fclose(cookie.fp); xfree(cookie.nextline); xfree(firstline); @@ -2794,26 +2966,23 @@ theend: } -/* - * ":scriptnames" - */ +/// ":scriptnames" void ex_scriptnames(exarg_T *eap) { - for (int i = 1; i <= script_items.ga_len && !got_int; ++i) + for (int i = 1; i <= script_items.ga_len && !got_int; i++) { if (SCRIPT_ITEM(i).sn_name != NULL) { home_replace(NULL, SCRIPT_ITEM(i).sn_name, - NameBuff, MAXPATHL, TRUE); + NameBuff, MAXPATHL, true); smsg("%3d: %s", i, NameBuff); } + } } # if defined(BACKSLASH_IN_FILENAME) -/* - * Fix slashes in the list of script names for 'shellslash'. - */ +/// Fix slashes in the list of script names for 'shellslash'. void scriptnames_slash_adjust(void) { - for (int i = 1; i <= script_items.ga_len; ++i) { + for (int i = 1; i <= script_items.ga_len; i++) { if (SCRIPT_ITEM(i).sn_name != NULL) { slash_adjust(SCRIPT_ITEM(i).sn_name); } @@ -2822,21 +2991,24 @@ void scriptnames_slash_adjust(void) # endif -/* - * Get a pointer to a script name. Used for ":verbose set". - */ +/// Get a pointer to a script name. Used for ":verbose set". char_u *get_scriptname(scid_T id) { - if (id == SID_MODELINE) + if (id == SID_MODELINE) { return (char_u *)_("modeline"); - if (id == SID_CMDARG) + } + if (id == SID_CMDARG) { return (char_u *)_("--cmd argument"); - if (id == SID_CARG) + } + if (id == SID_CARG) { return (char_u *)_("-c argument"); - if (id == SID_ENV) + } + if (id == SID_ENV) { return (char_u *)_("environment variable"); - if (id == SID_ERROR) + } + if (id == SID_ERROR) { return (char_u *)_("error handler"); + } return SCRIPT_ITEM(id).sn_name; } @@ -2849,51 +3021,49 @@ void free_scriptnames(void) # endif -/* - * Get one full line from a sourced file. - * Called by do_cmdline() when it's called from do_source(). - * - * Return a pointer to the line in allocated memory. - * Return NULL for end-of-file or some error. - */ +/// Get one full line from a sourced file. +/// Called by do_cmdline() when it's called from do_source(). +/// +/// @return pointer to the line in allocated memory, or NULL for end-of-file or +/// some error. char_u *getsourceline(int c, void *cookie, int indent) { struct source_cookie *sp = (struct source_cookie *)cookie; - char_u *line; - char_u *p; + char_u *line; + char_u *p; - /* If breakpoints have been added/deleted need to check for it. */ + // If breakpoints have been added/deleted need to check for it. if (sp->dbg_tick < debug_tick) { - sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum); + sp->breakpoint = dbg_find_breakpoint(true, sp->fname, sourcing_lnum); sp->dbg_tick = debug_tick; } - if (do_profiling == PROF_YES) + if (do_profiling == PROF_YES) { script_line_end(); - /* - * Get current line. If there is a read-ahead line, use it, otherwise get - * one now. - */ - if (sp->finished) + } + // Get current line. If there is a read-ahead line, use it, otherwise get + // one now. + if (sp->finished) { line = NULL; - else if (sp->nextline == NULL) + } else if (sp->nextline == NULL) { line = get_one_sourceline(sp); - else { + } else { line = sp->nextline; sp->nextline = NULL; - ++sourcing_lnum; + sourcing_lnum++; } - if (line != NULL && do_profiling == PROF_YES) + if (line != NULL && do_profiling == PROF_YES) { script_line_start(); + } - /* Only concatenate lines starting with a \ when 'cpoptions' doesn't - * contain the 'C' flag. */ + // Only concatenate lines starting with a \ when 'cpoptions' doesn't + // contain the 'C' flag. if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL)) { - /* compensate for the one line read-ahead */ - --sourcing_lnum; + // compensate for the one line read-ahead + sourcing_lnum--; - /* Get the next line and concatenate it when it starts with a - * backslash. We always need to read the next line, keep it in - * sp->nextline. */ + // Get the next line and concatenate it when it starts with a + // backslash. We always need to read the next line, keep it in + // sp->nextline. sp->nextline = get_one_sourceline(sp); if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\') { garray_T ga; @@ -2904,13 +3074,15 @@ char_u *getsourceline(int c, void *cookie, int indent) for (;; ) { xfree(sp->nextline); sp->nextline = get_one_sourceline(sp); - if (sp->nextline == NULL) + if (sp->nextline == NULL) { break; + } p = skipwhite(sp->nextline); - if (*p != '\\') + if (*p != '\\') { break; - /* Adjust the growsize to the current length to speed up - * concatenating many lines. */ + } + // Adjust the growsize to the current length to speed up + // concatenating many lines. if (ga.ga_len > 400) { ga_set_growsize(&ga, (ga.ga_len > 8000) ? 8000 : ga.ga_len); } @@ -2925,7 +3097,7 @@ char_u *getsourceline(int c, void *cookie, int indent) if (line != NULL && sp->conv.vc_type != CONV_NONE) { char_u *s; - /* Convert the encoding of the script line. */ + // Convert the encoding of the script line. s = string_convert(&sp->conv, line, NULL); if (s != NULL) { xfree(line); @@ -2933,11 +3105,11 @@ char_u *getsourceline(int c, void *cookie, int indent) } } - /* Did we encounter a breakpoint? */ + // Did we encounter a breakpoint? if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum) { dbg_breakpoint(sp->fname, sourcing_lnum); - /* Find next breakpoint. */ - sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum); + // Find next breakpoint. + sp->breakpoint = dbg_find_breakpoint(true, sp->fname, sourcing_lnum); sp->dbg_tick = debug_tick; } @@ -2951,175 +3123,170 @@ static char_u *get_one_sourceline(struct source_cookie *sp) int c; char_u *buf; #ifdef USE_CRNL - int has_cr; /* CR-LF found */ + int has_cr; // CR-LF found #endif - int have_read = FALSE; + bool have_read = false; - /* use a growarray to store the sourced line */ + // use a growarray to store the sourced line ga_init(&ga, 1, 250); - /* - * Loop until there is a finished line (or end-of-file). - */ + // Loop until there is a finished line (or end-of-file). sourcing_lnum++; for (;; ) { - /* make room to read at least 120 (more) characters */ + // make room to read at least 120 (more) characters ga_grow(&ga, 120); buf = (char_u *)ga.ga_data; if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len, - sp->fp) == NULL) + sp->fp) == NULL) { break; + } len = ga.ga_len + (int)STRLEN(buf + ga.ga_len); #ifdef USE_CRNL - /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the - * CTRL-Z by its own, or after a NL. */ - if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n')) - && sp->fileformat == EOL_DOS - && buf[len - 1] == Ctrl_Z) { + // Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the + // CTRL-Z by its own, or after a NL. + if ((len == 1 || (len >= 2 && buf[len - 2] == '\n')) + && sp->fileformat == EOL_DOS + && buf[len - 1] == Ctrl_Z) { buf[len - 1] = NUL; break; } #endif - have_read = TRUE; + have_read = true; ga.ga_len = len; - /* If the line was longer than the buffer, read more. */ - if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n') + // If the line was longer than the buffer, read more. + if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n') { continue; + } - if (len >= 1 && buf[len - 1] == '\n') { /* remove trailing NL */ + if (len >= 1 && buf[len - 1] == '\n') { // remove trailing NL #ifdef USE_CRNL has_cr = (len >= 2 && buf[len - 2] == '\r'); if (sp->fileformat == EOL_UNKNOWN) { - if (has_cr) + if (has_cr) { sp->fileformat = EOL_DOS; - else + } else { sp->fileformat = EOL_UNIX; + } } if (sp->fileformat == EOL_DOS) { - if (has_cr) { /* replace trailing CR */ + if (has_cr) { // replace trailing CR buf[len - 2] = '\n'; - --len; - --ga.ga_len; - } else { /* lines like ":map xx yy^M" will have failed */ + len--; + ga.ga_len--; + } else { // lines like ":map xx yy^M" will have failed if (!sp->error) { msg_source(hl_attr(HLF_W)); EMSG(_("W15: Warning: Wrong line separator, ^M may be missing")); } - sp->error = TRUE; + sp->error = true; sp->fileformat = EOL_UNIX; } } #endif - /* The '\n' is escaped if there is an odd number of ^V's just - * before it, first set "c" just before the 'V's and then check - * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */ - for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--) - ; - if ((len & 1) != (c & 1)) { /* escaped NL, read more */ + // The '\n' is escaped if there is an odd number of ^V's just + // before it, first set "c" just before the 'V's and then check + // len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo + for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--) {} + if ((len & 1) != (c & 1)) { // escaped NL, read more sourcing_lnum++; continue; } - buf[len - 1] = NUL; /* remove the NL */ + buf[len - 1] = NUL; // remove the NL } - /* - * Check for ^C here now and then, so recursive :so can be broken. - */ + // Check for ^C here now and then, so recursive :so can be broken. line_breakcheck(); break; } - if (have_read) + if (have_read) { return (char_u *)ga.ga_data; + } xfree(ga.ga_data); return NULL; } -/* - * Called when starting to read a script line. - * "sourcing_lnum" must be correct! - * When skipping lines it may not actually be executed, but we won't find out - * until later and we need to store the time now. - */ +/// Called when starting to read a script line. +/// "sourcing_lnum" must be correct! +/// When skipping lines it may not actually be executed, but we won't find out +/// until later and we need to store the time now. void script_line_start(void) { scriptitem_T *si; sn_prl_T *pp; - if (current_SID <= 0 || current_SID > script_items.ga_len) + if (current_SID <= 0 || current_SID > script_items.ga_len) { return; + } si = &SCRIPT_ITEM(current_SID); if (si->sn_prof_on && sourcing_lnum >= 1) { - /* Grow the array before starting the timer, so that the time spent - * here isn't counted. */ + // Grow the array before starting the timer, so that the time spent + // here isn't counted. ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len)); si->sn_prl_idx = sourcing_lnum - 1; while (si->sn_prl_ga.ga_len <= si->sn_prl_idx && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen) { - /* Zero counters for a line that was not used before. */ + // Zero counters for a line that was not used before. pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len); pp->snp_count = 0; pp->sn_prl_total = profile_zero(); pp->sn_prl_self = profile_zero(); - ++si->sn_prl_ga.ga_len; + si->sn_prl_ga.ga_len++; } - si->sn_prl_execed = FALSE; + si->sn_prl_execed = false; si->sn_prl_start = profile_start(); si->sn_prl_children = profile_zero(); si->sn_prl_wait = profile_get_wait(); } } -/* - * Called when actually executing a function line. - */ +/// Called when actually executing a function line. void script_line_exec(void) { scriptitem_T *si; - if (current_SID <= 0 || current_SID > script_items.ga_len) + if (current_SID <= 0 || current_SID > script_items.ga_len) { return; + } si = &SCRIPT_ITEM(current_SID); - if (si->sn_prof_on && si->sn_prl_idx >= 0) - si->sn_prl_execed = TRUE; + if (si->sn_prof_on && si->sn_prl_idx >= 0) { + si->sn_prl_execed = true; + } } -/* - * Called when done with a function line. - */ +/// Called when done with a function line. void script_line_end(void) { scriptitem_T *si; sn_prl_T *pp; - if (current_SID <= 0 || current_SID > script_items.ga_len) + if (current_SID <= 0 || current_SID > script_items.ga_len) { return; + } si = &SCRIPT_ITEM(current_SID); if (si->sn_prof_on && si->sn_prl_idx >= 0 && si->sn_prl_idx < si->sn_prl_ga.ga_len) { if (si->sn_prl_execed) { pp = &PRL_ITEM(si, si->sn_prl_idx); - ++pp->snp_count; + pp->snp_count++; si->sn_prl_start = profile_end(si->sn_prl_start); si->sn_prl_start = profile_sub_wait(si->sn_prl_wait, si->sn_prl_start); pp->sn_prl_total = profile_add(pp->sn_prl_total, si->sn_prl_start); pp->sn_prl_self = profile_self(pp->sn_prl_self, si->sn_prl_start, - si->sn_prl_children); + si->sn_prl_children); } si->sn_prl_idx = -1; } } -/* - * ":scriptencoding": Set encoding conversion for a sourced script. - * Without the multi-byte feature it's simply ignored. - */ +/// ":scriptencoding": Set encoding conversion for a sourced script. +/// Without the multi-byte feature it's simply ignored. void ex_scriptencoding(exarg_T *eap) { struct source_cookie *sp; @@ -3132,84 +3299,80 @@ void ex_scriptencoding(exarg_T *eap) if (*eap->arg != NUL) { name = enc_canonize(eap->arg); - } else + } else { name = eap->arg; + } - /* Setup for conversion from the specified encoding to 'encoding'. */ + // Setup for conversion from the specified encoding to 'encoding'. sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie); convert_setup(&sp->conv, name, p_enc); - if (name != eap->arg) + if (name != eap->arg) { xfree(name); + } } -/* - * ":finish": Mark a sourced file as finished. - */ +/// ":finish": Mark a sourced file as finished. void ex_finish(exarg_T *eap) { - if (getline_equal(eap->getline, eap->cookie, getsourceline)) - do_finish(eap, FALSE); - else + if (getline_equal(eap->getline, eap->cookie, getsourceline)) { + do_finish(eap, false); + } else { EMSG(_("E168: :finish used outside of a sourced file")); + } } -/* - * Mark a sourced file as finished. Possibly makes the ":finish" pending. - * Also called for a pending finish at the ":endtry" or after returning from - * an extra do_cmdline(). "reanimate" is used in the latter case. - */ +/// Mark a sourced file as finished. Possibly makes the ":finish" pending. +/// Also called for a pending finish at the ":endtry" or after returning from +/// an extra do_cmdline(). "reanimate" is used in the latter case. void do_finish(exarg_T *eap, int reanimate) { int idx; - if (reanimate) + if (reanimate) { ((struct source_cookie *)getline_cookie(eap->getline, - eap->cookie))->finished = FALSE; - - /* - * Cleanup (and inactivate) conditionals, but stop when a try conditional - * not in its finally clause (which then is to be executed next) is found. - * In this case, make the ":finish" pending for execution at the ":endtry". - * Otherwise, finish normally. - */ - idx = cleanup_conditionals(eap->cstack, 0, TRUE); + eap->cookie))->finished = false; + } + + // Cleanup (and inactivate) conditionals, but stop when a try conditional + // not in its finally clause (which then is to be executed next) is found. + // In this case, make the ":finish" pending for execution at the ":endtry". + // Otherwise, finish normally. + idx = cleanup_conditionals(eap->cstack, 0, true); if (idx >= 0) { eap->cstack->cs_pending[idx] = CSTP_FINISH; report_make_pending(CSTP_FINISH, NULL); - } else + } else { ((struct source_cookie *)getline_cookie(eap->getline, - eap->cookie))->finished = TRUE; + eap->cookie))->finished = true; + } } -/* - * Return TRUE when a sourced file had the ":finish" command: Don't give error - * message for missing ":endif". - * Return FALSE when not sourcing a file. - */ -int source_finished(LineGetter fgetline, void *cookie) +/// Return true when a sourced file had the ":finish" command: Don't give error +/// message for missing ":endif". +/// Return false when not sourcing a file. +bool source_finished(LineGetter fgetline, void *cookie) { return getline_equal(fgetline, cookie, getsourceline) && ((struct source_cookie *)getline_cookie( - fgetline, cookie))->finished; + fgetline, cookie))->finished; } -/* - * ":checktime [buffer]" - */ +/// ":checktime [buffer]" void ex_checktime(exarg_T *eap) { buf_T *buf; int save_no_check_timestamps = no_check_timestamps; no_check_timestamps = 0; - if (eap->addr_count == 0) /* default is all buffers */ - check_timestamps(FALSE); - else { + if (eap->addr_count == 0) { // default is all buffers + check_timestamps(false); + } else { buf = buflist_findnr((int)eap->line2); - if (buf != NULL) /* cannot happen? */ - (void)buf_check_timestamp(buf, FALSE); + if (buf != NULL) { // cannot happen? + (void)buf_check_timestamp(buf, false); + } } no_check_timestamps = save_no_check_timestamps; } @@ -3228,10 +3391,8 @@ static char *get_locale_val(int what) -/* - * Obtain the current messages language. Used to set the default for - * 'helplang'. May return NULL or an empty string. - */ +/// Obtain the current messages language. Used to set the default for +/// 'helplang'. May return NULL or an empty string. char *get_mess_lang(void) { char *p; @@ -3240,10 +3401,10 @@ char *get_mess_lang(void) # if defined(LC_MESSAGES) p = get_locale_val(LC_MESSAGES); # else - /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG - * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME - * and LC_MONETARY may be set differently for a Japanese working in the - * US. */ + // This is necessary for Win32, where LC_MESSAGES is not defined and $LANG + // may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME + // and LC_MONETARY may be set differently for a Japanese working in the + // US. p = get_locale_val(LC_COLLATE); # endif # else @@ -3258,11 +3419,9 @@ char *get_mess_lang(void) return p; } -/* Complicated #if; matches with where get_mess_env() is used below. */ +// Complicated #if; matches with where get_mess_env() is used below. #ifdef HAVE_WORKING_LIBINTL -/* - * Get the language used for messages from the environment. - */ +/// Get the language used for messages from the environment. static char_u *get_mess_env(void) { char_u *p; @@ -3273,7 +3432,7 @@ static char_u *get_mess_env(void) if (p == NULL) { p = (char_u *)os_getenv("LANG"); if (p != NULL && ascii_isdigit(*p)) { - p = NULL; /* ignore something like "1043" */ + p = NULL; // ignore something like "1043" } # ifdef HAVE_GET_LOCALE_VAL if (p == NULL) { @@ -3288,10 +3447,8 @@ static char_u *get_mess_env(void) #endif -/* - * Set the "v:lang" variable according to the current locale setting. - * Also do "v:lc_time"and "v:ctype". - */ +/// Set the "v:lang" variable according to the current locale setting. +/// Also do "v:lc_time"and "v:ctype". void set_lang_var(void) { const char *loc; @@ -3304,10 +3461,10 @@ void set_lang_var(void) # endif set_vim_var_string(VV_CTYPE, loc, -1); - /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall - * back to LC_CTYPE if it's empty. */ + // When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall + // back to LC_CTYPE if it's empty. # ifdef HAVE_WORKING_LIBINTL - loc = (char *) get_mess_env(); + loc = (char *)get_mess_env(); # elif defined(LC_MESSAGES) loc = get_locale_val(LC_MESSAGES); # else @@ -3323,9 +3480,11 @@ void set_lang_var(void) } #ifdef HAVE_WORKING_LIBINTL -/* - * ":language": Set the language (locale). - */ +/// +/// ":language": Set the language (locale). +/// +/// @param eap +/// void ex_language(exarg_T *eap) { char *loc; @@ -3341,9 +3500,9 @@ void ex_language(exarg_T *eap) name = eap->arg; - /* Check for "messages {name}", "ctype {name}" or "time {name}" argument. - * Allow abbreviation, but require at least 3 characters to avoid - * confusion with a two letter language name "me" or "ct". */ + // Check for "messages {name}", "ctype {name}" or "time {name}" argument. + // Allow abbreviation, but require at least 3 characters to avoid + // confusion with a two letter language name "me" or "ct". p = skiptowhite(eap->arg); if ((*p == NUL || ascii_iswhite(*p)) && p - eap->arg >= 3) { if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0) { @@ -3363,47 +3522,52 @@ void ex_language(exarg_T *eap) if (*name == NUL) { #ifdef HAVE_WORKING_LIBINTL - if (what == VIM_LC_MESSAGES) + if (what == VIM_LC_MESSAGES) { p = get_mess_env(); - else + } else { +#endif + p = (char_u *)setlocale(what, NULL); +#ifdef HAVE_WORKING_LIBINTL + } #endif - p = (char_u *)setlocale(what, NULL); - if (p == NULL || *p == NUL) + if (p == NULL || *p == NUL) { p = (char_u *)"Unknown"; + } smsg(_("Current %slanguage: \"%s\""), whatstr, p); } else { #ifndef LC_MESSAGES - if (what == VIM_LC_MESSAGES) + if (what == VIM_LC_MESSAGES) { loc = ""; - else + } else { #endif - { loc = setlocale(what, (char *)name); #ifdef LC_NUMERIC - /* Make sure strtod() uses a decimal point, not a comma. */ + // Make sure strtod() uses a decimal point, not a comma. setlocale(LC_NUMERIC, "C"); #endif +#ifndef LC_MESSAGES } - if (loc == NULL) +#endif + if (loc == NULL) { EMSG2(_("E197: Cannot set language to \"%s\""), name); - else { + } else { #ifdef HAVE_NL_MSG_CAT_CNTR - /* Need to do this for GNU gettext, otherwise cached translations - * will be used again. */ + // Need to do this for GNU gettext, otherwise cached translations + // will be used again. extern int _nl_msg_cat_cntr; - ++_nl_msg_cat_cntr; + _nl_msg_cat_cntr++; #endif - /* Reset $LC_ALL, otherwise it would overrule everything. */ + // Reset $LC_ALL, otherwise it would overrule everything. vim_setenv("LC_ALL", ""); if (what != LC_TIME) { - /* Tell gettext() what to translate to. It apparently doesn't - * use the currently effective locale. */ + // Tell gettext() what to translate to. It apparently doesn't + // use the currently effective locale. if (what == LC_ALL) { vim_setenv("LANG", (char *)name); - /* Clear $LANGUAGE because GNU gettext uses it. */ + // Clear $LANGUAGE because GNU gettext uses it. vim_setenv("LANGUAGE", ""); } if (what != LC_CTYPE) { @@ -3412,7 +3576,7 @@ void ex_language(exarg_T *eap) } } - /* Set v:lang, v:lc_time and v:ctype to the final result. */ + // Set v:lang, v:lc_time and v:ctype to the final result. set_lang_var(); maketitle(); } @@ -3420,43 +3584,43 @@ void ex_language(exarg_T *eap) } -static char_u **locales = NULL; /* Array of all available locales */ -static int did_init_locales = FALSE; +static char_u **locales = NULL; // Array of all available locales +static bool did_init_locales = false; -/* - * Lazy initialization of all available locales. - */ +/// Lazy initialization of all available locales. static void init_locales(void) { if (!did_init_locales) { - did_init_locales = TRUE; + did_init_locales = true; locales = find_locales(); } } -/* Return an array of strings for all available locales + NULL for the - * last element. Return NULL in case of error. */ +// Return an array of strings for all available locales + NULL for the +/// last element. Return NULL in case of error. static char_u **find_locales(void) { garray_T locales_ga; char_u *loc; + char *saveptr = NULL; - /* Find all available locales by running command "locale -a". If this - * doesn't work we won't have completion. */ + // Find all available locales by running command "locale -a". If this + // doesn't work we won't have completion. char_u *locale_a = get_cmd_output((char_u *)"locale -a", NULL, kShellOptSilent, NULL); - if (locale_a == NULL) + if (locale_a == NULL) { return NULL; + } ga_init(&locales_ga, sizeof(char_u *), 20); - /* Transform locale_a string where each locale is separated by "\n" - * into an array of locale strings. */ - loc = (char_u *)strtok((char *)locale_a, "\n"); + // Transform locale_a string where each locale is separated by "\n" + // into an array of locale strings. + loc = (char_u *)os_strtok((char *)locale_a, "\n", &saveptr); while (loc != NULL) { loc = vim_strsave(loc); GA_APPEND(char_u *, &locales_ga, loc); - loc = (char_u *)strtok(NULL, "\n"); + loc = (char_u *)os_strtok(NULL, "\n", &saveptr); } xfree(locale_a); // Guarantee that .ga_data is NULL terminated @@ -3470,8 +3634,9 @@ void free_locales(void) { int i; if (locales != NULL) { - for (i = 0; locales[i] != NULL; i++) + for (i = 0; locales[i] != NULL; i++) { xfree(locales[i]); + } xfree(locales); locales = NULL; } @@ -3479,33 +3644,34 @@ void free_locales(void) # endif -/* - * Function given to ExpandGeneric() to obtain the possible arguments of the - * ":language" command. - */ +/// Function given to ExpandGeneric() to obtain the possible arguments of the +/// ":language" command. char_u *get_lang_arg(expand_T *xp, int idx) { - if (idx == 0) + if (idx == 0) { return (char_u *)"messages"; - if (idx == 1) + } + if (idx == 1) { return (char_u *)"ctype"; - if (idx == 2) + } + if (idx == 2) { return (char_u *)"time"; + } init_locales(); - if (locales == NULL) + if (locales == NULL) { return NULL; + } return locales[idx - 3]; } -/* - * Function given to ExpandGeneric() to obtain the available locales. - */ +/// Function given to ExpandGeneric() to obtain the available locales. char_u *get_locales(expand_T *xp, int idx) { init_locales(); - if (locales == NULL) + if (locales == NULL) { return NULL; + } return locales[idx]; } @@ -3552,79 +3718,65 @@ static void script_host_do_range(char *name, exarg_T *eap) (void)eval_call_provider(name, "do_range", args); } -/* - * ":drop" - * Opens the first argument in a window. When there are two or more arguments - * the argument list is redefined. - */ +/// ":drop" +/// Opens the first argument in a window. When there are two or more arguments +/// the argument list is redefined. void ex_drop(exarg_T *eap) { - int split = FALSE; - buf_T *buf; - - /* - * Check if the first argument is already being edited in a window. If - * so, jump to that window. - * We would actually need to check all arguments, but that's complicated - * and mostly only one file is dropped. - * This also ignores wildcards, since it is very unlikely the user is - * editing a file name with a wildcard character. - */ - do_arglist(eap->arg, AL_SET, 0); - - /* - * Expanding wildcards may result in an empty argument list. E.g. when - * editing "foo.pyc" and ".pyc" is in 'wildignore'. Assume that we - * already did an error message for this. - */ - if (ARGCOUNT == 0) - return; - - if (cmdmod.tab) - { - /* ":tab drop file ...": open a tab for each argument that isn't - * edited in a window yet. It's like ":tab all" but without closing - * windows or tabs. */ - ex_all(eap); - } - else - { - /* ":drop file ...": Edit the first argument. Jump to an existing - * window if possible, edit in current window if the current buffer - * can be abandoned, otherwise open a new window. */ - buf = buflist_findnr(ARGLIST[0].ae_fnum); - - FOR_ALL_TAB_WINDOWS(tp, wp) - { - if (wp->w_buffer == buf) - { - goto_tabpage_win(tp, wp); - curwin->w_arg_idx = 0; - return; - } - } - - /* - * Check whether the current buffer is changed. If so, we will need - * to split the current window or data could be lost. - * Skip the check if the 'hidden' option is set, as in this case the - * buffer won't be lost. - */ - if (!P_HID(curbuf)) - { - ++emsg_off; - split = check_changed(curbuf, CCGD_AW | CCGD_EXCMD); - --emsg_off; - } - - /* Fake a ":sfirst" or ":first" command edit the first argument. */ - if (split) - { - eap->cmdidx = CMD_sfirst; - eap->cmd[0] = 's'; - } - else - eap->cmdidx = CMD_first; - ex_rewind(eap); + bool split = false; + buf_T *buf; + + // Check if the first argument is already being edited in a window. If + // so, jump to that window. + // We would actually need to check all arguments, but that's complicated + // and mostly only one file is dropped. + // This also ignores wildcards, since it is very unlikely the user is + // editing a file name with a wildcard character. + do_arglist(eap->arg, AL_SET, 0); + + // Expanding wildcards may result in an empty argument list. E.g. when + // editing "foo.pyc" and ".pyc" is in 'wildignore'. Assume that we + // already did an error message for this. + if (ARGCOUNT == 0) { + return; + } + + if (cmdmod.tab) { + // ":tab drop file ...": open a tab for each argument that isn't + // edited in a window yet. It's like ":tab all" but without closing + // windows or tabs. + ex_all(eap); + } else { + // ":drop file ...": Edit the first argument. Jump to an existing + // window if possible, edit in current window if the current buffer + // can be abandoned, otherwise open a new window. + buf = buflist_findnr(ARGLIST[0].ae_fnum); + + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (wp->w_buffer == buf) { + goto_tabpage_win(tp, wp); + curwin->w_arg_idx = 0; + return; + } } + + // Check whether the current buffer is changed. If so, we will need + // to split the current window or data could be lost. + // Skip the check if the 'hidden' option is set, as in this case the + // buffer won't be lost. + if (!P_HID(curbuf)) { + emsg_off++; + split = check_changed(curbuf, CCGD_AW | CCGD_EXCMD); + emsg_off--; + } + + // Fake a ":sfirst" or ":first" command edit the first argument. + if (split) { + eap->cmdidx = CMD_sfirst; + eap->cmd[0] = 's'; + } else { + eap->cmdidx = CMD_first; + } + ex_rewind(eap); + } } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 59962c153b..9bc7ec39da 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; @@ -3315,6 +3316,11 @@ set_one_cmd_context ( xp->xp_pattern = arg; break; + case CMD_packadd: + xp->xp_context = EXPAND_PACKADD; + xp->xp_pattern = arg; + break; + #ifdef HAVE_WORKING_LIBINTL case CMD_language: p = skiptowhite(arg); @@ -4640,14 +4646,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 } }; /* @@ -4659,41 +4665,42 @@ static struct { char *name; } command_complete[] = { - {EXPAND_AUGROUP, "augroup"}, - {EXPAND_BEHAVE, "behave"}, - {EXPAND_BUFFERS, "buffer"}, - {EXPAND_COLORS, "color"}, - {EXPAND_COMMANDS, "command"}, - {EXPAND_COMPILER, "compiler"}, - {EXPAND_CSCOPE, "cscope"}, - {EXPAND_USER_DEFINED, "custom"}, - {EXPAND_USER_LIST, "customlist"}, - {EXPAND_DIRECTORIES, "dir"}, - {EXPAND_ENV_VARS, "environment"}, - {EXPAND_EVENTS, "event"}, - {EXPAND_EXPRESSION, "expression"}, - {EXPAND_FILES, "file"}, - {EXPAND_FILES_IN_PATH, "file_in_path"}, - {EXPAND_FILETYPE, "filetype"}, - {EXPAND_FUNCTIONS, "function"}, - {EXPAND_HELP, "help"}, - {EXPAND_HIGHLIGHT, "highlight"}, - {EXPAND_HISTORY, "history"}, + { EXPAND_AUGROUP, "augroup" }, + { EXPAND_BEHAVE, "behave" }, + { EXPAND_BUFFERS, "buffer" }, + { EXPAND_COLORS, "color" }, + { EXPAND_COMMANDS, "command" }, + { EXPAND_COMPILER, "compiler" }, + { EXPAND_CSCOPE, "cscope" }, + { EXPAND_USER_DEFINED, "custom" }, + { EXPAND_USER_LIST, "customlist" }, + { EXPAND_DIRECTORIES, "dir" }, + { EXPAND_ENV_VARS, "environment" }, + { EXPAND_EVENTS, "event" }, + { EXPAND_EXPRESSION, "expression" }, + { EXPAND_FILES, "file" }, + { EXPAND_FILES_IN_PATH, "file_in_path" }, + { EXPAND_FILETYPE, "filetype" }, + { EXPAND_FUNCTIONS, "function" }, + { EXPAND_HELP, "help" }, + { EXPAND_HIGHLIGHT, "highlight" }, + { EXPAND_HISTORY, "history" }, #ifdef HAVE_WORKING_LIBINTL - {EXPAND_LOCALES, "locale"}, + { EXPAND_LOCALES, "locale" }, #endif - {EXPAND_MAPPINGS, "mapping"}, - {EXPAND_MENUS, "menu"}, - {EXPAND_OWNSYNTAX, "syntax"}, - {EXPAND_SYNTIME, "syntime"}, - {EXPAND_SETTINGS, "option"}, - {EXPAND_SHELLCMD, "shellcmd"}, - {EXPAND_SIGN, "sign"}, - {EXPAND_TAGS, "tag"}, - {EXPAND_TAGS_LISTFILES, "tag_listfiles"}, - {EXPAND_USER, "user"}, - {EXPAND_USER_VARS, "var"}, - {0, NULL} + { EXPAND_MAPPINGS, "mapping" }, + { EXPAND_MENUS, "menu" }, + { EXPAND_OWNSYNTAX, "syntax" }, + { EXPAND_SYNTIME, "syntime" }, + { EXPAND_SETTINGS, "option" }, + { EXPAND_PACKADD, "packadd" }, + { EXPAND_SHELLCMD, "shellcmd" }, + { EXPAND_SIGN, "sign" }, + { EXPAND_TAGS, "tag" }, + { EXPAND_TAGS_LISTFILES, "tag_listfiles" }, + { EXPAND_USER, "user" }, + { EXPAND_USER_VARS, "var" }, + { 0, NULL } }; static void uc_list(char_u *name, size_t name_len) @@ -6865,6 +6872,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 +7002,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 +7132,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 +7142,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 +7361,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) { @@ -7645,7 +7656,7 @@ open_exfile ( return NULL; } #endif - if (!forceit && *mode != 'a' && os_file_exists(fname)) { + if (!forceit && *mode != 'a' && os_path_exists(fname)) { EMSG2(_("E189: \"%s\" exists (add ! to override)"), fname); return NULL; } @@ -7855,19 +7866,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 } } @@ -9318,14 +9336,14 @@ static void ex_filetype(exarg_T *eap) } if (STRCMP(arg, "on") == 0 || STRCMP(arg, "detect") == 0) { if (*arg == 'o' || !filetype_detect) { - source_runtime((char_u *)FILETYPE_FILE, true); + source_runtime((char_u *)FILETYPE_FILE, DIP_ALL); filetype_detect = kTrue; if (plugin) { - source_runtime((char_u *)FTPLUGIN_FILE, true); + source_runtime((char_u *)FTPLUGIN_FILE, DIP_ALL); filetype_plugin = kTrue; } if (indent) { - source_runtime((char_u *)INDENT_FILE, true); + source_runtime((char_u *)INDENT_FILE, DIP_ALL); filetype_indent = kTrue; } } @@ -9336,15 +9354,15 @@ static void ex_filetype(exarg_T *eap) } else if (STRCMP(arg, "off") == 0) { if (plugin || indent) { if (plugin) { - source_runtime((char_u *)FTPLUGOF_FILE, true); + source_runtime((char_u *)FTPLUGOF_FILE, DIP_ALL); filetype_plugin = kFalse; } if (indent) { - source_runtime((char_u *)INDOFF_FILE, true); + source_runtime((char_u *)INDOFF_FILE, DIP_ALL); filetype_indent = kFalse; } } else { - source_runtime((char_u *)FTOFF_FILE, true); + source_runtime((char_u *)FTOFF_FILE, DIP_ALL); filetype_detect = kFalse; } } else 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..cd28554970 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; } @@ -3440,6 +3440,7 @@ addstar ( || context == EXPAND_COMPILER || context == EXPAND_OWNSYNTAX || context == EXPAND_FILETYPE + || context == EXPAND_PACKADD || (context == EXPAND_TAGS && fname[0] == '/')) retval = vim_strnsave(fname, len); else { @@ -3794,23 +3795,27 @@ ExpandFromContext ( || xp->xp_context == EXPAND_TAGS_LISTFILES) return expand_tags(xp->xp_context == EXPAND_TAGS, pat, num_file, file); if (xp->xp_context == EXPAND_COLORS) { - char *directories[] = {"colors", NULL}; - return ExpandRTDir(pat, num_file, file, directories); + char *directories[] = { "colors", NULL }; + return ExpandRTDir(pat, DIP_START + DIP_OPT, num_file, file, directories); } if (xp->xp_context == EXPAND_COMPILER) { - char *directories[] = {"compiler", NULL}; - return ExpandRTDir(pat, num_file, file, directories); + char *directories[] = { "compiler", NULL }; + return ExpandRTDir(pat, 0, num_file, file, directories); } if (xp->xp_context == EXPAND_OWNSYNTAX) { - char *directories[] = {"syntax", NULL}; - return ExpandRTDir(pat, num_file, file, directories); + char *directories[] = { "syntax", NULL }; + return ExpandRTDir(pat, 0, num_file, file, directories); } if (xp->xp_context == EXPAND_FILETYPE) { - char *directories[] = {"syntax", "indent", "ftplugin", NULL}; - return ExpandRTDir(pat, num_file, file, directories); + char *directories[] = { "syntax", "indent", "ftplugin", NULL }; + return ExpandRTDir(pat, 0, num_file, file, directories); } - if (xp->xp_context == EXPAND_USER_LIST) + if (xp->xp_context == EXPAND_USER_LIST) { return ExpandUserList(xp, num_file, file); + } + if (xp->xp_context == EXPAND_PACKADD) { + return ExpandPackAddDir(pat, num_file, file); + } regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0); if (regmatch.regprog == NULL) @@ -4190,12 +4195,16 @@ static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file) return OK; } -/* - * Expand color scheme, compiler or filetype names: - * 'runtimepath'/{dirnames}/{pat}.vim - * "dirnames" is an array with one or more directory names. - */ -static int ExpandRTDir(char_u *pat, int *num_file, char_u ***file, char *dirnames[]) +/// Expand color scheme, compiler or filetype names. +/// Search from 'runtimepath': +/// 'runtimepath'/{dirnames}/{pat}.vim +/// When "flags" has DIP_START: search also from 'start' of 'packpath': +/// 'packpath'/pack/ * /start/ * /{dirnames}/{pat}.vim +/// When "flags" has DIP_OPT: search also from 'opt' of 'packpath': +/// 'packpath'/pack/ * /opt/ * /{dirnames}/{pat}.vim +/// "dirnames" is an array with one or more directory names. +static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file, + char *dirnames[]) { *num_file = 0; *file = NULL; @@ -4212,6 +4221,26 @@ static int ExpandRTDir(char_u *pat, int *num_file, char_u ***file, char *dirname xfree(s); } + if (flags & DIP_START) { + for (int i = 0; dirnames[i] != NULL; i++) { + size_t size = STRLEN(dirnames[i]) + pat_len + 22; + char_u *s = xmalloc(size); + snprintf((char *)s, size, "pack/*/start/*/%s/%s*.vim", dirnames[i], pat); // NOLINT + globpath(p_pp, s, &ga, 0); + xfree(s); + } + } + + if (flags & DIP_OPT) { + for (int i = 0; dirnames[i] != NULL; i++) { + size_t size = STRLEN(dirnames[i]) + pat_len + 20; + char_u *s = xmalloc(size); + snprintf((char *)s, size, "pack/*/opt/*/%s/%s*.vim", dirnames[i], pat); // NOLINT + globpath(p_pp, s, &ga, 0); + xfree(s); + } + } + for (int i = 0; i < ga.ga_len; i++) { char_u *match = ((char_u **)ga.ga_data)[i]; char_u *s = match; @@ -4241,6 +4270,43 @@ static int ExpandRTDir(char_u *pat, int *num_file, char_u ***file, char *dirname return OK; } +/// Expand loadplugin names: +/// 'packpath'/pack/ * /opt/{pat} +static int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file) +{ + garray_T ga; + + *num_file = 0; + *file = NULL; + size_t pat_len = STRLEN(pat); + ga_init(&ga, (int)sizeof(char *), 10); + + size_t buflen = pat_len + 26; + char_u *s = xmalloc(buflen); + snprintf((char *)s, buflen, "pack/*/opt/%s*", pat); // NOLINT + globpath(p_pp, s, &ga, 0); + xfree(s); + + for (int i = 0; i < ga.ga_len; i++) { + char_u *match = ((char_u **)ga.ga_data)[i]; + s = path_tail(match); + char_u *e = s + STRLEN(s); + memmove(match, s, e - s + 1); + } + + if (GA_EMPTY(&ga)) { + return FAIL; + } + + // Sort and remove duplicates which can happen when specifying multiple + // directories in dirnames. + ga_remove_duplicate_strings(&ga); + + *file = ga.ga_data; + *num_file = ga.ga_len; + return OK; +} + /// Expand `file` for all comma-separated directories in `path`. /// Adds matches to `ga`. diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index beefc4238e..78b224f04c 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -791,7 +791,7 @@ char_u *vim_findfile(void *search_ctx_arg) for (;; ) { /* if file exists and we didn't already find it */ if ((path_with_url((char *)file_path) - || (os_file_exists(file_path) + || (os_path_exists(file_path) && (search_ctx->ffsc_find_what == FINDFILE_BOTH || ((search_ctx->ffsc_find_what @@ -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); @@ -1442,12 +1442,12 @@ find_file_in_path_option ( buf = suffixes; for (;; ) { if ( - (os_file_exists(NameBuff) - && (find_what == FINDFILE_BOTH - || ((find_what == FINDFILE_DIR) - == os_isdir(NameBuff))))) { - file_name = vim_strsave(NameBuff); - goto theend; + (os_path_exists(NameBuff) + && (find_what == FINDFILE_BOTH + || ((find_what == FINDFILE_DIR) + == os_isdir(NameBuff))))) { + file_name = vim_strsave(NameBuff); + goto theend; } if (*buf == NUL) break; diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index db1469db97..154558b332 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); @@ -2989,14 +2990,15 @@ nobackup: * delete an existing one, try to use another name. * Change one character, just before the extension. */ - if (!p_bk && os_file_exists(backup)) { + if (!p_bk && os_path_exists(backup)) { p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext); if (p < backup) /* empty file name ??? */ p = backup; *p = 'z'; - while (*p > 'a' && os_file_exists(backup)) - --*p; - /* They all exist??? Must be something wrong! */ + while (*p > 'a' && os_path_exists(backup)) { + (*p)--; + } + // They all exist??? Must be something wrong! if (*p == 'a') { xfree(backup); backup = NULL; @@ -3223,12 +3225,12 @@ restore_backup: * This may not work if the vim_rename() fails. * In that case we leave the copy around. */ - /* If file does not exist, put the copy in its place */ - if (!os_file_exists(fname)) { + // If file does not exist, put the copy in its place + if (!os_path_exists(fname)) { vim_rename(backup, fname); } - /* if original file does exist throw away the copy */ - if (os_file_exists(fname)) { + // if original file does exist throw away the copy + if (os_path_exists(fname)) { os_remove((char *)backup); } } else { @@ -3237,8 +3239,8 @@ restore_backup: } } - /* if original file no longer exists give an extra warning */ - if (!newfile && !os_file_exists(fname)) { + // if original file no longer exists give an extra warning + if (!newfile && !os_path_exists(fname)) { end = 0; } } @@ -3596,9 +3598,9 @@ restore_backup: * If the original file does not exist yet * the current backup file becomes the original file */ - if (org == NULL) + if (org == NULL) { EMSG(_("E205: Patchmode: can't save original file")); - else if (!os_file_exists((char_u *)org)) { + } else if (!os_path_exists((char_u *)org)) { vim_rename(backup, (char_u *)org); xfree(backup); /* don't delete the file */ backup = NULL; @@ -4513,9 +4515,11 @@ int vim_rename(char_u *from, char_u *to) if (STRLEN(from) >= MAXPATHL - 5) return -1; STRCPY(tempname, from); - for (n = 123; n < 99999; ++n) { - sprintf((char *)path_tail(tempname), "%d", n); - if (!os_file_exists(tempname)) { + for (n = 123; n < 99999; n++) { + char * tail = (char *)path_tail(tempname); + snprintf(tail, (MAXPATHL + 1) - (tail - (char *)tempname - 1), "%d", n); + + if (!os_path_exists(tempname)) { if (os_rename(from, tempname) == OK) { if (os_rename(tempname, to) == OK) return 0; @@ -4862,7 +4866,7 @@ buf_check_timestamp ( } } else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W) - && os_file_exists(buf->b_ffname)) { + && os_path_exists(buf->b_ffname)) { retval = 1; mesg = _("W13: Warning: File \"%s\" has been created after editing started"); buf->b_flags |= BF_NEW_W; diff --git a/src/nvim/func_attr.h b/src/nvim/func_attr.h index af8558d40d..ea017ab0c8 100644 --- a/src/nvim/func_attr.h +++ b/src/nvim/func_attr.h @@ -41,169 +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_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 +# 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 dafb75ca87..f2610ac868 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -414,7 +414,7 @@ EXTERN int provider_call_nesting INIT(= 0); EXTERN char_u hash_removed; -EXTERN int t_colors INIT(= 0); /* int value of T_CCO */ +EXTERN int t_colors INIT(= 256); // int value of T_CCO /* * When highlight_match is TRUE, highlight a match, starting at the cursor @@ -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 @@ -914,9 +914,6 @@ EXTERN int KeyTyped; // TRUE if user typed current char EXTERN int KeyStuffed; // TRUE if current char from stuffbuf EXTERN int maptick INIT(= 0); // tick for each non-mapped char -EXTERN uint8_t chartab[256]; // table used in charset.c; See - // init_chartab() for explanation - EXTERN int must_redraw INIT(= 0); /* type of redraw necessary */ EXTERN int skip_redraw INIT(= FALSE); /* skip redraw once */ EXTERN int do_redraw INIT(= FALSE); /* extra redraw once */ @@ -985,10 +982,11 @@ EXTERN int keep_help_flag INIT(= FALSE); /* doing :ta from help file */ */ EXTERN char_u *empty_option INIT(= (char_u *)""); -EXTERN int redir_off INIT(= FALSE); /* no redirection for a moment */ -EXTERN FILE *redir_fd INIT(= NULL); /* message redirection file */ -EXTERN int redir_reg INIT(= 0); /* message redirection register */ -EXTERN int redir_vname INIT(= 0); /* message redirection variable */ +EXTERN int redir_off INIT(= false); // no redirection for a moment +EXTERN FILE *redir_fd INIT(= NULL); // message redirection file +EXTERN int redir_reg INIT(= 0); // message redirection register +EXTERN int redir_vname INIT(= 0); // message redirection variable +EXTERN garray_T *capture_ga INIT(= NULL); // capture() buffer EXTERN char_u langmap_mapchar[256]; /* mapping for language keys */ @@ -1222,6 +1220,8 @@ EXTERN char_u e_invalpat[] INIT(= N_( EXTERN char_u e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer")); EXTERN char_u e_notset[] INIT(= N_("E764: Option '%s' is not set")); EXTERN char_u e_invalidreg[] INIT(= N_("E850: Invalid register name")); +EXTERN char_u e_dirnotf[] INIT(= N_( + "E919: Directory not found in '%s': \"%s\"")); EXTERN char_u e_unsupportedoption[] INIT(= N_("E519: Option not supported")); @@ -1243,7 +1243,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/hardcopy.c b/src/nvim/hardcopy.c index 916d27a964..1c9b8e18ef 100644 --- a/src/nvim/hardcopy.c +++ b/src/nvim/hardcopy.c @@ -1526,8 +1526,7 @@ static int prt_find_resource(char *name, struct prt_ps_resource_S *resource) vim_strcat(buffer, (char_u *)name, MAXPATHL); vim_strcat(buffer, (char_u *)".ps", MAXPATHL); resource->filename[0] = NUL; - retval = (do_in_runtimepath(buffer, FALSE, prt_resource_name, - resource->filename) + retval = (do_in_runtimepath(buffer, 0, prt_resource_name, resource->filename) && resource->filename[0] != NUL); xfree(buffer); return retval; diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index 2f9ec0b3ff..f2432dd71d 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -480,8 +480,9 @@ staterr: if (arg2 != NULL) { ppath = xmalloc(MAXPATHL + 1); expand_env((char_u *)arg2, (char_u *)ppath, MAXPATHL); - if (!os_file_exists((char_u *)ppath)) + if (!os_path_exists((char_u *)ppath)) { goto staterr; + } } int i; 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..584282d773 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,133 @@ 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 +/// +/// @note May not resize to an array smaller then init_array: if requested, +/// init_array will be used. +/// +/// @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, it is */ \ + /* hard to fix this here and is not very necessary if users will use */ \ + /* 2^x initial array size. */ \ + kvi_resize(v, (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/macros.h b/src/nvim/macros.h index 5f69fa2f6a..503daa9648 100644 --- a/src/nvim/macros.h +++ b/src/nvim/macros.h @@ -73,11 +73,6 @@ /* Returns empty string if it is NULL. */ #define EMPTY_IF_NULL(x) ((x) ? (x) : (char_u *)"") -/* macro version of chartab(). - * Only works with values 0-255! - * Doesn't work for UTF-8 mode with chars >= 0x80. */ -#define CHARSIZE(c) (chartab[c] & CT_CELL_MASK) - /* * Adjust chars in a language according to 'langmap' option. * NOTE that there is no noticeable overhead if 'langmap' is not set. diff --git a/src/nvim/main.c b/src/nvim/main.c index 71a972e8f6..e052d0d315 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. @@ -273,7 +276,6 @@ int main(int argc, char **argv) printf(_("%d files to edit\n"), GARGCOUNT); full_screen = true; - t_colors = 256; check_tty(¶ms); /* @@ -504,6 +506,9 @@ int main(int argc, char **argv) no_wait_return = FALSE; starting = 0; + // 'autochdir' has been postponed. + do_autochdir(); + /* start in insert mode */ if (p_im) need_start_insertmode = TRUE; @@ -665,8 +670,8 @@ static void init_locale(void) { char_u *p; - /* expand_env() doesn't work yet, because chartab[] is not initialized - * yet, call vim_getenv() directly */ + // expand_env() doesn't work yet, because g_chartab[] is not + // initialized yet, call vim_getenv() directly p = (char_u *)vim_getenv("VIMRUNTIME"); if (p != NULL && *p != NUL) { vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p); @@ -1236,8 +1241,11 @@ static void set_window_layout(mparm_T *paramp) static void load_plugins(void) { if (p_lpl) { - source_runtime((char_u *)"plugin/**/*.vim", TRUE); + source_runtime((char_u *)"plugin/**/*.vim", DIP_ALL); // NOLINT TIME_MSG("loading plugins"); + + ex_packloadall(NULL); + TIME_MSG("loading packages"); } } @@ -1665,8 +1673,6 @@ static bool do_user_initialization(void) } /// Source startup scripts -/// -/// @param[in] static void source_startup_scripts(const mparm_T *const parmp) FUNC_ATTR_NONNULL_ALL { 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..398e74268f 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) @@ -129,7 +129,10 @@ static inline khint_t String_hash(String s) static inline bool String_eq(String a, String b) { - return strncmp(a.data, b.data, MIN(a.size, b.size)) == 0; + if (a.size != b.size) { + return false; + } + return memcmp(a.data, b.data, a.size) == 0; } 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..673205f08f 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 } @@ -1358,7 +1359,7 @@ recover_names ( if (*dirp == NUL && file_count + num_files == 0 && fname != NULL) { char_u *swapname = (char_u *)modname((char *)fname_res, ".swp", TRUE); if (swapname != NULL) { - if (os_file_exists(swapname)) { + if (os_path_exists(swapname)) { files = xmalloc(sizeof(char_u *)); files[0] = swapname; swapname = NULL; @@ -3425,11 +3426,11 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, break; } - /* If the file was deleted this fname can be used. */ - if (!os_file_exists((char_u *) fname)) + // If the file was deleted this fname can be used. + if (!os_path_exists((char_u *)fname)) { break; - } else - { + } + } else { MSG_PUTS("\n"); if (msg_silent == 0) /* call wait_return() later */ diff --git a/src/nvim/message.c b/src/nvim/message.c index 521db85cf0..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. @@ -2389,6 +2392,19 @@ static void redir_write(char_u *str, int maxlen) char_u *s = str; static int cur_col = 0; + if (maxlen == 0) { + return; + } + + // Append output to capture(). + if (capture_ga) { + size_t len = 0; + while (str[len] && (maxlen < 0 ? 1 : (len < (size_t)maxlen))) { + len++; + } + ga_concat_len(capture_ga, (const char *)str, len); + } + /* Don't do anything for displaying prompts and the like. */ if (redir_off) return; @@ -2401,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 3a6d7c1434..5b249ee1c7 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -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; @@ -816,20 +816,55 @@ static void decref(Channel *channel) #define REQ "[request] " #define RES "[response] " #define NOT "[notification] " +#define ERR "[error] " + +// Cannot define array with negative offsets, so this one is needed to be added +// to MSGPACK_UNPACK_\* values. +#define MUR_OFF 2 + +static const char *const msgpack_error_messages[] = { + [MSGPACK_UNPACK_EXTRA_BYTES + MUR_OFF] = "extra bytes found", + [MSGPACK_UNPACK_CONTINUE + MUR_OFF] = "incomplete string", + [MSGPACK_UNPACK_PARSE_ERROR + MUR_OFF] = "parse error", + [MSGPACK_UNPACK_NOMEM_ERROR + MUR_OFF] = "not enough memory", +}; static void log_server_msg(uint64_t channel_id, msgpack_sbuffer *packed) { msgpack_unpacked unpacked; msgpack_unpacked_init(&unpacked); - msgpack_unpack_next(&unpacked, packed->data, packed->size, NULL); - uint64_t type = unpacked.data.via.array.ptr[0].via.u64; DLOGN("[msgpack-rpc] nvim -> client(%" PRIu64 ") ", channel_id); - log_lock(); - FILE *f = open_log_file(); - fprintf(f, type ? (type == 1 ? RES : NOT) : REQ); - log_msg_close(f, unpacked.data); - msgpack_unpacked_destroy(&unpacked); + const msgpack_unpack_return result = + msgpack_unpack_next(&unpacked, packed->data, packed->size, NULL); + switch (result) { + case MSGPACK_UNPACK_SUCCESS: { + uint64_t type = unpacked.data.via.array.ptr[0].via.u64; + log_lock(); + FILE *f = open_log_file(); + fprintf(f, type ? (type == 1 ? RES : NOT) : REQ); + log_msg_close(f, unpacked.data); + msgpack_unpacked_destroy(&unpacked); + break; + } + case MSGPACK_UNPACK_EXTRA_BYTES: + case MSGPACK_UNPACK_CONTINUE: + case MSGPACK_UNPACK_PARSE_ERROR: + case MSGPACK_UNPACK_NOMEM_ERROR: { + log_lock(); + FILE *f = open_log_file(); + fprintf(f, ERR); + log_msg_close(f, (msgpack_object) { + .type = MSGPACK_OBJECT_STR, + .via.str = { + .ptr = (char *)msgpack_error_messages[result + MUR_OFF], + .size = (uint32_t)strlen( + msgpack_error_messages[result + MUR_OFF]), + }, + }); + break; + } + } } static void log_client_msg(uint64_t channel_id, diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c index 0049ae6b95..9195b10614 100644 --- a/src/nvim/msgpack_rpc/helpers.c +++ b/src/nvim/msgpack_rpc/helpers.c @@ -7,9 +7,11 @@ #include "nvim/api/private/helpers.h" #include "nvim/msgpack_rpc/helpers.h" #include "nvim/msgpack_rpc/defs.h" +#include "nvim/lib/kvec.h" #include "nvim/vim.h" #include "nvim/log.h" #include "nvim/memory.h" +#include "nvim/assert.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "msgpack_rpc/helpers.c.generated.h" @@ -18,39 +20,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(const msgpack_object *const obj, t *const 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) @@ -63,34 +65,182 @@ HANDLE_TYPE_CONVERSION_IMPL(Buffer, buffer) HANDLE_TYPE_CONVERSION_IMPL(Window, window) HANDLE_TYPE_CONVERSION_IMPL(Tabpage, tabpage) -bool msgpack_rpc_to_boolean(msgpack_object *obj, Boolean *arg) +typedef struct { + const msgpack_object *mobj; + Object *aobj; + bool container; + size_t idx; +} MPToAPIObjectStackItem; + +/// Convert type used by msgpack parser to Neovim own API type +/// +/// @param[in] obj Msgpack value to convert. +/// @param[out] arg Location where result of conversion will be saved. +/// +/// @return true in case of success, false otherwise. +bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg) FUNC_ATTR_NONNULL_ALL { - *arg = obj->via.boolean; - return obj->type == MSGPACK_OBJECT_BOOLEAN; -} - -bool msgpack_rpc_to_integer(msgpack_object *obj, Integer *arg) - FUNC_ATTR_NONNULL_ALL -{ - if (obj->type == MSGPACK_OBJECT_POSITIVE_INTEGER - && obj->via.u64 <= INT64_MAX) { - *arg = (int64_t)obj->via.u64; - return true; + bool ret = true; + kvec_t(MPToAPIObjectStackItem) stack = KV_INITIAL_VALUE; + kv_push(stack, ((MPToAPIObjectStackItem) { obj, arg, false, 0 })); + while (ret && kv_size(stack)) { + MPToAPIObjectStackItem cur = kv_last(stack); + if (!cur.container) { + *cur.aobj = NIL; + } + switch (cur.mobj->type) { + case MSGPACK_OBJECT_NIL: { + break; + } + case MSGPACK_OBJECT_BOOLEAN: { + *cur.aobj = BOOLEAN_OBJ(cur.mobj->via.boolean); + break; + } + case MSGPACK_OBJECT_NEGATIVE_INTEGER: { + STATIC_ASSERT(sizeof(Integer) == sizeof(cur.mobj->via.i64), + "Msgpack integer size does not match API integer"); + *cur.aobj = INTEGER_OBJ(cur.mobj->via.i64); + break; + } + case MSGPACK_OBJECT_POSITIVE_INTEGER: { + STATIC_ASSERT(sizeof(Integer) == sizeof(cur.mobj->via.u64), + "Msgpack integer size does not match API integer"); + if (cur.mobj->via.u64 > API_INTEGER_MAX) { + ret = false; + } else { + *cur.aobj = INTEGER_OBJ((Integer)cur.mobj->via.u64); + } + break; + } + case MSGPACK_OBJECT_FLOAT: { + STATIC_ASSERT(sizeof(Float) == sizeof(cur.mobj->via.f64), + "Msgpack floating-point size does not match API integer"); + *cur.aobj = FLOATING_OBJ(cur.mobj->via.f64); + break; + } +#define STR_CASE(type, attr, obj, dest, conv) \ + case type: { \ + dest = conv(((String) { \ + .size = obj->via.attr.size, \ + .data = (obj->via.attr.ptr == NULL || obj->via.attr.size == 0 \ + ? NULL \ + : xmemdupz(obj->via.attr.ptr, obj->via.attr.size)), \ + })); \ + break; \ + } + STR_CASE(MSGPACK_OBJECT_STR, str, cur.mobj, *cur.aobj, STRING_OBJ) + STR_CASE(MSGPACK_OBJECT_BIN, bin, cur.mobj, *cur.aobj, STRING_OBJ) + case MSGPACK_OBJECT_ARRAY: { + const size_t size = cur.mobj->via.array.size; + if (cur.container) { + if (cur.idx >= size) { + (void)kv_pop(stack); + } else { + const size_t idx = cur.idx; + cur.idx++; + kv_last(stack) = cur; + kv_push(stack, ((MPToAPIObjectStackItem) { + .mobj = &cur.mobj->via.array.ptr[idx], + .aobj = &cur.aobj->data.array.items[idx], + .container = false, + })); + } + } else { + *cur.aobj = ARRAY_OBJ(((Array) { + .size = size, + .capacity = size, + .items = (size > 0 + ? xcalloc(size, sizeof(*cur.aobj->data.array.items)) + : NULL), + })); + cur.container = true; + kv_last(stack) = cur; + } + break; + } + case MSGPACK_OBJECT_MAP: { + const size_t size = cur.mobj->via.map.size; + if (cur.container) { + if (cur.idx >= size) { + (void)kv_pop(stack); + } else { + const size_t idx = cur.idx; + cur.idx++; + kv_last(stack) = cur; + const msgpack_object *const key = &cur.mobj->via.map.ptr[idx].key; + switch (key->type) { +#define ID(x) x + STR_CASE(MSGPACK_OBJECT_STR, str, key, + cur.aobj->data.dictionary.items[idx].key, ID) + STR_CASE(MSGPACK_OBJECT_BIN, bin, key, + cur.aobj->data.dictionary.items[idx].key, ID) +#undef ID + case MSGPACK_OBJECT_NIL: + case MSGPACK_OBJECT_BOOLEAN: + case MSGPACK_OBJECT_POSITIVE_INTEGER: + case MSGPACK_OBJECT_NEGATIVE_INTEGER: + case MSGPACK_OBJECT_FLOAT: + case MSGPACK_OBJECT_EXT: + case MSGPACK_OBJECT_MAP: + case MSGPACK_OBJECT_ARRAY: { + ret = false; + break; + } + } + if (ret) { + kv_push(stack, ((MPToAPIObjectStackItem) { + .mobj = &cur.mobj->via.map.ptr[idx].val, + .aobj = &cur.aobj->data.dictionary.items[idx].value, + .container = false, + })); + } + } + } else { + *cur.aobj = DICTIONARY_OBJ(((Dictionary) { + .size = size, + .capacity = size, + .items = (size > 0 + ? xcalloc(size, sizeof(*cur.aobj->data.dictionary.items)) + : NULL), + })); + cur.container = true; + kv_last(stack) = cur; + } + break; + } + case MSGPACK_OBJECT_EXT: { + switch (cur.mobj->via.ext.type) { + case kObjectTypeBuffer: { + cur.aobj->type = kObjectTypeBuffer; + ret = msgpack_rpc_to_buffer(cur.mobj, &cur.aobj->data.buffer); + break; + } + case kObjectTypeWindow: { + cur.aobj->type = kObjectTypeWindow; + ret = msgpack_rpc_to_window(cur.mobj, &cur.aobj->data.window); + break; + } + case kObjectTypeTabpage: { + cur.aobj->type = kObjectTypeTabpage; + ret = msgpack_rpc_to_tabpage(cur.mobj, &cur.aobj->data.tabpage); + break; + } + } + break; + } +#undef STR_CASE + } + if (!cur.container) { + (void)kv_pop(stack); + } } - - *arg = obj->via.i64; - return obj->type == MSGPACK_OBJECT_NEGATIVE_INTEGER; + kv_destroy(stack); + return ret; } -bool msgpack_rpc_to_float(msgpack_object *obj, Float *arg) - FUNC_ATTR_NONNULL_ALL -{ - *arg = obj->via.f64; - return obj->type == MSGPACK_OBJECT_FLOAT; -} - -bool msgpack_rpc_to_string(msgpack_object *obj, String *arg) +static bool msgpack_rpc_to_string(const msgpack_object *const obj, + String *const arg) FUNC_ATTR_NONNULL_ALL { if (obj->type == MSGPACK_OBJECT_BIN || obj->type == MSGPACK_OBJECT_STR) { @@ -103,58 +253,7 @@ bool msgpack_rpc_to_string(msgpack_object *obj, String *arg) return false; } -bool msgpack_rpc_to_object(msgpack_object *obj, Object *arg) - FUNC_ATTR_NONNULL_ALL -{ - switch (obj->type) { - case MSGPACK_OBJECT_NIL: - arg->type = kObjectTypeNil; - return true; - - case MSGPACK_OBJECT_BOOLEAN: - arg->type = kObjectTypeBoolean; - return msgpack_rpc_to_boolean(obj, &arg->data.boolean); - - case MSGPACK_OBJECT_POSITIVE_INTEGER: - case MSGPACK_OBJECT_NEGATIVE_INTEGER: - arg->type = kObjectTypeInteger; - return msgpack_rpc_to_integer(obj, &arg->data.integer); - - case MSGPACK_OBJECT_FLOAT: - arg->type = kObjectTypeFloat; - return msgpack_rpc_to_float(obj, &arg->data.floating); - - case MSGPACK_OBJECT_BIN: - case MSGPACK_OBJECT_STR: - arg->type = kObjectTypeString; - return msgpack_rpc_to_string(obj, &arg->data.string); - - case MSGPACK_OBJECT_ARRAY: - arg->type = kObjectTypeArray; - return msgpack_rpc_to_array(obj, &arg->data.array); - - case MSGPACK_OBJECT_MAP: - arg->type = kObjectTypeDictionary; - return msgpack_rpc_to_dictionary(obj, &arg->data.dictionary); - - case MSGPACK_OBJECT_EXT: - switch (obj->via.ext.type) { - case kObjectTypeBuffer: - arg->type = kObjectTypeBuffer; - return msgpack_rpc_to_buffer(obj, &arg->data.buffer); - case kObjectTypeWindow: - arg->type = kObjectTypeWindow; - return msgpack_rpc_to_window(obj, &arg->data.window); - case kObjectTypeTabpage: - arg->type = kObjectTypeTabpage; - return msgpack_rpc_to_tabpage(obj, &arg->data.tabpage); - } - default: - return false; - } -} - -bool msgpack_rpc_to_array(msgpack_object *obj, Array *arg) +bool msgpack_rpc_to_array(const msgpack_object *const obj, Array *const arg) FUNC_ATTR_NONNULL_ALL { if (obj->type != MSGPACK_OBJECT_ARRAY) { @@ -173,7 +272,8 @@ bool msgpack_rpc_to_array(msgpack_object *obj, Array *arg) return true; } -bool msgpack_rpc_to_dictionary(msgpack_object *obj, Dictionary *arg) +bool msgpack_rpc_to_dictionary(const msgpack_object *const obj, + Dictionary *const arg) FUNC_ATTR_NONNULL_ALL { if (obj->type != MSGPACK_OBJECT_MAP) { @@ -228,50 +328,108 @@ void msgpack_rpc_from_string(String result, msgpack_packer *res) msgpack_pack_str_body(res, result.data, result.size); } -void msgpack_rpc_from_object(Object result, msgpack_packer *res) +typedef struct { + const Object *aobj; + bool container; + size_t idx; +} APIToMPObjectStackItem; + +/// Convert type used by Neovim API to msgpack +/// +/// @param[in] result Object to convert. +/// @param[out] res Structure that defines where conversion results are saved. +/// +/// @return true in case of success, false otherwise. +void msgpack_rpc_from_object(const Object result, msgpack_packer *const res) FUNC_ATTR_NONNULL_ARG(2) { - switch (result.type) { - case kObjectTypeNil: - msgpack_pack_nil(res); - break; - - case kObjectTypeBoolean: - msgpack_rpc_from_boolean(result.data.boolean, res); - break; - - case kObjectTypeInteger: - msgpack_rpc_from_integer(result.data.integer, res); - break; - - case kObjectTypeFloat: - msgpack_rpc_from_float(result.data.floating, res); - break; - - case kObjectTypeString: - msgpack_rpc_from_string(result.data.string, res); - break; - - case kObjectTypeArray: - msgpack_rpc_from_array(result.data.array, res); - break; - - case kObjectTypeBuffer: - msgpack_rpc_from_buffer(result.data.buffer, res); - break; - - case kObjectTypeWindow: - msgpack_rpc_from_window(result.data.window, res); - break; - - case kObjectTypeTabpage: - msgpack_rpc_from_tabpage(result.data.tabpage, res); - break; - - case kObjectTypeDictionary: - msgpack_rpc_from_dictionary(result.data.dictionary, res); - break; + kvec_t(APIToMPObjectStackItem) stack = KV_INITIAL_VALUE; + kv_push(stack, ((APIToMPObjectStackItem) { &result, false, 0 })); + while (kv_size(stack)) { + APIToMPObjectStackItem cur = kv_last(stack); + switch (cur.aobj->type) { + case kObjectTypeNil: { + msgpack_pack_nil(res); + break; + } + case kObjectTypeBoolean: { + msgpack_rpc_from_boolean(cur.aobj->data.boolean, res); + break; + } + case kObjectTypeInteger: { + msgpack_rpc_from_integer(cur.aobj->data.integer, res); + break; + } + case kObjectTypeFloat: { + msgpack_rpc_from_float(cur.aobj->data.floating, res); + break; + } + case kObjectTypeString: { + msgpack_rpc_from_string(cur.aobj->data.string, res); + break; + } + case kObjectTypeBuffer: { + msgpack_rpc_from_buffer(cur.aobj->data.buffer, res); + break; + } + case kObjectTypeWindow: { + msgpack_rpc_from_window(cur.aobj->data.window, res); + break; + } + case kObjectTypeTabpage: { + msgpack_rpc_from_tabpage(cur.aobj->data.tabpage, res); + break; + } + case kObjectTypeArray: { + const size_t size = cur.aobj->data.array.size; + if (cur.container) { + if (cur.idx >= size) { + (void)kv_pop(stack); + } else { + const size_t idx = cur.idx; + cur.idx++; + kv_last(stack) = cur; + kv_push(stack, ((APIToMPObjectStackItem) { + .aobj = &cur.aobj->data.array.items[idx], + .container = false, + })); + } + } else { + msgpack_pack_array(res, size); + cur.container = true; + kv_last(stack) = cur; + } + break; + } + case kObjectTypeDictionary: { + const size_t size = cur.aobj->data.dictionary.size; + if (cur.container) { + if (cur.idx >= size) { + (void)kv_pop(stack); + } else { + const size_t idx = cur.idx; + cur.idx++; + kv_last(stack) = cur; + msgpack_rpc_from_string(cur.aobj->data.dictionary.items[idx].key, + res); + kv_push(stack, ((APIToMPObjectStackItem) { + .aobj = &cur.aobj->data.dictionary.items[idx].value, + .container = false, + })); + } + } else { + msgpack_pack_map(res, size); + cur.container = true; + kv_last(stack) = cur; + } + break; + } + } + if (!cur.container) { + (void)kv_pop(stack); + } } + kv_destroy(stack); } void msgpack_rpc_from_array(Array result, msgpack_packer *res) 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..25b3b85497 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; } /* @@ -1622,7 +1613,7 @@ int op_replace(oparg_T *oap, int c) int n, numc; int num_chars; char_u *newp, *oldp; - size_t oldlen; + colnr_T oldlen; struct block_def bd; char_u *after_p = NULL; int had_ctrl_v_cr = (c == -1 || c == -2); @@ -1690,42 +1681,56 @@ int op_replace(oparg_T *oap, int c) /* Compute bytes needed, move character count to num_chars. */ num_chars = numc; numc *= (*mb_char2len)(c); - /* oldlen includes textlen, so don't double count */ - n += numc - bd.textlen; 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 */ + oldlen = (int)STRLEN(oldp); + + size_t newp_size = (size_t)(bd.textcol + bd.startspaces); + if (had_ctrl_v_cr || (c != '\r' && c != '\n')) { + newp_size += (size_t)numc; + if (!bd.is_short) { + newp_size += (size_t)(bd.endspaces + oldlen + - bd.textcol - bd.textlen); + } + } + newp = xmallocz(newp_size); + // 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. + size_t after_p_len = 0; if (had_ctrl_v_cr || (c != '\r' && c != '\n')) { - if (has_mbyte) { - n = (int)STRLEN(newp); - while (--num_chars >= 0) - n += (*mb_char2bytes)(c, newp + n); - } else - memset(newp + STRLEN(newp), c, (size_t)numc); - if (!bd.is_short) { - /* insert post-spaces */ - memset(newp + STRLEN(newp), ' ', (size_t)bd.endspaces); - /* copy the part after the changed part */ - STRMOVE(newp + STRLEN(newp), oldp); + // strlen(newp) at this point + int newp_len = bd.textcol + bd.startspaces; + if (has_mbyte) { + while (--num_chars >= 0) { + newp_len += (*mb_char2bytes)(c, newp + newp_len); + } + } else { + memset(newp + newp_len, c, (size_t)numc); + newp_len += numc; + } + if (!bd.is_short) { + // insert post-spaces + memset(newp + newp_len, ' ', (size_t)bd.endspaces); + newp_len += bd.endspaces; + // copy the part after the changed part + memmove(newp + newp_len, oldp, + (size_t)(oldlen - bd.textcol - bd.textlen + 1)); } } else { - /* Replacing with \r or \n means splitting the line. */ - after_p = (char_u *) xmalloc((size_t)(oldlen + 1 + n - STRLEN(newp))); - STRMOVE(after_p, oldp); + // Replacing with \r or \n means splitting the line. + after_p_len = (size_t)(oldlen - bd.textcol - bd.textlen + 1); + after_p = (char_u *)xmalloc(after_p_len); + memmove(after_p, oldp, after_p_len); } /* replace the line */ ml_replace(curwin->w_cursor.lnum, newp, FALSE); if (after_p != NULL) { - ml_append(curwin->w_cursor.lnum++, after_p, 0, FALSE); + ml_append(curwin->w_cursor.lnum++, after_p, (int)after_p_len, false); appended_lines_mark(curwin->w_cursor.lnum, 1L); oap->end.lnum++; xfree(after_p); @@ -1992,7 +1997,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 +2071,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 +2080,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 +2114,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 +2143,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 +2204,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 +2224,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 +2280,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 +2317,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 +2356,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 +2484,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 +2515,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 +2551,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 +2568,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 +2585,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 +2709,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 +2740,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 +2765,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 +2817,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 +2870,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 +2907,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 +2932,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 +2950,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 +3001,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 +3044,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 +3224,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 +3265,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 +3442,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 +3465,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 +3559,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 +3596,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 +3779,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 +4474,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 +4484,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 +4592,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 +4605,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 +4768,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 +4803,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 +4814,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 +4831,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 +4887,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 +4912,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 +4941,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 +4991,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 +5005,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 +5061,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 +5080,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 +5092,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]); @@ -5450,7 +5452,7 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing) yankreg_T *target; if (cb_flags & CB_UNNAMEDPLUS) { - *name = cb_flags & CB_UNNAMED ? '"': '+'; + *name = (cb_flags & CB_UNNAMED && writing) ? '"': '+'; target = &y_regs[PLUS_REGISTER]; } else { *name = '*'; @@ -5474,7 +5476,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 +5521,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 +5553,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 +5569,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 +5593,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 +5618,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 +5681,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..de53b0b1f4 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); @@ -2313,50 +2314,46 @@ set_string_option_global ( } } -/* - * Set a string option to a new value, and handle the effects. - * - * Returns NULL on success or error message on error. - */ -static char_u * -set_string_option ( - int opt_idx, - char_u *value, - int opt_flags /* OPT_LOCAL and/or OPT_GLOBAL */ -) +/// Set a string option to a new value, handling the effects +/// +/// @param[in] opt_idx Option to set. +/// @param[in] value New value. +/// @param[in] opt_flags Option flags: expected to contain #OPT_LOCAL and/or +/// #OPT_GLOBAL. +/// +/// @return NULL on success, error message on error. +static char *set_string_option(const int opt_idx, const char *const value, + const int opt_flags) + FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_WARN_UNUSED_RESULT { - char_u *s; - char_u **varp; - char_u *oldval; - char *saved_oldval = NULL; - char_u *r = NULL; - - if (options[opt_idx].var == NULL) /* don't set hidden option */ + if (options[opt_idx].var == NULL) { // don't set hidden option return NULL; + } - s = vim_strsave(value); - varp = (char_u **)get_varp_scope(&(options[opt_idx]), - (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0 - ? (((int)options[opt_idx].indir & PV_BOTH) - ? OPT_GLOBAL : OPT_LOCAL) - : opt_flags); - oldval = *varp; + char *const s = xstrdup(value); + char **const varp = (char **)get_varp_scope( + &(options[opt_idx]), + ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0 + ? (((int)options[opt_idx].indir & PV_BOTH) + ? OPT_GLOBAL : OPT_LOCAL) + : opt_flags)); + char *const oldval = *varp; *varp = s; - if (!starting) { - saved_oldval = xstrdup((char *) oldval); - } + char *const saved_oldval = (starting ? NULL : xstrdup(oldval)); - if ((r = did_set_string_option(opt_idx, varp, (int)true, oldval, NULL, - opt_flags)) == NULL) - did_set_option(opt_idx, opt_flags, TRUE); + char *const r = (char *)did_set_string_option( + opt_idx, (char_u **)varp, (int)true, (char_u *)oldval, NULL, opt_flags); + if (r == NULL) { + did_set_option(opt_idx, opt_flags, true); + } // call autocommand after handling side effects if (saved_oldval != NULL) { char buf_type[7]; vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s", (opt_flags & OPT_LOCAL) ? "local" : "global"); - set_vim_var_string(VV_OPTION_NEW, (char *) (*varp), -1); + set_vim_var_string(VV_OPTION_NEW, (char *)(*varp), -1); set_vim_var_string(VV_OPTION_OLD, saved_oldval, -1); set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); apply_autocmds(EVENT_OPTIONSET, @@ -2442,16 +2439,13 @@ did_set_string_option ( else if (varp == &curwin->w_p_briopt) { if (briopt_check(curwin) == FAIL) errmsg = e_invarg; - } - /* - * 'isident', 'iskeyword', 'isprint or 'isfname' option: refill chartab[] - * If the new option is invalid, use old value. 'lisp' option: refill - * chartab[] for '-' char - */ - else if ( varp == &p_isi + } else if (varp == &p_isi || varp == &(curbuf->b_p_isk) || varp == &p_isp || varp == &p_isf) { + // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[] + // If the new option is invalid, use old value. 'lisp' option: refill + // g_chartab[] for '-' char if (init_chartab() == FAIL) { did_chartab = TRUE; /* need to restore it below */ errmsg = e_invarg; /* error in value */ @@ -3190,8 +3184,9 @@ did_set_string_option ( for (p = q; *p != NUL; ++p) if (vim_strchr((char_u *)"_.,", *p) != NULL) break; - vim_snprintf((char *)fname, 200, "spell/%.*s.vim", (int)(p - q), q); - source_runtime(fname, TRUE); + vim_snprintf((char *)fname, sizeof(fname), "spell/%.*s.vim", + (int)(p - q), q); + source_runtime(fname, DIP_ALL); } } @@ -3402,9 +3397,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 +4025,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) { @@ -4405,6 +4402,7 @@ bool get_tty_option(char *name, char **value) if (is_tty_option(name)) { if (value) { + // XXX: All other t_* options were removed in 3baba1e7. *value = xstrdup(""); } return true; @@ -4652,26 +4650,28 @@ set_option_value ( EMSG(_(e_sandbox)); return NULL; } - if (flags & P_STRING) - return set_string_option(opt_idx, string, opt_flags); - else { + if (flags & P_STRING) { + const char *s = (const char *)string; + if (s == NULL) { + s = ""; + } + return (char_u *)set_string_option(opt_idx, s, opt_flags); + } else { varp = get_varp_scope(&(options[opt_idx]), opt_flags); if (varp != NULL) { /* hidden option is not changed */ if (number == 0 && string != NULL) { int idx; - /* Either we are given a string or we are setting option - * to zero. */ - for (idx = 0; string[idx] == '0'; ++idx) - ; + // Either we are given a string or we are setting option + // to zero. + for (idx = 0; string[idx] == '0'; idx++) {} if (string[idx] != NUL || idx == 0) { - /* There's another character after zeros or the string - * is empty. In both cases, we are trying to set a - * num option using a string. */ + // There's another character after zeros or the string + // is empty. In both cases, we are trying to set a + // num option using a string. EMSG3(_("E521: Number required: &%s = '%s'"), - name, string); - return NULL; /* do nothing as we hit an error */ - + name, string); + return NULL; // do nothing as we hit an error } } if (flags & P_NUM) @@ -5606,6 +5606,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 +5656,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') @@ -5836,6 +5837,7 @@ set_context_in_set_cmd ( if (p == (char_u *)&p_bdir || p == (char_u *)&p_dir || p == (char_u *)&p_path + || p == (char_u *)&p_pp || p == (char_u *)&p_rtp || p == (char_u *)&p_cdpath || p == (char_u *)&p_vdir diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 904e97f8ca..8d6f42e088 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, \ }) @@ -456,80 +456,81 @@ EXTERN int p_hid; // 'hidden' // Use P_HID to check if a buffer is to be hidden when it is no longer // visible in a window. # define P_HID(buf) (buf_hide(buf)) -EXTERN char_u *p_hl; /* 'highlight' */ -EXTERN int p_hls; /* 'hlsearch' */ -EXTERN long p_hi; /* 'history' */ -EXTERN int p_hkmap; /* 'hkmap' */ -EXTERN int p_hkmapp; /* 'hkmapp' */ -EXTERN int p_fkmap; /* 'fkmap' */ -EXTERN int p_altkeymap; /* 'altkeymap' */ -EXTERN int p_arshape; /* 'arabicshape' */ -EXTERN int p_icon; /* 'icon' */ -EXTERN char_u *p_iconstring; /* 'iconstring' */ -EXTERN int p_ic; /* 'ignorecase' */ -EXTERN int p_is; /* 'incsearch' */ -EXTERN int p_im; /* 'insertmode' */ -EXTERN char_u *p_isf; /* 'isfname' */ -EXTERN char_u *p_isi; /* 'isident' */ -EXTERN char_u *p_isp; /* 'isprint' */ -EXTERN int p_js; /* 'joinspaces' */ -EXTERN char_u *p_kp; /* 'keywordprg' */ -EXTERN char_u *p_km; /* 'keymodel' */ -EXTERN char_u *p_langmap; /* 'langmap'*/ -EXTERN int p_lnr; /* 'langnoremap'*/ -EXTERN char_u *p_lm; /* 'langmenu' */ -EXTERN char_u *p_lispwords; /* 'lispwords' */ -EXTERN long p_ls; /* 'laststatus' */ -EXTERN long p_stal; /* 'showtabline' */ -EXTERN char_u *p_lcs; /* 'listchars' */ - -EXTERN int p_lz; /* 'lazyredraw' */ -EXTERN int p_lpl; /* 'loadplugins' */ -EXTERN int p_magic; /* 'magic' */ -EXTERN char_u *p_mef; /* 'makeef' */ -EXTERN char_u *p_mp; /* 'makeprg' */ -EXTERN char_u *p_cc; /* 'colorcolumn' */ -EXTERN int p_cc_cols[256]; /* array for 'colorcolumn' columns */ -EXTERN long p_mat; /* 'matchtime' */ -EXTERN long p_mco; /* 'maxcombine' */ -EXTERN long p_mfd; /* 'maxfuncdepth' */ -EXTERN long p_mmd; /* 'maxmapdepth' */ -EXTERN long p_mm; /* 'maxmem' */ -EXTERN long p_mmp; /* 'maxmempattern' */ -EXTERN long p_mmt; /* 'maxmemtot' */ -EXTERN long p_mis; /* 'menuitems' */ -EXTERN char_u *p_msm; /* 'mkspellmem' */ -EXTERN long p_mls; /* 'modelines' */ -EXTERN char_u *p_mouse; /* 'mouse' */ -EXTERN char_u *p_mousem; /* 'mousemodel' */ -EXTERN long p_mouset; /* 'mousetime' */ -EXTERN int p_more; /* 'more' */ -EXTERN char_u *p_opfunc; /* 'operatorfunc' */ -EXTERN char_u *p_para; /* 'paragraphs' */ -EXTERN int p_paste; /* 'paste' */ -EXTERN char_u *p_pt; /* 'pastetoggle' */ -EXTERN char_u *p_pex; /* 'patchexpr' */ -EXTERN char_u *p_pm; /* 'patchmode' */ -EXTERN char_u *p_path; /* 'path' */ -EXTERN char_u *p_cdpath; /* 'cdpath' */ -EXTERN long p_rdt; /* 'redrawtime' */ -EXTERN int p_remap; /* 'remap' */ -EXTERN long p_re; /* 'regexpengine' */ -EXTERN long p_report; /* 'report' */ -EXTERN long p_pvh; /* 'previewheight' */ -EXTERN int p_ari; /* 'allowrevins' */ -EXTERN int p_ri; /* 'revins' */ -EXTERN int p_ru; /* 'ruler' */ -EXTERN char_u *p_ruf; /* 'rulerformat' */ -EXTERN char_u *p_rtp; /* 'runtimepath' */ -EXTERN long p_sj; /* 'scrolljump' */ -EXTERN long p_so; /* 'scrolloff' */ -EXTERN char_u *p_sbo; /* 'scrollopt' */ -EXTERN char_u *p_sections; /* 'sections' */ -EXTERN int p_secure; /* 'secure' */ -EXTERN char_u *p_sel; /* 'selection' */ -EXTERN char_u *p_slm; /* 'selectmode' */ -EXTERN char_u *p_ssop; /* 'sessionoptions' */ +EXTERN char_u *p_hl; // 'highlight' +EXTERN int p_hls; // 'hlsearch' +EXTERN long p_hi; // 'history' +EXTERN int p_hkmap; // 'hkmap' +EXTERN int p_hkmapp; // 'hkmapp' +EXTERN int p_fkmap; // 'fkmap' +EXTERN int p_altkeymap; // 'altkeymap' +EXTERN int p_arshape; // 'arabicshape' +EXTERN int p_icon; // 'icon' +EXTERN char_u *p_iconstring; // 'iconstring' +EXTERN int p_ic; // 'ignorecase' +EXTERN int p_is; // 'incsearch' +EXTERN int p_im; // 'insertmode' +EXTERN char_u *p_isf; // 'isfname' +EXTERN char_u *p_isi; // 'isident' +EXTERN char_u *p_isp; // 'isprint' +EXTERN int p_js; // 'joinspaces' +EXTERN char_u *p_kp; // 'keywordprg' +EXTERN char_u *p_km; // 'keymodel' +EXTERN char_u *p_langmap; // 'langmap'*/ +EXTERN int p_lnr; // 'langnoremap'*/ +EXTERN char_u *p_lm; // 'langmenu' +EXTERN char_u *p_lispwords; // 'lispwords' +EXTERN long p_ls; // 'laststatus' +EXTERN long p_stal; // 'showtabline' +EXTERN char_u *p_lcs; // 'listchars' + +EXTERN int p_lz; // 'lazyredraw' +EXTERN int p_lpl; // 'loadplugins' +EXTERN int p_magic; // 'magic' +EXTERN char_u *p_mef; // 'makeef' +EXTERN char_u *p_mp; // 'makeprg' +EXTERN char_u *p_cc; // 'colorcolumn' +EXTERN int p_cc_cols[256]; // array for 'colorcolumn' columns +EXTERN long p_mat; // 'matchtime' +EXTERN long p_mco; // 'maxcombine' +EXTERN long p_mfd; // 'maxfuncdepth' +EXTERN long p_mmd; // 'maxmapdepth' +EXTERN long p_mm; // 'maxmem' +EXTERN long p_mmp; // 'maxmempattern' +EXTERN long p_mmt; // 'maxmemtot' +EXTERN long p_mis; // 'menuitems' +EXTERN char_u *p_msm; // 'mkspellmem' +EXTERN long p_mls; // 'modelines' +EXTERN char_u *p_mouse; // 'mouse' +EXTERN char_u *p_mousem; // 'mousemodel' +EXTERN long p_mouset; // 'mousetime' +EXTERN int p_more; // 'more' +EXTERN char_u *p_opfunc; // 'operatorfunc' +EXTERN char_u *p_para; // 'paragraphs' +EXTERN int p_paste; // 'paste' +EXTERN char_u *p_pt; // 'pastetoggle' +EXTERN char_u *p_pex; // 'patchexpr' +EXTERN char_u *p_pm; // 'patchmode' +EXTERN char_u *p_path; // 'path' +EXTERN char_u *p_cdpath; // 'cdpath' +EXTERN long p_rdt; // 'redrawtime' +EXTERN int p_remap; // 'remap' +EXTERN long p_re; // 'regexpengine' +EXTERN long p_report; // 'report' +EXTERN long p_pvh; // 'previewheight' +EXTERN int p_ari; // 'allowrevins' +EXTERN int p_ri; // 'revins' +EXTERN int p_ru; // 'ruler' +EXTERN char_u *p_ruf; // 'rulerformat' +EXTERN char_u *p_pp; // 'packpath' +EXTERN char_u *p_rtp; // 'runtimepath' +EXTERN long p_sj; // 'scrolljump' +EXTERN long p_so; // 'scrolloff' +EXTERN char_u *p_sbo; // 'scrollopt' +EXTERN char_u *p_sections; // 'sections' +EXTERN int p_secure; // 'secure' +EXTERN char_u *p_sel; // 'selection' +EXTERN char_u *p_slm; // 'selectmode' +EXTERN char_u *p_ssop; // 'sessionoptions' EXTERN unsigned ssop_flags; # ifdef IN_OPTION_C /* Also used for 'viewoptions'! */ diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 218e34f595..d19af4f73f 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1640,6 +1640,16 @@ return { defaults={if_true={vi=""}} }, { + full_name='packpath', abbreviation='pp', + type='string', list='onecomma', scope={'global'}, + deny_duplicates=true, + secure=true, + vi_def=true, + expand=true, + varname='p_pp', + defaults={if_true={vi=''}} + }, + { full_name='paragraphs', abbreviation='para', type='string', scope={'global'}, vi_def=true, diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c new file mode 100644 index 0000000000..6cee102305 --- /dev/null +++ b/src/nvim/os/fileio.c @@ -0,0 +1,319 @@ +/// @file fileio.c +/// +/// Buffered reading/writing to a file. Unlike fileio.c this is not dealing with +/// Neovim stuctures for buffer, with autocommands, etc: just fopen/fread/fwrite +/// replacement. + +#include <unistd.h> +#include <assert.h> +#include <stddef.h> +#include <stdbool.h> +#include <fcntl.h> + +#include "auto/config.h" + +#ifdef HAVE_SYS_UIO_H +# include <sys/uio.h> +#endif + +#include <uv.h> + +#include "nvim/os/fileio.h" +#include "nvim/memory.h" +#include "nvim/os/os.h" +#include "nvim/globals.h" +#include "nvim/rbuffer.h" +#include "nvim/macros.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "os/fileio.c.generated.h" +#endif + +/// Open file +/// +/// @param[out] ret_fp Address where information needed for reading from or +/// writing to a file is saved +/// @param[in] fname File name to open. +/// @param[in] flags Flags, @see FileOpenFlags. Currently reading from and +/// writing to the file at once is not supported, so either +/// FILE_WRITE_ONLY or FILE_READ_ONLY is required. +/// @param[in] mode Permissions for the newly created file (ignored if flags +/// does not have FILE_CREATE\*). +/// +/// @return Error code (@see os_strerror()) or 0. +int file_open(FileDescriptor *const ret_fp, const char *const fname, + const int flags, const int mode) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + int os_open_flags = 0; + int fd; + TriState wr = kNone; +#define FLAG(flags, flag, fcntl_flags, wrval, cond) \ + do { \ + if (flags & flag) { \ + os_open_flags |= fcntl_flags; \ + assert(cond); \ + if (wrval != kNone) { \ + wr = wrval; \ + } \ + } \ + } while (0) + FLAG(flags, kFileWriteOnly, O_WRONLY, kTrue, true); + FLAG(flags, kFileCreateOnly, O_CREAT|O_EXCL|O_WRONLY, kTrue, true); + FLAG(flags, kFileCreate, O_CREAT|O_WRONLY, kTrue, !(flags & kFileCreateOnly)); + FLAG(flags, kFileTruncate, O_TRUNC|O_WRONLY, kTrue, + !(flags & kFileCreateOnly)); + FLAG(flags, kFileReadOnly, O_RDONLY, kFalse, wr != kTrue); +#ifdef O_NOFOLLOW + FLAG(flags, kFileNoSymlink, O_NOFOLLOW, kNone, true); +#endif +#undef FLAG + + fd = os_open(fname, os_open_flags, mode); + + if (fd < 0) { + return fd; + } + + ret_fp->wr = (wr == kTrue); + ret_fp->fd = fd; + ret_fp->eof = false; + ret_fp->rv = rbuffer_new(kRWBufferSize); + ret_fp->_error = 0; + if (ret_fp->wr) { + ret_fp->rv->data = ret_fp; + ret_fp->rv->full_cb = (rbuffer_callback)&file_rb_write_full_cb; + } + return 0; +} + +/// Like file_open(), but allocate and return ret_fp +/// +/// @param[out] error Error code, @see os_strerror(). Is set to zero on +/// success. +/// @param[in] fname File name to open. +/// @param[in] flags Flags, @see FileOpenFlags. +/// @param[in] mode Permissions for the newly created file (ignored if flags +/// does not have FILE_CREATE\*). +/// +/// @return [allocated] Opened file or NULL in case of error. +FileDescriptor *file_open_new(int *const error, const char *const fname, + const int flags, const int mode) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT +{ + FileDescriptor *const fp = xmalloc(sizeof(*fp)); + if ((*error = file_open(fp, fname, flags, mode)) != 0) { + xfree(fp); + return NULL; + } + return fp; +} + +/// Close file and free its buffer +/// +/// @param[in,out] fp File to close. +/// +/// @return 0 or error code. +int file_close(FileDescriptor *const fp) FUNC_ATTR_NONNULL_ALL +{ + const int error = file_fsync(fp); + const int error2 = os_close(fp->fd); + rbuffer_free(fp->rv); + if (error2 != 0) { + return error2; + } + return error; +} + +/// Close and free file obtained using file_open_new() +/// +/// @param[in,out] fp File to close. +/// +/// @return 0 or error code. +int file_free(FileDescriptor *const fp) FUNC_ATTR_NONNULL_ALL +{ + const int ret = file_close(fp); + xfree(fp); + return ret; +} + +/// Flush file modifications to disk +/// +/// @param[in,out] fp File to work with. +/// +/// @return 0 or error code. +int file_fsync(FileDescriptor *const fp) + FUNC_ATTR_NONNULL_ALL +{ + if (!fp->wr) { + return 0; + } + file_rb_write_full_cb(fp->rv, fp); + if (fp->_error != 0) { + const int error = fp->_error; + fp->_error = 0; + return error; + } + return os_fsync(fp->fd); +} + +/// Buffer used for writing +/// +/// Like IObuff, but allows file_\* callers not to care about spoiling it. +static char writebuf[kRWBufferSize]; + +/// Function run when RBuffer is full when writing to a file +/// +/// Actually does writing to the file, may also be invoked directly. +/// +/// @param[in,out] rv RBuffer instance used. +/// @param[in,out] fp File to work with. +static void file_rb_write_full_cb(RBuffer *const rv, FileDescriptor *const fp) + FUNC_ATTR_NONNULL_ALL +{ + assert(fp->wr); + assert(rv->data == (void *)fp); + if (rbuffer_size(rv) == 0) { + return; + } + const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize); + const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes); + if (wres != (ptrdiff_t)read_bytes) { + if (wres >= 0) { + fp->_error = UV_EIO; + } else { + fp->_error = (int)wres; + } + } +} + +/// Read from file +/// +/// @param[in,out] fp File to work with. +/// @param[out] ret_buf Buffer to read to. Must not be NULL. +/// @param[in] size Number of bytes to read. Buffer must have at least ret_buf +/// bytes. +/// +/// @return error_code (< 0) or number of bytes read. +ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, + const size_t size) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + assert(!fp->wr); + char *buf = ret_buf; + size_t read_remaining = size; + RBuffer *const rv = fp->rv; + while (read_remaining) { + const size_t rv_size = rbuffer_size(rv); + if (rv_size > 0) { + const size_t rsize = rbuffer_read(rv, buf, MIN(rv_size, read_remaining)); + buf += rsize; + read_remaining -= rsize; + } + if (fp->eof) { + break; + } + if (read_remaining) { + assert(rbuffer_size(rv) == 0); + rbuffer_reset(rv); +#ifdef HAVE_READV + // If there is readv() syscall, then take an opportunity to populate + // both target buffer and RBuffer at once, … + size_t write_count; + struct iovec iov[] = { + { .iov_base = buf, .iov_len = read_remaining }, + { .iov_base = rbuffer_write_ptr(rv, &write_count), + .iov_len = kRWBufferSize }, + }; + assert(write_count == kRWBufferSize); + const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov, + ARRAY_SIZE(iov)); + if (r_ret > 0) { + if (r_ret > (ptrdiff_t)read_remaining) { + rbuffer_produced(rv, (size_t)(r_ret - (ptrdiff_t)read_remaining)); + read_remaining = 0; + } else { + buf += (size_t)r_ret; + read_remaining -= (size_t)r_ret; + } + } else if (r_ret < 0) { + return r_ret; + } +#else + if (read_remaining >= kRWBufferSize) { + // …otherwise leave RBuffer empty and populate only target buffer, + // because filtering information through rbuffer will be more syscalls. + const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining); + if (r_ret >= 0) { + read_remaining -= (size_t)r_ret; + return (ptrdiff_t)(size - read_remaining); + } else if (r_ret < 0) { + return r_ret; + } + } else { + size_t write_count; + const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, + rbuffer_write_ptr(rv, &write_count), + kRWBufferSize); + assert(write_count == kRWBufferSize); + if (r_ret > 0) { + rbuffer_produced(rv, (size_t)r_ret); + } else if (r_ret < 0) { + return r_ret; + } + } +#endif + } + } + return (ptrdiff_t)(size - read_remaining); +} + +/// Write to a file +/// +/// @param[in] fd File descriptor to write to. +/// @param[in] buf Data to write. May be NULL if size is zero. +/// @param[in] size Amount of bytes to write. +/// +/// @return Number of bytes written or libuv error code (< 0). +ptrdiff_t file_write(FileDescriptor *const fp, const char *const buf, + const size_t size) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) +{ + assert(fp->wr); + const size_t written = rbuffer_write(fp->rv, buf, size); + if (fp->_error != 0) { + const int error = fp->_error; + fp->_error = 0; + return error; + } else if (written != size) { + return UV_EIO; + } + return (ptrdiff_t)written; +} + +/// Buffer used for skipping. Its contents is undefined and should never be +/// used. +static char skipbuf[kRWBufferSize]; + +/// Skip some bytes +/// +/// This is like `fseek(fp, size, SEEK_CUR)`, but actual implementation simply +/// reads to a buffer and discards the result. +ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size) + FUNC_ATTR_NONNULL_ALL +{ + assert(!fp->wr); + size_t read_bytes = 0; + do { + const ptrdiff_t new_read_bytes = file_read( + fp, skipbuf, MIN(size - read_bytes, sizeof(skipbuf))); + if (new_read_bytes < 0) { + return new_read_bytes; + } else if (new_read_bytes == 0) { + break; + } + read_bytes += (size_t)new_read_bytes; + } while (read_bytes < size && !file_eof(fp)); + + return (ptrdiff_t)read_bytes; +} diff --git a/src/nvim/os/fileio.h b/src/nvim/os/fileio.h new file mode 100644 index 0000000000..2cffd5c851 --- /dev/null +++ b/src/nvim/os/fileio.h @@ -0,0 +1,72 @@ +#ifndef NVIM_OS_FILEIO_H +#define NVIM_OS_FILEIO_H + +#include <stdbool.h> +#include <stddef.h> + +#include "nvim/func_attr.h" +#include "nvim/rbuffer.h" + +/// Structure used to read from/write to file +typedef struct { + int fd; ///< File descriptor. + int _error; ///< Error code for use with RBuffer callbacks or zero. + RBuffer *rv; ///< Read or write buffer. + bool wr; ///< True if file is in write mode. + bool eof; ///< True if end of file was encountered. +} FileDescriptor; + +/// file_open() flags +typedef enum { + kFileReadOnly = 1, ///< Open file read-only. Default. + kFileCreate = 2, ///< Create file if it does not exist yet. + ///< Implies kFileWriteOnly. + kFileWriteOnly = 4, ///< Open file for writing only. + ///< Cannot be used with kFileReadOnly. + kFileNoSymlink = 8, ///< Do not allow symbolic links. + kFileCreateOnly = 16, ///< Only create the file, failing if it already + ///< exists. Implies kFileWriteOnly. Cannot be used + ///< with kFileCreate. + kFileTruncate = 32, ///< Truncate the file if it exists. + ///< Implies kFileWriteOnly. Cannot be used with + ///< kFileCreateOnly. +} FileOpenFlags; + +static inline bool file_eof(const FileDescriptor *const fp) + REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; + +/// Check whether end of file was encountered +/// +/// @param[in] fp File to check. +/// +/// @return true if it was, false if it was not or read operation was never +/// performed. +static inline bool file_eof(const FileDescriptor *const fp) +{ + return fp->eof && rbuffer_size(fp->rv) == 0; +} + +static inline int file_fd(const FileDescriptor *const fp) + REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; + +/// Return the file descriptor associated with the FileDescriptor structure +/// +/// @param[in] fp File to check. +/// +/// @return File descriptor. +static inline int file_fd(const FileDescriptor *const fp) +{ + return fp->fd; +} + +enum { + /// Read or write buffer size + /// + /// Currently equal to (IOSIZE - 1), but they do not need to be connected. + kRWBufferSize = 1024 +}; + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "os/fileio.h.generated.h" +#endif +#endif // NVIM_OS_FILEIO_H diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 143a7160b0..d12d34d595 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -1,14 +1,26 @@ // fs.c -- filesystem access #include <stdbool.h> - +#include <stddef.h> #include <assert.h> +#include <limits.h> +#include <unistd.h> #include <fcntl.h> +#include <errno.h> + +#include "auto/config.h" + +#ifdef HAVE_SYS_UIO_H +# include <sys/uio.h> +#endif + +#include <uv.h> #include "nvim/os/os.h" #include "nvim/os/os_defs.h" #include "nvim/ascii.h" #include "nvim/memory.h" #include "nvim/message.h" +#include "nvim/assert.h" #include "nvim/misc1.h" #include "nvim/misc2.h" #include "nvim/path.h" @@ -18,6 +30,20 @@ # include "os/fs.c.generated.h" #endif +#define RUN_UV_FS_FUNC(ret, func, ...) \ + do { \ + bool did_try_to_free = false; \ +uv_call_start: {} \ + uv_fs_t req; \ + ret = func(&fs_loop, &req, __VA_ARGS__); \ + uv_fs_req_cleanup(&req); \ + if (ret == UV_ENOMEM && !did_try_to_free) { \ + try_to_free_memory(); \ + did_try_to_free = true; \ + goto uv_call_start; \ + } \ + } while (0) + // Many fs functions from libuv return that value on success. static const int kLibuvSuccess = 0; static uv_loop_t fs_loop; @@ -325,13 +351,190 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath) int os_open(const char* path, int flags, int mode) FUNC_ATTR_NONNULL_ALL { - uv_fs_t open_req; - int r = uv_fs_open(&fs_loop, &open_req, path, flags, mode, NULL); - uv_fs_req_cleanup(&open_req); - // r is the same as open_req.result (except for OOM: then only r is set). + int r; + RUN_UV_FS_FUNC(r, uv_fs_open, path, flags, mode, NULL); + return r; +} + +/// Close a file +/// +/// @return 0 or libuv error code on failure. +int os_close(const int fd) +{ + int r; + RUN_UV_FS_FUNC(r, uv_fs_close, fd, NULL); return r; } +/// Read from a file +/// +/// Handles EINTR and ENOMEM, but not other errors. +/// +/// @param[in] fd File descriptor to read from. +/// @param[out] ret_eof Is set to true if EOF was encountered, otherwise set +/// to false. Initial value is ignored. +/// @param[out] ret_buf Buffer to write to. May be NULL if size is zero. +/// @param[in] size Amount of bytes to read. +/// +/// @return Number of bytes read or libuv error code (< 0). +ptrdiff_t os_read(const int fd, bool *ret_eof, char *const ret_buf, + const size_t size) + FUNC_ATTR_WARN_UNUSED_RESULT +{ + *ret_eof = false; + if (ret_buf == NULL) { + assert(size == 0); + return 0; + } + size_t read_bytes = 0; + bool did_try_to_free = false; + while (read_bytes != size) { + const ptrdiff_t cur_read_bytes = read(fd, ret_buf + read_bytes, + size - read_bytes); + if (cur_read_bytes > 0) { + read_bytes += (size_t)cur_read_bytes; + assert(read_bytes <= size); + } + if (cur_read_bytes < 0) { +#ifdef HAVE_UV_TRANSLATE_SYS_ERROR + const int error = uv_translate_sys_error(errno); +#else + const int error = -errno; + STATIC_ASSERT(-EINTR == UV_EINTR, "Need to translate error codes"); + STATIC_ASSERT(-EAGAIN == UV_EAGAIN, "Need to translate error codes"); + STATIC_ASSERT(-ENOMEM == UV_ENOMEM, "Need to translate error codes"); +#endif + errno = 0; + if (error == UV_EINTR || error == UV_EAGAIN) { + continue; + } else if (error == UV_ENOMEM && !did_try_to_free) { + try_to_free_memory(); + did_try_to_free = true; + continue; + } else { + return (ptrdiff_t)error; + } + } + if (cur_read_bytes == 0) { + *ret_eof = true; + break; + } + } + return (ptrdiff_t)read_bytes; +} + +#ifdef HAVE_READV +/// Read from a file to multiple buffers at once +/// +/// Wrapper for readv(). +/// +/// @param[in] fd File descriptor to read from. +/// @param[out] ret_eof Is set to true if EOF was encountered, otherwise set +/// to false. Initial value is ignored. +/// @param[out] iov Description of buffers to write to. Note: this description +/// may change, it is incorrect to use data it points to after +/// os_readv(). +/// @param[in] iov_size Number of buffers in iov. +ptrdiff_t os_readv(int fd, bool *ret_eof, struct iovec *iov, size_t iov_size) + FUNC_ATTR_NONNULL_ALL +{ + *ret_eof = false; + size_t read_bytes = 0; + bool did_try_to_free = false; + size_t toread = 0; + for (size_t i = 0; i < iov_size; i++) { + // Overflow, trying to read too much data + assert(toread <= SIZE_MAX - iov[i].iov_len); + toread += iov[i].iov_len; + } + while (read_bytes < toread && iov_size && !*ret_eof) { + ptrdiff_t cur_read_bytes = readv(fd, iov, (int)iov_size); + if (toread && cur_read_bytes == 0) { + *ret_eof = true; + } + if (cur_read_bytes > 0) { + read_bytes += (size_t)cur_read_bytes; + while (iov_size && cur_read_bytes) { + if (cur_read_bytes < (ptrdiff_t)iov->iov_len) { + iov->iov_len -= (size_t)cur_read_bytes; + iov->iov_base = (char *)iov->iov_base + cur_read_bytes; + cur_read_bytes = 0; + } else { + cur_read_bytes -= (ptrdiff_t)iov->iov_len; + iov_size--; + iov++; + } + } + } else if (cur_read_bytes < 0) { +#ifdef HAVE_UV_TRANSLATE_SYS_ERROR + const int error = uv_translate_sys_error(errno); +#else + const int error = -errno; + STATIC_ASSERT(-EINTR == UV_EINTR, "Need to translate error codes"); + STATIC_ASSERT(-EAGAIN == UV_EAGAIN, "Need to translate error codes"); + STATIC_ASSERT(-ENOMEM == UV_ENOMEM, "Need to translate error codes"); +#endif + errno = 0; + if (error == UV_EINTR || error == UV_EAGAIN) { + continue; + } else if (error == UV_ENOMEM && !did_try_to_free) { + try_to_free_memory(); + did_try_to_free = true; + continue; + } else { + return (ptrdiff_t)error; + } + } + } + return (ptrdiff_t)read_bytes; +} +#endif // HAVE_READV + +/// Write to a file +/// +/// @param[in] fd File descriptor to write to. +/// @param[in] buf Data to write. May be NULL if size is zero. +/// @param[in] size Amount of bytes to write. +/// +/// @return Number of bytes written or libuv error code (< 0). +ptrdiff_t os_write(const int fd, const char *const buf, const size_t size) + FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (buf == NULL) { + assert(size == 0); + return 0; + } + size_t written_bytes = 0; + while (written_bytes != size) { + const ptrdiff_t cur_written_bytes = write(fd, buf + written_bytes, + size - written_bytes); + if (cur_written_bytes > 0) { + written_bytes += (size_t)cur_written_bytes; + } + if (cur_written_bytes < 0) { +#ifdef HAVE_UV_TRANSLATE_SYS_ERROR + const int error = uv_translate_sys_error(errno); +#else + const int error = -errno; + STATIC_ASSERT(-EINTR == UV_EINTR, "Need to translate error codes"); + STATIC_ASSERT(-EAGAIN == UV_EAGAIN, "Need to translate error codes"); + // According to the man page open() may fail with ENOMEM, but write() + // can’t. +#endif + errno = 0; + if (error == UV_EINTR || error == UV_EAGAIN) { + continue; + } else { + return error; + } + } + if (cur_written_bytes == 0) { + return UV_UNKNOWN; + } + } + return (ptrdiff_t)written_bytes; +} + /// Flushes file modifications to disk. /// /// @param fd the file descriptor of the file to flush to disk. @@ -339,9 +542,8 @@ int os_open(const char* path, int flags, int mode) /// @return `0` on success, a libuv error code on failure. int os_fsync(int fd) { - uv_fs_t fsync_req; - int r = uv_fs_fsync(&fs_loop, &fsync_req, fd, NULL); - uv_fs_req_cleanup(&fsync_req); + int r; + RUN_UV_FS_FUNC(r, uv_fs_fsync, fd, NULL); return r; } @@ -379,16 +581,9 @@ int32_t os_getperm(const char_u *name) int os_setperm(const char_u *name, int perm) FUNC_ATTR_NONNULL_ALL { - uv_fs_t request; - int result = uv_fs_chmod(&fs_loop, &request, - (const char*)name, perm, NULL); - uv_fs_req_cleanup(&request); - - if (result == kLibuvSuccess) { - return OK; - } - - return FAIL; + int r; + RUN_UV_FS_FUNC(r, uv_fs_chmod, (const char *)name, perm, NULL); + return (r == kLibuvSuccess ? OK : FAIL); } /// Changes the ownership of the file referred to by the open file descriptor. @@ -397,24 +592,21 @@ 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 +int os_fchown(int fd, uv_uid_t owner, uv_gid_t group) { - uv_fs_t request; - int result = uv_fs_fchown(&fs_loop, &request, file_descriptor, - owner, group, NULL); - uv_fs_req_cleanup(&request); - return result; + int r; + RUN_UV_FS_FUNC(r, uv_fs_fchown, fd, owner, group, NULL); + return r; } -/// Check if a file exists. +/// Check if a path exists. /// -/// @return `true` if `name` exists. -bool os_file_exists(const char_u *name) +/// @return `true` if `path` exists +bool os_path_exists(const char_u *path) FUNC_ATTR_NONNULL_ALL { uv_stat_t statbuf; - return os_stat((char *)name, &statbuf) == kLibuvSuccess; + return os_stat((char *)path, &statbuf) == kLibuvSuccess; } /// Check if a file is readable. @@ -423,9 +615,8 @@ bool os_file_exists(const char_u *name) bool os_file_is_readable(const char *name) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - uv_fs_t req; - int r = uv_fs_access(&fs_loop, &req, name, R_OK, NULL); - uv_fs_req_cleanup(&req); + int r; + RUN_UV_FS_FUNC(r, uv_fs_access, name, R_OK, NULL); return (r == 0); } @@ -437,9 +628,8 @@ bool os_file_is_readable(const char *name) int os_file_is_writable(const char *name) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - uv_fs_t req; - int r = uv_fs_access(&fs_loop, &req, name, W_OK, NULL); - uv_fs_req_cleanup(&req); + int r; + RUN_UV_FS_FUNC(r, uv_fs_access, name, W_OK, NULL); if (r == 0) { return os_isdir((char_u *)name) ? 2 : 1; } @@ -452,16 +642,10 @@ int os_file_is_writable(const char *name) int os_rename(const char_u *path, const char_u *new_path) FUNC_ATTR_NONNULL_ALL { - uv_fs_t request; - int result = uv_fs_rename(&fs_loop, &request, - (const char *)path, (const char *)new_path, NULL); - uv_fs_req_cleanup(&request); - - if (result == kLibuvSuccess) { - return OK; - } - - return FAIL; + int r; + RUN_UV_FS_FUNC(r, uv_fs_rename, (const char *)path, (const char *)new_path, + NULL); + return (r == kLibuvSuccess ? OK : FAIL); } /// Make a directory. @@ -470,10 +654,9 @@ int os_rename(const char_u *path, const char_u *new_path) int os_mkdir(const char *path, int32_t mode) FUNC_ATTR_NONNULL_ALL { - uv_fs_t request; - int result = uv_fs_mkdir(&fs_loop, &request, path, mode, NULL); - uv_fs_req_cleanup(&request); - return result; + int r; + RUN_UV_FS_FUNC(r, uv_fs_mkdir, path, mode, NULL); + return r; } /// Make a directory, with higher levels when needed @@ -555,10 +738,9 @@ int os_mkdtemp(const char *template, char *path) int os_rmdir(const char *path) FUNC_ATTR_NONNULL_ALL { - uv_fs_t request; - int result = uv_fs_rmdir(&fs_loop, &request, path, NULL); - uv_fs_req_cleanup(&request); - return result; + int r; + RUN_UV_FS_FUNC(r, uv_fs_rmdir, path, NULL); + return r; } /// Opens a directory. @@ -600,10 +782,9 @@ void os_closedir(Directory *dir) int os_remove(const char *path) FUNC_ATTR_NONNULL_ALL { - uv_fs_t request; - int result = uv_fs_unlink(&fs_loop, &request, path, NULL); - uv_fs_req_cleanup(&request); - return result; + int r; + RUN_UV_FS_FUNC(r, uv_fs_unlink, path, NULL); + return r; } /// Get the file information for a given path 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/os_defs.h b/src/nvim/os/os_defs.h index eee0cdd10b..5e164b54a5 100644 --- a/src/nvim/os/os_defs.h +++ b/src/nvim/os/os_defs.h @@ -46,4 +46,10 @@ /// negative libuv error codes are returned by a number of os functions. #define os_strerror uv_strerror +#ifdef WIN32 +# define os_strtok strtok_s +#else +# define os_strtok strtok_r +#endif + #endif // NVIM_OS_OS_DEFS_H 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..64c673930a 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 ")); @@ -309,25 +310,70 @@ static void system_data_cb(Stream *stream, RBuffer *buf, size_t count, dbuf->len += nread; } +/// Continue to append data to last screen line. +/// +/// @param output Data to append to screen lines. +/// @param remaining Size of data. +/// @param new_line If true, next data output will be on a new line. +static void append_to_screen_end(char *output, size_t remaining, bool new_line) +{ + // Column of last row to start appending data to. + static colnr_T last_col = 0; + + size_t off = 0; + int last_row = (int)Rows - 1; + + while (off < remaining) { + // Found end of line? + if (output[off] == NL) { + // Can we start a new line or do we need to continue the last one? + if (last_col == 0) { + screen_del_lines(0, 0, 1, (int)Rows, NULL); + } + screen_puts_len((char_u *)output, (int)off, last_row, last_col, 0); + last_col = 0; + + size_t skip = off + 1; + output += skip; + remaining -= skip; + off = 0; + continue; + } + + // Translate NUL to SOH + if (output[off] == NUL) { + output[off] = 1; + } + + off++; + } + + if (remaining) { + if (last_col == 0) { + screen_del_lines(0, 0, 1, (int)Rows, NULL); + } + screen_puts_len((char_u *)output, (int)remaining, last_row, last_col, 0); + last_col += (colnr_T)remaining; + } + + if (new_line) { + last_col = 0; + } + + ui_flush(); +} + static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) { + // We always output the whole buffer, so the buffer can never + // wrap around. size_t cnt; char *ptr = rbuffer_read_ptr(buf, &cnt); - if (!cnt) { - return; - } - - size_t written = write_output(ptr, cnt, false, eof); - // No output written, force emptying the Rbuffer if it is full. - if (!written && rbuffer_size(buf) == rbuffer_capacity(buf)) { - screen_del_lines(0, 0, 1, (int)Rows, NULL); - screen_puts_len((char_u *)ptr, (int)cnt, (int)Rows - 1, 0, 0); - written = cnt; - } - if (written) { - rbuffer_consumed(buf, written); + append_to_screen_end(ptr, cnt, eof); + if (cnt) { + rbuffer_consumed(buf, cnt); } } 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/os_unix.c b/src/nvim/os_unix.c index 2ed0c2c856..def7e3b0e5 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -566,10 +566,11 @@ int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file, /* * Move the file names to allocated memory. */ - for (j = 0, i = 0; i < *num_file; ++i) { - /* Require the files to exist. Helps when using /bin/sh */ - if (!(flags & EW_NOTFOUND) && !os_file_exists((*file)[i])) + for (j = 0, i = 0; i < *num_file; i++) { + // Require the files to exist. Helps when using /bin/sh + if (!(flags & EW_NOTFOUND) && !os_path_exists((*file)[i])) { continue; + } /* check if this entry should be included */ dir = (os_isdir((*file)[i])); diff --git a/src/nvim/path.c b/src/nvim/path.c index 41fd69f238..57499429ec 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -684,7 +684,7 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, } // add existing file or symbolic link if ((flags & EW_ALLLINKS) ? os_fileinfo_link((char *)buf, &file_info) - : os_file_exists(buf)) { + : os_path_exists(buf)) { addfile(gap, buf, flags); } } @@ -1205,10 +1205,11 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, /* When EW_NOTFOUND is used, always add files and dirs. Makes * "vim c:/" work. */ - if (flags & EW_NOTFOUND) + if (flags & EW_NOTFOUND) { addfile(&ga, t, flags | EW_DIR | EW_FILE); - else if (os_file_exists(t)) + } else if (os_path_exists(t)) { addfile(&ga, t, flags); + } xfree(t); } @@ -1327,7 +1328,7 @@ void addfile( if (!(flags & EW_NOTFOUND) && ((flags & EW_ALLLINKS) ? !os_fileinfo_link((char *)f, &file_info) - : !os_file_exists(f))) { + : !os_path_exists(f))) { return; } 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..0326f33bb5 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,14 +5646,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 +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/quickfix.c b/src/nvim/quickfix.c index 151b9d3790..dfd795b0ba 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -571,8 +571,9 @@ restofline: *regmatch.endp[i] = c; if (vim_strchr((char_u *)"OPQ", idx) != NULL - && !os_file_exists(namebuf)) + && !os_path_exists(namebuf)) { continue; + } } if ((i = (int)fmt_ptr->addr[1]) > 0) { /* %n */ if (regmatch.startp[i] == NULL) @@ -706,11 +707,12 @@ restofline: } else if (vim_strchr((char_u *)"OPQ", idx) != NULL) { // global file names valid = false; - if (*namebuf == NUL || os_file_exists(namebuf)) { - if (*namebuf && idx == 'P') + if (*namebuf == NUL || os_path_exists(namebuf)) { + if (*namebuf && idx == 'P') { currfile = qf_push_dir(namebuf, &file_stack); - else if (idx == 'Q') + } else if (idx == 'Q') { currfile = qf_pop_dir(&file_stack); + } *namebuf = NUL; if (tail && *tail) { STRMOVE(IObuff, skipwhite(tail)); @@ -1080,7 +1082,7 @@ static int qf_get_fnum(char_u *directory, char_u *fname) * "leaving directory"-messages we might have missed a * directory change. */ - if (!os_file_exists(ptr)) { + if (!os_path_exists(ptr)) { xfree(ptr); directory = qf_guess_filepath(fname); if (directory) @@ -1232,8 +1234,9 @@ static char_u *qf_guess_filepath(char_u *filename) xfree(fullname); fullname = (char_u *)concat_fnames((char *)ds_ptr->dirname, (char *)filename, TRUE); - if (os_file_exists(fullname)) + if (os_path_exists(fullname)) { break; + } ds_ptr = ds_ptr->next; } @@ -1576,14 +1579,23 @@ win_found: * set b_p_ro flag). */ if (!can_abandon(curbuf, forceit)) { EMSG(_(e_nowrtmsg)); - ok = FALSE; - } else + ok = false; + } else { ok = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1, - ECMD_HIDE + ECMD_SET_HELP, - oldwin == curwin ? curwin : NULL); - } else - ok = buflist_getfile(qf_ptr->qf_fnum, - (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit); + ECMD_HIDE + ECMD_SET_HELP, + oldwin == curwin ? curwin : NULL); + } + } else { + ok = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1, + GETF_SETMARK | GETF_SWITCH, forceit); + if (qi != &ql_info && !win_valid(oldwin)) { + EMSG(_("E924: Current window was closed")); + ok = false; + qi = NULL; + qf_ptr = NULL; + opened_window = false; + } + } } if (ok == OK) { @@ -1663,21 +1675,22 @@ win_found: msg_scroll = (int)i; } } else { - if (opened_window) - win_close(curwin, TRUE); /* Close opened window */ - if (qf_ptr->qf_fnum != 0) { - /* - * Couldn't open file, so put index back where it was. This could - * happen if the file was readonly and we changed something. - */ + if (opened_window) { + win_close(curwin, true); // Close opened window + } + if (qf_ptr != NULL && qf_ptr->qf_fnum != 0) { + // Couldn't open file, so put index back where it was. This could + // happen if the file was readonly and we changed something. failed: qf_ptr = old_qf_ptr; qf_index = old_qf_index; } } theend: - qi->qf_lists[qi->qf_curlist].qf_ptr = qf_ptr; - qi->qf_lists[qi->qf_curlist].qf_index = qf_index; + if (qi != NULL) { + qi->qf_lists[qi->qf_curlist].qf_ptr = qf_ptr; + qi->qf_lists[qi->qf_curlist].qf_index = qf_index; + } if (p_swb != old_swb && opened_window) { /* Restore old 'switchbuf' value, but not when an autocommand or * modeline has changed the value. */ diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c index b3805a3a28..a2cc432eca 100644 --- a/src/nvim/rbuffer.c +++ b/src/nvim/rbuffer.c @@ -15,7 +15,7 @@ RBuffer *rbuffer_new(size_t capacity) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET { if (!capacity) { - capacity = 0xffff; + capacity = 0x10000; } RBuffer *rv = xmalloc(sizeof(RBuffer) + capacity); @@ -153,7 +153,7 @@ void rbuffer_consumed(RBuffer *buf, size_t count) // Higher level functions for copying from/to RBuffer instances and data // pointers -size_t rbuffer_write(RBuffer *buf, char *src, size_t src_size) +size_t rbuffer_write(RBuffer *buf, const char *src, size_t src_size) FUNC_ATTR_NONNULL_ALL { size_t size = src_size; 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/screen.c b/src/nvim/screen.c index 34eef83164..d67142822f 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -3416,12 +3416,10 @@ win_line ( /* * Handling of non-printable characters. */ - if (!(chartab[c & 0xff] & CT_PRINT_CHAR)) { - /* - * when getting a character from the file, we may have to - * turn it into something else on the way to putting it - * into "ScreenLines". - */ + if (!vim_isprintc(c)) { + // when getting a character from the file, we may have to + // turn it into something else on the way to putting it + // into "ScreenLines". if (c == TAB && (!wp->w_p_list || lcs_tab1)) { int tab_len = 0; long vcol_adjusted = vcol; // removed showbreak length diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 51c8597d53..b5921eb810 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -5,7 +5,6 @@ #include <stdint.h> #include <inttypes.h> #include <errno.h> -#include <fcntl.h> #include <assert.h> #include <msgpack.h> @@ -36,6 +35,7 @@ #include "nvim/version.h" #include "nvim/path.h" #include "nvim/fileio.h" +#include "nvim/os/fileio.h" #include "nvim/strings.h" #include "nvim/quickfix.h" #include "nvim/eval/encode.h" @@ -409,7 +409,7 @@ typedef struct sd_read_def { ShaDaFileSkipper skip; ///< Function used to skip some bytes. void *cookie; ///< Data describing object read from. bool eof; ///< True if reader reached end of file. - char *error; ///< Error message in case of error. + const char *error; ///< Error message in case of error. uintmax_t fpos; ///< Current position (amount of bytes read since ///< reader structure initialization). May overflow. vimconv_T sd_conv; ///< Structure used for converting encodings of some @@ -433,7 +433,7 @@ typedef struct sd_write_def { ShaDaFileWriter write; ///< Writer function. ShaDaWriteCloser close; ///< Close function. void *cookie; ///< Data describing object written to. - char *error; ///< Error message in case of error. + const char *error; ///< Error message in case of error. vimconv_T sd_conv; ///< Structure used for converting encodings of some ///< items. } ShaDaWriteDef; @@ -666,38 +666,14 @@ static ptrdiff_t read_file(ShaDaReadDef *const sd_reader, void *const dest, const size_t size) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - size_t read_bytes = 0; - bool did_try_to_free = false; - const int fd = (int)(intptr_t) sd_reader->cookie; - while (read_bytes != size) { - const ptrdiff_t cur_read_bytes = read(fd, ((char *) dest) + read_bytes, - size - read_bytes); - if (cur_read_bytes > 0) { - read_bytes += (size_t) cur_read_bytes; - sd_reader->fpos += (uintmax_t) cur_read_bytes; - assert(read_bytes <= size); - } - if (cur_read_bytes < 0) { - if (errno == EINTR || errno == EAGAIN) { - errno = 0; - continue; - } else if (errno == ENOMEM && !did_try_to_free) { - try_to_free_memory(); - did_try_to_free = true; - errno = 0; - continue; - } else { - sd_reader->error = strerror(errno); - errno = 0; - return -1; - } - } - if (cur_read_bytes == 0) { - sd_reader->eof = true; - break; - } + const ptrdiff_t ret = file_read(sd_reader->cookie, dest, size); + sd_reader->eof = file_eof(sd_reader->cookie); + if (ret < 0) { + sd_reader->error = os_strerror((int)ret); + return -1; } - return (ptrdiff_t) read_bytes; + sd_reader->fpos += (size_t)ret; + return ret; } /// Read one character @@ -720,50 +696,26 @@ static ptrdiff_t write_file(ShaDaWriteDef *const sd_writer, const size_t size) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - size_t written_bytes = 0; - const int fd = (int)(intptr_t) sd_writer->cookie; - while (written_bytes != size) { - const ptrdiff_t cur_written_bytes = write(fd, (char *) dest + written_bytes, - size - written_bytes); - if (cur_written_bytes > 0) { - written_bytes += (size_t) cur_written_bytes; - } - if (cur_written_bytes < 0) { - if (errno == EINTR || errno == EAGAIN) { - errno = 0; - continue; - } else { - sd_writer->error = strerror(errno); - errno = 0; - return -1; - } - } - if (cur_written_bytes == 0) { - sd_writer->error = "Zero bytes written."; - return -1; - } + const ptrdiff_t ret = file_write(sd_writer->cookie, dest, size); + if (ret < 0) { + sd_writer->error = os_strerror((int)ret); + return -1; } - return (ptrdiff_t) written_bytes; + return ret; } /// Wrapper for closing file descriptors opened for reading static void close_sd_reader(ShaDaReadDef *const sd_reader) FUNC_ATTR_NONNULL_ALL { - close_file((int)(intptr_t) sd_reader->cookie); + close_file(sd_reader->cookie); } /// Wrapper for closing file descriptors opened for writing static void close_sd_writer(ShaDaWriteDef *const sd_writer) FUNC_ATTR_NONNULL_ALL { - const int fd = (int)(intptr_t) sd_writer->cookie; - if (os_fsync(fd) < 0) { - emsgf(_(SERR "System error while synchronizing ShaDa file: %s"), - os_strerror(errno)); - errno = 0; - } - close_file(fd); + close_file(sd_writer->cookie); } /// Wrapper for read that reads to IObuff and ignores bytes read @@ -779,19 +731,20 @@ static int sd_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offset) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - size_t read_bytes = 0; - do { - ptrdiff_t new_read_bytes = sd_reader->read( - sd_reader, IObuff, (size_t) (offset - read_bytes > IOSIZE - ? IOSIZE - : offset - read_bytes)); - if (new_read_bytes == -1) { - return FAIL; + const ptrdiff_t skip_bytes = file_skip(sd_reader->cookie, offset); + if (skip_bytes < 0) { + sd_reader->error = os_strerror((int)skip_bytes); + return FAIL; + } else if (skip_bytes != (ptrdiff_t)offset) { + assert(skip_bytes < (ptrdiff_t)offset); + sd_reader->eof = file_eof(sd_reader->cookie); + if (!sd_reader->eof) { + sd_reader->error = _("too few bytes read"); } - read_bytes += (size_t) new_read_bytes; - } while (read_bytes < offset && !sd_reader->eof); - - return (read_bytes == offset ? OK : FAIL); + return FAIL; + } + sd_reader->fpos += (size_t)skip_bytes; + return OK; } /// Wrapper for read that can be used when lseek cannot be used @@ -824,37 +777,6 @@ static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader, return kSDReadStatusSuccess; } -/// Wrapper for opening file descriptors -/// -/// All arguments are passed to os_open(). -/// -/// @return file descriptor or libuv error on failure. -static int open_file(const char *const fname, const int flags, const int mode) - FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL -{ - bool did_try_to_free = false; - int fd; -open_file_start: - fd = os_open(fname, flags, mode); - - if (fd < 0) { - if (fd == UV_ENOENT) { - return fd; - } - if (fd == UV_ENOMEM && !did_try_to_free) { - try_to_free_memory(); - did_try_to_free = true; - goto open_file_start; - } - if (fd != UV_EEXIST) { - emsgf(_(SERR "System error while opening ShaDa file %s: %s"), - fname, os_strerror(fd)); - } - return fd; - } - return fd; -} - /// Open ShaDa file for reading /// /// @param[in] fname File name to open. @@ -865,11 +787,7 @@ static int open_shada_file_for_reading(const char *const fname, ShaDaReadDef *sd_reader) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - const intptr_t fd = (intptr_t) open_file(fname, O_RDONLY, 0); - - if (fd < 0) { - return (int) fd; - } + int error; *sd_reader = (ShaDaReadDef) { .read = &read_file, @@ -878,8 +796,11 @@ static int open_shada_file_for_reading(const char *const fname, .error = NULL, .eof = false, .fpos = 0, - .cookie = (void *) fd, + .cookie = file_open_new(&error, fname, kFileReadOnly, 0), }; + if (sd_reader->cookie == NULL) { + return error; + } convert_setup(&sd_reader->sd_conv, "utf-8", p_enc); @@ -887,18 +808,12 @@ static int open_shada_file_for_reading(const char *const fname, } /// Wrapper for closing file descriptors -static void close_file(int fd) +static void close_file(void *cookie) { -close_file_start: - if (close(fd) == -1) { - if (errno == EINTR) { - errno = 0; - goto close_file_start; - } else { - emsgf(_(SERR "System error while closing ShaDa file: %s"), - strerror(errno)); - errno = 0; - } + const int error = file_free(cookie); + if (error != 0) { + emsgf(_(SERR "System error while closing ShaDa file: %s"), + os_strerror(error)); } } @@ -978,7 +893,7 @@ static int shada_read_file(const char *const file, const int flags) } if (of_ret != 0) { - if (of_ret == UV_ENOENT && (flags & kShaDaMissingError)) { + if (of_ret != UV_ENOENT || (flags & kShaDaMissingError)) { emsgf(_(SERR "System error while opening ShaDa file %s for reading: %s"), fname, os_strerror(of_ret)); } @@ -1421,8 +1336,8 @@ 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_array = (char_u **)cur_entry.data.reg.contents, + .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 +2660,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) { @@ -2968,17 +2883,23 @@ int shada_write_file(const char *const file, bool nomerge) char *const fname = shada_filename(file); char *tempname = NULL; - ShaDaWriteDef sd_writer = (ShaDaWriteDef) { + ShaDaWriteDef sd_writer = { .write = &write_file, .close = &close_sd_writer, .error = NULL, }; - ShaDaReadDef sd_reader; - - intptr_t fd; + ShaDaReadDef sd_reader = { .close = NULL }; if (!nomerge) { - if (open_shada_file_for_reading(fname, &sd_reader) != 0) { + int error; + if ((error = open_shada_file_for_reading(fname, &sd_reader)) != 0) { + if (error != UV_ENOENT) { + emsgf(_(SERR "System error while opening ShaDa file %s for reading " + "to merge before writing it: %s"), + fname, os_strerror(error)); + // Try writing the file even if opening it emerged any issues besides + // file not existing: maybe writing will succeed nevertheless. + } nomerge = true; goto shada_write_file_nomerge; } @@ -2996,15 +2917,11 @@ int shada_write_file(const char *const file, bool nomerge) // 2: Make sure that user can always read and write the result. // 3: If somebody happened to delete the file after it was opened for // reading use u=rw permissions. -shada_write_file_open: - fd = (intptr_t) open_file(tempname, O_CREAT|O_WRONLY|O_NOFOLLOW|O_EXCL, - perm); - if (fd < 0) { - if (fd == UV_EEXIST -#ifdef ELOOP - || fd == UV_ELOOP -#endif - ) { +shada_write_file_open: {} + sd_writer.cookie = file_open_new( + &error, tempname, kFileCreateOnly|kFileNoSymlink, perm); + if (sd_writer.cookie == NULL) { + if (error == UV_EEXIST || error == UV_ELOOP) { // File already exists, try another name char *const wp = tempname + strlen(tempname) - 1; if (*wp == 'z') { @@ -3014,11 +2931,16 @@ shada_write_file_open: fname); xfree(fname); xfree(tempname); + assert(sd_reader.close != NULL); + sd_reader.close(&sd_reader); return FAIL; } else { (*wp)++; goto shada_write_file_open; } + } else { + emsgf(_(SERR "System error while opening temporary ShaDa file %s " + "for writing: %s"), tempname, os_strerror(error)); } } } @@ -3042,23 +2964,29 @@ shada_write_file_nomerge: {} } *tail = tail_save; } - fd = (intptr_t) open_file(fname, O_CREAT|O_WRONLY|O_TRUNC, - 0600); - } - - if (p_verbose > 0) { - verbose_enter(); - smsg(_("Writing ShaDa file \"%s\""), fname); - verbose_leave(); + int error; + sd_writer.cookie = file_open_new(&error, fname, kFileCreate|kFileTruncate, + 0600); + if (sd_writer.cookie == NULL) { + emsgf(_(SERR "System error while opening ShaDa file %s for writing: %s"), + fname, os_strerror(error)); + } } - if (fd < 0) { + if (sd_writer.cookie == NULL) { xfree(fname); xfree(tempname); + if (sd_reader.close != NULL) { + sd_reader.close(&sd_reader); + } return FAIL; } - sd_writer.cookie = (void *) fd; + if (p_verbose > 0) { + verbose_enter(); + smsg(_("Writing ShaDa file \"%s\""), fname); + verbose_leave(); + } convert_setup(&sd_writer.sd_conv, p_enc, "utf-8"); @@ -3066,15 +2994,11 @@ shada_write_file_nomerge: {} ? NULL : &sd_reader)); assert(sw_ret != kSDWriteIgnError); -#ifndef UNIX - sd_writer.close(&sd_writer); -#endif if (!nomerge) { sd_reader.close(&sd_reader); bool did_remove = false; if (sw_ret == kSDWriteSuccessfull) { #ifdef UNIX - bool closed = false; // For Unix we check the owner of the file. It's not very nice to // overwrite a user’s viminfo file after a "su root", with a // viminfo file that the user can't read. @@ -3083,16 +3007,15 @@ shada_write_file_nomerge: {} if (getuid() == ROOT_UID) { if (old_info.stat.st_uid != ROOT_UID || old_info.stat.st_gid != getgid()) { - const uv_uid_t old_uid = (uv_uid_t) old_info.stat.st_uid; - const uv_gid_t old_gid = (uv_gid_t) old_info.stat.st_gid; - const int fchown_ret = os_fchown((int) fd, old_uid, old_gid); - sd_writer.close(&sd_writer); + const uv_uid_t old_uid = (uv_uid_t)old_info.stat.st_uid; + const uv_gid_t old_gid = (uv_gid_t)old_info.stat.st_gid; + const int fchown_ret = os_fchown(file_fd(sd_writer.cookie), + old_uid, old_gid); if (fchown_ret != 0) { EMSG3(_(RNERR "Failed setting uid and gid for file %s: %s"), tempname, os_strerror(fchown_ret)); goto shada_write_file_did_not_remove; } - closed = true; } } else if (!(old_info.stat.st_uid == getuid() ? (old_info.stat.st_mode & 0200) @@ -3100,13 +3023,9 @@ shada_write_file_nomerge: {} ? (old_info.stat.st_mode & 0020) : (old_info.stat.st_mode & 0002)))) { EMSG2(_("E137: ShaDa file is not writable: %s"), fname); - sd_writer.close(&sd_writer); goto shada_write_file_did_not_remove; } } - if (!closed) { - sd_writer.close(&sd_writer); - } #endif if (vim_rename(tempname, fname) == -1) { EMSG3(_(RNERR "Can't rename ShaDa file from %s to %s!"), @@ -3133,6 +3052,7 @@ shada_write_file_did_not_remove: } xfree(tempname); } + sd_writer.close(&sd_writer); xfree(fname); return OK; @@ -3262,20 +3182,20 @@ static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader, FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { const ptrdiff_t read_bytes = sd_reader->read(sd_reader, buffer, length); - (void) read_bytes; - if (sd_reader->error != NULL) { - emsgf(_(SERR "System error while reading ShaDa file: %s"), - sd_reader->error); - return kSDReadStatusReadError; - } else if (sd_reader->eof) { - emsgf(_(RCERR "Error while reading ShaDa file: " - "last entry specified that it occupies %" PRIu64 " bytes, " - "but file ended earlier"), - (uint64_t) length); - return kSDReadStatusNotShaDa; + if (read_bytes != (ptrdiff_t)length) { + if (sd_reader->error != NULL) { + emsgf(_(SERR "System error while reading ShaDa file: %s"), + sd_reader->error); + return kSDReadStatusReadError; + } else { + emsgf(_(RCERR "Error while reading ShaDa file: " + "last entry specified that it occupies %" PRIu64 " bytes, " + "but file ended earlier"), + (uint64_t)length); + return kSDReadStatusNotShaDa; + } } - assert(read_bytes >= 0 && (size_t) read_bytes == length); return kSDReadStatusSuccess; } diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 84906a3548..610fb660e7 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -2317,16 +2317,14 @@ static void spell_load_lang(char_u *lang) for (round = 1; round <= 2; ++round) { // Find the first spell file for "lang" in 'runtimepath' and load it. vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5, - "spell/%s.%s.spl", - lang, spell_enc()); - r = do_in_runtimepath(fname_enc, FALSE, spell_load_cb, &sl); + "spell/%s.%s.spl", lang, spell_enc()); + r = do_in_runtimepath(fname_enc, 0, spell_load_cb, &sl); if (r == FAIL && *sl.sl_lang != NUL) { // Try loading the ASCII version. vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5, - "spell/%s.ascii.spl", - lang); - r = do_in_runtimepath(fname_enc, FALSE, spell_load_cb, &sl); + "spell/%s.ascii.spl", lang); + r = do_in_runtimepath(fname_enc, 0, spell_load_cb, &sl); if (r == FAIL && *sl.sl_lang != NUL && round == 1 && apply_autocmds(EVENT_SPELLFILEMISSING, lang, @@ -2354,7 +2352,7 @@ static void spell_load_lang(char_u *lang) } else if (sl.sl_slang != NULL) { // At least one file was loaded, now load ALL the additions. STRCPY(fname_enc + STRLEN(fname_enc) - 3, "add.spl"); - do_in_runtimepath(fname_enc, TRUE, spell_load_cb, &sl); + do_in_runtimepath(fname_enc, DIP_ALL, spell_load_cb, &sl); } } @@ -7630,7 +7628,7 @@ mkspell ( else { // Check for overwriting before doing things that may take a lot of // time. - if (!over_write && os_file_exists(wfname)) { + if (!over_write && os_path_exists(wfname)) { EMSG(_(e_exists)); goto theend; } @@ -7686,7 +7684,7 @@ mkspell ( spin.si_region = 1 << i; vim_snprintf((char *)fname, MAXPATHL, "%s.aff", innames[i]); - if (os_file_exists(fname)) { + if (os_path_exists(fname)) { // Read the .aff file. Will init "spin->si_conv" based on the // "SET" line. afile[i] = spell_read_aff(&spin, fname); @@ -9319,7 +9317,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 +9391,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 +9532,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 +9572,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 +9926,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 +9993,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 +10006,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 +10021,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 +10036,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 +10173,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 +10226,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 +10236,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 +10258,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 +10319,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 +10327,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 +10352,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 +10360,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 +10371,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 +10386,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 +10434,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 +10445,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 +10459,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 +10488,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 +10503,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 +10522,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 +10555,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 +10574,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 +10607,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 +10620,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 +10655,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 +10675,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 +10695,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 +11106,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 +13462,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..27855184df 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) { @@ -4131,9 +4207,10 @@ static void syn_cmd_include(exarg_T *eap, int syncing) current_syn_inc_tag = ++running_syn_inc_tag; prev_toplvl_grp = curwin->w_s->b_syn_topgrp; curwin->w_s->b_syn_topgrp = sgl_id; - if (source ? do_source(eap->arg, FALSE, DOSO_NONE) == FAIL - : source_runtime(eap->arg, TRUE) == FAIL) + if (source ? do_source(eap->arg, false, DOSO_NONE) == FAIL + : source_runtime(eap->arg, DIP_ALL) == FAIL) { EMSG2(_(e_notopen), eap->arg); + } curwin->w_s->b_syn_topgrp = prev_toplvl_grp; current_syn_inc_tag = prev_syn_inc_tag; } @@ -5363,24 +5440,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 +5512,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 */ @@ -5945,12 +6024,12 @@ init_highlight ( if (get_var_value((char_u *)"g:syntax_on") != NULL) { static int recursive = 0; - if (recursive >= 5) + if (recursive >= 5) { EMSG(_("E679: recursive loop loading syncolor.vim")); - else { - ++recursive; - (void)source_runtime((char_u *)"syntax/syncolor.vim", TRUE); - --recursive; + } else { + recursive++; + (void)source_runtime((char_u *)"syntax/syncolor.vim", DIP_ALL); + recursive--; } } } @@ -5963,22 +6042,24 @@ int load_colors(char_u *name) { char_u *buf; int retval = FAIL; - static int recursive = FALSE; + static int recursive = false; - /* When being called recursively, this is probably because setting - * 'background' caused the highlighting to be reloaded. This means it is - * working, thus we should return OK. */ - if (recursive) + // When being called recursively, this is probably because setting + // 'background' caused the highlighting to be reloaded. This means it is + // working, thus we should return OK. + if (recursive) { return OK; + } - recursive = TRUE; - buf = xmalloc(STRLEN(name) + 12); - sprintf((char *)buf, "colors/%s.vim", name); - retval = source_runtime(buf, FALSE); + recursive = true; + size_t buflen = STRLEN(name) + 12; + buf = xmalloc(buflen); + snprintf((char *)buf, buflen, "colors/%s.vim", name); + retval = source_runtime(buf, DIP_START + DIP_OPT); xfree(buf); apply_autocmds(EVENT_COLORSCHEME, name, curbuf->b_fname, FALSE, curbuf); - recursive = FALSE; + recursive = false; ui_refresh(); return retval; @@ -6874,8 +6955,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/tag.c b/src/nvim/tag.c index 7885d467d8..dfecfb776d 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -2023,9 +2023,8 @@ get_tagfname ( if (first) { ga_clear_strings(&tag_fnames); ga_init(&tag_fnames, (int)sizeof(char_u *), 10); - do_in_runtimepath((char_u *) - "doc/tags doc/tags-??" - , TRUE, found_tagfile_cb, NULL); + do_in_runtimepath((char_u *)"doc/tags doc/tags-??", DIP_ALL, + found_tagfile_cb, NULL); } if (tnp->tn_hf_idx >= tag_fnames.ga_len) { @@ -2353,7 +2352,7 @@ jumpto_tag ( * file. Also accept a file name for which there is a matching BufReadCmd * autocommand event (e.g., http://sys/file). */ - if (!os_file_exists(fname) + if (!os_path_exists(fname) && !has_autocmd(EVENT_BUFREADCMD, fname, NULL) ) { retval = NOTAGFILE; diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 104cc47cda..6f50c03be9 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) @@ -240,6 +241,7 @@ Terminal *terminal_open(TerminalOptions opts) set_option_value((uint8_t *)"wrap", false, NULL, OPT_LOCAL); set_option_value((uint8_t *)"number", false, NULL, OPT_LOCAL); set_option_value((uint8_t *)"relativenumber", false, NULL, OPT_LOCAL); + buf_set_term_title(curbuf, (char *)curbuf->b_ffname); RESET_BINDING(curwin); // Apply TermOpen autocmds so the user can configure the terminal apply_autocmds(EVENT_TERMOPEN, NULL, NULL, false, curbuf); @@ -347,15 +349,6 @@ void terminal_resize(Terminal *term, uint16_t width, uint16_t height) height = (uint16_t)curheight; } - // The new width/height are the minimum for all windows that display the - // terminal in the current tab. - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (!wp->w_closing && wp->w_buffer->terminal == term) { - width = (uint16_t)MIN(width, (uint16_t)(wp->w_width - win_col_off(wp))); - height = (uint16_t)MIN(height, (uint16_t)wp->w_height); - } - } - if (curheight == height && curwidth == width) { return; } @@ -452,7 +445,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; @@ -626,6 +619,17 @@ static int term_movecursor(VTermPos new, VTermPos old, int visible, return 1; } +static void buf_set_term_title(buf_T *buf, char *title) + FUNC_ATTR_NONNULL_ALL +{ + Error err; + api_free_object(dict_set_value(buf->b_vars, + cstr_as_string("term_title"), + STRING_OBJ(cstr_as_string(title)), + false, + &err)); +} + static int term_settermprop(VTermProp prop, VTermValue *val, void *data) { Terminal *term = data; @@ -641,12 +645,7 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data) case VTERM_PROP_TITLE: { buf_T *buf = handle_get_buffer(term->buf_handle); - Error err; - api_free_object(dict_set_value(buf->b_vars, - cstr_as_string("term_title"), - STRING_OBJ(cstr_as_string(val->string)), - false, - &err)); + buf_set_term_title(buf, val->string); break; } @@ -1158,15 +1157,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 867cab9fbf..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,7 +24,6 @@ SCRIPTS := \ test49.out \ test52.out \ test53.out \ - test55.out \ test64.out \ test69.out \ test73.out \ @@ -37,9 +34,13 @@ SCRIPTS := \ # 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 @@ -59,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..1b1f5d7688 100644 --- a/src/nvim/testdir/runtest.vim +++ b/src/nvim/testdir/runtest.vim @@ -39,6 +39,9 @@ set nomore " Output all messages in English. lang mess C +" Always use forward slashes. +set shellslash + " Source the test script. First grab the file name, in case the script " navigates away. let testname = expand('%') @@ -61,12 +64,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_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..d220df508a 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" @@ -134,6 +135,8 @@ static void terminfo_start(UI *ui) data->ut = unibi_dummy(); } fix_terminfo(data); + // Set 't_Co' from the result of unibilium & fix_terminfo. + t_colors = unibi_get_num(data->ut, unibi_max_colors); // Enter alternate screen and clear unibi_out(ui, unibi_enter_ca_mode); unibi_out(ui, unibi_clear_screen); @@ -261,7 +264,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 +684,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 })); } } @@ -785,6 +788,7 @@ static void fix_terminfo(TUIData *data) unibi_term *ut = data->ut; const char *term = os_getenv("TERM"); + const char *colorterm = os_getenv("COLORTERM"); if (!term) { goto end; } @@ -830,10 +834,10 @@ static void fix_terminfo(TUIData *data) #define XTERM_SETAB \ "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m" - if (os_getenv("COLORTERM") != NULL - && (!strcmp(term, "xterm") || !strcmp(term, "screen"))) { - // probably every modern terminal that sets TERM=xterm supports 256 - // colors(eg: gnome-terminal). Also do it when TERM=screen. + if ((colorterm && strstr(colorterm, "256")) + || strstr(term, "256") + || strstr(term, "xterm")) { + // Assume TERM~=xterm or COLORTERM~=256 supports 256 colors. unibi_set_num(ut, unibi_max_colors, 256); unibi_set_str(ut, unibi_set_a_foreground, XTERM_SETAF); unibi_set_str(ut, unibi_set_a_background, XTERM_SETAB); 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 ae38754c1e..d968cbc390 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -60,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) diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c index d17fa4a782..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) @@ -100,7 +101,7 @@ 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); 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/undo.c b/src/nvim/undo.c index f16b4264d7..fc5d6acaa4 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -712,7 +712,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading) // When reading check if the file exists. if (undo_file_name != NULL - && (!reading || os_file_exists((char_u *)undo_file_name))) { + && (!reading || os_path_exists((char_u *)undo_file_name))) { break; } xfree(undo_file_name); @@ -1094,7 +1094,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, /* If the undo file already exists, verify that it actually is an undo * file, and delete it. */ - if (os_file_exists((char_u *)file_name)) { + if (os_path_exists((char_u *)file_name)) { if (name == NULL || !forceit) { /* Check we can read it and it's an undo file. */ fd = os_open(file_name, O_RDONLY, 0); diff --git a/src/nvim/version.c b/src/nvim/version.c index c491021328..966e4f9b4f 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -75,6 +75,9 @@ static char *features[] = { // clang-format off static int included_patches[] = { + 1973, + 1960, + 1840, 1832, 1831, 1809, @@ -85,8 +88,12 @@ static int included_patches[] = { 1755, 1753, 1728, + 1716, + 1712, + 1695, 1654, 1652, + 1649, 1643, 1641, // 1624 NA @@ -95,11 +102,11 @@ static int included_patches[] = { // 1599 NA // 1598 NA // 1597 NA - // 1596, + 1596, // 1595 NA // 1594 NA // 1593 NA - // 1592, + 1592, // 1591, // 1590, // 1589, @@ -113,13 +120,13 @@ static int included_patches[] = { // 1581, // 1580, - // 1579, + // 1579 NA 1578, // 1577, 1576, // 1575 NA 1574, - // 1573, + // 1573 NA // 1572 NA 1571, 1570, @@ -132,17 +139,17 @@ static int included_patches[] = { // 1563, // 1562 NA // 1561 NA - // 1560, + // 1560 NA // 1559, // 1558, // 1557, - // 1556, - // 1555, - // 1554, - // 1553, - // 1552, - // 1551, - // 1550, + // 1556 NA + // 1555 NA + 1554, + 1553, + 1552, + 1551, + 1550, // 1549, // 1548, // 1547, @@ -164,7 +171,7 @@ static int included_patches[] = { // 1531 NA // 1530 NA // 1529 NA - // 1528, + 1528, // 1527 NA // 1526 NA // 1525 NA @@ -193,28 +200,28 @@ static int included_patches[] = { // 1502 NA // 1501 NA 1500, - // 1499, + 1499, // 1498 NA // 1497 NA // 1496 NA // 1495 NA // 1494, // 1493 NA - // 1492, + 1492, // 1491, // 1490 NA // 1489 NA // 1488 NA // 1487 NA - // 1486, + 1486, // 1485 NA // 1484 NA // 1483 NA // 1482 NA // 1481 NA - // 1480, - // 1479, - // 1478, + 1480, + 1479, + 1478, // 1477, // 1476 NA // 1475 NA @@ -224,11 +231,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 @@ -295,20 +302,20 @@ static int included_patches[] = { // 1400 NA // 1399 NA // 1398 NA - // 1397, - // 1396, + 1397, + 1396, // 1395 NA - // 1394, + 1394, // 1393 NA // 1392 NA // 1391 NA // 1390 NA // 1389 NA - // 1388, + 1388, // 1387 NA // 1386 NA // 1385 NA - // 1384, + 1384, // 1383 NA // 1382 NA // 1381 NA @@ -340,7 +347,7 @@ static int included_patches[] = { // 1355 NA // 1354 NA // 1353 NA - // 1352, + 1352, // 1351 NA // 1350 NA // 1349 NA @@ -416,7 +423,7 @@ static int included_patches[] = { // 1279 NA // 1278 NA // 1277 NA - // 1276, + 1276, // 1275 NA // 1274 NA // 1273, @@ -469,7 +476,7 @@ static int included_patches[] = { // 1226 NA // 1225 NA // 1224 NA - // 1223, + 1223, // 1222 NA // 1221 NA // 1220 NA @@ -531,7 +538,7 @@ static int included_patches[] = { 1164, 1163, // 1162 NA - // 1161, + 1161, 1160, // 1159 NA // 1158 NA @@ -539,41 +546,41 @@ static int included_patches[] = { // 1156 NA // 1155 NA // 1154 NA - // 1153, + 1153, // 1152 NA - // 1151, - // 1150, + 1151, + 1150, 1149, // 1148 NA - // 1147, + 1147, // 1146 NA // 1145 NA 1144, 1143, - // 1142, + 1142, 1141, - // 1140, + 1140, // 1139 NA // 1138 NA 1137, - // 1136, + 1136, // 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, + 1121, 1120, - // 1119, + 1119, 1118, 1117, 1116, @@ -581,10 +588,10 @@ static int included_patches[] = { 1114, 1113, 1112, - // 1111, + 1111, 1110, // 1109 NA - // 1108, + 1108, 1107, // 1106 NA 1105, @@ -595,14 +602,14 @@ static int included_patches[] = { // 1100 NA // 1099 NA // 1098 NA - // 1097, + // 1097 NA 1096, // 1095 NA - // 1094, + 1094, 1093, 1092, 1091, - // 1090, + 1090, 1089, 1088, 1087, @@ -613,18 +620,18 @@ static int included_patches[] = { // 1082 NA 1081, // 1080 NA - // 1079, + // 1079 NA // 1078 NA // 1077 NA 1076, 1075, // 1074 NA, - // 1073, + // 1073 NA 1072, 1071, // 1070 NA // 1069 NA - // 1068, + 1068, // 1067 NA // 1066 NA 1065, @@ -634,14 +641,14 @@ static int included_patches[] = { 1061, // 1060 NA 1059, - // 1058, + // 1058 NA 1057, - // 1056, + 1056, 1055, 1054, 1053, 1052, - // 1051, + 1051, 1050, 1049, 1048, @@ -653,7 +660,7 @@ static int included_patches[] = { 1042, 1041, // 1040 NA - // 1039, + // 1039 NA // 1038 NA 1037, 1036, @@ -1903,21 +1910,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 @@ -2019,3 +2020,4 @@ void ex_intro(exarg_T *eap) intro_message(TRUE); wait_return(TRUE); } + diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 165a44a148..09e9e850a7 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -174,6 +174,7 @@ enum { EXPAND_USER, EXPAND_SYNTIME, EXPAND_USER_ADDR_TYPE, + EXPAND_PACKADD, }; @@ -307,4 +308,12 @@ enum { # define SET_NO_HLSEARCH(flag) no_hlsearch = (flag); set_vim_var_nr( \ VV_HLSEARCH, !no_hlsearch && p_hls) +// Used for flags in do_in_path() +#define DIP_ALL 0x01 // all matches, not just the first one +#define DIP_DIR 0x02 // find directories instead of files +#define DIP_ERR 0x04 // give an error message when none found +#define DIP_START 0x08 // also use "start" directory in 'packpath' +#define DIP_OPT 0x10 // also use "opt" directory in 'packpath' +#define DIP_NORTP 0x20 // do not use 'runtimepath' + #endif /* NVIM_VIM_H */ diff --git a/src/nvim/window.c b/src/nvim/window.c index bea55c465f..e267d493bf 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -251,11 +251,14 @@ newwindow: if (win_new_tabpage((int)Prenum, NULL) == OK && valid_tabpage(oldtab)) { newtab = curtab; - goto_tabpage_tp(oldtab, TRUE, TRUE); - if (curwin == wp) - win_close(curwin, FALSE); - if (valid_tabpage(newtab)) - goto_tabpage_tp(newtab, TRUE, TRUE); + goto_tabpage_tp(oldtab, true, true); + if (curwin == wp) { + win_close(curwin, false); + } + if (valid_tabpage(newtab)) { + goto_tabpage_tp(newtab, true, true); + apply_autocmds(EVENT_TABNEWENTERED, NULL, NULL, false, curbuf); + } } } break; @@ -3293,8 +3296,11 @@ void tabpage_move(int nr) tabpage_T *tp; tabpage_T *tp_dst; - if (first_tabpage->tp_next == NULL) + assert(curtab != NULL); + + if (first_tabpage->tp_next == NULL) { return; + } for (tp = first_tabpage; tp->tp_next != NULL && n < nr; tp = tp->tp_next) { ++n; @@ -3613,6 +3619,10 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, int tri /* Change directories when the 'acd' option is set. */ do_autochdir(); + + if (curbuf->terminal) { + terminal_resize(curbuf->terminal, curwin->w_width, curwin->w_height); + } } diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index 0eefa25a13..cf8a83ad81 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -1,5 +1,5 @@ -- Sanity checks for buffer_* API calls via msgpack-rpc -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, nvim, buffer = helpers.clear, helpers.nvim, helpers.buffer local curbuf, curwin, eq = helpers.curbuf, helpers.curwin, helpers.eq local curbufmeths, ok = helpers.curbufmeths, helpers.ok diff --git a/test/functional/api/menu_spec.lua b/test/functional/api/menu_spec.lua index 5b414fb559..d55b7b118a 100644 --- a/test/functional/api/menu_spec.lua +++ b/test/functional/api/menu_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear = helpers.clear diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua index 6791fbb4ba..88e8c60560 100644 --- a/test/functional/api/server_notifications_spec.lua +++ b/test/functional/api/server_notifications_spec.lua @@ -1,8 +1,9 @@ -- Tests for nvim notifications -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local eq, clear, eval, execute, nvim, next_message = helpers.eq, helpers.clear, helpers.eval, helpers.execute, helpers.nvim, helpers.next_message +local meths = helpers.meths describe('notify', function() local channel @@ -36,5 +37,33 @@ describe('notify', function() eval('rpcnotify(0, "event1", 13, 14, 15)') eq({'notification', 'event1', {13, 14, 15}}, next_message()) end) + + it('does not crash for deeply nested variable', function() + meths.set_var('l', {}) + local nest_level = 1000 + meths.command(('call map(range(%u), "extend(g:, {\'l\': [g:l]})")'):format(nest_level - 1)) + eval('rpcnotify('..channel..', "event", g:l)') + local msg = next_message() + eq('notification', msg[1]) + eq('event', msg[2]) + local act_ret = msg[3] + local act_nest_level = 0 + while act_ret do + if type(act_ret) == 'table' then + local cur_act_ret = nil + for k, v in pairs(act_ret) do + eq(1, k) + cur_act_ret = v + end + if cur_act_ret then + act_nest_level = act_nest_level + 1 + end + act_ret = cur_act_ret + else + eq(nil, act_ret) + end + end + eq(nest_level, act_nest_level) + end) end) end) diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 1b33275803..54095112fb 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -1,7 +1,7 @@ -- Tests for some server->client RPC scenarios. Note that unlike with -- `rpcnotify`, to evaluate `rpcrequest` calls we need the client event loop to -- be running. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, nvim, eval = helpers.clear, helpers.nvim, helpers.eval local eq, neq, run, stop = helpers.eq, helpers.neq, helpers.run, helpers.stop local nvim_prog = helpers.nvim_prog diff --git a/test/functional/api/tabpage_spec.lua b/test/functional/api/tabpage_spec.lua index c782107714..7b97c7f067 100644 --- a/test/functional/api/tabpage_spec.lua +++ b/test/functional/api/tabpage_spec.lua @@ -1,5 +1,5 @@ -- Sanity checks for tabpage_* API calls via msgpack-rpc -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, nvim, tabpage, curtab, eq, ok = helpers.clear, helpers.nvim, helpers.tabpage, helpers.curtab, helpers.eq, helpers.ok diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 20de6d0072..c4976ea06b 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1,5 +1,5 @@ -- Sanity checks for vim_* API calls via msgpack-rpc -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local NIL = helpers.NIL local clear, nvim, eq, neq = helpers.clear, helpers.nvim, helpers.eq, helpers.neq diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 92a33b4cdb..d90323181c 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1,5 +1,5 @@ -- Sanity checks for window_* API calls via msgpack-rpc -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, nvim, curbuf, curbuf_contents, window, curwin, eq, neq, ok, feed, insert, eval = helpers.clear, helpers.nvim, helpers.curbuf, helpers.curbuf_contents, helpers.window, helpers.curwin, helpers.eq, diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua index 3c813abc2e..72aff58d73 100644 --- a/test/functional/autocmd/autocmd_spec.lua +++ b/test/functional/autocmd/autocmd_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local command = helpers.command diff --git a/test/functional/autocmd/tabclose_spec.lua b/test/functional/autocmd/tabclose_spec.lua index bf609d1846..65182ad859 100644 --- a/test/functional/autocmd/tabclose_spec.lua +++ b/test/functional/autocmd/tabclose_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, nvim, eq = helpers.clear, helpers.nvim, helpers.eq describe('TabClosed', function() diff --git a/test/functional/autocmd/tabnew_spec.lua b/test/functional/autocmd/tabnew_spec.lua index aaf9db0a99..8c94dee49b 100644 --- a/test/functional/autocmd/tabnew_spec.lua +++ b/test/functional/autocmd/tabnew_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local command = helpers.command diff --git a/test/functional/autocmd/tabnewentered_spec.lua b/test/functional/autocmd/tabnewentered_spec.lua index 64b9a22f41..7044307399 100644 --- a/test/functional/autocmd/tabnewentered_spec.lua +++ b/test/functional/autocmd/tabnewentered_spec.lua @@ -1,22 +1,31 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, nvim, eq = helpers.clear, helpers.nvim, helpers.eq describe('TabNewEntered', function() - describe('au TabNewEntered', function() - describe('with * as <afile>', function() - it('matches when entering any new tab', function() - clear() - nvim('command', 'au! TabNewEntered * echom "tabnewentered:".tabpagenr().":".bufnr("")') - eq("\ntabnewentered:2:2", nvim('command_output', 'tabnew')) - eq("\n\"test.x2\" [New File]\ntabnewentered:3:3", nvim('command_output', 'tabnew test.x2')) - end) - end) - describe('with FILE as <afile>', function() - it('matches when opening a new tab for FILE', function() - local tmp_path = nvim('eval', 'tempname()') - nvim('command', 'au! TabNewEntered '..tmp_path..' echom "tabnewentered:match"') - eq("\n\""..tmp_path.."\" [New File]\ntabnewentered:4:4\ntabnewentered:match", nvim('command_output', 'tabnew '..tmp_path)) - end) - end) + describe('au TabNewEntered', function() + describe('with * as <afile>', function() + it('matches when entering any new tab', function() + clear() + nvim('command', 'au! TabNewEntered * echom "tabnewentered:".tabpagenr().":".bufnr("")') + eq("\ntabnewentered:2:2", nvim('command_output', 'tabnew')) + eq("\n\"test.x2\" [New File]\ntabnewentered:3:3", nvim('command_output', 'tabnew test.x2')) + end) end) + describe('with FILE as <afile>', function() + it('matches when opening a new tab for FILE', function() + local tmp_path = nvim('eval', 'tempname()') + nvim('command', 'au! TabNewEntered '..tmp_path..' echom "tabnewentered:match"') + eq("\n\""..tmp_path.."\" [New File]\ntabnewentered:4:4\ntabnewentered:match", nvim('command_output', 'tabnew '..tmp_path)) + end) + end) + describe('with CTRL-W T', function() + it('works when opening a new tab with CTRL-W T', function() + clear() + nvim('command', 'au! TabNewEntered * echom "entered"') + nvim('command', 'tabnew test.x2') + nvim('command', 'split') + eq('\nentered', nvim('command_output', 'execute "normal \\<C-W>T"')) + end) + end) + end) end) diff --git a/test/functional/autocmd/termclose_spec.lua b/test/functional/autocmd/termclose_spec.lua index 4de3f039c1..02ea0dbd95 100644 --- a/test/functional/autocmd/termclose_spec.lua +++ b/test/functional/autocmd/termclose_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, execute, feed, nvim, nvim_dir = helpers.clear, diff --git a/test/functional/autocmd/textyankpost_spec.lua b/test/functional/autocmd/textyankpost_spec.lua index c26ceeaedc..bd5f1912c5 100644 --- a/test/functional/autocmd/textyankpost_spec.lua +++ b/test/functional/autocmd/textyankpost_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, eval, eq = helpers.clear, helpers.eval, helpers.eq local feed, execute, expect, command = helpers.feed, helpers.execute, helpers.expect, helpers.command local curbufmeths, funcs, neq = helpers.curbufmeths, helpers.funcs, helpers.neq diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/clipboard/clipboard_provider_spec.lua index 898ec556a2..15977b9777 100644 --- a/test/functional/clipboard/clipboard_provider_spec.lua +++ b/test/functional/clipboard/clipboard_provider_spec.lua @@ -1,6 +1,6 @@ -- Test clipboard provider support -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect, eq, eval = helpers.execute, helpers.expect, helpers.eq, helpers.eval @@ -308,6 +308,7 @@ describe('clipboard usage', function() end) it('links the "+ and unnamed registers', function() + eq('+', eval('v:register')) insert("one two") feed('^"+dwdw"+P') expect('two') @@ -335,6 +336,7 @@ describe('clipboard usage', function() eq({{'really unnamed', ''}, 'V'}, eval("g:test_clip['*']")) -- unnamedplus takes predecence when pasting + eq('+', eval('v:register')) execute("let g:test_clip['+'] = ['the plus','']") execute("let g:test_clip['*'] = ['the star','']") feed("p") diff --git a/test/functional/job/job_spec.lua b/test/functional/core/job_spec.lua index d21b9051e2..61ecdd1835 100644 --- a/test/functional/job/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -1,11 +1,10 @@ - -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, eq, eval, execute, feed, insert, neq, next_msg, nvim, - nvim_dir, ok, source, write_file = helpers.clear, + nvim_dir, ok, source, write_file, mkdir, rmdir = helpers.clear, helpers.eq, helpers.eval, helpers.execute, helpers.feed, helpers.insert, helpers.neq, helpers.next_message, helpers.nvim, helpers.nvim_dir, helpers.ok, helpers.source, - helpers.write_file + helpers.write_file, helpers.mkdir, helpers.rmdir local Screen = require('test.functional.ui.screen') @@ -37,6 +36,32 @@ describe('jobs', function() eq({'notification', 'exit', {0, 0}}, next_msg()) end) + it('changes to given / directory', function() + nvim('command', "let g:job_opts.cwd = '/'") + nvim('command', "let j = jobstart('pwd', g:job_opts)") + eq({'notification', 'stdout', {0, {'/', ''}}}, next_msg()) + eq({'notification', 'exit', {0, 0}}, next_msg()) + end) + + it('changes to given `cwd` directory', function() + local dir = eval('resolve(tempname())') + mkdir(dir) + nvim('command', "let g:job_opts.cwd = '" .. dir .. "'") + nvim('command', "let j = jobstart('pwd', g:job_opts)") + eq({'notification', 'stdout', {0, {dir, ''}}}, next_msg()) + eq({'notification', 'exit', {0, 0}}, next_msg()) + rmdir(dir) + end) + + it('fails to change to invalid `cwd`', function() + local dir = eval('resolve(tempname())."-bogus"') + local _, err = pcall(function() + nvim('command', "let g:job_opts.cwd = '" .. dir .. "'") + nvim('command', "let j = jobstart('pwd', g:job_opts)") + end) + ok(string.find(err, "E475: Invalid argument: expected valid directory$") ~= nil) + end) + it('returns 0 when it fails to start', function() local status, rv = pcall(eval, "jobstart([])") eq(false, status) @@ -94,7 +119,7 @@ describe('jobs', function() {0, {'a', '', 'c', '', '', '', 'b', '', ''}}}, next_msg()) end) - it('can preserve nuls', function() + it('can preserve NULs', function() nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") nvim('command', 'call jobsend(j, ["\n123\n", "abc\\nxyz\n", ""])') eq({'notification', 'stdout', {0, {'\n123\n', 'abc\nxyz\n', ''}}}, @@ -118,7 +143,7 @@ describe('jobs', function() eq({'notification', 'exit', {0, 0}}, next_msg()) end) - it("won't allow jobsend with a job that closed stdin", function() + it("disallows jobsend on a job that closed stdin", function() nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") nvim('command', 'call jobclose(j, "stdin")') eq(false, pcall(function() @@ -126,12 +151,12 @@ describe('jobs', function() end)) end) - it('will not allow jobsend/stop on a non-existent job', function() + it('disallows jobsend/stop on a non-existent job', function() eq(false, pcall(eval, "jobsend(-1, 'lol')")) eq(false, pcall(eval, "jobstop(-1)")) end) - it('will not allow jobstop twice on the same job', function() + it('disallows jobstop twice on the same job', function() nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") neq(0, eval('j')) eq(true, pcall(eval, "jobstop(j)")) @@ -218,7 +243,7 @@ describe('jobs', function() eq({'notification', 'exit', {45, 10}}, next_msg()) end) - it('cant redefine callbacks being used by a job', function() + it('cannot redefine callbacks being used by a job', function() local screen = Screen.new() screen:attach() local script = [[ @@ -441,3 +466,41 @@ describe('jobs', function() end) end) end) + +describe("pty process teardown", function() + local screen + before_each(function() + clear() + screen = Screen.new(30, 6) + screen:attach() + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + end) + after_each(function() + screen:detach() + end) + + it("does not prevent/delay exit. #4798 #4900", function() + -- Use a nested nvim (in :term) to test without --headless. + execute(":terminal '"..helpers.nvim_prog + -- Use :term again in the _nested_ nvim to get a PTY process. + -- Use `sleep` to simulate a long-running child of the PTY. + .."' +terminal +'!(sleep 300 &)' +qa") + + -- Exiting should terminate all descendants (PTY, its children, ...). + screen:expect([[ + | + [Process exited 0] | + | + | + | + -- TERMINAL -- | + ]]) + end) +end) diff --git a/test/functional/dict_notifications_spec.lua b/test/functional/dict_notifications_spec.lua index 2540929126..dc87312911 100644 --- a/test/functional/dict_notifications_spec.lua +++ b/test/functional/dict_notifications_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, nvim, source = helpers.clear, helpers.nvim, helpers.source local eq, next_msg = helpers.eq, helpers.next_message local exc_exec = helpers.exc_exec diff --git a/test/functional/eval/capture_spec.lua b/test/functional/eval/capture_spec.lua new file mode 100644 index 0000000000..d9265f1b5b --- /dev/null +++ b/test/functional/eval/capture_spec.lua @@ -0,0 +1,86 @@ +local helpers = require('test.functional.helpers')(after_each) +local eq = helpers.eq +local eval = helpers.eval +local clear = helpers.clear +local source = helpers.source +local redir_exec = helpers.redir_exec +local exc_exec = helpers.exc_exec +local funcs = helpers.funcs +local Screen = require('test.functional.ui.screen') +local feed = helpers.feed + +describe('capture()', function() + before_each(clear) + + it('returns the same result with :redir', function() + eq(redir_exec('messages'), funcs.capture('messages')) + end) + + it('returns the output of the commands if the argument is List', function() + eq("foobar", funcs.capture({'echon "foo"', 'echon "bar"'})) + eq("\nfoo\nbar", funcs.capture({'echo "foo"', 'echo "bar"'})) + end) + + it('supports the nested redirection', function() + source([[ + function! g:Foo() + let a = '' + redir => a + silent echon "foo" + redir END + return a + endfunction + function! g:Bar() + let a = '' + redir => a + call g:Foo() + redir END + return a + endfunction + ]]) + eq('foo', funcs.capture('call g:Bar()')) + + eq('42', funcs.capture([[echon capture("echon capture('echon 42')")]])) + end) + + it('returns the transformed string', function() + eq('^A', funcs.capture('echon "\\<C-a>"')) + end) + + it('returns the empty string if the argument list is empty', function() + eq('', funcs.capture({})) + eq(0, exc_exec('let g:ret = capture(v:_null_list)')) + eq('', eval('g:ret')) + end) + + it('returns the errors', function() + local ret + ret = exc_exec('call capture(0.0)') + eq('Vim(call):E806: using Float as a String', ret) + ret = exc_exec('call capture(v:_null_dict)') + eq('Vim(call):E731: using Dictionary as a String', ret) + ret = exc_exec('call capture(function("tr"))') + eq('Vim(call):E729: using Funcref as a String', ret) + ret = exc_exec('call capture(["echo 42", 0.0, "echo 44"])') + eq('Vim(call):E806: using Float as a String', ret) + ret = exc_exec('call capture(["echo 42", v:_null_dict, "echo 44"])') + eq('Vim(call):E731: using Dictionary as a String', ret) + ret = exc_exec('call capture(["echo 42", function("tr"), "echo 44"])') + eq('Vim(call):E729: using Funcref as a String', ret) + end) + + it('silences command run inside', function() + local screen = Screen.new(20, 5) + screen:attach() + screen:set_default_attr_ignore({{bold=true, foreground=255}}) + feed(':let g:mes = capture("echon 42")<CR>') + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + | + ]]) + eq('42', eval('g:mes')) + end) +end) diff --git a/test/functional/eval/glob_spec.lua b/test/functional/eval/glob_spec.lua index c6bba46424..599b3dcdc3 100644 --- a/test/functional/eval/glob_spec.lua +++ b/test/functional/eval/glob_spec.lua @@ -1,5 +1,5 @@ local lfs = require('lfs') -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, execute, eval, eq = helpers.clear, helpers.execute, helpers.eval, helpers.eq before_each(function() diff --git a/test/functional/eval/json_functions_spec.lua b/test/functional/eval/json_functions_spec.lua index b32688a9d2..159d775ff1 100644 --- a/test/functional/eval/json_functions_spec.lua +++ b/test/functional/eval/json_functions_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local funcs = helpers.funcs local meths = helpers.meths @@ -10,8 +10,8 @@ local redir_exec = helpers.redir_exec local NIL = helpers.NIL describe('json_decode() function', function() - local restart = function(cmd) - clear(cmd) + local restart = function(...) + clear(...) execute('language C') execute([[ function Eq(exp, act) @@ -490,13 +490,13 @@ describe('json_decode() function', function() end) it('converts strings to latin1 when &encoding is latin1', function() - restart('set encoding=latin1') + restart('--cmd', 'set encoding=latin1') eq('\171', funcs.json_decode('"\\u00AB"')) sp_decode_eq({_TYPE='string', _VAL={'\n\171\n'}}, '"\\u0000\\u00AB\\u0000"') end) it('fails to convert string to latin1 if it is impossible', function() - restart('set encoding=latin1') + restart('--cmd', 'set encoding=latin1') eq('Vim(call):E474: Failed to convert string "ê¯" from UTF-8', exc_exec('call json_decode(\'"\\uABCD"\')')) end) @@ -532,7 +532,7 @@ describe('json_decode() function', function() -- When &encoding is latin1 string "«" is U+00C2 U+00AB U+00C2: «Â. So if -- '"«"' was parsed as latin1 json_decode would return three characters, and -- only one U+00AB when this string is parsed as latin1. - restart('set encoding=latin1') + restart('--cmd', 'set encoding=latin1') eq(('%c'):format(0xAB), funcs.json_decode('"«"')) end) @@ -763,7 +763,7 @@ describe('json_encode() function', function() end) it('converts strings from latin1 when &encoding is latin1', function() - clear('set encoding=latin1') + clear('--cmd', 'set encoding=latin1') eq('"\\u00AB"', funcs.json_encode('\171')) eq('"\\u0000\\u00AB\\u0000"', eval('json_encode({"_TYPE": v:msgpack_types.string, "_VAL": ["\\n\171\\n"]})')) end) diff --git a/test/functional/eval/msgpack_functions_spec.lua b/test/functional/eval/msgpack_functions_spec.lua index 9e501353a5..5b87b05652 100644 --- a/test/functional/eval/msgpack_functions_spec.lua +++ b/test/functional/eval/msgpack_functions_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local funcs = helpers.funcs local eval, eq = helpers.eval, helpers.eq diff --git a/test/functional/eval/operators_spec.lua b/test/functional/eval/operators_spec.lua index bc9a17935c..4d07bc1b05 100644 --- a/test/functional/eval/operators_spec.lua +++ b/test/functional/eval/operators_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local eq = helpers.eq local eval = helpers.eval local clear = helpers.clear diff --git a/test/functional/eval/printf_spec.lua b/test/functional/eval/printf_spec.lua index 6180f4156a..c84290ceef 100644 --- a/test/functional/eval/printf_spec.lua +++ b/test/functional/eval/printf_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local eq = helpers.eq local funcs = helpers.funcs diff --git a/test/functional/eval/reltime_spec.lua b/test/functional/eval/reltime_spec.lua index da55a3fac3..0b19d372ec 100644 --- a/test/functional/eval/reltime_spec.lua +++ b/test/functional/eval/reltime_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, eq, ok = helpers.clear, helpers.eq, helpers.ok local neq, execute, funcs = helpers.neq, helpers.execute, helpers.funcs local reltime, reltimestr, reltimefloat = funcs.reltime, funcs.reltimestr, funcs.reltimefloat diff --git a/test/functional/eval/server_spec.lua b/test/functional/eval/server_spec.lua index 7f53522c08..0fd55ce2f9 100644 --- a/test/functional/eval/server_spec.lua +++ b/test/functional/eval/server_spec.lua @@ -1,5 +1,5 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local nvim, eq, neq, eval = helpers.nvim, helpers.eq, helpers.neq, helpers.eval local clear, funcs, meths = helpers.clear, helpers.funcs, helpers.meths local os_name = helpers.os_name diff --git a/test/functional/eval/special_vars_spec.lua b/test/functional/eval/special_vars_spec.lua index 2526483830..4c5d63ce23 100644 --- a/test/functional/eval/special_vars_spec.lua +++ b/test/functional/eval/special_vars_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local exc_exec = helpers.exc_exec local execute = helpers.execute local funcs = helpers.funcs diff --git a/test/functional/eval/string_spec.lua b/test/functional/eval/string_spec.lua index abda2c59cb..9e2dc4e111 100644 --- a/test/functional/eval/string_spec.lua +++ b/test/functional/eval/string_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local eq = helpers.eq local command = helpers.command diff --git a/test/functional/eval/timer_spec.lua b/test/functional/eval/timer_spec.lua index 611113f560..2f83edb9e4 100644 --- a/test/functional/eval/timer_spec.lua +++ b/test/functional/eval/timer_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local ok, feed, eq, eval = helpers.ok, helpers.feed, helpers.eq, helpers.eval local source, nvim_async, run = helpers.source, helpers.nvim_async, helpers.run @@ -22,6 +22,14 @@ describe('timers', function() eq(1,eval("g:val")) end) + it('works one-shot when repeat=0', function() + execute("call timer_start(50, 'MyHandler', {'repeat': 0})") + eq(0,eval("g:val")) + run(nil, nil, nil, 200) + eq(1,eval("g:val")) + end) + + it('works with repeat two', function() execute("call timer_start(50, 'MyHandler', {'repeat': 2})") eq(0,eval("g:val")) @@ -37,6 +45,13 @@ describe('timers', function() eq(2,eval("g:val")) end) + it('works with zero timeout', function() + -- timer_start does still not invoke the callback immediately + eq(0,eval("[timer_start(0, 'MyHandler', {'repeat': 1000}), g:val][1]")) + run(nil, nil, nil, 300) + eq(1000,eval("g:val")) + end) + it('can be started during sleep', function() nvim_async("command", "sleep 10") -- this also tests that remote requests works during sleep diff --git a/test/functional/eval/vvar_event_spec.lua b/test/functional/eval/vvar_event_spec.lua index bbac86524f..eec8aa917a 100644 --- a/test/functional/eval/vvar_event_spec.lua +++ b/test/functional/eval/vvar_event_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, eval, eq = helpers.clear, helpers.eval, helpers.eq local command = helpers.command describe('v:event', function() diff --git a/test/functional/ex_cmds/append_spec.lua b/test/functional/ex_cmds/append_spec.lua index 2d5ab8e8c8..3e326d9460 100644 --- a/test/functional/ex_cmds/append_spec.lua +++ b/test/functional/ex_cmds/append_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local eq = helpers.eq local feed = helpers.feed diff --git a/test/functional/ex_cmds/cd_spec.lua b/test/functional/ex_cmds/cd_spec.lua index 69467632a4..fcd826c25d 100644 --- a/test/functional/ex_cmds/cd_spec.lua +++ b/test/functional/ex_cmds/cd_spec.lua @@ -1,49 +1,145 @@ -- Specs for :cd, :tcd, :lcd and getcwd() -local helpers = require('test.functional.helpers') -local execute, eq, clear, eval, exc_exec = - helpers.execute, helpers.eq, helpers.clear, helpers.eval, helpers.exc_exec local lfs = require('lfs') +local helpers = require('test.functional.helpers')(after_each) + +local eq = helpers.eq +local call = helpers.call +local clear = helpers.clear +local execute = helpers.execute +local exc_exec = helpers.exc_exec -- These directories will be created for testing local directories = { - 'Xtest-functional-ex_cmds-cd_spec.1', -- Tab - 'Xtest-functional-ex_cmds-cd_spec.2', -- Window - 'Xtest-functional-ex_cmds-cd_spec.3', -- New global + tab = 'Xtest-functional-ex_cmds-cd_spec.tab', -- Tab + window = 'Xtest-functional-ex_cmds-cd_spec.window', -- Window + global = 'Xtest-functional-ex_cmds-cd_spec.global', -- New global } -- Shorthand writing to get the current working directory -local cwd = function() return eval('getcwd( )') end -- effective working dir -local wcwd = function() return eval('getcwd( 0 )') end -- window dir -local tcwd = function() return eval('getcwd(-1, 0)') end -- tab dir ---local gcwd = function() return eval('getcwd(-1, -1)') end -- global dir +local cwd = function(...) return call('getcwd', ...) end -- effective working dir +local wcwd = function() return cwd(0) end -- window dir +local tcwd = function() return cwd(-1, 0) end -- tab dir -- Same, except these tell us if there is a working directory at all ---local lwd = function() return eval('haslocaldir( )') end -- effective working dir -local wlwd = function() return eval('haslocaldir( 0 )') end -- window dir -local tlwd = function() return eval('haslocaldir(-1, 0)') end -- tab dir +local lwd = function(...) return call('haslocaldir', ...) end -- effective working dir +local wlwd = function() return lwd(0) end -- window dir +local tlwd = function() return lwd(-1, 0) end -- tab dir --local glwd = function() return eval('haslocaldir(-1, -1)') end -- global dir -- Test both the `cd` and `chdir` variants for _, cmd in ipairs {'cd', 'chdir'} do - describe(':*' .. cmd, function() + describe(':' .. cmd, function() before_each(function() clear() - for _, d in ipairs(directories) do + for _, d in pairs(directories) do lfs.mkdir(d) end + directories.start = cwd() end) after_each(function() - for _, d in ipairs(directories) do + for _, d in pairs(directories) do lfs.rmdir(d) end end) - it('works', function() - -- Store the initial working directory - local globalDir = cwd() + describe('using explicit scope', function() + it('for window', function() + local globalDir = directories.start + local globalwin = call('winnr') + local tabnr = call('tabpagenr') + + -- Everything matches globalDir to start + eq(globalDir, cwd(globalwin)) + eq(globalDir, cwd(globalwin, tabnr)) + eq(0, lwd(globalwin)) + eq(0, lwd(globalwin, tabnr)) + + execute('bot split') + local localwin = call('winnr') + -- Initial window is still using globalDir + eq(globalDir, cwd(localwin)) + eq(globalDir, cwd(localwin, tabnr)) + eq(0, lwd(globalwin)) + eq(0, lwd(globalwin, tabnr)) + + execute('silent l' .. cmd .. ' ' .. directories.window) + -- From window with local dir, the original window + -- is still reporting the global dir + eq(globalDir, cwd(globalwin)) + eq(globalDir, cwd(globalwin, tabnr)) + eq(0, lwd(globalwin)) + eq(0, lwd(globalwin, tabnr)) + + -- Window with local dir reports as such + eq(globalDir .. '/' .. directories.window, cwd(localwin)) + eq(globalDir .. '/' .. directories.window, cwd(localwin, tabnr)) + eq(1, lwd(localwin)) + eq(1, lwd(localwin, tabnr)) + + execute('tabnew') + -- From new tab page, original window reports global dir + eq(globalDir, cwd(globalwin, tabnr)) + eq(0, lwd(globalwin, tabnr)) + + -- From new tab page, local window reports as such + eq(globalDir .. '/' .. directories.window, cwd(localwin, tabnr)) + eq(1, lwd(localwin, tabnr)) + end) + + it('for tab page', function() + local globalDir = directories.start + local globaltab = call('tabpagenr') + + -- Everything matches globalDir to start + eq(globalDir, cwd(-1, 0)) + eq(globalDir, cwd(-1, globaltab)) + eq(0, lwd(-1, 0)) + eq(0, lwd(-1, globaltab)) + + execute('tabnew') + execute('silent t' .. cmd .. ' ' .. directories.tab) + local localtab = call('tabpagenr') + + -- From local tab page, original tab reports globalDir + eq(globalDir, cwd(-1, globaltab)) + eq(0, lwd(-1, globaltab)) + + -- new tab reports local + eq(globalDir .. '/' .. directories.tab, cwd(-1, 0)) + eq(globalDir .. '/' .. directories.tab, cwd(-1, localtab)) + eq(1, lwd(-1, 0)) + eq(1, lwd(-1, localtab)) + + execute('tabnext') + -- From original tab page, local reports as such + eq(globalDir .. '/' .. directories.tab, cwd(-1, localtab)) + eq(1, lwd(-1, localtab)) + end) + end) + describe('getcwd(-1, -1)', function() + it('works', function() + eq(directories.start, cwd(-1, -1)) + eq(0, lwd(-1, -1)) + end) + + it('works with tab-local pwd', function() + execute('silent t' .. cmd .. ' ' .. directories.tab) + eq(directories.start, cwd(-1, -1)) + eq(0, lwd(-1, -1)) + end) + + it('works with window-local pwd', function() + execute('silent l' .. cmd .. ' ' .. directories.window) + eq(directories.start, cwd(-1, -1)) + eq(0, lwd(-1, -1)) + end) + end) + + it('works', function() + local globalDir = directories.start -- Create a new tab first and verify that is has the same working dir execute('tabnew') eq(globalDir, cwd()) @@ -53,8 +149,8 @@ for _, cmd in ipairs {'cd', 'chdir'} do eq(0, wlwd()) -- Change tab-local working directory and verify it is different - execute('silent t' .. cmd .. ' ' .. directories[1]) - eq(globalDir .. '/' .. directories[1], cwd()) + execute('silent t' .. cmd .. ' ' .. directories.tab) + eq(globalDir .. '/' .. directories.tab, cwd()) eq(cwd(), tcwd()) -- working directory maches tab directory eq(1, tlwd()) eq(cwd(), wcwd()) -- still no window-directory @@ -64,16 +160,16 @@ for _, cmd in ipairs {'cd', 'chdir'} do execute('new') eq(1, tlwd()) -- Still tab-local working directory eq(0, wlwd()) -- Still no window-local working directory - eq(globalDir .. '/' .. directories[1], cwd()) - execute('silent l' .. cmd .. ' ../' .. directories[2]) - eq(globalDir .. '/' .. directories[2], cwd()) - eq(globalDir .. '/' .. directories[1], tcwd()) + eq(globalDir .. '/' .. directories.tab, cwd()) + execute('silent l' .. cmd .. ' ../' .. directories.window) + eq(globalDir .. '/' .. directories.window, cwd()) + eq(globalDir .. '/' .. directories.tab, tcwd()) eq(1, wlwd()) -- Verify the first window still has the tab local directory execute('wincmd w') - eq(globalDir .. '/' .. directories[1], cwd()) - eq(globalDir .. '/' .. directories[1], tcwd()) + eq(globalDir .. '/' .. directories.tab, cwd()) + eq(globalDir .. '/' .. directories.tab, tcwd()) eq(0, wlwd()) -- No window-local directory -- Change back to initial tab and verify working directory has stayed @@ -83,11 +179,11 @@ for _, cmd in ipairs {'cd', 'chdir'} do eq(0, wlwd()) -- Verify global changes don't affect local ones - execute('silent ' .. cmd .. ' ' .. directories[3]) - eq(globalDir .. '/' .. directories[3], cwd()) + execute('silent ' .. cmd .. ' ' .. directories.global) + eq(globalDir .. '/' .. directories.global, cwd()) execute('tabnext') - eq(globalDir .. '/' .. directories[1], cwd()) - eq(globalDir .. '/' .. directories[1], tcwd()) + eq(globalDir .. '/' .. directories.tab, cwd()) + eq(globalDir .. '/' .. directories.tab, tcwd()) eq(0, wlwd()) -- Still no window-local directory in this window -- Unless the global change happened in a tab with local directory @@ -101,9 +197,9 @@ for _, cmd in ipairs {'cd', 'chdir'} do -- But not in a window with its own local directory execute('tabnext | wincmd w') - eq(globalDir .. '/' .. directories[2], cwd() ) + eq(globalDir .. '/' .. directories.window, cwd() ) eq(0 , tlwd()) - eq(globalDir .. '/' .. directories[2], wcwd()) + eq(globalDir .. '/' .. directories.window, wcwd()) end) end) end diff --git a/test/functional/ex_cmds/drop_spec.lua b/test/functional/ex_cmds/drop_spec.lua new file mode 100644 index 0000000000..16b194dd7d --- /dev/null +++ b/test/functional/ex_cmds/drop_spec.lua @@ -0,0 +1,80 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute + +describe(":drop", function() + local screen + + before_each(function() + clear() + screen = Screen.new(35, 10) + screen:attach() + screen:set_default_attr_ignore({{bold=true, foreground=Screen.colors.Blue}}) + screen:set_default_attr_ids({ + [1] = {bold = true, reverse = true}, + [2] = {reverse = true}, + [3] = {bold = true}, + }) + execute("set laststatus=2") + end) + + after_each(function() + screen:detach() + end) + + it("works like :e when called with only one window open", function() + execute("drop tmp1.vim") + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + {1:tmp1.vim }| + "tmp1.vim" [New File] | + ]]) + end) + + it("switches to an open window showing the buffer", function() + execute("edit tmp1") + execute("vsplit") + execute("edit tmp2") + execute("drop tmp1") + screen:expect([[ + {2:|}^ | + ~ {2:|}~ | + ~ {2:|}~ | + ~ {2:|}~ | + ~ {2:|}~ | + ~ {2:|}~ | + ~ {2:|}~ | + ~ {2:|}~ | + {2:tmp2 }{1:tmp1 }| + :drop tmp1 | + ]]) + end) + + it("splits off a new window when a buffer can't be abandoned", function() + execute("edit tmp1") + execute("vsplit") + execute("edit tmp2") + feed("iABC<esc>") + execute("drop tmp3") + screen:expect([[ + ^ {2:|} | + ~ {2:|}~ | + ~ {2:|}~ | + ~ {2:|}~ | + {1:tmp3 }{2:|}~ | + ABC {2:|}~ | + ~ {2:|}~ | + ~ {2:|}~ | + {2:tmp2 [+] tmp1 }| + "tmp3" [New File] | + ]]) + end) + +end) diff --git a/test/functional/ex_cmds/encoding_spec.lua b/test/functional/ex_cmds/encoding_spec.lua index 6d402b7974..e2b3e7e31d 100644 --- a/test/functional/ex_cmds/encoding_spec.lua +++ b/test/functional/ex_cmds/encoding_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, execute, feed = helpers.clear, helpers.execute, helpers.feed local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval @@ -22,7 +22,7 @@ describe('&encoding', function() end) it('can be changed before startup', function() - clear('set enc=latin1') + clear('--cmd', 'set enc=latin1') execute('set encoding=utf-8') -- error message expected feed('<cr>') @@ -32,7 +32,7 @@ describe('&encoding', function() it('is not changed by `set all&`', function() -- we need to set &encoding to something non-default. Use 'latin1' - clear('set enc=latin1') + clear('--cmd', 'set enc=latin1') execute('set all&') eq('latin1', eval('&encoding')) eq(4, eval('strwidth("Bär")')) diff --git a/test/functional/ex_cmds/grep_spec.lua b/test/functional/ex_cmds/grep_spec.lua index f3ff0a3817..13f88b7e03 100644 --- a/test/functional/ex_cmds/grep_spec.lua +++ b/test/functional/ex_cmds/grep_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, execute, feed, ok, eval = helpers.clear, helpers.execute, helpers.feed, helpers.ok, helpers.eval diff --git a/test/functional/ex_cmds/menu_spec.lua b/test/functional/ex_cmds/menu_spec.lua index f5fd30465d..52df9e1592 100644 --- a/test/functional/ex_cmds/menu_spec.lua +++ b/test/functional/ex_cmds/menu_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, execute, nvim = helpers.clear, helpers.execute, helpers.nvim local expect, feed, command = helpers.expect, helpers.feed, helpers.command local eq, eval = helpers.eq, helpers.eval @@ -39,7 +39,7 @@ describe(':emenu', function() end) it('executes correct bindings in command mode', function() - feed('ithis is a sentence<esc>^"+yiwo<esc>') + feed('ithis is a sentence<esc>^yiwo<esc>') -- Invoke "Edit.Paste" in normal-mode. nvim('command', 'emenu Edit.Paste') diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua index 5bba1a0e7c..b7109f2f98 100644 --- a/test/functional/ex_cmds/oldfiles_spec.lua +++ b/test/functional/ex_cmds/oldfiles_spec.lua @@ -1,5 +1,5 @@ local Screen = require('test.functional.ui.screen') -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local buf, eq, execute = helpers.curbufmeths, helpers.eq, helpers.execute local feed, nvim_prog, wait = helpers.feed, helpers.nvim_prog, helpers.wait diff --git a/test/functional/ex_cmds/profile_spec.lua b/test/functional/ex_cmds/profile_spec.lua index 744b22621f..d390806679 100644 --- a/test/functional/ex_cmds/profile_spec.lua +++ b/test/functional/ex_cmds/profile_spec.lua @@ -1,7 +1,7 @@ require('os') local lfs = require('lfs') -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local eval = helpers.eval local command = helpers.command local eq, neq = helpers.eq, helpers.neq diff --git a/test/functional/ex_cmds/quit_spec.lua b/test/functional/ex_cmds/quit_spec.lua index a8156228d3..016a607743 100644 --- a/test/functional/ex_cmds/quit_spec.lua +++ b/test/functional/ex_cmds/quit_spec.lua @@ -1,9 +1,9 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear describe(':qa', function() before_each(function() - clear('qa') + clear('--cmd', 'qa') end) it('verify #3334', function() diff --git a/test/functional/ex_cmds/recover_spec.lua b/test/functional/ex_cmds/recover_spec.lua index e1d01f6896..60673d25ef 100644 --- a/test/functional/ex_cmds/recover_spec.lua +++ b/test/functional/ex_cmds/recover_spec.lua @@ -1,6 +1,6 @@ -- Tests for :recover -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local lfs = require('lfs') local execute, eq, clear, eval, feed, expect, source = helpers.execute, helpers.eq, helpers.clear, helpers.eval, helpers.feed, diff --git a/test/functional/ex_cmds/sign_spec.lua b/test/functional/ex_cmds/sign_spec.lua index c50704504d..b37e6e8563 100644 --- a/test/functional/ex_cmds/sign_spec.lua +++ b/test/functional/ex_cmds/sign_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, nvim, eq = helpers.clear, helpers.nvim, helpers.eq describe('sign', function() diff --git a/test/functional/ex_cmds/write_spec.lua b/test/functional/ex_cmds/write_spec.lua index d90b297ca8..b38ae29f7d 100644 --- a/test/functional/ex_cmds/write_spec.lua +++ b/test/functional/ex_cmds/write_spec.lua @@ -1,15 +1,18 @@ -- Specs for :write -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local eq, eval, clear, write_file, execute, source = helpers.eq, helpers.eval, helpers.clear, helpers.write_file, helpers.execute, helpers.source describe(':write', function() - it('&backupcopy=auto preserves symlinks', function() - clear('set backupcopy=auto') + after_each(function() os.remove('test_bkc_file.txt') os.remove('test_bkc_link.txt') + end) + + it('&backupcopy=auto preserves symlinks', function() + clear('--cmd', 'set backupcopy=auto') write_file('test_bkc_file.txt', 'content0') execute("silent !ln -s test_bkc_file.txt test_bkc_link.txt") source([[ @@ -22,9 +25,7 @@ describe(':write', function() end) it('&backupcopy=no replaces symlink with new file', function() - clear('set backupcopy=no') - os.remove('test_bkc_file.txt') - os.remove('test_bkc_link.txt') + clear('--cmd', 'set backupcopy=no') write_file('test_bkc_file.txt', 'content0') execute("silent !ln -s test_bkc_file.txt test_bkc_link.txt") source([[ diff --git a/test/functional/ex_cmds/wundo_spec.lua b/test/functional/ex_cmds/wundo_spec.lua index 969dfea3d9..e1216fa5d4 100644 --- a/test/functional/ex_cmds/wundo_spec.lua +++ b/test/functional/ex_cmds/wundo_spec.lua @@ -1,6 +1,6 @@ -- Specs for :wundo and underlying functions -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local execute, clear, eval, feed, spawn, nvim_prog, set_session = helpers.execute, helpers.clear, helpers.eval, helpers.feed, helpers.spawn, helpers.nvim_prog, helpers.set_session diff --git a/test/functional/ex_cmds/wviminfo_spec.lua b/test/functional/ex_cmds/wviminfo_spec.lua index 21f14be62c..37f45da2d4 100644 --- a/test/functional/ex_cmds/wviminfo_spec.lua +++ b/test/functional/ex_cmds/wviminfo_spec.lua @@ -1,4 +1,5 @@ -local helpers, lfs = require('test.functional.helpers'), require('lfs') +local helpers = require('test.functional.helpers')(after_each) +local lfs = require('lfs') local execute, eq, neq, spawn, nvim_prog, set_session, wait, write_file = helpers.execute, helpers.eq, helpers.neq, helpers.spawn, helpers.nvim_prog, helpers.set_session, helpers.wait, helpers.write_file diff --git a/test/functional/ex_getln/history_spec.lua b/test/functional/ex_getln/history_spec.lua index 532c81dab9..c1d2ffda53 100644 --- a/test/functional/ex_getln/history_spec.lua +++ b/test/functional/ex_getln/history_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, meths, funcs, eq = helpers.clear, helpers.meths, helpers.funcs, helpers.eq diff --git a/test/functional/fixtures/autoload/provider/clipboard.vim b/test/functional/fixtures/autoload/provider/clipboard.vim index 0935ea45ff..411e095c71 100644 --- a/test/functional/fixtures/autoload/provider/clipboard.vim +++ b/test/functional/fixtures/autoload/provider/clipboard.vim @@ -9,13 +9,12 @@ function! s:methods.get(reg) if g:cliperror return 0 end - let reg = a:reg == '"' ? '+' : a:reg if g:cliplossy " behave like pure text clipboard - return g:test_clip[reg][0] + return g:test_clip[a:reg][0] else " behave like VIMENC clipboard - return g:test_clip[reg] + return g:test_clip[a:reg] end endfunction diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 37b7bf664c..02109d0889 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -1,8 +1,13 @@ require('coxpcall') local lfs = require('lfs') -local assert = require('luassert') local ChildProcessStream = require('nvim.child_process_stream') local Session = require('nvim.session') +local global_helpers = require('test.helpers') + +local check_logs = global_helpers.check_logs +local neq = global_helpers.neq +local eq = global_helpers.eq +local ok = global_helpers.ok local nvim_prog = os.getenv('NVIM_PROG') or 'build/bin/nvim' local nvim_argv = {nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N', @@ -30,7 +35,7 @@ if os.getenv('VALGRIND') then prepend_argv = {'valgrind', '-q', '--tool=memcheck', '--leak-check=yes', '--track-origins=yes', '--show-possibly-lost=no', - '--suppressions=.valgrind.supp', + '--suppressions=src/.valgrind.supp', '--log-file='..log_file} if os.getenv('GDB') then table.insert(prepend_argv, '--vgdb=yes') @@ -216,11 +221,10 @@ local function spawn(argv, merge) return Session.new(child_stream) end -local function clear(extra_cmd) +local function clear(...) local args = {unpack(nvim_argv)} - if extra_cmd ~= nil then - table.insert(args, '--cmd') - table.insert(args, extra_cmd) + for _, arg in ipairs({...}) do + table.insert(args, arg) end set_session(spawn(args)) end @@ -267,18 +271,6 @@ local function source(code) return tmpname end -local function eq(expected, actual) - return assert.are.same(expected, actual) -end - -local function neq(expected, actual) - return assert.are_not.same(expected, actual) -end - -local function ok(expr) - assert.is_true(expr) -end - local function nvim(method, ...) return request('vim_'..method, ...) end @@ -308,14 +300,18 @@ local function curbuf(method, ...) end local function wait() + -- Execute 'vim_eval' (a deferred function) to block + -- until all pending input is processed. session:request('vim_eval', '1') end +-- sleeps the test runner (_not_ the nvim instance) +local function sleep(timeout) + run(nil, nil, nil, timeout) +end + local function curbuf_contents() - -- Before inspecting the buffer, execute 'vim_eval' to wait until all - -- previously sent keys are processed(vim_eval is a deferred function, and - -- only processed after all input) - wait() + wait() -- Before inspecting the buffer, process all input. return table.concat(curbuf('get_lines', 0, -1, true), '\n') end @@ -345,10 +341,18 @@ local function rmdir(path) end for file in lfs.dir(path) do if file ~= '.' and file ~= '..' then - local ret, err = os.remove(path..'/'..file) - if not ret then - error('os.remove: '..err) - return nil + local abspath = path..'/'..file + if lfs.attributes(abspath, 'mode') == 'directory' then + local ret = rmdir(abspath) -- recurse + if not ret then + return nil + end + else + local ret, err = os.remove(abspath) + if not ret then + error('os.remove: '..err) + return nil + end end end end @@ -404,54 +408,60 @@ local curbufmeths = create_callindex(curbuf) local curwinmeths = create_callindex(curwin) local curtabmeths = create_callindex(curtab) -return { - prepend_argv = prepend_argv, - clear = clear, - spawn = spawn, - dedent = dedent, - source = source, - rawfeed = rawfeed, - insert = insert, - feed = feed, - execute = execute, - eval = nvim_eval, - call = nvim_call, - command = nvim_command, - request = request, - next_message = next_message, - run = run, - stop = stop, - eq = eq, - neq = neq, - expect = expect, - ok = ok, - nvim = nvim, - nvim_async = nvim_async, - nvim_prog = nvim_prog, - nvim_dir = nvim_dir, - buffer = buffer, - window = window, - tabpage = tabpage, - curbuf = curbuf, - curwin = curwin, - curtab = curtab, - curbuf_contents = curbuf_contents, - wait = wait, - set_session = set_session, - write_file = write_file, - os_name = os_name, - rmdir = rmdir, - mkdir = lfs.mkdir, - exc_exec = exc_exec, - redir_exec = redir_exec, - merge_args = merge_args, - funcs = funcs, - meths = meths, - bufmeths = bufmeths, - winmeths = winmeths, - tabmeths = tabmeths, - curbufmeths = curbufmeths, - curwinmeths = curwinmeths, - curtabmeths = curtabmeths, - NIL = mpack.NIL -} +return function(after_each) + if after_each then + after_each(check_logs) + end + return { + prepend_argv = prepend_argv, + clear = clear, + spawn = spawn, + dedent = dedent, + source = source, + rawfeed = rawfeed, + insert = insert, + feed = feed, + execute = execute, + eval = nvim_eval, + call = nvim_call, + command = nvim_command, + request = request, + next_message = next_message, + run = run, + stop = stop, + eq = eq, + neq = neq, + expect = expect, + ok = ok, + nvim = nvim, + nvim_async = nvim_async, + nvim_prog = nvim_prog, + nvim_dir = nvim_dir, + buffer = buffer, + window = window, + tabpage = tabpage, + curbuf = curbuf, + curwin = curwin, + curtab = curtab, + curbuf_contents = curbuf_contents, + wait = wait, + sleep = sleep, + set_session = set_session, + write_file = write_file, + os_name = os_name, + rmdir = rmdir, + mkdir = lfs.mkdir, + exc_exec = exc_exec, + redir_exec = redir_exec, + merge_args = merge_args, + funcs = funcs, + meths = meths, + bufmeths = bufmeths, + winmeths = winmeths, + tabmeths = tabmeths, + curbufmeths = curbufmeths, + curwinmeths = curwinmeths, + curtabmeths = curtabmeths, + NIL = mpack.NIL, + } +end diff --git a/test/functional/legacy/002_filename_recognition_spec.lua b/test/functional/legacy/002_filename_recognition_spec.lua index 569e748631..5a833281e7 100644 --- a/test/functional/legacy/002_filename_recognition_spec.lua +++ b/test/functional/legacy/002_filename_recognition_spec.lua @@ -1,7 +1,7 @@ -- Test if URLs are recognized as filenames by commands such as "gf". Here -- we'll use `expand("<cfile>")` since "gf" would need to open the file. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/003_cindent_spec.lua b/test/functional/legacy/003_cindent_spec.lua index 4b838eda1d..83388bd1eb 100644 --- a/test/functional/legacy/003_cindent_spec.lua +++ b/test/functional/legacy/003_cindent_spec.lua @@ -3,7 +3,7 @@ -- There are 50+ test command blocks (the stuff between STARTTEST and ENDTEST) -- in the original test. These have been converted to "it" test cases here. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert = helpers.feed, helpers.insert local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/004_bufenter_with_modelines_spec.lua b/test/functional/legacy/004_bufenter_with_modelines_spec.lua index 34e702b798..3e5cdd2ff2 100644 --- a/test/functional/legacy/004_bufenter_with_modelines_spec.lua +++ b/test/functional/legacy/004_bufenter_with_modelines_spec.lua @@ -2,7 +2,7 @@ -- Test for autocommand that changes current buffer on BufEnter event. -- Check if modelines are interpreted for the correct buffer. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/005_bufleave_delete_buffer_spec.lua b/test/functional/legacy/005_bufleave_delete_buffer_spec.lua index e6989a6674..895f4ad181 100644 --- a/test/functional/legacy/005_bufleave_delete_buffer_spec.lua +++ b/test/functional/legacy/005_bufleave_delete_buffer_spec.lua @@ -1,7 +1,7 @@ -- Test for autocommand that deletes the current buffer on BufLeave event. -- Also test deleting the last buffer, should give a new, empty buffer. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/006_argument_list_spec.lua b/test/functional/legacy/006_argument_list_spec.lua index 1266a876d4..764854314f 100644 --- a/test/functional/legacy/006_argument_list_spec.lua +++ b/test/functional/legacy/006_argument_list_spec.lua @@ -1,6 +1,6 @@ -- Test for autocommand that redefines the argument list, when doing ":all". -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, dedent, eq = helpers.execute, helpers.dedent, helpers.eq local curbuf_contents = helpers.curbuf_contents diff --git a/test/functional/legacy/007_ball_buffer_list_spec.lua b/test/functional/legacy/007_ball_buffer_list_spec.lua index 295f63f044..07e3fe6e7a 100644 --- a/test/functional/legacy/007_ball_buffer_list_spec.lua +++ b/test/functional/legacy/007_ball_buffer_list_spec.lua @@ -1,6 +1,6 @@ -- Test for autocommand that changes the buffer list, when doing ":ball". -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/009_bufleave_autocommand_spec.lua b/test/functional/legacy/009_bufleave_autocommand_spec.lua index 8c18639c8f..7481c639cf 100644 --- a/test/functional/legacy/009_bufleave_autocommand_spec.lua +++ b/test/functional/legacy/009_bufleave_autocommand_spec.lua @@ -1,6 +1,6 @@ -- Test for Bufleave autocommand that deletes the buffer we are about to edit. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, insert = helpers.clear, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/010_errorformat_spec.lua b/test/functional/legacy/010_errorformat_spec.lua new file mode 100644 index 0000000000..785bf136b5 --- /dev/null +++ b/test/functional/legacy/010_errorformat_spec.lua @@ -0,0 +1,156 @@ +-- Test for 'errorformat'. This will fail if the quickfix feature was +-- disabled. + +local helpers = require('test.functional.helpers')(after_each) +local feed, clear, execute = helpers.feed, helpers.clear, helpers.execute +local expect, write_file = helpers.expect, helpers.write_file + +describe('errorformat', function() + setup(function() + clear() + local error_file_text = [[ + 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? + ]] + write_file('Xerrorfile1', error_file_text .. 'end of errorfile\n') + write_file('Xerrorfile2', error_file_text) + write_file('Xtestfile', [[ + 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 + ]]) + end) + teardown(function() + os.remove('Xerrorfile1') + os.remove('Xerrorfile2') + os.remove('Xtestfile') + end) + + it('is working', function() + -- Also test a BOM is ignored. + execute( + 'set encoding=utf-8', + [[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' + ) + feed('lgR<C-R>=a<CR><esc>') + execute('cf Xerrorfile1') + feed('grA<cr>') + execute('cn') + feed('gRLINE 6, COL 19<esc>') + execute('cn') + feed('gRNO COLUMN SPECIFIED<esc>') + execute('cn') + feed('gRAGAIN NO COLUMN<esc>') + execute('cn') + feed('gRCOL 1<esc>') + execute('cn') + feed('gRCOL 2<esc>') + execute('cn') + feed('gRCOL 10<esc>') + execute('cn') + feed('gRVCOL 10<esc>') + execute('cn') + feed('grI<cr>') + execute('cn') + feed('gR. SPACE POINTER<esc>') + execute('cn') + feed('gR. DOT POINTER<esc>') + execute('cn') + feed('gR. DASH POINTER<esc>') + execute('cn') + feed('gR. TAB-SPACE POINTER<esc>') + execute( + 'clast', + 'cprev', + 'cprev', + 'wincmd w', + 'let a=w:quickfix_title', + 'wincmd p' + ) + feed('lgR<C-R>=a<CR><esc>') + + -- Assert buffer contents. + expect([[ + 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]]) + end) +end) diff --git a/test/functional/legacy/011_autocommands_spec.lua b/test/functional/legacy/011_autocommands_spec.lua index 483e465cee..6e613c85df 100644 --- a/test/functional/legacy/011_autocommands_spec.lua +++ b/test/functional/legacy/011_autocommands_spec.lua @@ -12,7 +12,8 @@ -- Use a FileChangedShell autocommand to avoid a prompt for "Xtestfile.gz" -- being modified outside of Vim (noticed on Solaris). -local helpers, lfs = require('test.functional.helpers'), require('lfs') +local helpers= require('test.functional.helpers')(after_each) +local lfs = require('lfs') local clear, execute, expect, eq, neq, dedent, write_file, feed = helpers.clear, helpers.execute, helpers.expect, helpers.eq, helpers.neq, helpers.dedent, helpers.write_file, helpers.feed diff --git a/test/functional/legacy/015_alignment_spec.lua b/test/functional/legacy/015_alignment_spec.lua index 3b19f4ff42..48d4042ff2 100644 --- a/test/functional/legacy/015_alignment_spec.lua +++ b/test/functional/legacy/015_alignment_spec.lua @@ -2,7 +2,7 @@ -- Also test formatting a paragraph. -- Also test undo after ":%s" and formatting. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert = helpers.feed, helpers.insert local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/018_unset_smart_indenting_spec.lua b/test/functional/legacy/018_unset_smart_indenting_spec.lua index 6975cb7f26..ba1eac02cb 100644 --- a/test/functional/legacy/018_unset_smart_indenting_spec.lua +++ b/test/functional/legacy/018_unset_smart_indenting_spec.lua @@ -1,6 +1,6 @@ -- Tests for not doing smart indenting when it isn't set. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/019_smarttab_expandtab_spec.lua b/test/functional/legacy/019_smarttab_expandtab_spec.lua index a33bd0c3ae..2287a9f786 100644 --- a/test/functional/legacy/019_smarttab_expandtab_spec.lua +++ b/test/functional/legacy/019_smarttab_expandtab_spec.lua @@ -1,7 +1,7 @@ -- Tests for "r<Tab>" with 'smarttab' and 'expandtab' set/not set. -- Also test that dv_ works correctly -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert = helpers.feed, helpers.insert local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/020_blockwise_visual_spec.lua b/test/functional/legacy/020_blockwise_visual_spec.lua index 95574a0957..660348a792 100644 --- a/test/functional/legacy/020_blockwise_visual_spec.lua +++ b/test/functional/legacy/020_blockwise_visual_spec.lua @@ -3,7 +3,7 @@ -- First test for undo working properly when executing commands from a register. -- Also test this in an empty buffer. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/021_control_wi_spec.lua b/test/functional/legacy/021_control_wi_spec.lua index 9fd83fec5f..787a384fca 100644 --- a/test/functional/legacy/021_control_wi_spec.lua +++ b/test/functional/legacy/021_control_wi_spec.lua @@ -1,7 +1,7 @@ -- vim: set foldmethod=marker foldmarker=[[,]] : -- Tests for [ CTRL-I with a count and CTRL-W CTRL-I with a count -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/022_line_ending_spec.lua b/test/functional/legacy/022_line_ending_spec.lua index a841378a82..092440bb16 100644 --- a/test/functional/legacy/022_line_ending_spec.lua +++ b/test/functional/legacy/022_line_ending_spec.lua @@ -1,6 +1,6 @@ -- Tests for file with some lines ending in CTRL-M, some not -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed = helpers.clear, helpers.feed local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/023_edit_arguments_spec.lua b/test/functional/legacy/023_edit_arguments_spec.lua index 15b30bfa3a..95ab983d24 100644 --- a/test/functional/legacy/023_edit_arguments_spec.lua +++ b/test/functional/legacy/023_edit_arguments_spec.lua @@ -1,6 +1,6 @@ -- Tests for complicated + argument to :edit command -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, insert = helpers.clear, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/025_jump_tag_hidden_spec.lua b/test/functional/legacy/025_jump_tag_hidden_spec.lua index bd434c013c..7b7ddb07b9 100644 --- a/test/functional/legacy/025_jump_tag_hidden_spec.lua +++ b/test/functional/legacy/025_jump_tag_hidden_spec.lua @@ -1,7 +1,7 @@ -- Test for jumping to a tag with 'hidden' set, with symbolic link in path of tag. -- This only works for Unix, because of the symbolic link. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/026_execute_while_if_spec.lua b/test/functional/legacy/026_execute_while_if_spec.lua index f17bb79702..74ef34bb20 100644 --- a/test/functional/legacy/026_execute_while_if_spec.lua +++ b/test/functional/legacy/026_execute_while_if_spec.lua @@ -1,6 +1,6 @@ -- Test for :execute, :while and :if -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local execute, expect = helpers.execute, helpers.expect local source = helpers.source diff --git a/test/functional/legacy/027_expand_file_names_spec.lua b/test/functional/legacy/027_expand_file_names_spec.lua deleted file mode 100644 index 4778d16d43..0000000000 --- a/test/functional/legacy/027_expand_file_names_spec.lua +++ /dev/null @@ -1,37 +0,0 @@ --- Test for expanding file names - -local helpers = require('test.functional.helpers') -local clear, feed = helpers.clear, helpers.feed -local execute = helpers.execute -local curbuf_contents = helpers.curbuf_contents -local eq = helpers.eq - -describe('expand file name', function() - setup(clear) - - it('is working', function() - execute('!mkdir Xdir1') - execute('!mkdir Xdir2') - execute('!mkdir Xdir3') - execute('cd Xdir3') - execute('!mkdir Xdir4') - execute('cd ..') - execute('w Xdir1/file') - execute('w Xdir3/Xdir4/file') - execute('n Xdir?/*/file') - - -- Yank current file path to @a register - feed('i<C-R>%<Esc>V"ad') - - -- Put @a and current file path in the current buffer - execute('n! Xdir?/*/nofile') - feed('V"ap') - feed('o<C-R>%<Esc>') - - eq("Xdir3/Xdir4/file\nXdir?/*/nofile", curbuf_contents()) - end) - - teardown(function() - os.execute('rm -rf Xdir1 Xdir2 Xdir3') - end) -end) diff --git a/test/functional/legacy/028_source_ctrl_v_spec.lua b/test/functional/legacy/028_source_ctrl_v_spec.lua index fc36b436ef..a8c43260be 100644 --- a/test/functional/legacy/028_source_ctrl_v_spec.lua +++ b/test/functional/legacy/028_source_ctrl_v_spec.lua @@ -1,6 +1,6 @@ -- Test for sourcing a file with CTRL-V's at the end of the line -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/029_join_spec.lua b/test/functional/legacy/029_join_spec.lua index 25a072ad6e..7a183fcbec 100644 --- a/test/functional/legacy/029_join_spec.lua +++ b/test/functional/legacy/029_join_spec.lua @@ -1,6 +1,6 @@ -- Test for joining lines with marks in them (and with 'joinspaces' set/reset) -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert = helpers.feed, helpers.insert local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/031_close_commands_spec.lua b/test/functional/legacy/031_close_commands_spec.lua index b79b1903ba..eaf4e2982f 100644 --- a/test/functional/legacy/031_close_commands_spec.lua +++ b/test/functional/legacy/031_close_commands_spec.lua @@ -9,9 +9,14 @@ -- :buf -- :edit -local helpers = require('test.functional.helpers') -local feed, insert, source = helpers.feed, helpers.insert, helpers.source -local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect +local helpers = require('test.functional.helpers')(after_each) + +local feed = helpers.feed +local clear = helpers.clear +local source = helpers.source +local insert = helpers.insert +local expect = helpers.expect +local execute = helpers.execute describe('Commands that close windows and/or buffers', function() setup(clear) diff --git a/test/functional/legacy/033_lisp_indent_spec.lua b/test/functional/legacy/033_lisp_indent_spec.lua index 0a5577fad3..b4abb02ac2 100644 --- a/test/functional/legacy/033_lisp_indent_spec.lua +++ b/test/functional/legacy/033_lisp_indent_spec.lua @@ -2,7 +2,7 @@ -- Test for 'lisp' -- If the lisp feature is not enabled, this will fail! -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/034_user_function_spec.lua b/test/functional/legacy/034_user_function_spec.lua new file mode 100644 index 0000000000..38989cd982 --- /dev/null +++ b/test/functional/legacy/034_user_function_spec.lua @@ -0,0 +1,102 @@ +-- 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. + +local helpers = require('test.functional.helpers')(after_each) +local feed, insert, source = helpers.feed, helpers.insert, helpers.source +local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect + +describe('user functions, expr-mappings, overwrite protected builtin functions and regression on calling expressions', function() + setup(clear) + + it('are working', function() + insert('here') + + source([[ + 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 + ]]) + feed('C<C-R>=Table("xxx", 4, "asdf")<cr>') + -- Using a actual space will not work as feed() calls dedent on the input. + feed('<space><C-R>=Compute(45, 0, "retval")<cr>') + feed('<space><C-R>=retval<cr>') + feed('<space><C-R>=Compute(45, 5, "retval")<cr>') + feed('<space><C-R>=retval<cr>') + feed('<space><C-R>=g:FuncRef(333)<cr>') + feed('<cr>') + feed('XX+-XX<cr>') + feed('---*---<cr>') + feed('(one<cr>') + feed('(two<cr>') + feed('[(one again<esc>') + execute('call append(line("$"), max([1, 2, 3]))') + execute('call extend(g:, {"max": function("min")})') + execute('call append(line("$"), max([1, 2, 3]))') + execute('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 &&. + execute([[ $put =(0&&(function('tr'))(1, 2, 3))]]) + execute([[ $put =(1&&(function('tr'))(1, 2, 3))]]) + execute('catch') + execute([[ $put ='!!! Unexpected exception:']]) + execute(' $put =v:exception') + execute('endtry') + + -- Assert buffer contents. + expect([[ + xxx4asdf fail nop ok 9 333 + XX111-XX + ---222--- + 1. one + 2. two + 1. one again + 3 + 3 + 0 + 1]]) + end) +end) diff --git a/test/functional/legacy/035_increment_and_decrement_spec.lua b/test/functional/legacy/035_increment_and_decrement_spec.lua index e6252c384b..3b9f7a9d85 100644 --- a/test/functional/legacy/035_increment_and_decrement_spec.lua +++ b/test/functional/legacy/035_increment_and_decrement_spec.lua @@ -1,7 +1,7 @@ -- Test Ctrl-A and Ctrl-X, which increment and decrement decimal, hexadecimal, -- and octal numbers. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/036_regexp_character_classes_spec.lua b/test/functional/legacy/036_regexp_character_classes_spec.lua index de080f4b43..3d5e69d1e5 100644 --- a/test/functional/legacy/036_regexp_character_classes_spec.lua +++ b/test/functional/legacy/036_regexp_character_classes_spec.lua @@ -1,6 +1,6 @@ -- Test character classes in regexp using regexpengine 0, 1, 2. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect local source, write_file = helpers.source, helpers.write_file local os_name = helpers.os_name diff --git a/test/functional/legacy/038_virtual_replace_spec.lua b/test/functional/legacy/038_virtual_replace_spec.lua index 10d42f0cea..dcbc9c39f7 100644 --- a/test/functional/legacy/038_virtual_replace_spec.lua +++ b/test/functional/legacy/038_virtual_replace_spec.lua @@ -1,6 +1,6 @@ -- Test Virtual replace mode. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed = helpers.feed local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/039_visual_block_mode_commands_spec.lua b/test/functional/legacy/039_visual_block_mode_commands_spec.lua index 7195d7d11d..63335985cc 100644 --- a/test/functional/legacy/039_visual_block_mode_commands_spec.lua +++ b/test/functional/legacy/039_visual_block_mode_commands_spec.lua @@ -1,7 +1,7 @@ -- Test Visual block mode commands -- And test "U" in Visual mode, also on German sharp S. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local nvim, eq = helpers.meths, helpers.eq local insert, feed = helpers.insert, helpers.feed local clear, expect = helpers.clear, helpers.expect diff --git a/test/functional/legacy/041_writing_and_reading_hundred_kbyte_spec.lua b/test/functional/legacy/041_writing_and_reading_hundred_kbyte_spec.lua index 42fb5ed2b3..b6451eb720 100644 --- a/test/functional/legacy/041_writing_and_reading_hundred_kbyte_spec.lua +++ b/test/functional/legacy/041_writing_and_reading_hundred_kbyte_spec.lua @@ -1,6 +1,6 @@ -- Test for writing and reading a file of over 100 Kbyte -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/043_magic_settings_spec.lua b/test/functional/legacy/043_magic_settings_spec.lua index 27694e3754..f174751de2 100644 --- a/test/functional/legacy/043_magic_settings_spec.lua +++ b/test/functional/legacy/043_magic_settings_spec.lua @@ -1,7 +1,7 @@ -- vim: set foldmethod=marker foldmarker=[[,]] : -- Tests for regexp with various magic settings. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/044_099_regexp_multibyte_magic_spec.lua b/test/functional/legacy/044_099_regexp_multibyte_magic_spec.lua index 2a4c0149fa..4189e8a33a 100644 --- a/test/functional/legacy/044_099_regexp_multibyte_magic_spec.lua +++ b/test/functional/legacy/044_099_regexp_multibyte_magic_spec.lua @@ -3,7 +3,7 @@ -- -- This test contains both "test44" and "test99" from the old test suite. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert = helpers.feed, helpers.insert local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/045_folding_spec.lua b/test/functional/legacy/045_folding_spec.lua index 04b623ff3b..cefd7c0d42 100644 --- a/test/functional/legacy/045_folding_spec.lua +++ b/test/functional/legacy/045_folding_spec.lua @@ -1,6 +1,6 @@ -- Tests for folding. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert, clear, execute, expect = helpers.feed, helpers.insert, helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/046_multi_line_regexps_spec.lua b/test/functional/legacy/046_multi_line_regexps_spec.lua index b17ab42fe3..30ec76ea3e 100644 --- a/test/functional/legacy/046_multi_line_regexps_spec.lua +++ b/test/functional/legacy/046_multi_line_regexps_spec.lua @@ -1,7 +1,7 @@ -- vim: set foldmethod=marker foldmarker=[[,]] : -- Tests for multi-line regexps with ":s" -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local expect = helpers.expect diff --git a/test/functional/legacy/051_highlight_spec.lua b/test/functional/legacy/051_highlight_spec.lua index 94c42b73e5..5bf3b51b90 100644 --- a/test/functional/legacy/051_highlight_spec.lua +++ b/test/functional/legacy/051_highlight_spec.lua @@ -2,7 +2,7 @@ -- Tests for ":highlight". local Screen = require('test.functional.ui.screen') -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed = helpers.clear, helpers.feed local execute, expect = helpers.execute, helpers.expect local wait = helpers.wait diff --git a/test/functional/legacy/054_buffer_local_autocommands_spec.lua b/test/functional/legacy/054_buffer_local_autocommands_spec.lua index bcedb26b7e..494ea8f927 100644 --- a/test/functional/legacy/054_buffer_local_autocommands_spec.lua +++ b/test/functional/legacy/054_buffer_local_autocommands_spec.lua @@ -1,6 +1,6 @@ -- Some tests for buffer-local autocommands -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, execute, eq = helpers.clear, helpers.execute, helpers.eq local curbuf_contents = helpers.curbuf_contents diff --git a/test/functional/legacy/055_list_and_dict_types_spec.lua b/test/functional/legacy/055_list_and_dict_types_spec.lua new file mode 100644 index 0000000000..dee138e6d8 --- /dev/null +++ b/test/functional/legacy/055_list_and_dict_types_spec.lua @@ -0,0 +1,949 @@ +-- Tests for List and Dictionary types. + +local helpers = require('test.functional.helpers')(after_each) +local feed, source = helpers.feed, helpers.source +local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect + +describe('list and dictionary types', function() + before_each(clear) + + it('creating list directly with different types', function() + source([[ + lang C + 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]]) + expect([[ + + [1, 'as''d', [1, 2, function('strlen')], {'a': 1}] + {'a': 1} + 1 + Vim(put):E684: ]]) + end) + + it('list slices', function() + source([[ + lang C + " The list from the first test repeated after splitting the tests. + let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},] + $put =string(l[:]) + $put =string(l[1:]) + $put =string(l[:-2]) + $put =string(l[0:8]) + $put =string(l[8:-1])]]) + expect([=[ + + [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}] + []]=]) + end) + + it('list identity', function() + source([[ + lang C + " The list from the first test repeated after splitting the tests. + let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},] + 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]]) + expect('\n101101') + end) + + it('creating dictionary directly with different types', function() + source([[ + lang C + 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)]]) + expect([[ + + {'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}}]]) + end) + + it('dictionary identity', function() + source([[ + lang C + " The dict from the first test repeated after splitting the tests. + let d = {'c': 'ccc', '1': 99, '3': 33, '-1': {'a': 1}} + 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]]) + expect('\n101101') + end) + + it('changing var type should fail', function() + source([[ + lang C + " The list from the first test repeated after splitting the tests. + let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},] + " The dict from the first test repeated after splitting the tests. + let d = {'c': 'ccc', '1': 99, '3': 33, '-1': {'a': 1}} + 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]]) + expect([[ + + Vim(let):E706: d + Vim(let):E706: l]]) + end) + + it('removing items with :unlet', function() + source([[ + lang C + " The list from the first test repeated after splitting the tests. + let l = [1, 'as''d', [1, 2, function("strlen")], {'a': 1},] + " The dict from the first test repeated after splitting the tests. + let d = {'c': 'ccc', '1': 99, '3': 33, '-1': {'a': 1}} + 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)]]) + expect([[ + + [1, 'as''d', {'a': 1}] + [4] + {'1': 99, '3': 33}]]) + end) + + it("removing items out of range: silently skip items that don't exist", function() + -- We can not use source() here as we want to ignore all errors. + execute('lang C') + execute('let l = [0, 1, 2, 3]') + execute('unlet l[2:1]') + execute('$put =string(l)') + execute('let l = [0, 1, 2, 3]') + execute('unlet l[2:2]') + execute('$put =string(l)') + execute('let l = [0, 1, 2, 3]') + execute('unlet l[2:3]') + execute('$put =string(l)') + execute('let l = [0, 1, 2, 3]') + execute('unlet l[2:4]') + execute('$put =string(l)') + execute('let l = [0, 1, 2, 3]') + execute('unlet l[2:5]') + execute('$put =string(l)') + execute('let l = [0, 1, 2, 3]') + execute('unlet l[-1:2]') + execute('$put =string(l)') + execute('let l = [0, 1, 2, 3]') + execute('unlet l[-2:2]') + execute('$put =string(l)') + execute('let l = [0, 1, 2, 3]') + execute('unlet l[-3:2]') + execute('$put =string(l)') + execute('let l = [0, 1, 2, 3]') + execute('unlet l[-4:2]') + execute('$put =string(l)') + execute('let l = [0, 1, 2, 3]') + execute('unlet l[-5:2]') + execute('$put =string(l)') + execute('let l = [0, 1, 2, 3]') + execute('unlet l[-6:2]') + execute('$put =string(l)') + expect([=[ + + [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]]=]) + end) + + it('assignment to a list', function() + source([[ + 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]]) + expect([[ + + 2 + 3 + Vim(let):E687: + Vim(let):E688: ]]) + end) + + it('manipulating a big dictionary', function() + -- Manipulating a big Dictionary (hashtable.c has a border of 1000 + -- entries). + source([[ + 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 + " Must be almost empty now. + $put =string(d)]]) + expect([[ + + 3000 2900 2001 1600 1501 + Vim(let):E716: 1500 + NONE 2999 + 33=999 + {'33': 999}]]) + end) + + it('dictionary function', function() + source([[ + 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]]) + expect([[ + + len: 3 + again: 3 + Vim(call):E725: ]]) + end) + + it('Function in script-local List or Dict', function() + source([[ + 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()]]) + expect('\ng:dict.func-4') + end) + + it("remove func from dict that's being called (works)", function() + source([[ + let d = {1:1} + func d.func(a) + return "a:". a:a + endfunc + $put =d.func(string(remove(d, 'func')))]]) + -- The function number changed from 3 to 1 because we split the test. + -- There were two other functions in the old test before this. + expect("\na:function('1')") + end) + + it('deepcopy() dict that refers to itself', function() + -- Nasty: deepcopy() dict that refers to itself (fails when noref used). + source([[ + 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])]]) + expect([[ + + Vim(let):E698: + same list: 1]]) + end) + + it('locked variables (part 1)', function() + source([=[ + let l = [] + 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]=]) + expect([[ + + 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]]) + end) + + -- TODO In the original test the 5th line of this source() call was used. + -- But now the test only passes if I comment it. + it('unletting locked variables', function() + source([=[ + let l = [] + 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]=]) + expect([[ + + 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]]) + end) + + it('locked variables and :unlet or list / dict functions', function() + source([[ + $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)]]) + + expect([=[ + + 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]]=]) + end) + + it('locked variables (part 2)', function() + execute( + '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)') + expect([=[ + + [1, 2, 3, 4] + [1, 2, 3, 4] + [1, 2, 3, 4] + [1, 2, 3, 4] + [1, 2, 3, 4]]=]) + end) + + it(':lockvar/islocked() triggering script autoloading.', function() + source([[ + set rtp+=test/functional/fixtures + 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]]) + expect([[ + + locked g:footest#x:-1 + exists g:footest#x:0 + g:footest#x: 1]]) + end) + + it('a:000 function argument', function() + source([[ + function Test(...) + " 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 + endfunction]]) + execute('call Test(1, 2, [3, 4], {5: 6})') + expect([=[ + + 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}]]=]) + end) + + it('reverse(), sort(), uniq()', function() + source([=[ + 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)))]=]) + expect([=[ + + ['-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, [], {}]]=]) + end) + + it('splitting a string to a list', function() + source([[ + $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))]]) + expect([=[ + + ['aa', 'bb'] + ['aa', 'bb'] + ['', 'aa', 'bb', ''] + ['', '', 'aa', '', 'bb', '', ''] + ['aa', '', 'bb'] + ['', 'aa', '', 'bb', ''] + ['aa', '', 'bb', 'cc', ''] + ['a', 'b', 'c'] + ['', 'a', '', 'b', '', 'c', '']]=]) + end) + + it('compare recursively linked list and dict', function() + source([[ + 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))]]) + expect([[ + + 1 + 1 + 0 + 0]]) + end) + + it('compare complex recursively linked list and dict', function() + source([[ + 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)]]) + expect([[ + + 1 + 1]]) + end) + + it('pass the same list to extend()', function() + source([[ + let l = [1, 2, 3, 4, 5] + call extend(l, l) + $put =string(l)]]) + expect([=[ + + [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]]=]) + end) + + it('pass the same dict to extend()', function() + source([[ + let d = { 'a': {'b': 'B'}} + call extend(d, d) + $put =string(d)]]) + expect([[ + + {'a': {'b': 'B'}}]]) + end) + + it('pass the same dict to extend() with "error"', function() + source([[ + " Copy dict from previous test. + let d = { 'a': {'b': 'B'}} + try + call extend(d, d, "error") + catch + $put =v:exception[:15] . v:exception[-1:-1] + endtry + $put =string(d)]]) + expect([[ + + Vim(call):E737: a + {'a': {'b': 'B'}}]]) + end) + + it('test for range assign', function() + source([[ + let l = [0] + let l[:] = [1, 2] + $put =string(l)]]) + expect([=[ + + [1, 2]]=]) + end) + + it('vim patch 7.3.637', function() + execute('let a = "No error caught"') + execute('try') + execute(' foldopen') + execute('catch') + execute(" let a = matchstr(v:exception,'^[^ ]*')") + execute('endtry') + feed('o<C-R>=a<CR><esc>') + execute('lang C') + execute('redir => a') + -- The test failes if this is not in one line. + execute("try|foobar|catch|let a = matchstr(v:exception,'^[^ ]*')|endtry") + execute('redir END') + feed('o<C-R>=a<CR><esc>') + expect([[ + + Vim(foldopen):E490: + + + Error detected while processing : + E492: Not an editor command: foobar|catch|let a = matchstr(v:exception,'^[^ ]*')|endtry + ]]) + end) +end) diff --git a/test/functional/legacy/056_script_local_function_spec.lua b/test/functional/legacy/056_script_local_function_spec.lua index dec88e8001..084817ad7a 100644 --- a/test/functional/legacy/056_script_local_function_spec.lua +++ b/test/functional/legacy/056_script_local_function_spec.lua @@ -1,7 +1,7 @@ -- vim: set foldmethod=marker foldmarker=[[,]] : -- Test for script-local function. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local expect = helpers.expect diff --git a/test/functional/legacy/057_sort_spec.lua b/test/functional/legacy/057_sort_spec.lua index 36062ded3a..6984ad0de2 100644 --- a/test/functional/legacy/057_sort_spec.lua +++ b/test/functional/legacy/057_sort_spec.lua @@ -1,6 +1,6 @@ -- Tests for :sort command. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local insert, execute, clear, expect, eq, eval, source = helpers.insert, helpers.execute, helpers.clear, helpers.expect, helpers.eq, helpers.eval, helpers.source diff --git a/test/functional/legacy/059_utf8_spell_checking_spec.lua b/test/functional/legacy/059_utf8_spell_checking_spec.lua index 63df387be3..c44ab44b3c 100644 --- a/test/functional/legacy/059_utf8_spell_checking_spec.lua +++ b/test/functional/legacy/059_utf8_spell_checking_spec.lua @@ -1,6 +1,6 @@ -- Tests for spell checking with 'encoding' set to "utf-8". -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert, source = helpers.feed, helpers.insert, helpers.source local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect local write_file, call = helpers.write_file, helpers.call diff --git a/test/functional/legacy/060_exists_and_has_functions_spec.lua b/test/functional/legacy/060_exists_and_has_functions_spec.lua index 7f44b35a4e..cbd857c524 100644 --- a/test/functional/legacy/060_exists_and_has_functions_spec.lua +++ b/test/functional/legacy/060_exists_and_has_functions_spec.lua @@ -1,6 +1,6 @@ -- Tests for the exists() and has() functions. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local source = helpers.source local clear, expect = helpers.clear, helpers.expect local write_file = helpers.write_file diff --git a/test/functional/legacy/061_undo_tree_spec.lua b/test/functional/legacy/061_undo_tree_spec.lua index 350a77b2c5..9bf69ccba1 100644 --- a/test/functional/legacy/061_undo_tree_spec.lua +++ b/test/functional/legacy/061_undo_tree_spec.lua @@ -1,9 +1,15 @@ -- Tests for undo tree and :earlier and :later. +local helpers = require('test.functional.helpers')(after_each) -local helpers = require('test.functional.helpers') -local expect, feed, source = helpers.expect, helpers.feed, helpers.source -local eval, clear, execute = helpers.eval, helpers.clear, helpers.execute -local write_file, command, eq = helpers.write_file, helpers.command, helpers.eq +local write_file = helpers.write_file +local execute = helpers.execute +local command = helpers.command +local source = helpers.source +local expect = helpers.expect +local clear = helpers.clear +local feed = helpers.feed +local eval = helpers.eval +local eq = helpers.eq local function expect_empty_buffer() -- The space will be removed by helpers.dedent but is needed because dedent diff --git a/test/functional/legacy/062_tab_pages_spec.lua b/test/functional/legacy/062_tab_pages_spec.lua index f1c8b8d58b..d5b10b160e 100644 --- a/test/functional/legacy/062_tab_pages_spec.lua +++ b/test/functional/legacy/062_tab_pages_spec.lua @@ -1,6 +1,6 @@ -- Tests for tab pages -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert, source, clear, execute, expect, eval, eq = helpers.feed, helpers.insert, helpers.source, helpers.clear, helpers.execute, helpers.expect, helpers.eval, helpers.eq diff --git a/test/functional/legacy/063_match_and_matchadd_spec.lua b/test/functional/legacy/063_match_and_matchadd_spec.lua index 23b4f4551b..298e0a31ea 100644 --- a/test/functional/legacy/063_match_and_matchadd_spec.lua +++ b/test/functional/legacy/063_match_and_matchadd_spec.lua @@ -1,6 +1,6 @@ -- Tests for adjusting window and contents -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local feed, insert = helpers.feed, helpers.insert local eval, clear, execute = helpers.eval, helpers.clear, helpers.execute diff --git a/test/functional/legacy/065_float_and_logic_operators_spec.lua b/test/functional/legacy/065_float_and_logic_operators_spec.lua index e78b230956..d12ea502f3 100644 --- a/test/functional/legacy/065_float_and_logic_operators_spec.lua +++ b/test/functional/legacy/065_float_and_logic_operators_spec.lua @@ -1,6 +1,6 @@ -- Test for floating point and logical operators. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local insert, source = helpers.insert, helpers.source local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/066_visual_block_tab_spec.lua b/test/functional/legacy/066_visual_block_tab_spec.lua index 82bb988c67..72fa7d881b 100644 --- a/test/functional/legacy/066_visual_block_tab_spec.lua +++ b/test/functional/legacy/066_visual_block_tab_spec.lua @@ -1,7 +1,7 @@ -- vim: set foldmethod=marker foldmarker=[[,]] : -- Test for visual block shift and tab characters. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/067_augroup_exists_spec.lua b/test/functional/legacy/067_augroup_exists_spec.lua index dc4c9c7eeb..8f6b881ed8 100644 --- a/test/functional/legacy/067_augroup_exists_spec.lua +++ b/test/functional/legacy/067_augroup_exists_spec.lua @@ -1,7 +1,7 @@ -- Test that groups and patterns are tested correctly when calling exists() for -- autocommands. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/068_text_formatting_spec.lua b/test/functional/legacy/068_text_formatting_spec.lua index cac8be77f3..e232e5073d 100644 --- a/test/functional/legacy/068_text_formatting_spec.lua +++ b/test/functional/legacy/068_text_formatting_spec.lua @@ -1,6 +1,10 @@ -local helpers = require('test.functional.helpers') -local feed, insert = helpers.feed, helpers.insert -local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect +local helpers = require('test.functional.helpers')(after_each) + +local feed = helpers.feed +local clear = helpers.clear +local insert = helpers.insert +local execute = helpers.execute +local expect = helpers.expect describe('text formatting', function() setup(clear) diff --git a/test/functional/legacy/072_undo_file_spec.lua b/test/functional/legacy/072_undo_file_spec.lua index efcc2f2cc3..4682a82008 100644 --- a/test/functional/legacy/072_undo_file_spec.lua +++ b/test/functional/legacy/072_undo_file_spec.lua @@ -2,7 +2,7 @@ -- Since this script is sourced we need to explicitly break changes up in -- undo-able pieces. Do that by setting 'undolevels'. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert = helpers.feed, helpers.insert local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/074_global_var_in_viminfo_spec.lua b/test/functional/legacy/074_global_var_in_viminfo_spec.lua index 49c4827613..2fc30c9d83 100644 --- a/test/functional/legacy/074_global_var_in_viminfo_spec.lua +++ b/test/functional/legacy/074_global_var_in_viminfo_spec.lua @@ -1,6 +1,7 @@ -- Tests for storing global variables in the .shada file -local helpers, lfs = require('test.functional.helpers'), require('lfs') +local helpers = require('test.functional.helpers')(after_each) +local lfs = require('lfs') local clear, execute, eq, neq, eval, wait, spawn = helpers.clear, helpers.execute, helpers.eq, helpers.neq, helpers.eval, helpers.wait, helpers.spawn diff --git a/test/functional/legacy/075_maparg_spec.lua b/test/functional/legacy/075_maparg_spec.lua index 82965f5cb2..e9d2acdaf5 100644 --- a/test/functional/legacy/075_maparg_spec.lua +++ b/test/functional/legacy/075_maparg_spec.lua @@ -1,7 +1,7 @@ -- Tests for maparg(). -- Also test utf8 map with a 0x80 byte. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed = helpers.clear, helpers.feed local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/076_completefunc_spec.lua b/test/functional/legacy/076_completefunc_spec.lua index 8af3be003e..bf3f56eb84 100644 --- a/test/functional/legacy/076_completefunc_spec.lua +++ b/test/functional/legacy/076_completefunc_spec.lua @@ -1,6 +1,6 @@ -- Tests for completefunc/omnifunc. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert, source = helpers.feed, helpers.insert, helpers.source local clear, expect, execute = helpers.clear, helpers.expect, helpers.execute diff --git a/test/functional/legacy/077_mf_hash_grow_spec.lua b/test/functional/legacy/077_mf_hash_grow_spec.lua index 029fe98fe9..b43263300d 100644 --- a/test/functional/legacy/077_mf_hash_grow_spec.lua +++ b/test/functional/legacy/077_mf_hash_grow_spec.lua @@ -6,7 +6,7 @@ -- cksum is part of POSIX and so should be available on most Unixes. -- If it isn't available then the test will be skipped. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed = helpers.feed local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/078_swapfile_recover_spec.lua b/test/functional/legacy/078_swapfile_recover_spec.lua index e48fddaac1..4390ba2ca8 100644 --- a/test/functional/legacy/078_swapfile_recover_spec.lua +++ b/test/functional/legacy/078_swapfile_recover_spec.lua @@ -3,7 +3,7 @@ -- restored. We need about 10000 lines of 100 characters to get two levels of -- pointer blocks. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, expect, source = helpers.clear, helpers.expect, helpers.source describe('78', function() diff --git a/test/functional/legacy/080_substitute_spec.lua b/test/functional/legacy/080_substitute_spec.lua index 96082364e0..1bdae9be59 100644 --- a/test/functional/legacy/080_substitute_spec.lua +++ b/test/functional/legacy/080_substitute_spec.lua @@ -2,7 +2,7 @@ -- Test for submatch() on substitue(). -- Test for *:s%* on :substitute. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert = helpers.feed, helpers.insert local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect local eq, eval = helpers.eq, helpers.eval diff --git a/test/functional/legacy/081_coptions_movement_spec.lua b/test/functional/legacy/081_coptions_movement_spec.lua index f27667b976..2ac1332687 100644 --- a/test/functional/legacy/081_coptions_movement_spec.lua +++ b/test/functional/legacy/081_coptions_movement_spec.lua @@ -1,6 +1,6 @@ -- Test for t movement command and 'cpo-;' setting -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/082_string_comparison_spec.lua b/test/functional/legacy/082_string_comparison_spec.lua index 933c6c8fa3..d6f3c45e1f 100644 --- a/test/functional/legacy/082_string_comparison_spec.lua +++ b/test/functional/legacy/082_string_comparison_spec.lua @@ -1,7 +1,7 @@ -- Tests for case-insensitive UTF-8 comparisons (utf_strnicmp() in mbyte.c) -- Also test "g~ap". -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, source = helpers.feed, helpers.source local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/083_tag_search_with_file_encoding_spec.lua b/test/functional/legacy/083_tag_search_with_file_encoding_spec.lua index 6b5ee60568..e94b46ca66 100644 --- a/test/functional/legacy/083_tag_search_with_file_encoding_spec.lua +++ b/test/functional/legacy/083_tag_search_with_file_encoding_spec.lua @@ -1,6 +1,6 @@ -- Tests for tag search with !_TAG_FILE_ENCODING. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local insert, source, clear, expect, write_file = helpers.insert, helpers.source, helpers.clear, helpers.expect, helpers.write_file diff --git a/test/functional/legacy/084_curswant_spec.lua b/test/functional/legacy/084_curswant_spec.lua index 946dd5e501..818914eeb9 100644 --- a/test/functional/legacy/084_curswant_spec.lua +++ b/test/functional/legacy/084_curswant_spec.lua @@ -1,6 +1,6 @@ -- Tests for curswant not changing when setting an option. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local insert, source = helpers.insert, helpers.source local clear, expect = helpers.clear, helpers.expect diff --git a/test/functional/legacy/088_conceal_tabs_spec.lua b/test/functional/legacy/088_conceal_tabs_spec.lua index c78f4e5c3e..00e7312bf8 100644 --- a/test/functional/legacy/088_conceal_tabs_spec.lua +++ b/test/functional/legacy/088_conceal_tabs_spec.lua @@ -1,7 +1,7 @@ -- Tests for correct display (cursor column position) with +conceal and -- tabulators. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert, clear, execute = helpers.feed, helpers.insert, helpers.clear, helpers.execute diff --git a/test/functional/legacy/089_number_relnumber_findfile_spec.lua b/test/functional/legacy/089_number_relnumber_findfile_spec.lua index f72ebf3f72..7a87fc8603 100644 --- a/test/functional/legacy/089_number_relnumber_findfile_spec.lua +++ b/test/functional/legacy/089_number_relnumber_findfile_spec.lua @@ -2,7 +2,7 @@ -- This is not all that useful now that the options are no longer reset when -- setting the other. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed = helpers.feed local clear, expect, source = helpers.clear, helpers.expect, helpers.source diff --git a/test/functional/legacy/090_sha256_spec.lua b/test/functional/legacy/090_sha256_spec.lua index 95e50063a1..e364af9400 100644 --- a/test/functional/legacy/090_sha256_spec.lua +++ b/test/functional/legacy/090_sha256_spec.lua @@ -1,6 +1,6 @@ -- Tests for sha256() function. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local insert, source = helpers.insert, helpers.source local clear, expect = helpers.clear, helpers.expect diff --git a/test/functional/legacy/091_context_variables_spec.lua b/test/functional/legacy/091_context_variables_spec.lua index 2c46ef643c..edf497d397 100644 --- a/test/functional/legacy/091_context_variables_spec.lua +++ b/test/functional/legacy/091_context_variables_spec.lua @@ -1,6 +1,6 @@ -- Tests for getbufvar(), getwinvar(), gettabvar() and gettabwinvar(). -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local insert, source = helpers.insert, helpers.source local clear, expect = helpers.clear, helpers.expect diff --git a/test/functional/legacy/092_mksession_cursor_cols_utf8_spec.lua b/test/functional/legacy/092_mksession_cursor_cols_utf8_spec.lua index f76ba25d7a..f8564384e9 100644 --- a/test/functional/legacy/092_mksession_cursor_cols_utf8_spec.lua +++ b/test/functional/legacy/092_mksession_cursor_cols_utf8_spec.lua @@ -3,7 +3,7 @@ -- -- Same as legacy test 93 but using UTF-8 file encoding. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert = helpers.feed, helpers.insert local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua b/test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua index bf3af1a827..719ce25099 100644 --- a/test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua +++ b/test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua @@ -3,7 +3,7 @@ -- -- Same as legacy test 92 but using Latin-1 file encoding. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert = helpers.feed, helpers.insert local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/094_visual_mode_operators_spec.lua b/test/functional/legacy/094_visual_mode_operators_spec.lua index 4dce39b8d2..a52fa00672 100644 --- a/test/functional/legacy/094_visual_mode_operators_spec.lua +++ b/test/functional/legacy/094_visual_mode_operators_spec.lua @@ -4,7 +4,7 @@ -- followed by an operator and those executed via Operator-pending mode. Also -- part of the test are mappings, counts, and repetition with the . command. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert, source = helpers.feed, helpers.insert, helpers.source local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/095_regexp_multibyte_spec.lua b/test/functional/legacy/095_regexp_multibyte_spec.lua index a80a247612..845ebaaad7 100644 --- a/test/functional/legacy/095_regexp_multibyte_spec.lua +++ b/test/functional/legacy/095_regexp_multibyte_spec.lua @@ -3,7 +3,7 @@ -- A pattern that gives the expected result produces OK, so that we know it was -- actually tried. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local insert, source = helpers.insert, helpers.source local clear, expect = helpers.clear, helpers.expect diff --git a/test/functional/legacy/096_location_list_spec.lua b/test/functional/legacy/096_location_list_spec.lua index 6e2f22ea33..eac8d6356d 100644 --- a/test/functional/legacy/096_location_list_spec.lua +++ b/test/functional/legacy/096_location_list_spec.lua @@ -6,7 +6,7 @@ -- C. make sure that the location list window is not reused instead of the window -- it belongs to. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local source = helpers.source local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/097_glob_path_spec.lua b/test/functional/legacy/097_glob_path_spec.lua index 5c467fbb20..a6c146891a 100644 --- a/test/functional/legacy/097_glob_path_spec.lua +++ b/test/functional/legacy/097_glob_path_spec.lua @@ -2,7 +2,7 @@ -- Test whether glob()/globpath() return correct results with certain escaped -- characters. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/098_scrollbind_spec.lua b/test/functional/legacy/098_scrollbind_spec.lua index 6850e373ab..d22aefdcbc 100644 --- a/test/functional/legacy/098_scrollbind_spec.lua +++ b/test/functional/legacy/098_scrollbind_spec.lua @@ -1,6 +1,6 @@ -- Test for 'scrollbind' causing an unexpected scroll of one of the windows. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local source = helpers.source local clear, expect = helpers.clear, helpers.expect diff --git a/test/functional/legacy/101_hlsearch_spec.lua b/test/functional/legacy/101_hlsearch_spec.lua index 335d275c2a..0d88e99278 100644 --- a/test/functional/legacy/101_hlsearch_spec.lua +++ b/test/functional/legacy/101_hlsearch_spec.lua @@ -1,6 +1,6 @@ -- Test for v:hlsearch -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed = helpers.clear, helpers.feed local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/102_fnameescape_spec.lua b/test/functional/legacy/102_fnameescape_spec.lua index a3b0313d7a..c1a6c57956 100644 --- a/test/functional/legacy/102_fnameescape_spec.lua +++ b/test/functional/legacy/102_fnameescape_spec.lua @@ -1,6 +1,6 @@ -- Test if fnameescape is correct for special chars like! -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/103_visual_mode_reset_spec.lua b/test/functional/legacy/103_visual_mode_reset_spec.lua index c1407ef10a..d05b47fa32 100644 --- a/test/functional/legacy/103_visual_mode_reset_spec.lua +++ b/test/functional/legacy/103_visual_mode_reset_spec.lua @@ -1,6 +1,6 @@ -- Test for visual mode not being reset causing E315 error. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, source = helpers.feed, helpers.source local clear, expect = helpers.clear, helpers.expect diff --git a/test/functional/legacy/104_let_assignment_spec.lua b/test/functional/legacy/104_let_assignment_spec.lua index a2431da835..27c3715231 100644 --- a/test/functional/legacy/104_let_assignment_spec.lua +++ b/test/functional/legacy/104_let_assignment_spec.lua @@ -1,6 +1,6 @@ -- Tests for :let. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, source = helpers.clear, helpers.source local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/106_errorformat_spec.lua b/test/functional/legacy/106_errorformat_spec.lua index 5958f1aa7b..2b17d63378 100644 --- a/test/functional/legacy/106_errorformat_spec.lua +++ b/test/functional/legacy/106_errorformat_spec.lua @@ -1,6 +1,6 @@ -- Tests for errorformat. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/107_adjust_window_and_contents_spec.lua b/test/functional/legacy/107_adjust_window_and_contents_spec.lua index 7a6de3d748..ce8d967e00 100644 --- a/test/functional/legacy/107_adjust_window_and_contents_spec.lua +++ b/test/functional/legacy/107_adjust_window_and_contents_spec.lua @@ -1,6 +1,6 @@ -- Tests for adjusting window and contents -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local insert = helpers.insert local clear, execute = helpers.clear, helpers.execute diff --git a/test/functional/legacy/108_backtrace_debug_commands_spec.lua b/test/functional/legacy/108_backtrace_debug_commands_spec.lua index 6df645d255..a03092e446 100644 --- a/test/functional/legacy/108_backtrace_debug_commands_spec.lua +++ b/test/functional/legacy/108_backtrace_debug_commands_spec.lua @@ -1,6 +1,6 @@ -- Tests for backtrace debug commands. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, clear = helpers.feed, helpers.clear local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/arglist_spec.lua b/test/functional/legacy/arglist_spec.lua new file mode 100644 index 0000000000..c128aaf115 --- /dev/null +++ b/test/functional/legacy/arglist_spec.lua @@ -0,0 +1,268 @@ +-- Test argument list commands + +local helpers = require('test.functional.helpers')(after_each) +local clear, execute, eq = helpers.clear, helpers.execute, helpers.eq +local eval, exc_exec, neq = helpers.eval, helpers.exc_exec, helpers.neq + +describe('argument list commands', function() + before_each(clear) + + local function init_abc() + execute('args a b c') + execute('next') + end + + local function reset_arglist() + execute('arga a | %argd') + end + + local function assert_fails(cmd, err) + neq(exc_exec(cmd):find(err), nil) + end + + it('test that argidx() works', function() + execute('args a b c') + execute('last') + eq(2, eval('argidx()')) + execute('%argdelete') + eq(0, eval('argidx()')) + + execute('args a b c') + eq(0, eval('argidx()')) + execute('next') + eq(1, eval('argidx()')) + execute('next') + eq(2, eval('argidx()')) + execute('1argdelete') + eq(1, eval('argidx()')) + execute('1argdelete') + eq(0, eval('argidx()')) + execute('1argdelete') + eq(0, eval('argidx()')) + end) + + it('test that argadd() works', function() + execute('%argdelete') + execute('argadd a b c') + eq(0, eval('argidx()')) + + execute('%argdelete') + execute('argadd a') + eq(0, eval('argidx()')) + execute('argadd b c d') + eq(0, eval('argidx()')) + + init_abc() + execute('argadd x') + eq({'a', 'b', 'x', 'c'}, eval('argv()')) + eq(1, eval('argidx()')) + + init_abc() + execute('0argadd x') + eq({'x', 'a', 'b', 'c'}, eval('argv()')) + eq(2, eval('argidx()')) + + init_abc() + execute('1argadd x') + eq({'a', 'x', 'b', 'c'}, eval('argv()')) + eq(2, eval('argidx()')) + + init_abc() + execute('$argadd x') + eq({'a', 'b', 'c', 'x'}, eval('argv()')) + eq(1, eval('argidx()')) + + init_abc() + execute('$argadd x') + execute('+2argadd y') + eq({'a', 'b', 'c', 'x', 'y'}, eval('argv()')) + eq(1, eval('argidx()')) + + execute('%argd') + execute('edit d') + execute('arga') + eq(1, eval('len(argv())')) + eq('d', eval('get(argv(), 0, "")')) + + execute('%argd') + execute('new') + execute('arga') + eq(0, eval('len(argv())')) + end) + + it('test for [count]argument and [count]argdelete commands', function() + reset_arglist() + execute('let save_hidden = &hidden') + execute('set hidden') + execute('let g:buffers = []') + execute('augroup TEST') + execute([[au BufEnter * call add(buffers, expand('%:t'))]]) + execute('augroup END') + + execute('argadd a b c d') + execute('$argu') + execute('$-argu') + execute('-argu') + execute('1argu') + execute('+2argu') + + execute('augroup TEST') + execute('au!') + execute('augroup END') + + eq({'d', 'c', 'b', 'a', 'c'}, eval('g:buffers')) + + execute('redir => result') + execute('ar') + execute('redir END') + eq(1, eval([[result =~# 'a b \[c] d']])) + + execute('.argd') + eq({'a', 'b', 'd'}, eval('argv()')) + + execute('-argd') + eq({'a', 'd'}, eval('argv()')) + + execute('$argd') + eq({'a'}, eval('argv()')) + + execute('1arga c') + execute('1arga b') + execute('$argu') + execute('$arga x') + eq({'a', 'b', 'c', 'x'}, eval('argv()')) + + execute('0arga Y') + eq({'Y', 'a', 'b', 'c', 'x'}, eval('argv()')) + + execute('%argd') + eq({}, eval('argv()')) + + execute('arga a b c d e f') + execute('2,$-argd') + eq({'a', 'f'}, eval('argv()')) + + execute('let &hidden = save_hidden') + + -- Setting the argument list should fail when the current buffer has + -- unsaved changes + execute('%argd') + execute('enew!') + execute('set modified') + assert_fails('args x y z', 'E37:') + execute('args! x y z') + eq({'x', 'y', 'z'}, eval('argv()')) + eq('x', eval('expand("%:t")')) + + execute('%argdelete') + assert_fails('argument', 'E163:') + end) + + it('test for 0argadd and 0argedit', function() + reset_arglist() + + execute('arga a b c d') + execute('2argu') + execute('0arga added') + eq({'added', 'a', 'b', 'c', 'd'}, eval('argv()')) + + execute('%argd') + execute('arga a b c d') + execute('2argu') + execute('0arge edited') + eq({'edited', 'a', 'b', 'c', 'd'}, eval('argv()')) + + execute('2argu') + execute('arga third') + eq({'edited', 'a', 'third', 'b', 'c', 'd'}, eval('argv()')) + end) + + it('test for argc()', function() + reset_arglist() + eq(0, eval('argc()')) + execute('argadd a b') + eq(2, eval('argc()')) + end) + + it('test for arglistid()', function() + reset_arglist() + execute('arga a b') + eq(0, eval('arglistid()')) + execute('split') + execute('arglocal') + eq(1, eval('arglistid()')) + execute('tabnew | tabfirst') + eq(0, eval('arglistid(2)')) + eq(1, eval('arglistid(1, 1)')) + eq(0, eval('arglistid(2, 1)')) + eq(1, eval('arglistid(1, 2)')) + execute('tabonly | only | enew!') + execute('argglobal') + eq(0, eval('arglistid()')) + end) + + it('test for argv()', function() + reset_arglist() + eq({}, eval('argv()')) + eq('', eval('argv(2)')) + execute('argadd a b c d') + eq('c', eval('argv(2)')) + end) + + it('test for :argedit command', function() + reset_arglist() + execute('argedit a') + eq({'a'}, eval('argv()')) + eq('a', eval('expand("%:t")')) + execute('argedit b') + eq({'a', 'b'}, eval('argv()')) + eq('b', eval('expand("%:t")')) + execute('argedit a') + eq({'a', 'b'}, eval('argv()')) + eq('a', eval('expand("%:t")')) + assert_fails('argedit a b', 'E172:') + execute('argedit c') + eq({'a', 'c', 'b'}, eval('argv()')) + execute('0argedit x') + eq({'x', 'a', 'c', 'b'}, eval('argv()')) + execute('enew! | set modified') + assert_fails('argedit y', 'E37:') + execute('argedit! y') + eq({'x', 'y', 'a', 'c', 'b'}, eval('argv()')) + execute('%argd') + end) + + it('test for :argdelete command', function() + reset_arglist() + execute('args aa a aaa b bb') + execute('argdelete a*') + eq({'b', 'bb'}, eval('argv()')) + eq('aa', eval('expand("%:t")')) + execute('last') + execute('argdelete %') + eq({'b'}, eval('argv()')) + assert_fails('argdelete', 'E471:') + assert_fails('1,100argdelete', 'E16:') + execute('%argd') + end) + + it('test for the :next, :prev, :first, :last, :rewind commands', function() + reset_arglist() + execute('args a b c d') + execute('last') + eq(3, eval('argidx()')) + assert_fails('next', 'E165:') + execute('prev') + eq(2, eval('argidx()')) + execute('Next') + eq(1, eval('argidx()')) + execute('first') + eq(0, eval('argidx()')) + assert_fails('prev', 'E164:') + execute('3next') + eq(3, eval('argidx()')) + execute('rewind') + eq(0, eval('argidx()')) + execute('%argd') + end) +end) diff --git a/test/functional/legacy/argument_0count_spec.lua b/test/functional/legacy/argument_0count_spec.lua deleted file mode 100644 index 6e8b60547b..0000000000 --- a/test/functional/legacy/argument_0count_spec.lua +++ /dev/null @@ -1,28 +0,0 @@ --- Tests for :0argadd and :0argedit - -local helpers = require('test.functional.helpers') -local eq, eval, clear, execute = - helpers.eq, helpers.eval, helpers.clear, helpers.execute - -describe('argument_0count', function() - setup(clear) - - it('is working', function() - execute('arga a b c d') - eq({'a', 'b', 'c', 'd'}, eval('argv()')) - execute('2argu') - execute('0arga added') - eq({'added', 'a', 'b', 'c', 'd'}, eval('argv()')) - execute('2argu') - execute('arga third') - eq({'added', 'a', 'third', 'b', 'c', 'd'}, eval('argv()')) - execute('%argd') - execute('arga a b c d') - execute('2argu') - execute('0arge edited') - eq({'edited', 'a', 'b', 'c', 'd'}, eval('argv()')) - execute('2argu') - execute('arga third') - eq({'edited', 'a', 'third', 'b', 'c', 'd'}, eval('argv()')) - end) -end) diff --git a/test/functional/legacy/argument_count_spec.lua b/test/functional/legacy/argument_count_spec.lua deleted file mode 100644 index 182cce9475..0000000000 --- a/test/functional/legacy/argument_count_spec.lua +++ /dev/null @@ -1,47 +0,0 @@ --- Tests for :[count]argument! and :[count]argdelete - -local helpers = require('test.functional.helpers') -local clear, execute, eq, eval = - helpers.clear, helpers.execute, helpers.eq, helpers.eval - -describe('argument_count', function() - setup(clear) - - it('is working', function() - execute('%argd') - execute('argadd a b c d') - eq({'a', 'b', 'c', 'd'}, eval('argv()')) - execute('set hidden') - execute('let buffers = []') - execute('augroup TEST') - execute([[au BufEnter * call add(buffers, expand('%:t'))]]) - execute('augroup END') - execute('$argu') - execute('$-argu') - execute('-argu') - execute('1argu') - execute('+2argu') - execute('augroup TEST') - execute('au!') - execute('augroup END') - eq({'d', 'c', 'b', 'a', 'c'}, eval('buffers')) - execute('.argd') - eq({'a', 'b', 'd'}, eval('argv()')) - execute('-argd') - eq({'a', 'd'}, eval('argv()')) - execute('$argd') - eq({'a'}, eval('argv()')) - execute('1arga c') - execute('1arga b') - execute('$argu') - execute('$arga x') - eq({'a', 'b', 'c', 'x'}, eval('argv()')) - execute('0arga Y') - eq({'Y', 'a', 'b', 'c', 'x'}, eval('argv()')) - execute('%argd') - eq({}, eval('argv()')) - execute('arga a b c d e f') - execute('2,$-argd') - eq({'a', 'f'}, eval('argv()')) - end) -end) diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua index 63699387c1..8da6ee45d7 100644 --- a/test/functional/legacy/assert_spec.lua +++ b/test/functional/legacy/assert_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local nvim, call = helpers.meths, helpers.call local clear, eq = helpers.clear, helpers.eq local source, execute = helpers.source, helpers.execute @@ -141,6 +141,18 @@ describe('assert function:', function() tmpname_two .. " line 1: 'file two'", }) end) + + it('is reset to a list by assert functions', function() + source([[ + let save_verrors = v:errors + let v:['errors'] = {'foo': 3} + call assert_equal('yes', 'no') + let verrors = v:errors + let v:errors = save_verrors + call assert_equal(type([]), type(verrors)) + ]]) + expected_empty() + end) end) -- assert_fails({cmd}, [, {error}]) @@ -160,4 +172,34 @@ describe('assert function:', function() expected_errors({'command did not fail: call empty("")'}) end) end) + + -- assert_exception({cmd}, [, {error}]) + describe('assert_exception()', function() + it('should assert thrown exceptions properly', function() + source([[ + try + nocommand + catch + call assert_exception('E492') + endtry + ]]) + expected_empty() + end) + + it('should work properly when nested', function() + source([[ + try + nocommand + catch + try + " illegal argument, get NULL for error + call assert_exception([]) + catch + call assert_exception('E730') + endtry + endtry + ]]) + expected_empty() + end) + end) end) diff --git a/test/functional/legacy/autocmd_option_spec.lua b/test/functional/legacy/autocmd_option_spec.lua index 6349371808..28037e17c5 100644 --- a/test/functional/legacy/autocmd_option_spec.lua +++ b/test/functional/legacy/autocmd_option_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local nvim = helpers.meths local clear, eq, neq = helpers.clear, helpers.eq, helpers.neq local curbuf, buf = helpers.curbuf, helpers.bufmeths diff --git a/test/functional/legacy/autoformat_join_spec.lua b/test/functional/legacy/autoformat_join_spec.lua index a99cabca24..4110d66f5b 100644 --- a/test/functional/legacy/autoformat_join_spec.lua +++ b/test/functional/legacy/autoformat_join_spec.lua @@ -1,7 +1,7 @@ -- vim: set foldmethod=marker foldmarker=[[,]] : -- Tests for setting the '[,'] marks when joining lines. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/backspace_opt_spec.lua b/test/functional/legacy/backspace_opt_spec.lua index b40019a410..90bc6f74f0 100644 --- a/test/functional/legacy/backspace_opt_spec.lua +++ b/test/functional/legacy/backspace_opt_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local call, clear = helpers.call, helpers.clear local source, eq, nvim = helpers.source, helpers.eq, helpers.meths diff --git a/test/functional/legacy/breakindent_spec.lua b/test/functional/legacy/breakindent_spec.lua index a12d4add10..2504fe8e51 100644 --- a/test/functional/legacy/breakindent_spec.lua +++ b/test/functional/legacy/breakindent_spec.lua @@ -1,6 +1,6 @@ -- Test for breakindent -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert = helpers.feed, helpers.insert local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/cdo_spec.lua b/test/functional/legacy/cdo_spec.lua index 4b313ede3f..5e46431cc1 100644 --- a/test/functional/legacy/cdo_spec.lua +++ b/test/functional/legacy/cdo_spec.lua @@ -1,6 +1,6 @@ -- Tests for the :cdo, :cfdo, :ldo and :lfdo commands -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local nvim, clear = helpers.meths, helpers.clear local call, feed = helpers.call, helpers.feed local source, eq = helpers.source, helpers.eq diff --git a/test/functional/legacy/changelist_spec.lua b/test/functional/legacy/changelist_spec.lua index 7c696369d4..c718da3736 100644 --- a/test/functional/legacy/changelist_spec.lua +++ b/test/functional/legacy/changelist_spec.lua @@ -1,7 +1,7 @@ -- Test changelist position after splitting window -- Set 'undolevels' to make changelist for sourced file -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/charsearch_spec.lua b/test/functional/legacy/charsearch_spec.lua index 4a83801cfc..ef3369728d 100644 --- a/test/functional/legacy/charsearch_spec.lua +++ b/test/functional/legacy/charsearch_spec.lua @@ -1,6 +1,6 @@ -- Test for character searches -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert = helpers.feed, helpers.insert local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/close_count_spec.lua b/test/functional/legacy/close_count_spec.lua index ee6b29c618..ad1812f22e 100644 --- a/test/functional/legacy/close_count_spec.lua +++ b/test/functional/legacy/close_count_spec.lua @@ -1,6 +1,6 @@ -- Tests for :[count]close! and :[count]hide -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, eval, eq, clear, execute = helpers.feed, helpers.eval, helpers.eq, helpers.clear, helpers.execute diff --git a/test/functional/legacy/command_count_spec.lua b/test/functional/legacy/command_count_spec.lua index d9b4f09263..c463ada968 100644 --- a/test/functional/legacy/command_count_spec.lua +++ b/test/functional/legacy/command_count_spec.lua @@ -1,25 +1,20 @@ -- Test for user command counts -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, source, expect = helpers.clear, helpers.source, helpers.expect -local execute, spawn = helpers.execute, helpers.spawn -local nvim_prog = helpers.nvim_prog +local execute = helpers.execute describe('command_count', function() - setup(clear) - teardown(function() - os.remove('test.out') - end) - it('is working', function() -- It is relevant for the test to load a file initially. If this is -- emulated with :arg the buffer count is wrong as nvim creates an empty -- buffer if it was started without a filename. - local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', - 'test_command_count.in'}) - helpers.set_session(nvim2) + clear('test_command_count.in') source([[ + let g:tmpname = tempname() + call mkdir(g:tmpname) + execute "cd ".g:tmpname lang C let g:lines = [] com -range=% RangeLines @@ -239,5 +234,10 @@ describe('command_count', function() bufdo: 2 3 4 5 6 7 8 9 10 15 bufdo: 4 5 6 7 tabdo: 2 3 4]]) + + source([[ + cd .. + call delete(g:tmpname, 'rf') + ]]) end) end) diff --git a/test/functional/legacy/comparators_spec.lua b/test/functional/legacy/comparators_spec.lua index e3fa3eea23..27879b0f65 100644 --- a/test/functional/legacy/comparators_spec.lua +++ b/test/functional/legacy/comparators_spec.lua @@ -1,6 +1,6 @@ -- " Test for expression comparators. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, eq = helpers.clear, helpers.eq local eval, execute = helpers.eval, helpers.execute diff --git a/test/functional/legacy/delete_spec.lua b/test/functional/legacy/delete_spec.lua index cd18a8f750..42238b3a9e 100644 --- a/test/functional/legacy/delete_spec.lua +++ b/test/functional/legacy/delete_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, source = helpers.clear, helpers.source local eq, eval, execute = helpers.eq, helpers.eval, helpers.execute diff --git a/test/functional/legacy/erasebackword_spec.lua b/test/functional/legacy/erasebackword_spec.lua index cb3967b763..33b7704b65 100644 --- a/test/functional/legacy/erasebackword_spec.lua +++ b/test/functional/legacy/erasebackword_spec.lua @@ -1,6 +1,6 @@ -- Test for CTRL-W in Insert mode -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, expect = helpers.clear, helpers.feed, helpers.expect describe('CTRL-W in Insert mode', function() diff --git a/test/functional/legacy/eval_spec.lua b/test/functional/legacy/eval_spec.lua index 3ff1092a4b..3684fe714d 100644 --- a/test/functional/legacy/eval_spec.lua +++ b/test/functional/legacy/eval_spec.lua @@ -1,15 +1,10 @@ -- Test for various eval features. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert, source = helpers.feed, helpers.insert, helpers.source local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect local eq, eval, write_file = helpers.eq, helpers.eval, helpers.write_file -local function has_clipboard() - clear() - return 1 == eval("has('clipboard')") -end - describe('eval', function() setup(function() write_file('test_eval_setup.vim', [[ @@ -539,8 +534,13 @@ describe('eval', function() =: type v; value: abc/]].."\000 (['abc/\000"..[[']), expr: "abc/]]..'\000'..[[" (['"abc/]]..'\000'..[["'])]]) end) - if has_clipboard() then - it('system clipboard', function() + describe('system clipboard', function() + before_each(function() + execute('let &runtimepath = "test/functional/fixtures,".&runtimepath') + execute('call getreg("*")') -- force load of provider + end) + + it('works', function() insert([[ Some first line (this text was at the top of the old test_eval.in). @@ -570,9 +570,7 @@ describe('eval', function() *: type V; value: clipboard contents]]..'\00'..[[ (['clipboard contents']), expr: clipboard contents]]..'\00'..[[ (['clipboard contents']) *: type V; value: something else]]..'\00'..[[ (['something else']), expr: something else]]..'\00'..[[ (['something else'])]]) end) - else - pending('system clipboard not available', function() end) - end + end) it('errors', function() source([[ diff --git a/test/functional/legacy/expand_spec.lua b/test/functional/legacy/expand_spec.lua new file mode 100644 index 0000000000..7bf6fb67dc --- /dev/null +++ b/test/functional/legacy/expand_spec.lua @@ -0,0 +1,77 @@ +-- Test for expanding file names + +local helpers = require('test.functional.helpers')(after_each) +local eq = helpers.eq +local call = helpers.call +local nvim = helpers.meths +local clear = helpers.clear +local source = helpers.source + +local function expected_empty() + eq({}, nvim.get_vvar('errors')) +end + +describe('expand file name', function() + after_each(function() + helpers.rmdir('Xdir1') + helpers.rmdir('Xdir2') + helpers.rmdir('Xdir3') + helpers.rmdir('Xdir4') + end) + + before_each(function() + clear() + + source([[ + func Test_with_directories() + call mkdir('Xdir1') + call mkdir('Xdir2') + call mkdir('Xdir3') + cd Xdir3 + call mkdir('Xdir4') + cd .. + + split Xdir1/file + call setline(1, ['a', 'b']) + w + w Xdir3/Xdir4/file + close + + next Xdir?/*/file + call assert_equal('Xdir3/Xdir4/file', expand('%')) + if has('unix') + next! Xdir?/*/nofile + call assert_equal('Xdir?/*/nofile', expand('%')) + endif + " Edit another file, on MS-Windows the swap file would be in use and can't + " be deleted + edit foo + + call assert_equal(0, delete('Xdir1', 'rf')) + call assert_equal(0, delete('Xdir2', 'rf')) + call assert_equal(0, delete('Xdir3', 'rf')) + endfunc + + func Test_with_tilde() + let dir = getcwd() + call mkdir('Xdir ~ dir') + call assert_true(isdirectory('Xdir ~ dir')) + cd Xdir\ ~\ dir + call assert_true(getcwd() =~ 'Xdir \~ dir') + exe 'cd ' . fnameescape(dir) + call delete('Xdir ~ dir', 'd') + call assert_false(isdirectory('Xdir ~ dir')) + endfunc + ]]) + end) + + it('works with directories', function() + call('Test_with_directories') + expected_empty() + end) + + it('works with tilde', function() + call('Test_with_tilde') + expected_empty() + end) +end) diff --git a/test/functional/legacy/file_perm_spec.lua b/test/functional/legacy/file_perm_spec.lua index cabeecdc9c..98bdf630dd 100644 --- a/test/functional/legacy/file_perm_spec.lua +++ b/test/functional/legacy/file_perm_spec.lua @@ -1,7 +1,7 @@ -- Test getting and setting file permissions. require('os') -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, call, eq = helpers.clear, helpers.call, helpers.eq local neq, exc_exec = helpers.neq, helpers.exc_exec diff --git a/test/functional/legacy/fixeol_spec.lua b/test/functional/legacy/fixeol_spec.lua index 2d1824c8cd..bba1415535 100644 --- a/test/functional/legacy/fixeol_spec.lua +++ b/test/functional/legacy/fixeol_spec.lua @@ -1,6 +1,6 @@ -- Tests for 'fixeol' -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed = helpers.feed local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/fnamemodify_spec.lua b/test/functional/legacy/fnamemodify_spec.lua index 2a32aea127..f614b07b36 100644 --- a/test/functional/legacy/fnamemodify_spec.lua +++ b/test/functional/legacy/fnamemodify_spec.lua @@ -1,6 +1,6 @@ -- Test filename modifiers. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, source = helpers.clear, helpers.source local call, eq, nvim = helpers.call, helpers.eq, helpers.meths diff --git a/test/functional/legacy/function_sort_spec.lua b/test/functional/legacy/function_sort_spec.lua index 9083911021..1b65f1ce95 100644 --- a/test/functional/legacy/function_sort_spec.lua +++ b/test/functional/legacy/function_sort_spec.lua @@ -1,7 +1,10 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local eq = helpers.eq local eval = helpers.eval +local execute = helpers.execute +local exc_exec = helpers.exc_exec +local neq = helpers.neq describe('sort', function() before_each(clear) @@ -26,4 +29,25 @@ describe('sort', function() it('numbers compared as float', function() eq({0.28, 3, 13.5}, eval("sort([13.5, 0.28, 3], 'f')")) end) + + it('ability to call sort() from a compare function', function() + execute('func Compare1(a, b) abort') + execute([[call sort(range(3), 'Compare2')]]) + execute('return a:a - a:b') + execute('endfunc') + + execute('func Compare2(a, b) abort') + execute('return a:a - a:b') + execute('endfunc') + eq({1, 3, 5}, eval("sort([3, 1, 5], 'Compare1')")) + end) + + it('default sort', function() + -- docs say omitted, empty or zero argument sorts on string representation + eq({'2', 'A', 'AA', 'a', 1, 3.3}, eval('sort([3.3, 1, "2", "A", "a", "AA"])')) + eq({'2', 'A', 'AA', 'a', 1, 3.3}, eval([[sort([3.3, 1, "2", "A", "a", "AA"], '')]])) + eq({'2', 'A', 'AA', 'a', 1, 3.3}, eval('sort([3.3, 1, "2", "A", "a", "AA"], 0)')) + eq({'2', 'A', 'a', 'AA', 1, 3.3}, eval('sort([3.3, 1, "2", "A", "a", "AA"], 1)')) + neq(exc_exec('call sort([3.3, 1, "2"], 3)'):find('E474:'), nil) + end) end) diff --git a/test/functional/legacy/getcwd_spec.lua b/test/functional/legacy/getcwd_spec.lua new file mode 100644 index 0000000000..3bb9930b74 --- /dev/null +++ b/test/functional/legacy/getcwd_spec.lua @@ -0,0 +1,86 @@ +-- Tests for getcwd(), haslocaldir(), and :lcd + +local helpers = require('test.functional.helpers')(after_each) +local eq, eval, source = helpers.eq, helpers.eval, helpers.source +local call, clear, execute = helpers.call, helpers.clear, helpers.execute + +describe('getcwd', function() + before_each(clear) + + after_each(function() + helpers.rmdir('Xtopdir') + end) + + it('is working', function() + source([[ + function! GetCwdInfo(win, tab) + let tab_changed = 0 + let mod = ":t" + if a:tab > 0 && a:tab != tabpagenr() + let tab_changed = 1 + exec "tabnext " . a:tab + endif + let bufname = fnamemodify(bufname(winbufnr(a:win)), mod) + if tab_changed + tabprevious + endif + if a:win == 0 && a:tab == 0 + let dirname = fnamemodify(getcwd(), mod) + let lflag = haslocaldir() + elseif a:tab == 0 + let dirname = fnamemodify(getcwd(a:win), mod) + let lflag = haslocaldir(a:win) + else + let dirname = fnamemodify(getcwd(a:win, a:tab), mod) + let lflag = haslocaldir(a:win, a:tab) + endif + return bufname . ' ' . dirname . ' ' . lflag + endfunction + ]]) + execute('new') + execute('let cwd=getcwd()') + call('mkdir', 'Xtopdir') + execute('silent cd Xtopdir') + call('mkdir', 'Xdir1') + call('mkdir', 'Xdir2') + call('mkdir', 'Xdir3') + execute('new a') + execute('new b') + execute('new c') + execute('3wincmd w') + execute('silent lcd Xdir1') + eq('a Xdir1 1', eval('GetCwdInfo(0, 0)')) + execute('wincmd W') + eq('b Xtopdir 0', eval('GetCwdInfo(0, 0)')) + execute('wincmd W') + execute('silent lcd Xdir3') + eq('c Xdir3 1', eval('GetCwdInfo(0, 0)')) + eq('a Xdir1 1', eval('GetCwdInfo(bufwinnr("a"), 0)')) + eq('b Xtopdir 0', eval('GetCwdInfo(bufwinnr("b"), 0)')) + eq('c Xdir3 1', eval('GetCwdInfo(bufwinnr("c"), 0)')) + execute('wincmd W') + eq('a Xdir1 1', eval('GetCwdInfo(bufwinnr("a"), tabpagenr())')) + eq('b Xtopdir 0', eval('GetCwdInfo(bufwinnr("b"), tabpagenr())')) + eq('c Xdir3 1', eval('GetCwdInfo(bufwinnr("c"), tabpagenr())')) + + execute('tabnew x') + execute('new y') + execute('new z') + execute('3wincmd w') + eq('x Xtopdir 0', eval('GetCwdInfo(0, 0)')) + execute('wincmd W') + execute('silent lcd Xdir2') + eq('y Xdir2 1', eval('GetCwdInfo(0, 0)')) + execute('wincmd W') + execute('silent lcd Xdir3') + eq('z Xdir3 1', eval('GetCwdInfo(0, 0)')) + eq('x Xtopdir 0', eval('GetCwdInfo(bufwinnr("x"), 0)')) + eq('y Xdir2 1', eval('GetCwdInfo(bufwinnr("y"), 0)')) + eq('z Xdir3 1', eval('GetCwdInfo(bufwinnr("z"), 0)')) + execute('let tp_nr = tabpagenr()') + execute('tabrewind') + eq('x Xtopdir 0', eval('GetCwdInfo(3, tp_nr)')) + eq('y Xdir2 1', eval('GetCwdInfo(2, tp_nr)')) + eq('z Xdir3 1', eval('GetCwdInfo(1, tp_nr)')) + end) +end) diff --git a/test/functional/legacy/glob2regpat_spec.lua b/test/functional/legacy/glob2regpat_spec.lua index 0492143616..82e7e3010f 100644 --- a/test/functional/legacy/glob2regpat_spec.lua +++ b/test/functional/legacy/glob2regpat_spec.lua @@ -1,6 +1,6 @@ -- Tests for signs -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, execute = helpers.clear, helpers.execute local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval diff --git a/test/functional/legacy/increment_spec.lua b/test/functional/legacy/increment_spec.lua index 4aa24c0d53..0483edc934 100644 --- a/test/functional/legacy/increment_spec.lua +++ b/test/functional/legacy/increment_spec.lua @@ -1,6 +1,6 @@ -- Tests for using Ctrl-A/Ctrl-X on visual selections -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local source, execute = helpers.source, helpers.execute local call, clear = helpers.call, helpers.clear local eq, nvim = helpers.eq, helpers.meths diff --git a/test/functional/legacy/insertcount_spec.lua b/test/functional/legacy/insertcount_spec.lua index 01236e1afe..3142f040b3 100644 --- a/test/functional/legacy/insertcount_spec.lua +++ b/test/functional/legacy/insertcount_spec.lua @@ -1,6 +1,6 @@ -- Tests for repeating insert and replace. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect diff --git a/test/functional/legacy/join_spec.lua b/test/functional/legacy/join_spec.lua index 17ff2e71ad..3c4da8119c 100644 --- a/test/functional/legacy/join_spec.lua +++ b/test/functional/legacy/join_spec.lua @@ -1,6 +1,6 @@ -- Test for joining lines -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, eq = helpers.clear, helpers.eq local eval, execute = helpers.eval, helpers.execute diff --git a/test/functional/legacy/lispwords_spec.lua b/test/functional/legacy/lispwords_spec.lua index 48df4de55e..2ec51dca1b 100644 --- a/test/functional/legacy/lispwords_spec.lua +++ b/test/functional/legacy/lispwords_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local eq = helpers.eq local eval = helpers.eval diff --git a/test/functional/legacy/listchars_spec.lua b/test/functional/legacy/listchars_spec.lua index 89ed90178b..d2838cddb6 100644 --- a/test/functional/legacy/listchars_spec.lua +++ b/test/functional/legacy/listchars_spec.lua @@ -1,6 +1,6 @@ -- Tests for 'listchars' display with 'list' and :list. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert, source = helpers.feed, helpers.insert, helpers.source local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/listlbr_spec.lua b/test/functional/legacy/listlbr_spec.lua index 6601a922ef..eb979edc69 100644 --- a/test/functional/legacy/listlbr_spec.lua +++ b/test/functional/legacy/listlbr_spec.lua @@ -1,6 +1,6 @@ -- Test for linebreak and list option (non-utf8) -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert, source = helpers.feed, helpers.insert, helpers.source local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/listlbr_utf8_spec.lua b/test/functional/legacy/listlbr_utf8_spec.lua index df0e817533..f06bca72ba 100644 --- a/test/functional/legacy/listlbr_utf8_spec.lua +++ b/test/functional/legacy/listlbr_utf8_spec.lua @@ -1,6 +1,6 @@ -- Test for linebreak and list option in utf-8 mode -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local source = helpers.source local feed = helpers.feed local clear, expect = helpers.clear, helpers.expect diff --git a/test/functional/legacy/mapping_spec.lua b/test/functional/legacy/mapping_spec.lua index a0d19926cb..1712219d04 100644 --- a/test/functional/legacy/mapping_spec.lua +++ b/test/functional/legacy/mapping_spec.lua @@ -1,6 +1,6 @@ -- Test for mappings and abbreviations -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect, wait = helpers.execute, helpers.expect, helpers.wait diff --git a/test/functional/legacy/marks_spec.lua b/test/functional/legacy/marks_spec.lua index 8e9ceb1653..6ecba70f08 100644 --- a/test/functional/legacy/marks_spec.lua +++ b/test/functional/legacy/marks_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert, source = helpers.feed, helpers.insert, helpers.source local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/match_conceal_spec.lua b/test/functional/legacy/match_conceal_spec.lua index 0ffa3cae7a..d95b07d695 100644 --- a/test/functional/legacy/match_conceal_spec.lua +++ b/test/functional/legacy/match_conceal_spec.lua @@ -1,6 +1,6 @@ -- Test for matchadd() and conceal feature -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local expect = helpers.expect local source = helpers.source diff --git a/test/functional/legacy/nested_function_spec.lua b/test/functional/legacy/nested_function_spec.lua index fac3b03191..be9b66ee38 100644 --- a/test/functional/legacy/nested_function_spec.lua +++ b/test/functional/legacy/nested_function_spec.lua @@ -1,6 +1,6 @@ -- Tests for nested function. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, insert = helpers.clear, helpers.insert local execute, expect, source = helpers.execute, helpers.expect, helpers.source diff --git a/test/functional/legacy/options_spec.lua b/test/functional/legacy/options_spec.lua index 21e99c4aa1..4f4d4ceaf9 100644 --- a/test/functional/legacy/options_spec.lua +++ b/test/functional/legacy/options_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local command, clear = helpers.command, helpers.clear local source, expect = helpers.source, helpers.expect diff --git a/test/functional/legacy/packadd_spec.lua b/test/functional/legacy/packadd_spec.lua new file mode 100644 index 0000000000..b2ed39f288 --- /dev/null +++ b/test/functional/legacy/packadd_spec.lua @@ -0,0 +1,350 @@ +-- Tests for 'packpath' and :packadd + +local helpers = require('test.functional.helpers')(after_each) +local clear, source, execute = helpers.clear, helpers.source, helpers.execute +local call, eq, nvim = helpers.call, helpers.eq, helpers.meths +local feed = helpers.feed + +local function expected_empty() + eq({}, nvim.get_vvar('errors')) +end + +describe('packadd', function() + before_each(function() + clear() + + source([=[ + func SetUp() + let s:topdir = expand('%:p:h') . '/Xdir' + exe 'set packpath=' . s:topdir + let s:plugdir = s:topdir . '/pack/mine/opt/mytest' + endfunc + + func TearDown() + call delete(s:topdir, 'rf') + endfunc + + func Test_packadd() + call mkdir(s:plugdir . '/plugin', 'p') + call mkdir(s:plugdir . '/ftdetect', 'p') + call mkdir(s:plugdir . '/after', 'p') + set rtp& + let rtp = &rtp + filetype on + + exe 'split ' . s:plugdir . '/plugin/test.vim' + call setline(1, 'let g:plugin_works = 42') + wq + + exe 'split ' . s:plugdir . '/ftdetect/test.vim' + call setline(1, 'let g:ftdetect_works = 17') + wq + + packadd mytest + + call assert_true(42, g:plugin_works) + call assert_true(17, g:ftdetect_works) + call assert_true(len(&rtp) > len(rtp)) + call assert_true(&rtp =~ (s:plugdir . '\($\|,\)')) + call assert_true(&rtp =~ (s:plugdir . '/after$')) + + " Check exception + call assert_fails("packadd directorynotfound", 'E919:') + call assert_fails("packadd", 'E471:') + endfunc + + func Test_packadd_noload() + call mkdir(s:plugdir . '/plugin', 'p') + call mkdir(s:plugdir . '/syntax', 'p') + set rtp& + let rtp = &rtp + + exe 'split ' . s:plugdir . '/plugin/test.vim' + call setline(1, 'let g:plugin_works = 42') + wq + let g:plugin_works = 0 + + packadd! mytest + + call assert_true(len(&rtp) > len(rtp)) + call assert_true(&rtp =~ (s:plugdir . '\($\|,\)')) + call assert_equal(0, g:plugin_works) + + " check the path is not added twice + let new_rtp = &rtp + packadd! mytest + call assert_equal(new_rtp, &rtp) + endfunc + + func Test_packloadall() + " plugin foo with an autoload directory + let fooplugindir = &packpath . '/pack/mine/start/foo/plugin' + call mkdir(fooplugindir, 'p') + call writefile(['let g:plugin_foo_number = 1234', + \ 'let g:plugin_foo_auto = bbb#value', + \ 'let g:plugin_extra_auto = extra#value'], fooplugindir . '/bar.vim') + let fooautodir = &packpath . '/pack/mine/start/foo/autoload' + call mkdir(fooautodir, 'p') + call writefile(['let bar#value = 77'], fooautodir . '/bar.vim') + + " plugin aaa with an autoload directory + let aaaplugindir = &packpath . '/pack/mine/start/aaa/plugin' + call mkdir(aaaplugindir, 'p') + call writefile(['let g:plugin_aaa_number = 333', + \ 'let g:plugin_aaa_auto = bar#value'], aaaplugindir . '/bbb.vim') + let aaaautodir = &packpath . '/pack/mine/start/aaa/autoload' + call mkdir(aaaautodir, 'p') + call writefile(['let bbb#value = 55'], aaaautodir . '/bbb.vim') + + " plugin extra with only an autoload directory + let extraautodir = &packpath . '/pack/mine/start/extra/autoload' + call mkdir(extraautodir, 'p') + call writefile(['let extra#value = 99'], extraautodir . '/extra.vim') + + packloadall + call assert_equal(1234, g:plugin_foo_number) + call assert_equal(55, g:plugin_foo_auto) + call assert_equal(99, g:plugin_extra_auto) + call assert_equal(333, g:plugin_aaa_number) + call assert_equal(77, g:plugin_aaa_auto) + + " only works once + call writefile(['let g:plugin_bar_number = 4321'], + \ fooplugindir . '/bar2.vim') + packloadall + call assert_false(exists('g:plugin_bar_number')) + + " works when ! used + packloadall! + call assert_equal(4321, g:plugin_bar_number) + endfunc + + func Test_helptags() + let docdir1 = &packpath . '/pack/mine/start/foo/doc' + let docdir2 = &packpath . '/pack/mine/start/bar/doc' + call mkdir(docdir1, 'p') + call mkdir(docdir2, 'p') + call writefile(['look here: *look-here*'], docdir1 . '/bar.txt') + call writefile(['look away: *look-away*'], docdir2 . '/foo.txt') + exe 'set rtp=' . &packpath . '/pack/mine/start/foo,' . &packpath . '/pack/mine/start/bar' + + helptags ALL + + let tags1 = readfile(docdir1 . '/tags') + call assert_true(tags1[0] =~ 'look-here') + let tags2 = readfile(docdir2 . '/tags') + call assert_true(tags2[0] =~ 'look-away') + endfunc + + func Test_colorscheme() + let colordirrun = &packpath . '/runtime/colors' + let colordirstart = &packpath . '/pack/mine/start/foo/colors' + let colordiropt = &packpath . '/pack/mine/opt/bar/colors' + call mkdir(colordirrun, 'p') + call mkdir(colordirstart, 'p') + call mkdir(colordiropt, 'p') + call writefile(['let g:found_one = 1'], colordirrun . '/one.vim') + call writefile(['let g:found_two = 1'], colordirstart . '/two.vim') + call writefile(['let g:found_three = 1'], colordiropt . '/three.vim') + exe 'set rtp=' . &packpath . '/runtime' + + colorscheme one + call assert_equal(1, g:found_one) + colorscheme two + call assert_equal(1, g:found_two) + colorscheme three + call assert_equal(1, g:found_three) + endfunc + + func Test_runtime() + let rundir = &packpath . '/runtime/extra' + let startdir = &packpath . '/pack/mine/start/foo/extra' + let optdir = &packpath . '/pack/mine/opt/bar/extra' + call mkdir(rundir, 'p') + call mkdir(startdir, 'p') + call mkdir(optdir, 'p') + call writefile(['let g:sequence .= "run"'], rundir . '/bar.vim') + call writefile(['let g:sequence .= "start"'], startdir . '/bar.vim') + call writefile(['let g:sequence .= "foostart"'], startdir . '/foo.vim') + call writefile(['let g:sequence .= "opt"'], optdir . '/bar.vim') + call writefile(['let g:sequence .= "xxxopt"'], optdir . '/xxx.vim') + exe 'set rtp=' . &packpath . '/runtime' + + let g:sequence = '' + runtime extra/bar.vim + call assert_equal('run', g:sequence) + let g:sequence = '' + runtime START extra/bar.vim + call assert_equal('start', g:sequence) + let g:sequence = '' + runtime OPT extra/bar.vim + call assert_equal('opt', g:sequence) + let g:sequence = '' + runtime PACK extra/bar.vim + call assert_equal('start', g:sequence) + let g:sequence = '' + runtime! PACK extra/bar.vim + call assert_equal('startopt', g:sequence) + let g:sequence = '' + runtime PACK extra/xxx.vim + call assert_equal('xxxopt', g:sequence) + + let g:sequence = '' + runtime ALL extra/bar.vim + call assert_equal('run', g:sequence) + let g:sequence = '' + runtime ALL extra/foo.vim + call assert_equal('foostart', g:sequence) + let g:sequence = '' + runtime! ALL extra/xxx.vim + call assert_equal('xxxopt', g:sequence) + let g:sequence = '' + runtime! ALL extra/bar.vim + call assert_equal('runstartopt', g:sequence) + endfunc + ]=]) + call('SetUp') + end) + + after_each(function() + call('TearDown') + end) + + it('is working', function() + call('Test_packadd') + expected_empty() + end) + + it('works with packadd!', function() + call('Test_packadd_noload') + expected_empty() + end) + + it('works with :packloadall', function() + call('Test_packloadall') + expected_empty() + end) + + it('works with helptags', function() + call('Test_helptags') + expected_empty() + end) + + it('works with colorschemes', function() + call('Test_colorscheme') + expected_empty() + end) + + it('works with :runtime [what]', function() + call('Test_runtime') + expected_empty() + end) + + describe('command line completion', function() + local Screen = require('test.functional.ui.screen') + local screen + + before_each(function() + screen = Screen.new(30, 5) + screen:attach() + screen:set_default_attr_ids({ + [1] = { + foreground = Screen.colors.Black, + background = Screen.colors.Yellow, + }, + [2] = {bold = true, reverse = true} + }) + local NonText = Screen.colors.Blue + screen:set_default_attr_ignore({{}, {bold=true, foreground=NonText}}) + + execute([[let optdir1 = &packpath . '/pack/mine/opt']]) + execute([[let optdir2 = &packpath . '/pack/candidate/opt']]) + execute([[call mkdir(optdir1 . '/pluginA', 'p')]]) + execute([[call mkdir(optdir1 . '/pluginC', 'p')]]) + execute([[call mkdir(optdir2 . '/pluginB', 'p')]]) + execute([[call mkdir(optdir2 . '/pluginC', 'p')]]) + end) + + it('works', function() + feed(':packadd <Tab>') + screen:expect([=[ + | + ~ | + ~ | + {1:pluginA}{2: pluginB pluginC }| + :packadd pluginA^ | + ]=]) + feed('<Tab>') + screen:expect([=[ + | + ~ | + ~ | + {2:pluginA }{1:pluginB}{2: pluginC }| + :packadd pluginB^ | + ]=]) + feed('<Tab>') + screen:expect([=[ + | + ~ | + ~ | + {2:pluginA pluginB }{1:pluginC}{2: }| + :packadd pluginC^ | + ]=]) + feed('<Tab>') + screen:expect([=[ + | + ~ | + ~ | + {2:pluginA pluginB pluginC }| + :packadd ^ | + ]=]) + end) + + it('works for colorschemes', function() + source([[ + let colordirrun = &packpath . '/runtime/colors' + let colordirstart = &packpath . '/pack/mine/start/foo/colors' + let colordiropt = &packpath . '/pack/mine/opt/bar/colors' + call mkdir(colordirrun, 'p') + call mkdir(colordirstart, 'p') + call mkdir(colordiropt, 'p') + call writefile(['let g:found_one = 1'], colordirrun . '/one.vim') + call writefile(['let g:found_two = 1'], colordirstart . '/two.vim') + call writefile(['let g:found_three = 1'], colordiropt . '/three.vim') + exe 'set rtp=' . &packpath . '/runtime']]) + + feed(':colorscheme <Tab>') + screen:expect([=[ + | + ~ | + ~ | + {1:one}{2: three two }| + :colorscheme one^ | + ]=]) + feed('<Tab>') + screen:expect([=[ + | + ~ | + ~ | + {2:one }{1:three}{2: two }| + :colorscheme three^ | + ]=]) + feed('<Tab>') + screen:expect([=[ + | + ~ | + ~ | + {2:one three }{1:two}{2: }| + :colorscheme two^ | + ]=]) + feed('<Tab>') + screen:expect([=[ + | + ~ | + ~ | + {2:one three two }| + :colorscheme ^ | + ]=]) + end) + end) +end) diff --git a/test/functional/legacy/qf_title_spec.lua b/test/functional/legacy/qf_title_spec.lua index 01c781cc05..9f97eb27b2 100644 --- a/test/functional/legacy/qf_title_spec.lua +++ b/test/functional/legacy/qf_title_spec.lua @@ -1,6 +1,6 @@ -- Tests for quickfix window's title -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local insert, source = helpers.insert, helpers.source local clear, expect = helpers.clear, helpers.expect diff --git a/test/functional/legacy/quickfix_spec.lua b/test/functional/legacy/quickfix_spec.lua index 315b8ca682..df8f2625db 100644 --- a/test/functional/legacy/quickfix_spec.lua +++ b/test/functional/legacy/quickfix_spec.lua @@ -1,8 +1,10 @@ -- Test for the quickfix commands. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local source, clear = helpers.source, helpers.clear local eq, nvim, call = helpers.eq, helpers.meths, helpers.call +local eval = helpers.eval +local execute = helpers.execute local function expected_empty() eq({}, nvim.get_vvar('errors')) @@ -256,6 +258,25 @@ describe('helpgrep', function() \ l[3].lnum == 750 && l[3].col == 25 && l[3].text ==# 'Line 750') endfunction + + function Test_locationlist_curwin_was_closed() + augroup testgroup + au! + autocmd BufReadCmd t call R(expand("<amatch>")) + augroup END + + function R(n) + quit + endfunc + + new + let q = [] + call add(q, {'filename': 't' }) + call setloclist(0, q) + call assert_fails('lrewind', 'E924:') + + augroup! testgroup + endfunction ]]) end) @@ -306,4 +327,16 @@ describe('helpgrep', function() call('XbufferTests', 'l') expected_empty() end) + + it('autocommands triggered by quickfix can get title', function() + execute('au FileType qf let g:foo = get(w:, "quickfix_title", "NONE")') + execute('call setqflist([])') + execute('copen') + eq(':setqflist()', eval('g:foo')) + end) + + it('errors when an autocommand closes the location list\'s window', function() + call('Test_locationlist_curwin_was_closed') + expected_empty() + end) end) diff --git a/test/functional/legacy/search_mbyte_spec.lua b/test/functional/legacy/search_mbyte_spec.lua index 075b24b897..a5a5822a45 100644 --- a/test/functional/legacy/search_mbyte_spec.lua +++ b/test/functional/legacy/search_mbyte_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local insert = helpers.insert local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect diff --git a/test/functional/legacy/searchpos_spec.lua b/test/functional/legacy/searchpos_spec.lua index 1c9b1ccee6..7d4b7a3734 100644 --- a/test/functional/legacy/searchpos_spec.lua +++ b/test/functional/legacy/searchpos_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local call = helpers.call local clear = helpers.clear local execute = helpers.execute diff --git a/test/functional/legacy/set_spec.lua b/test/functional/legacy/set_spec.lua index f2c907084e..11f371569d 100644 --- a/test/functional/legacy/set_spec.lua +++ b/test/functional/legacy/set_spec.lua @@ -1,6 +1,6 @@ -- Tests for :set -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, execute, eval, eq = helpers.clear, helpers.execute, helpers.eval, helpers.eq diff --git a/test/functional/legacy/signs_spec.lua b/test/functional/legacy/signs_spec.lua index 5a834c39e3..e80a32455a 100644 --- a/test/functional/legacy/signs_spec.lua +++ b/test/functional/legacy/signs_spec.lua @@ -1,6 +1,6 @@ -- Tests for signs -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect describe('signs', function() diff --git a/test/functional/legacy/tagcase_spec.lua b/test/functional/legacy/tagcase_spec.lua index 9a8c6fbe42..ed2876a375 100644 --- a/test/functional/legacy/tagcase_spec.lua +++ b/test/functional/legacy/tagcase_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local eq = helpers.eq local eval = helpers.eval diff --git a/test/functional/legacy/textobjects_spec.lua b/test/functional/legacy/textobjects_spec.lua index 1e8e0b0bcb..15a93e3819 100644 --- a/test/functional/legacy/textobjects_spec.lua +++ b/test/functional/legacy/textobjects_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local call = helpers.call local clear = helpers.clear local execute = helpers.execute diff --git a/test/functional/legacy/undolevels_spec.lua b/test/functional/legacy/undolevels_spec.lua index 41274b3a04..9902b101f6 100644 --- a/test/functional/legacy/undolevels_spec.lua +++ b/test/functional/legacy/undolevels_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local source, clear = helpers.source, helpers.clear local eq, nvim = helpers.eq, helpers.meths diff --git a/test/functional/legacy/utf8_spec.lua b/test/functional/legacy/utf8_spec.lua index d33ba6b5fd..4d4f55b9eb 100644 --- a/test/functional/legacy/utf8_spec.lua +++ b/test/functional/legacy/utf8_spec.lua @@ -1,6 +1,6 @@ -- Tests for Unicode manipulations -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, expect = helpers.execute, helpers.expect local eq, eval = helpers.eq, helpers.eval diff --git a/test/functional/legacy/wordcount_spec.lua b/test/functional/legacy/wordcount_spec.lua index ba7be8f21b..300a777772 100644 --- a/test/functional/legacy/wordcount_spec.lua +++ b/test/functional/legacy/wordcount_spec.lua @@ -1,6 +1,6 @@ -- Test for wordcount() function -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, insert, source = helpers.feed, helpers.insert, helpers.source local clear, execute = helpers.clear, helpers.execute local eq, eval = helpers.eq, helpers.eval diff --git a/test/functional/legacy/writefile_spec.lua b/test/functional/legacy/writefile_spec.lua index efdfc1d09f..f096aa23b9 100644 --- a/test/functional/legacy/writefile_spec.lua +++ b/test/functional/legacy/writefile_spec.lua @@ -1,6 +1,6 @@ -- Tests for writefile() -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect describe('writefile', function() diff --git a/test/functional/normal/K_spec.lua b/test/functional/normal/K_spec.lua index df6b429f50..af0f82ef9a 100644 --- a/test/functional/normal/K_spec.lua +++ b/test/functional/normal/K_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local eq, clear, eval, feed = helpers.eq, helpers.clear, helpers.eval, helpers.feed diff --git a/test/functional/options/autochdir_spec.lua b/test/functional/options/autochdir_spec.lua new file mode 100644 index 0000000000..0e293761ad --- /dev/null +++ b/test/functional/options/autochdir_spec.lua @@ -0,0 +1,18 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear +local eq = helpers.eq +local getcwd = helpers.funcs.getcwd + +describe("'autochdir'", function() + it('given on the shell gets processed properly', function() + local targetdir = 'test/functional/fixtures' + + -- By default 'autochdir' is off, thus getcwd() returns the repo root. + clear(targetdir..'/tty-test.c') + local rootdir = getcwd() + + -- With 'autochdir' on, we should get the directory of tty-test.c. + clear('--cmd', 'set autochdir', targetdir..'/tty-test.c') + eq(rootdir..'/'..targetdir, getcwd()) + end) +end) diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index d4c3267997..a36939b0bd 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -1,6 +1,6 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') -local clear, eval, eq = helpers.clear, helpers.eval, helpers.eq +local eval, eq = helpers.eval, helpers.eq local execute = helpers.execute local function init_session(...) @@ -15,10 +15,6 @@ local function init_session(...) end describe('startup defaults', function() - before_each(function() - clear() - end) - describe(':filetype', function() local function expect_filetype(expected) local screen = Screen.new(48, 4) diff --git a/test/functional/options/shortmess_spec.lua b/test/functional/options/shortmess_spec.lua index 4455ef663f..d531e47e28 100644 --- a/test/functional/options/shortmess_spec.lua +++ b/test/functional/options/shortmess_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, execute = helpers.clear, helpers.execute diff --git a/test/functional/plugin/helpers.lua b/test/functional/plugin/helpers.lua index 5b6ea88c34..7580670149 100644 --- a/test/functional/plugin/helpers.lua +++ b/test/functional/plugin/helpers.lua @@ -1,6 +1,6 @@ local paths = require('test.config.paths') -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(nil) local spawn, set_session, nvim_prog, merge_args = helpers.spawn, helpers.set_session, helpers.nvim_prog, helpers.merge_args diff --git a/test/functional/plugin/matchparen_spec.lua b/test/functional/plugin/matchparen_spec.lua index d8c1f2d392..4181f69263 100644 --- a/test/functional/plugin/matchparen_spec.lua +++ b/test/functional/plugin/matchparen_spec.lua @@ -1,20 +1,27 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) +local plugin_helpers = require('test.functional.plugin.helpers') local Screen = require('test.functional.ui.screen') -local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute + +local execute = helpers.execute +local meths = helpers.meths +local feed = helpers.feed +local eq = helpers.eq + +local reset = plugin_helpers.reset describe('matchparen', function() local screen before_each(function() - clear() + reset() screen = Screen.new(20,5) screen:attach() screen:set_default_attr_ignore( {{bold=true, foreground=Screen.colors.Blue}} ) end) it('uses correct column after i_<Up>. Vim patch 7.4.1296', function() - execute('set noai nosi nocin') - execute('runtime plugin/matchparen.vim') + execute('set noautoindent nosmartindent nocindent laststatus=0') + eq(1, meths.get_var('loaded_matchparen')) feed('ivoid f_test()<cr>') feed('{<cr>') feed('}') diff --git a/test/functional/plugin/msgpack_spec.lua b/test/functional/plugin/msgpack_spec.lua index 60ba88e55b..c8da8e8f6c 100644 --- a/test/functional/plugin/msgpack_spec.lua +++ b/test/functional/plugin/msgpack_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local meths = helpers.meths local eq, nvim_eval, nvim_command, exc_exec = helpers.eq, helpers.eval, helpers.command, helpers.exc_exec diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua index aad0e366bf..e18e9ef428 100644 --- a/test/functional/plugin/shada_spec.lua +++ b/test/functional/plugin/shada_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local eq, nvim_eval, nvim_command, nvim, exc_exec, funcs, nvim_feed, curbuf = helpers.eq, helpers.eval, helpers.command, helpers.nvim, helpers.exc_exec, helpers.funcs, helpers.feed, helpers.curbuf diff --git a/test/functional/preload.lua b/test/functional/preload.lua index 1971ef77cc..1107b45d54 100644 --- a/test/functional/preload.lua +++ b/test/functional/preload.lua @@ -1,4 +1,4 @@ -- Modules loaded here will not be cleared and reloaded by Busted. -- Busted started doing this to help provide more isolation. See issue #62 -- for more information about this. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(nil) diff --git a/test/functional/provider/define_spec.lua b/test/functional/provider/define_spec.lua index c30ad6d8c2..b0363eb435 100644 --- a/test/functional/provider/define_spec.lua +++ b/test/functional/provider/define_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local eval, command, nvim = helpers.eval, helpers.command, helpers.nvim local eq, run, stop = helpers.eq, helpers.run, helpers.stop local clear = helpers.clear diff --git a/test/functional/provider/python3_spec.lua b/test/functional/provider/python3_spec.lua index a94880d4a2..a4e9a49c8a 100644 --- a/test/functional/provider/python3_spec.lua +++ b/test/functional/provider/python3_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local eval, command, feed = helpers.eval, helpers.command, helpers.feed local eq, clear, insert = helpers.eq, helpers.clear, helpers.insert local expect, write_file = helpers.expect, helpers.write_file diff --git a/test/functional/provider/python_spec.lua b/test/functional/provider/python_spec.lua index 06fdbef669..94dfa90ea8 100644 --- a/test/functional/provider/python_spec.lua +++ b/test/functional/provider/python_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local eq = helpers.eq local neq = helpers.neq diff --git a/test/functional/provider/ruby_spec.lua b/test/functional/provider/ruby_spec.lua new file mode 100644 index 0000000000..7b0e17688d --- /dev/null +++ b/test/functional/provider/ruby_spec.lua @@ -0,0 +1,96 @@ +local helpers = require('test.functional.helpers')(after_each) + +local eq = helpers.eq +local feed = helpers.feed +local clear = helpers.clear +local funcs = helpers.funcs +local meths = helpers.meths +local insert = helpers.insert +local expect = helpers.expect +local command = helpers.command +local write_file = helpers.write_file +local curbufmeths = helpers.curbufmeths + +do + clear() + command('let g:prog = provider#ruby#Detect()') + local prog = meths.get_var('prog') + + if prog == '' then + pending( + "Cannot find the neovim RubyGem. Try :CheckHealth", + function() end) + return + end +end + +before_each(function() + clear() +end) + +describe('ruby feature test', function() + it('works', function() + eq(1, funcs.has('ruby')) + end) +end) + +describe(':ruby command', function() + it('evaluates ruby', function() + command('ruby VIM.command("let g:set_by_ruby = [100, 0]")') + eq({100, 0}, meths.get_var('set_by_ruby')) + end) + + it('supports nesting', function() + command([[ruby VIM.command('ruby VIM.command("let set_by_nested_ruby = 555")')]]) + eq(555, meths.get_var('set_by_nested_ruby')) + end) +end) + +describe(':rubyfile command', function() + it('evaluates a ruby file', function() + local fname = 'rubyfile.rb' + write_file(fname, 'VIM.command("let set_by_rubyfile = 123")') + command('rubyfile rubyfile.rb') + eq(123, meths.get_var('set_by_rubyfile')) + os.remove(fname) + end) +end) + +describe(':rubydo command', function() + it('exposes the $_ variable for modifying lines', function() + insert('abc\ndef\nghi\njkl') + expect([[ + abc + def + ghi + jkl]]) + + feed('ggjvj:rubydo $_.upcase!<CR>') + expect([[ + abc + DEF + GHI + jkl]]) + end) + + it('operates on all lines when not given a range', function() + insert('abc\ndef\nghi\njkl') + expect([[ + abc + def + ghi + jkl]]) + + feed(':rubydo $_.upcase!<CR>') + expect([[ + ABC + DEF + GHI + JKL]]) + end) + + it('does not modify the buffer if no changes are made', function() + command('normal :rubydo 42') + eq(false, curbufmeths.get_option('modified')) + end) +end) diff --git a/test/functional/shada/buffers_spec.lua b/test/functional/shada/buffers_spec.lua index fd4809e01a..e4d02c268b 100644 --- a/test/functional/shada/buffers_spec.lua +++ b/test/functional/shada/buffers_spec.lua @@ -1,5 +1,5 @@ -- ShaDa buffer list saving/reading support -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local nvim_command, funcs, eq, curbufmeths = helpers.command, helpers.funcs, helpers.eq, helpers.curbufmeths diff --git a/test/functional/shada/compatibility_spec.lua b/test/functional/shada/compatibility_spec.lua index 1fa88c58e5..1287ac010c 100644 --- a/test/functional/shada/compatibility_spec.lua +++ b/test/functional/shada/compatibility_spec.lua @@ -1,5 +1,5 @@ -- ShaDa compatibility support -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local nvim_command, funcs, eq = helpers.command, helpers.funcs, helpers.eq local exc_exec = helpers.exc_exec diff --git a/test/functional/shada/errors_spec.lua b/test/functional/shada/errors_spec.lua index e7951ee74c..98ead6cc3d 100644 --- a/test/functional/shada/errors_spec.lua +++ b/test/functional/shada/errors_spec.lua @@ -1,5 +1,5 @@ -- ShaDa errors handling support -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local nvim_command, eq, exc_exec, redir_exec = helpers.command, helpers.eq, helpers.exc_exec, helpers.redir_exec diff --git a/test/functional/shada/helpers.lua b/test/functional/shada/helpers.lua index d4eb7f57bd..bb2919d4fb 100644 --- a/test/functional/shada/helpers.lua +++ b/test/functional/shada/helpers.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(nil) local spawn, set_session, meths, nvim_prog = helpers.spawn, helpers.set_session, helpers.meths, helpers.nvim_prog local write_file, merge_args = helpers.write_file, helpers.merge_args diff --git a/test/functional/shada/history_spec.lua b/test/functional/shada/history_spec.lua index 94513945d0..22e653b1d6 100644 --- a/test/functional/shada/history_spec.lua +++ b/test/functional/shada/history_spec.lua @@ -1,5 +1,5 @@ -- ShaDa history saving/reading support -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local nvim_command, funcs, meths, nvim_feed, eq = helpers.command, helpers.funcs, helpers.meths, helpers.feed, helpers.eq diff --git a/test/functional/shada/marks_spec.lua b/test/functional/shada/marks_spec.lua index 955a6f382b..ace3c74a62 100644 --- a/test/functional/shada/marks_spec.lua +++ b/test/functional/shada/marks_spec.lua @@ -1,5 +1,5 @@ -- ShaDa marks saving/reading support -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local meths, curwinmeths, curbufmeths, nvim_command, funcs, eq = helpers.meths, helpers.curwinmeths, helpers.curbufmeths, helpers.command, helpers.funcs, helpers.eq diff --git a/test/functional/shada/merging_spec.lua b/test/functional/shada/merging_spec.lua index 221f989409..25c73b99eb 100644 --- a/test/functional/shada/merging_spec.lua +++ b/test/functional/shada/merging_spec.lua @@ -1,5 +1,5 @@ -- ShaDa merging data support -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local nvim_command, funcs, curbufmeths, eq = helpers.command, helpers.funcs, helpers.curbufmeths, helpers.eq diff --git a/test/functional/shada/registers_spec.lua b/test/functional/shada/registers_spec.lua index 4043d94a69..f1c587c640 100644 --- a/test/functional/shada/registers_spec.lua +++ b/test/functional/shada/registers_spec.lua @@ -1,5 +1,5 @@ -- ShaDa registers saving/reading support -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local nvim_command, funcs, eq = helpers.command, helpers.funcs, helpers.eq local shada_helpers = require('test.functional.shada.helpers') diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua index 683d520627..32e7b16fc5 100644 --- a/test/functional/shada/shada_spec.lua +++ b/test/functional/shada/shada_spec.lua @@ -1,5 +1,5 @@ -- Other ShaDa tests -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local meths, nvim_command, funcs, eq = helpers.meths, helpers.command, helpers.funcs, helpers.eq local write_file, spawn, set_session, nvim_prog, exc_exec = diff --git a/test/functional/shada/variables_spec.lua b/test/functional/shada/variables_spec.lua index 7ceeafdc71..40101baf8f 100644 --- a/test/functional/shada/variables_spec.lua +++ b/test/functional/shada/variables_spec.lua @@ -1,5 +1,5 @@ -- ShaDa variables saving/reading support -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local meths, funcs, nvim_command, eq, exc_exec = helpers.meths, helpers.funcs, helpers.command, helpers.eq, helpers.exc_exec diff --git a/test/functional/shell/bang_filter_spec.lua b/test/functional/shell/bang_filter_spec.lua index 964dbd1029..cd5325c4e1 100644 --- a/test/functional/shell/bang_filter_spec.lua +++ b/test/functional/shell/bang_filter_spec.lua @@ -1,6 +1,6 @@ -- Specs for bang/filter commands -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local feed, execute, clear = helpers.feed, helpers.execute, helpers.clear local mkdir, write_file, rmdir = helpers.mkdir, helpers.write_file, helpers.rmdir diff --git a/test/functional/shell/viml_system_spec.lua b/test/functional/shell/viml_system_spec.lua index 00b16e9158..3de022cbd9 100644 --- a/test/functional/shell/viml_system_spec.lua +++ b/test/functional/shell/viml_system_spec.lua @@ -2,7 +2,7 @@ -- - `system()` -- - `systemlist()` -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local eq, clear, eval, feed, nvim = helpers.eq, helpers.clear, helpers.eval, helpers.feed, helpers.nvim @@ -151,8 +151,8 @@ describe('system()', function() describe('with output containing NULs', function() local fname = 'Xtest' - setup(create_file_with_nuls(fname)) - teardown(delete_file(fname)) + before_each(create_file_with_nuls(fname)) + after_each(delete_file(fname)) it('replaces NULs by SOH characters', function() eq('part1\001part2\001part3\n', eval('system("cat '..fname..'")')) @@ -310,8 +310,8 @@ describe('systemlist()', function() describe('with output containing NULs', function() local fname = 'Xtest' - setup(create_file_with_nuls(fname)) - teardown(delete_file(fname)) + before_each(create_file_with_nuls(fname)) + after_each(delete_file(fname)) it('replaces NULs by newline characters', function() eq({'part1\npart2\npart3'}, eval('systemlist("cat '..fname..'")')) diff --git a/test/functional/terminal/altscreen_spec.lua b/test/functional/terminal/altscreen_spec.lua index d9d96b25f9..e1760c8ad8 100644 --- a/test/functional/terminal/altscreen_spec.lua +++ b/test/functional/terminal/altscreen_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local thelpers = require('test.functional.terminal.helpers') local clear, eq, curbuf = helpers.clear, helpers.eq, helpers.curbuf local feed = helpers.feed diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index cefb603a7e..8a535d6864 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local thelpers = require('test.functional.terminal.helpers') local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim local wait = helpers.wait diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua index c15da2f760..461ddd0ec7 100644 --- a/test/functional/terminal/cursor_spec.lua +++ b/test/functional/terminal/cursor_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local thelpers = require('test.functional.terminal.helpers') local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim diff --git a/test/functional/terminal/edit_spec.lua b/test/functional/terminal/edit_spec.lua index dcc4a54610..c98aef70b1 100644 --- a/test/functional/terminal/edit_spec.lua +++ b/test/functional/terminal/edit_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local screen = require('test.functional.ui.screen') local curbufmeths = helpers.curbufmeths diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua index d89092ff27..458fa02fca 100644 --- a/test/functional/terminal/ex_terminal_spec.lua +++ b/test/functional/terminal/ex_terminal_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, wait, nvim = helpers.clear, helpers.wait, helpers.nvim local nvim_dir, source, eq = helpers.nvim_dir, helpers.source, helpers.eq diff --git a/test/functional/terminal/helpers.lua b/test/functional/terminal/helpers.lua index a32ae650d6..3d1530bd90 100644 --- a/test/functional/terminal/helpers.lua +++ b/test/functional/terminal/helpers.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(nil) local Screen = require('test.functional.ui.screen') local nvim_dir = helpers.nvim_dir local execute, nvim, wait = helpers.execute, helpers.nvim, helpers.wait diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua index 97875c5147..8d7c7451d3 100644 --- a/test/functional/terminal/highlight_spec.lua +++ b/test/functional/terminal/highlight_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local thelpers = require('test.functional.terminal.helpers') local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim @@ -165,24 +165,49 @@ end) describe('synIDattr()', function() local screen - before_each(function() clear() screen = Screen.new(50, 7) - execute('highlight Normal ctermfg=1 guifg=#ff0000') + execute('highlight Normal ctermfg=252 guifg=#ff0000 guibg=Black') + -- Salmon #fa8072 Maroon #800000 + execute('highlight Keyword ctermfg=79 guifg=Salmon guisp=Maroon') + end) + + it('returns cterm-color if RGB-capable UI is _not_ attached', function() + eq('252', eval('synIDattr(hlID("Normal"), "fg")')) + eq('252', eval('synIDattr(hlID("Normal"), "fg#")')) + eq('-1', eval('synIDattr(hlID("Normal"), "bg")')) + eq('-1', eval('synIDattr(hlID("Normal"), "bg#")')) + eq('79', eval('synIDattr(hlID("Keyword"), "fg")')) + eq('79', eval('synIDattr(hlID("Keyword"), "fg#")')) + eq('', eval('synIDattr(hlID("Keyword"), "sp")')) + eq('', eval('synIDattr(hlID("Keyword"), "sp#")')) end) - after_each(function() - screen:detach() + it('returns gui-color if "gui" arg is passed', function() + eq('Black', eval('synIDattr(hlID("Normal"), "bg", "gui")')) + eq('Maroon', eval('synIDattr(hlID("Keyword"), "sp", "gui")')) + end) + + it('returns gui-color if RGB-capable UI is attached', function() + screen:attach(true) + eq('#ff0000', eval('synIDattr(hlID("Normal"), "fg")')) + eq('Black', eval('synIDattr(hlID("Normal"), "bg")')) + eq('Salmon', eval('synIDattr(hlID("Keyword"), "fg")')) + eq('Maroon', eval('synIDattr(hlID("Keyword"), "sp")')) end) - it('returns RGB number if GUI', function() + it('returns #RRGGBB value for fg#/bg#/sp#', function() screen:attach(true) - eq('#ff0000', eval('synIDattr(hlID("Normal"), "fg")')) + eq('#ff0000', eval('synIDattr(hlID("Normal"), "fg#")')) + eq('#000000', eval('synIDattr(hlID("Normal"), "bg#")')) + eq('#fa8072', eval('synIDattr(hlID("Keyword"), "fg#")')) + eq('#800000', eval('synIDattr(hlID("Keyword"), "sp#")')) end) it('returns color number if non-GUI', function() screen:attach(false) - eq('1', eval('synIDattr(hlID("Normal"), "fg")')) + eq('252', eval('synIDattr(hlID("Normal"), "fg")')) + eq('79', eval('synIDattr(hlID("Keyword"), "fg")')) end) end) diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua index c4bd3c2663..a86615184d 100644 --- a/test/functional/terminal/mouse_spec.lua +++ b/test/functional/terminal/mouse_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local thelpers = require('test.functional.terminal.helpers') local clear = helpers.clear local feed, nvim = helpers.feed, helpers.nvim @@ -112,7 +112,7 @@ describe('terminal mouse', function() line28 |line28 | line29 |line29 | line30 |line30 | - rows: 5, cols: 24 |rows: 5, cols: 24 | + rows: 5, cols: 25 |rows: 5, cols: 25 | {2:^ } |{2: } | ========== ========== | | @@ -122,7 +122,7 @@ describe('terminal mouse', function() 1 ^ |line28 | ~ |line29 | ~ |line30 | - ~ |rows: 5, cols: 24 | + ~ |rows: 5, cols: 25 | ~ |{2: } | ========== ========== | :enew | set number | @@ -132,16 +132,16 @@ describe('terminal mouse', function() 27 line |line28 | 28 line |line29 | 29 line |line30 | - 30 line |rows: 5, cols: 24 | + 30 line |rows: 5, cols: 25 | 31 ^ |{2: } | ========== ========== | | ]]) feed('<c-w>li') screen:expect([[ - 27 line |line28 | - 28 line |line29 | - 29 line |line30 | + 27 line |line29 | + 28 line |line30 | + 29 line |rows: 5, cols: 25 | 30 line |rows: 5, cols: 24 | 31 |{1: } | ========== ========== | @@ -151,8 +151,8 @@ describe('terminal mouse', function() thelpers.enable_mouse() thelpers.feed_data('mouse enabled\n') screen:expect([[ - 27 line |line29 | - 28 line |line30 | + 27 line |line30 | + 28 line |rows: 5, cols: 25 | 29 line |rows: 5, cols: 24 | 30 line |mouse enabled | 31 |{1: } | @@ -164,8 +164,8 @@ describe('terminal mouse', function() it('wont lose focus if another window is scrolled', function() feed('<MouseDown><0,0><MouseDown><0,0>') screen:expect([[ - 21 line |line29 | - 22 line |line30 | + 21 line |line30 | + 22 line |rows: 5, cols: 25 | 23 line |rows: 5, cols: 24 | 24 line |mouse enabled | 25 line |{1: } | @@ -174,8 +174,8 @@ describe('terminal mouse', function() ]]) feed('<S-MouseUp><0,0>') screen:expect([[ - 26 line |line29 | - 27 line |line30 | + 26 line |line30 | + 27 line |rows: 5, cols: 25 | 28 line |rows: 5, cols: 24 | 29 line |mouse enabled | 30 line |{1: } | @@ -187,8 +187,8 @@ describe('terminal mouse', function() it('will lose focus if another window is clicked', function() feed('<LeftMouse><5,1>') screen:expect([[ - 27 line |line29 | - 28 l^ine |line30 | + 27 line |line30 | + 28 l^ine |rows: 5, cols: 25 | 29 line |rows: 5, cols: 24 | 30 line |mouse enabled | 31 |{2: } | diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index 4b56698520..7914e30a44 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -1,5 +1,5 @@ local Screen = require('test.functional.ui.screen') -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local thelpers = require('test.functional.terminal.helpers') local clear, eq, curbuf = helpers.clear, helpers.eq, helpers.curbuf local feed, nvim_dir, execute = helpers.feed, helpers.nvim_dir, helpers.execute diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 364ca327a4..e6586c7892 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -1,6 +1,6 @@ -- Some sanity checks for the TUI using the builtin terminal emulator -- as a simple way to send keys and assert screen state. -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local thelpers = require('test.functional.terminal.helpers') local feed = thelpers.feed_data local execute = helpers.execute @@ -301,3 +301,72 @@ describe('tui focus event handling', function() ]]) end) end) + +-- These tests require `thelpers` because --headless/--embed +-- does not initialize the TUI. +describe("tui 't_Co' (terminal colors)", function() + local screen + local is_linux = (helpers.eval("system('uname') =~? 'linux'") == 1) + + local function assert_term_colors(term, colorterm, maxcolors) + helpers.clear({env={TERM=term}, args={}}) + -- This is ugly because :term/termopen() forces TERM=xterm-256color. + -- TODO: Revisit this after jobstart/termopen accept `env` dict. + screen = thelpers.screen_setup(0, string.format( + [=[['sh', '-c', 'TERM=%s %s %s -u NONE -i NONE --cmd "silent set noswapfile"']]=], + term, + (colorterm ~= nil and "COLORTERM="..colorterm or ""), + helpers.nvim_prog)) + + thelpers.feed_data(":echo &t_Co\n") + screen:expect(string.format([[ + {1: } | + ~ | + ~ | + ~ | + [No Name] | + %-3s | + -- TERMINAL -- | + ]], tostring(maxcolors and maxcolors or ""))) + end + + it("unknown TERM sets empty 't_Co'", function() + assert_term_colors("yet-another-term", nil, nil) + end) + + it("unknown TERM with COLORTERM=screen-256color uses 256 colors", function() + assert_term_colors("yet-another-term", "screen-256color", 256) + end) + + it("TERM=linux uses 8 colors", function() + if is_linux then + assert_term_colors("linux", nil, 8) + else + pending() + end + end) + + it("TERM=screen uses 8 colors", function() + if is_linux then + assert_term_colors("screen", nil, 8) + else + pending() + end + end) + + it("TERM=screen COLORTERM=screen-256color uses 256 colors", function() + assert_term_colors("screen", "screen-256color", 256) + end) + + it("TERM=yet-another-term COLORTERM=screen-256color uses 256 colors", function() + assert_term_colors("screen", "screen-256color", 256) + end) + + it("TERM=xterm uses 256 colors", function() + assert_term_colors("xterm", nil, 256) + end) + + it("TERM=xterm-256color uses 256 colors", function() + assert_term_colors("xterm-256color", nil, 256) + end) +end) diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua index 6c236ed868..eec8b53f4d 100644 --- a/test/functional/terminal/window_spec.lua +++ b/test/functional/terminal/window_spec.lua @@ -1,8 +1,8 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local thelpers = require('test.functional.terminal.helpers') local feed, clear = helpers.feed, helpers.clear local wait = helpers.wait - +local execute = helpers.execute describe('terminal window', function() local screen @@ -12,6 +12,23 @@ describe('terminal window', function() screen = thelpers.screen_setup() end) + it('resets its size when entering terminal buffer', function() + feed('<c-\\><c-n>') + execute('set hidden') + execute('edit foo') + execute('doautoall SessionLoadPost') + execute('silent bnext') + screen:expect([[ + tty ready | + {2: } | + | + | + | + ^ | + :silent bnext | + ]]) + end) + describe('with colorcolumn set', function() before_each(function() feed('<c-\\><c-n>') diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua index 727eba2717..644060103a 100644 --- a/test/functional/terminal/window_split_tab_spec.lua +++ b/test/functional/terminal/window_split_tab_spec.lua @@ -1,7 +1,8 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local thelpers = require('test.functional.terminal.helpers') local clear = helpers.clear local feed, nvim = helpers.feed, helpers.nvim +local execute = helpers.execute describe('terminal', function() local screen @@ -21,6 +22,49 @@ describe('terminal', function() screen:detach() end) + it('resets its size when entering terminal window', function() + feed('<c-\\><c-n>') + execute('2split') + screen:expect([[ + tty ready | + ^rows: 2, cols: 50 | + ========== | + tty ready | + rows: 2, cols: 50 | + {2: } | + ~ | + ~ | + ========== | + | + ]]) + execute('wincmd p') + screen:expect([[ + tty ready | + rows: 2, cols: 50 | + ========== | + tty ready | + rows: 2, cols: 50 | + rows: 5, cols: 50 | + {2: } | + ^ | + ========== | + :wincmd p | + ]]) + execute('wincmd p') + screen:expect([[ + rows: 5, cols: 50 | + ^rows: 2, cols: 50 | + ========== | + rows: 5, cols: 50 | + rows: 2, cols: 50 | + {2: } | + ~ | + ~ | + ========== | + :wincmd p | + ]]) + end) + describe('when the screen is resized', function() it('will forward a resize request to the program', function() screen:try_resize(screen._width + 3, screen._height + 5) @@ -51,87 +95,4 @@ describe('terminal', function() ]]) end) end) - - describe('split horizontally', function() - before_each(function() - nvim('command', 'sp') - end) - - local function reduce_height() - screen:expect([[ - tty ready | - rows: 3, cols: 50 | - {1: } | - ~ | - ========== | - tty ready | - rows: 3, cols: 50 | - {2: } | - ========== | - -- TERMINAL -- | - ]]) - end - - it('uses the minimum height of all window displaying it', reduce_height) - - describe('and then vertically', function() - before_each(function() - reduce_height() - nvim('command', 'vsp') - end) - - local function reduce_width() - screen:expect([[ - rows: 3, cols: 50 |rows: 3, cols: 50 | - rows: 3, cols: 24 |rows: 3, cols: 24 | - {1: } |{2: } | - ~ |~ | - ========== ========== | - rows: 3, cols: 50 | - rows: 3, cols: 24 | - {2: } | - ========== | - -- TERMINAL -- | - ]]) - feed('<c-\\><c-n>gg') - screen:expect([[ - ^tty ready |rows: 3, cols: 50 | - rows: 3, cols: 50 |rows: 3, cols: 24 | - rows: 3, cols: 24 |{2: } | - {2: } |~ | - ========== ========== | - rows: 3, cols: 50 | - rows: 3, cols: 24 | - {2: } | - ========== | - | - ]]) - end - - it('uses the minimum width of all window displaying it', reduce_width) - - describe('and then closes one of the vertical splits with q:', function() - before_each(function() - reduce_width() - nvim('command', 'q') - feed('<c-w>ja') - end) - - it('will restore the width', function() - screen:expect([[ - rows: 3, cols: 24 | - rows: 3, cols: 50 | - {2: } | - ~ | - ========== | - rows: 3, cols: 24 | - rows: 3, cols: 50 | - {1: } | - ========== | - -- TERMINAL -- | - ]]) - end) - end) - end) - end) end) diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index 58f5b11de0..f91aa8d402 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute, request, neq = helpers.execute, helpers.request, helpers.neq diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 85fca4d7ca..6ef40fff62 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local os = require('os') local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert @@ -38,7 +38,6 @@ describe('manual syntax highlight', function() os.remove('Xtest-functional-ui-highlight.tmp.vim') end) - -- test with "set hidden" even if the bug did not occur this way it("works with buffer switch and 'hidden'", function() execute('e tmp1.vim') execute('e Xtest-functional-ui-highlight.tmp.vim') diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua index 6f5cadaf81..407c576002 100644 --- a/test/functional/ui/input_spec.lua +++ b/test/functional/ui/input_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear, execute, nvim = helpers.clear, helpers.execute, helpers.nvim local feed, next_message, eq = helpers.feed, helpers.next_message, helpers.eq local expect = helpers.expect diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 993bbd5b0e..a433143266 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, meths = helpers.clear, helpers.feed, helpers.meths local insert, execute = helpers.insert, helpers.execute diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua new file mode 100644 index 0000000000..c7c8986527 --- /dev/null +++ b/test/functional/ui/output_spec.lua @@ -0,0 +1,39 @@ +local session = require('test.functional.helpers')(after_each) +local child_session = require('test.functional.terminal.helpers') + +describe("shell command :!", function() + local screen + before_each(function() + session.clear() + screen = child_session.screen_setup(0, '["'..session.nvim_prog.. + '", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile"]') + screen:expect([[ + {1: } | + ~ | + ~ | + ~ | + [No Name] | + | + -- TERMINAL -- | + ]]) + end) + + after_each(function() + screen:detach() + end) + + it("displays output even without LF/EOF. #4646 #4569 #3772", function() + -- NOTE: We use a child nvim (within a :term buffer) + -- to avoid triggering a UI flush. + child_session.feed_data(":!printf foo; sleep 200\n") + screen:expect([[ + ~ | + ~ | + [No Name] | + :!printf foo; sleep 200 | + | + foo | + -- TERMINAL -- | + ]]) + end) +end) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 99b85caf10..d7af2a4fce 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -105,7 +105,7 @@ -- To generate a text-only test without highlight checks, -- use `screen:snapshot_util({},true)` -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(nil) local request, run = helpers.request, helpers.run local dedent = helpers.dedent diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index a4545eeff0..9249be4aec 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local spawn, set_session, clear = helpers.spawn, helpers.set_session, helpers.clear local feed, execute = helpers.feed, helpers.execute diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index e4217abcfe..894a75d355 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local execute = helpers.execute diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua index c32a7b9381..2b6e294627 100644 --- a/test/functional/ui/sign_spec.lua +++ b/test/functional/ui/sign_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua index 66ea779011..c2ab0711c0 100644 --- a/test/functional/ui/syntax_conceal_spec.lua +++ b/test/functional/ui/syntax_conceal_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute local insert = helpers.insert diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index c57d4abcbf..2a55d27567 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute local funcs = helpers.funcs diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua index 2b3844bf6d..33f481bae2 100644 --- a/test/functional/viml/completion_spec.lua +++ b/test/functional/viml/completion_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed = helpers.clear, helpers.feed local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq diff --git a/test/functional/viml/errorlist_spec.lua b/test/functional/viml/errorlist_spec.lua index 30cb86f8d1..56d08771b7 100644 --- a/test/functional/viml/errorlist_spec.lua +++ b/test/functional/viml/errorlist_spec.lua @@ -1,4 +1,4 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local command = helpers.command diff --git a/test/functional/viml/function_spec.lua b/test/functional/viml/function_spec.lua index 665f5d4467..f0a4406593 100644 --- a/test/functional/viml/function_spec.lua +++ b/test/functional/viml/function_spec.lua @@ -1,7 +1,8 @@ -local helpers = require('test.functional.helpers') +local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local eq = helpers.eq +local eval = helpers.eval local exc_exec = helpers.exc_exec describe('Up to MAX_FUNC_ARGS arguments are handled by', function() @@ -27,3 +28,11 @@ describe('Up to MAX_FUNC_ARGS arguments are handled by', function() eq('Vim(call):E740: Too many arguments for function rpcnotify', ret) end) end) + +describe('api_info()', function() + before_each(clear) + it('has the right keys', function() + local api_keys = eval("sort(keys(api_info()))") + eq({'error_types', 'functions', 'types'}, api_keys) + end) +end) diff --git a/test/functional/viml/lang_spec.lua b/test/functional/viml/lang_spec.lua new file mode 100644 index 0000000000..a27e18f695 --- /dev/null +++ b/test/functional/viml/lang_spec.lua @@ -0,0 +1,22 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear, eval, eq = helpers.clear, helpers.eval, helpers.eq +local execute, source = helpers.execute, helpers.source + +describe('viml', function() + before_each(clear) + + it('parses `<SID>` with turkish locale', function() + execute('lang ctype tr_TR.UTF-8') + if string.find(eval('v:errmsg'), '^E197: ') then + pending("Locale tr_TR.UTF-8 not supported") + return + end + source([[ + func! <sid>_dummy_function() + echo 1 + endfunc + au VimEnter * call <sid>_dummy_function() + ]]) + eq(nil, string.find(eval('v:errmsg'), '^E129')) + end) +end) diff --git a/test/helpers.lua b/test/helpers.lua new file mode 100644 index 0000000000..4c50c7644f --- /dev/null +++ b/test/helpers.lua @@ -0,0 +1,60 @@ +local assert = require('luassert') +local lfs = require('lfs') + +local check_logs_useless_lines = { + ['Warning: noted but unhandled ioctl']=1, + ['could cause spurious value errors to appear']=2, + ['See README_MISSING_SYSCALL_OR_IOCTL for guidance']=3, +} + +local eq = function(exp, act) + return assert.are.same(exp, act) +end +local neq = function(exp, act) + return assert.are_not.same(exp, act) +end +local ok = function(res) + return assert.is_true(res) +end + +local function check_logs() + local log_dir = os.getenv('LOG_DIR') + local runtime_errors = 0 + if log_dir and lfs.attributes(log_dir, 'mode') == 'directory' then + for tail in lfs.dir(log_dir) do + if tail:sub(1, 30) == 'valgrind-' or tail:find('san%.') then + local file = log_dir .. '/' .. tail + local fd = io.open(file) + local start_msg = ('='):rep(20) .. ' File ' .. file .. ' ' .. ('='):rep(20) + local lines = {} + local warning_line = 0 + for line in fd:lines() do + local cur_warning_line = check_logs_useless_lines[line] + if cur_warning_line == warning_line + 1 then + warning_line = cur_warning_line + else + lines[#lines + 1] = line + end + end + fd:close() + os.remove(file) + if #lines > 0 then + -- local out = os.getenv('TRAVIS_CI_BUILD') and io.stdout or io.stderr + local out = io.stdout + out:write(start_msg .. '\n') + out:write('= ' .. table.concat(lines, '\n= ') .. '\n') + out:write(select(1, start_msg:gsub('.', '=')) .. '\n') + runtime_errors = runtime_errors + 1 + end + end + end + end + assert(0 == runtime_errors) +end + +return { + eq = eq, + neq = neq, + ok = ok, + check_logs = check_logs, +} diff --git a/test/unit/api/helpers.lua b/test/unit/api/helpers.lua new file mode 100644 index 0000000000..883e1c6c19 --- /dev/null +++ b/test/unit/api/helpers.lua @@ -0,0 +1,156 @@ +local helpers = require('test.unit.helpers') +local eval_helpers = require('test.unit.eval.helpers') + +local cimport = helpers.cimport +local to_cstr = helpers.to_cstr +local ffi = helpers.ffi + +local list_type = eval_helpers.list_type +local dict_type = eval_helpers.dict_type +local func_type = eval_helpers.func_type +local nil_value = eval_helpers.nil_value +local int_type = eval_helpers.int_type +local flt_type = eval_helpers.flt_type +local type_key = eval_helpers.type_key + +local api = cimport('./src/nvim/api/private/defs.h', + './src/nvim/api/private/helpers.h', + './src/nvim/memory.h') + +local obj2lua + +local obj2lua_tab = { + [tonumber(api.kObjectTypeArray)] = function(obj) + local ret = {[type_key]=list_type} + for i = 1,tonumber(obj.data.array.size) do + ret[i] = obj2lua(obj.data.array.items[i - 1]) + end + if ret[1] then + ret[type_key] = nil + end + return ret + end, + [tonumber(api.kObjectTypeDictionary)] = function(obj) + local ret = {} + for i = 1,tonumber(obj.data.dictionary.size) do + local kv_pair = obj.data.dictionary.items[i - 1] + ret[ffi.string(kv_pair.key.data, kv_pair.key.size)] = obj2lua(kv_pair.value) + end + return ret + end, + [tonumber(api.kObjectTypeBoolean)] = function(obj) + if obj.data.boolean == false then + return false + else + return true + end + end, + [tonumber(api.kObjectTypeNil)] = function(_) + return nil_value + end, + [tonumber(api.kObjectTypeFloat)] = function(obj) + return tonumber(obj.data.floating) + end, + [tonumber(api.kObjectTypeInteger)] = function(obj) + return {[type_key]=int_type, value=tonumber(obj.data.integer)} + end, + [tonumber(api.kObjectTypeString)] = function(obj) + return ffi.string(obj.data.string.data, obj.data.string.size) + end, +} + +obj2lua = function(obj) + return ((obj2lua_tab[tonumber(obj['type'])] or function(obj_inner) + assert(false, 'Converting ' .. tostring(tonumber(obj_inner['type'])) .. ' is not implementing yet') + end)(obj)) +end + +local obj = function(typ, data) + return ffi.gc(ffi.new('Object', {['type']=typ, data=data}), + api.api_free_object) +end + +local lua2obj + +local lua2obj_type_tab = { + [int_type] = function(l) + return obj(api.kObjectTypeInteger, {integer=l.value}) + end, + [flt_type] = function(l) + return obj(api.kObjectTypeFloat, {floating=l}) + end, + [list_type] = function(l) + local len = #l + local arr = obj(api.kObjectTypeArray, {array={ + size=len, + capacity=len, + items=ffi.cast('Object *', api.xmalloc(len * ffi.sizeof('Object'))), + }}) + for i = 1, len do + arr.data.array.items[i - 1] = ffi.gc(lua2obj(l[i]), nil) + end + return arr + end, + [dict_type] = function(l) + local kvs = {} + for k, v in pairs(l) do + if type(k) == 'string' then + kvs[#kvs + 1] = {k, v} + end + end + local len = #kvs + local dct = obj(api.kObjectTypeDictionary, {dictionary={ + size=len, + capacity=len, + items=ffi.cast('KeyValuePair *', + api.xmalloc(len * ffi.sizeof('KeyValuePair'))), + }}) + for i = 1, len do + local key, val = table.unpack(kvs[i]) + dct.data.dictionary.items[i - 1] = ffi.new( + 'KeyValuePair', {key=ffi.gc(lua2obj(key), nil).data.string, + value=ffi.gc(lua2obj(val), nil)}) + end + return dct + end, +} + +lua2obj = function(l) + if type(l) == 'table' then + if l[type_key] then + return lua2obj_type_tab[l[type_key]](l) + else + if l[1] then + return lua2obj_type_tab[list_type](l) + else + return lua2obj_type_tab[dict_type](l) + end + end + elseif type(l) == 'number' then + return lua2obj_type_tab[flt_type](l) + elseif type(l) == 'boolean' then + return obj(api.kObjectTypeBoolean, {boolean=l}) + elseif type(l) == 'string' then + return obj(api.kObjectTypeString, {string={ + size=#l, + data=api.xmemdupz(to_cstr(l), #l), + }}) + elseif l == nil or l == nil_value then + return obj(api.kObjectTypeNil, {integer=0}) + end +end + +return { + list_type=list_type, + dict_type=dict_type, + func_type=func_type, + int_type=int_type, + flt_type=flt_type, + + nil_value=nil_value, + + type_key=type_key, + + obj2lua=obj2lua, + lua2obj=lua2obj, +} diff --git a/test/unit/api/private_helpers_spec.lua b/test/unit/api/private_helpers_spec.lua new file mode 100644 index 0000000000..1d7c03787b --- /dev/null +++ b/test/unit/api/private_helpers_spec.lua @@ -0,0 +1,88 @@ +local helpers = require('test.unit.helpers') +local eval_helpers = require('test.unit.eval.helpers') +local api_helpers = require('test.unit.api.helpers') + +local cimport = helpers.cimport +local NULL = helpers.NULL +local eq = helpers.eq + +local lua2typvalt = eval_helpers.lua2typvalt +local typvalt = eval_helpers.typvalt + +local nil_value = api_helpers.nil_value +local list_type = api_helpers.list_type +local int_type = api_helpers.int_type +local type_key = api_helpers.type_key +local obj2lua = api_helpers.obj2lua + +local api = cimport('./src/nvim/api/private/helpers.h') + +describe('vim_to_object', function() + local vim_to_object = function(l) + return obj2lua(api.vim_to_object(lua2typvalt(l))) + end + + local different_output_test = function(name, input, output) + it(name, function() + eq(output, vim_to_object(input)) + end) + end + + local simple_test = function(name, l) + different_output_test(name, l, l) + end + + simple_test('converts true', true) + simple_test('converts false', false) + simple_test('converts nil', nil_value) + simple_test('converts 1', 1) + simple_test('converts -1.5', -1.5) + simple_test('converts empty string', '') + simple_test('converts non-empty string', 'foobar') + simple_test('converts integer 10', {[type_key]=int_type, value=10}) + simple_test('converts empty dictionary', {}) + simple_test('converts dictionary with scalar values', {test=10, test2=true, test3='test'}) + simple_test('converts dictionary with containers inside', {test={}, test2={1, 2}}) + simple_test('converts empty list', {[type_key]=list_type}) + simple_test('converts list with scalar values', {1, 2, 'test', 'foo'}) + simple_test('converts list with containers inside', {{}, {test={}, test3={test4=true}}}) + + local dct = {} + dct.dct = dct + different_output_test('outputs nil for nested dictionaries (1 level)', dct, {dct=nil_value}) + + local lst = {} + lst[1] = lst + different_output_test('outputs nil for nested lists (1 level)', lst, {nil_value}) + + local dct2 = {test=true, dict=nil_value} + dct2.dct = {dct2} + different_output_test('outputs nil for nested dictionaries (2 level, in list)', + dct2, {dct={nil_value}, test=true, dict=nil_value}) + + local dct3 = {test=true, dict=nil_value} + dct3.dct = {dctin=dct3} + different_output_test('outputs nil for nested dictionaries (2 level, in dict)', + dct3, {dct={dctin=nil_value}, test=true, dict=nil_value}) + + local lst2 = {} + lst2[1] = {lst2} + different_output_test('outputs nil for nested lists (2 level, in list)', lst2, {{nil_value}}) + + local lst3 = {nil, true, false, 'ttest'} + lst3[1] = {lst=lst3} + different_output_test('outputs nil for nested lists (2 level, in dict)', + lst3, {{lst=nil_value}, true, false, 'ttest'}) + + it('outputs empty list for NULL list', function() + local tt = typvalt('VAR_LIST', {v_list=NULL}) + eq(nil, tt.vval.v_list) + eq({[type_key]=list_type}, obj2lua(api.vim_to_object(tt))) + end) + + it('outputs empty dict for NULL dict', function() + local tt = typvalt('VAR_DICT', {v_dict=NULL}) + eq(nil, tt.vval.v_dict) + eq({}, obj2lua(api.vim_to_object(tt))) + end) +end) diff --git a/test/unit/buffer_spec.lua b/test/unit/buffer_spec.lua index b7f82064d7..317c9be6e7 100644 --- a/test/unit/buffer_spec.lua +++ b/test/unit/buffer_spec.lua @@ -1,10 +1,9 @@ -local assert = require("luassert") local helpers = require("test.unit.helpers") local to_cstr = helpers.to_cstr +local get_str = helpers.ffi.string local eq = helpers.eq -local neq = helpers.neq local NULL = helpers.NULL local globals = helpers.cimport("./src/nvim/globals.h") @@ -211,93 +210,246 @@ describe('buffer functions', function() end) describe('build_stl_str_hl', function() + local buffer_byte_size = 100 + local STL_MAX_ITEM = 80 + local output_buffer = '' + + -- This function builds the statusline + -- + -- @param arg Optional arguments are: + -- .pat The statusline format string + -- .fillchar The fill character used in the statusline + -- .maximum_cell_count The number of cells available in the statusline + local function build_stl_str_hl(arg) + output_buffer = to_cstr(string.rep(" ", buffer_byte_size)) + + local pat = arg.pat or '' + local fillchar = arg.fillchar or (' '):byte() + local maximum_cell_count = arg.maximum_cell_count or buffer_byte_size - local output_buffer = to_cstr(string.rep(" ", 100)) - - local build_stl_str_hl = function(pat) return buffer.build_stl_str_hl(globals.curwin, output_buffer, - 100, + buffer_byte_size, to_cstr(pat), false, - 32, - 80, + fillchar, + maximum_cell_count, NULL, NULL) end - it('should copy plain text', function() - local width = build_stl_str_hl("this is a test") - - eq(14, width) - eq("this is a test", helpers.ffi.string(output_buffer, width)) - - end) - - it('should print no file name', function() - local width = build_stl_str_hl("%f") - - eq(9, width) - eq("[No Name]", helpers.ffi.string(output_buffer, width)) - - end) - - it('should print the relative file name', function() - buffer.setfname(globals.curbuf, to_cstr("Makefile"), NULL, 1) - local width = build_stl_str_hl("%f") - - eq(8, width) - eq("Makefile", helpers.ffi.string(output_buffer, width)) - - end) - - it('should print the full file name', function() - buffer.setfname(globals.curbuf, to_cstr("Makefile"), NULL, 1) - - local width = build_stl_str_hl("%F") - - assert.is_true(8 < width) - neq(NULL, string.find(helpers.ffi.string(output_buffer, width), "Makefile")) - - end) - - it('should print the tail file name', function() - buffer.setfname(globals.curbuf, to_cstr("src/nvim/buffer.c"), NULL, 1) - - local width = build_stl_str_hl("%t") - - eq(8, width) - eq("buffer.c", helpers.ffi.string(output_buffer, width)) - - end) - - it('should print the buffer number', function() - buffer.setfname(globals.curbuf, to_cstr("src/nvim/buffer.c"), NULL, 1) - - local width = build_stl_str_hl("%n") - - eq(1, width) - eq("1", helpers.ffi.string(output_buffer, width)) - end) - - it('should print the current line number in the buffer', function() - buffer.setfname(globals.curbuf, to_cstr("test/unit/buffer_spec.lua"), NULL, 1) - - local width = build_stl_str_hl("%l") - - eq(1, width) - eq("0", helpers.ffi.string(output_buffer, width)) - - end) - - it('should print the number of lines in the buffer', function() - buffer.setfname(globals.curbuf, to_cstr("test/unit/buffer_spec.lua"), NULL, 1) - - local width = build_stl_str_hl("%L") + -- Use this function to simplify testing the comparison between + -- the format string and the resulting statusline. + -- + -- @param description The description of what the test should be doing + -- @param statusline_cell_count The number of cells available in the statusline + -- @param input_stl The format string for the statusline + -- @param expected_stl The expected result string for the statusline + -- + -- @param arg Options can be placed in an optional dictionary as the last parameter + -- .expected_cell_count The expected number of cells build_stl_str_hl will return + -- .expected_byte_length The expected byte length of the string + -- .file_name The name of the file to be tested (useful in %f type tests) + -- .fillchar The character that will be used to fill any 'extra' space in the stl + local function statusline_test (description, + statusline_cell_count, + input_stl, + expected_stl, + arg) + + -- arg is the optional parameter + -- so we either fill in option with arg or an empty dictionary + local option = arg or {} + + local fillchar = option.fillchar or (' '):byte() + local expected_cell_count = option.expected_cell_count or statusline_cell_count + local expected_byte_length = option.expected_byte_length or expected_cell_count + + it(description, function() + if option.file_name then + buffer.setfname(globals.curbuf, to_cstr(option.file_name), NULL, 1) + else + buffer.setfname(globals.curbuf, nil, NULL, 1) + end + + local result_cell_count = build_stl_str_hl{pat=input_stl, + maximum_cell_count=statusline_cell_count, + fillchar=fillchar} + + eq(expected_stl, get_str(output_buffer, expected_byte_length)) + eq(expected_cell_count, result_cell_count) + end) + end - eq(1, width) - eq("1", helpers.ffi.string(output_buffer, width)) + -- file name testing + statusline_test('should print no file name', 10, + '%f', '[No Name]', + {expected_cell_count=9}) + statusline_test('should print the relative file name', 30, + '%f', 'test/unit/buffer_spec.lua', + {file_name='test/unit/buffer_spec.lua', expected_cell_count=25}) + statusline_test('should print the full file name', 40, + '%F', '/test/unit/buffer_spec.lua', + {file_name='/test/unit/buffer_spec.lua', expected_cell_count=26}) + + -- fillchar testing + statusline_test('should handle `!` as a fillchar', 10, + 'abcde%=', 'abcde!!!!!', + {fillchar=('!'):byte()}) + statusline_test('should handle `~` as a fillchar', 10, + '%=abcde', '~~~~~abcde', + {fillchar=('~'):byte()}) + statusline_test('should put fillchar `!` in between text', 10, + 'abc%=def', 'abc!!!!def', + {fillchar=('!'):byte()}) + statusline_test('should put fillchar `~` in between text', 10, + 'abc%=def', 'abc~~~~def', + {fillchar=('~'):byte()}) + statusline_test('should print the tail file name', 80, + '%t', 'buffer_spec.lua', + {file_name='test/unit/buffer_spec.lua', expected_cell_count=15}) + + -- standard text testing + statusline_test('should copy plain text', 80, + 'this is a test', 'this is a test', + {expected_cell_count=14}) + + -- line number testing + statusline_test('should print the buffer number', 80, + '%n', '1', + {expected_cell_count=1}) + statusline_test('should print the current line number in the buffer', 80, + '%l', '0', + {expected_cell_count=1}) + statusline_test('should print the number of lines in the buffer', 80, + '%L', '1', + {expected_cell_count=1}) + + -- truncation testing + statusline_test('should truncate when standard text pattern is too long', 10, + '0123456789abcde', '<6789abcde') + statusline_test('should truncate when using =', 10, + 'abcdef%=ghijkl', 'abcdef<jkl') + statusline_test('should truncate centered text when using ==', 10, + 'abcde%=gone%=fghij', 'abcde<ghij') + statusline_test('should respect the `<` marker', 10, + 'abc%<defghijkl', 'abc<ghijkl') + statusline_test('should truncate at `<` with one `=`, test 1', 10, + 'abc%<def%=ghijklmno', 'abc<jklmno') + statusline_test('should truncate at `<` with one `=`, test 2', 10, + 'abcdef%=ghijkl%<mno', 'abcdefghi>') + statusline_test('should truncate at `<` with one `=`, test 3', 10, + 'abc%<def%=ghijklmno', 'abc<jklmno') + statusline_test('should truncate at `<` with one `=`, test 4', 10, + 'abc%<def%=ghij', 'abcdefghij') + statusline_test('should truncate at `<` with one `=`, test 4', 10, + 'abc%<def%=ghijk', 'abc<fghijk') + + statusline_test('should truncate at `<` with many `=`, test 4', 10, + 'ab%<cdef%=g%=h%=ijk', 'ab<efghijk') + + statusline_test('should truncate at the first `<`', 10, + 'abc%<def%<ghijklm', 'abc<hijklm') + + -- alignment testing + statusline_test('should right align when using =', 20, + 'neo%=vim', 'neo vim') + statusline_test('should, when possible, center text when using %=text%=', 20, + 'abc%=neovim%=def', 'abc neovim def') + statusline_test('should handle uneven spacing in the buffer when using %=text%=', 20, + 'abc%=neo_vim%=def', 'abc neo_vim def') + statusline_test('should have equal spaces even with non-equal sides when using =', 20, + 'foobar%=test%=baz', 'foobar test baz') + statusline_test('should have equal spaces even with longer right side when using =', 20, + 'a%=test%=longtext', 'a test longtext') + statusline_test('should handle an empty left side when using ==', 20, + '%=test%=baz', ' test baz') + statusline_test('should handle an empty right side when using ==', 20, + 'foobar%=test%=', 'foobar test ') + statusline_test('should handle consecutive empty ==', 20, + '%=%=test%=', ' test ') + statusline_test('should handle an = alone', 20, + '%=', ' ') + statusline_test('should right align text when it is alone with =', 20, + '%=foo', ' foo') + statusline_test('should left align text when it is alone with =', 20, + 'foo%=', 'foo ') + + statusline_test('should approximately center text when using %=text%=', 21, + 'abc%=neovim%=def', 'abc neovim def') + statusline_test('should completely fill the buffer when using %=text%=', 21, + 'abc%=neo_vim%=def', 'abc neo_vim def') + statusline_test('should have equal spaces even with non-equal sides when using =', 21, + 'foobar%=test%=baz', 'foobar test baz') + statusline_test('should have equal spaces even with longer right side when using =', 21, + 'a%=test%=longtext', 'a test longtext') + statusline_test('should handle an empty left side when using ==', 21, + '%=test%=baz', ' test baz') + statusline_test('should handle an empty right side when using ==', 21, + 'foobar%=test%=', 'foobar test ') + + statusline_test('should quadrant the text when using 3 %=', 40, + 'abcd%=n%=eovim%=ef', 'abcd n eovim ef') + statusline_test('should work well with %t', 40, + '%t%=right_aligned', 'buffer_spec.lua right_aligned', + {file_name='test/unit/buffer_spec.lua'}) + statusline_test('should work well with %t and regular text', 40, + 'l%=m_l %t m_r%=r', 'l m_l buffer_spec.lua m_r r', + {file_name='test/unit/buffer_spec.lua'}) + statusline_test('should work well with %=, %t, %L, and %l', 40, + '%t %= %L %= %l', 'buffer_spec.lua 1 0', + {file_name='test/unit/buffer_spec.lua'}) + + statusline_test('should quadrant the text when using 3 %=', 41, + 'abcd%=n%=eovim%=ef', 'abcd n eovim ef') + statusline_test('should work well with %t', 41, + '%t%=right_aligned', 'buffer_spec.lua right_aligned', + {file_name='test/unit/buffer_spec.lua'}) + statusline_test('should work well with %t and regular text', 41, + 'l%=m_l %t m_r%=r', 'l m_l buffer_spec.lua m_r r', + {file_name='test/unit/buffer_spec.lua'}) + statusline_test('should work well with %=, %t, %L, and %l', 41, + '%t %= %L %= %l', 'buffer_spec.lua 1 0', + {file_name='test/unit/buffer_spec.lua'}) + + statusline_test('should work with 10 %=', 50, + 'aaaa%=b%=c%=d%=e%=fg%=hi%=jk%=lmnop%=qrstuv%=wxyz', + 'aaaa b c d e fg hi jk lmnop qrstuv wxyz') + + -- maximum stl item testing + statusline_test('should handle a much larger amount of = than buffer locations', 20, + ('%='):rep(STL_MAX_ITEM - 1), + ' ') -- Should be fine, because within limit + statusline_test('should handle a much larger amount of = than stl max item', 20, + ('%='):rep(STL_MAX_ITEM + 1), + ' E541') -- Should show the VIM error + statusline_test('should handle many extra characters', 20, + 'a' .. ('a'):rep(STL_MAX_ITEM * 4), + '<aaaaaaaaaaaaaaaaaaa') -- Does not show the error because there are no items + statusline_test('should handle almost maximum of characters and flags', 20, + 'a' .. ('%=a'):rep(STL_MAX_ITEM - 1), + 'a<aaaaaaaaaaaaaaaaaa') -- Should not show the VIM error + statusline_test('should handle many extra characters and flags', 20, + 'a' .. ('%=a'):rep(STL_MAX_ITEM), + 'a<aaaaaaaaaaaaa E541') -- Should show the VIM error + statusline_test('should handle many extra characters and flags', 20, + 'a' .. ('%=a'):rep(STL_MAX_ITEM * 2), + 'a<aaaaaaaaaaaaa E541') -- Should show the VIM error + statusline_test('should handle many extra characters and flags with truncation', 20, + 'aaa%<' .. ('%=a'):rep(STL_MAX_ITEM), + 'aaa<aaaaaaaaaaa E541') -- Should show the VIM error + statusline_test('should handle many characters and flags before and after truncation', 20, + 'a%=a%=a%<' .. ('%=a'):rep(STL_MAX_ITEM), + 'aaa<aaaaaaaaaaa E541') -- Should show the VIM error + + + -- multi-byte testing + statusline_test('should handle multibyte characters', 10, + 'Ĉ%=x', 'Ĉ x', + {expected_byte_length=11}) + statusline_test('should handle multibyte characters and different fillchars', 10, + 'Ä„%=mid%=end', 'Ä„@mid@@end', + {fillchar=('@'):byte(), expected_byte_length=11}) - end) end) end) diff --git a/test/unit/eval/encode_spec.lua b/test/unit/eval/encode_spec.lua index f151a191fb..98fc8305e0 100644 --- a/test/unit/eval/encode_spec.lua +++ b/test/unit/eval/encode_spec.lua @@ -27,74 +27,74 @@ describe('encode_list_write()', function() it('writes ASCII string literal with printable characters', function() local l = list() eq(0, encode_list_write(l, 'abc')) - eq({[type_key]=list_type, 'abc'}, lst2tbl(l)) + eq({'abc'}, lst2tbl(l)) end) it('writes string starting with NL', function() local l = list() eq(0, encode_list_write(l, '\nabc')) - eq({[type_key]=list_type, null_string, 'abc'}, lst2tbl(l)) + eq({null_string, 'abc'}, lst2tbl(l)) end) it('writes string starting with NL twice', function() local l = list() eq(0, encode_list_write(l, '\nabc')) - eq({[type_key]=list_type, null_string, 'abc'}, lst2tbl(l)) + eq({null_string, 'abc'}, lst2tbl(l)) eq(0, encode_list_write(l, '\nabc')) - eq({[type_key]=list_type, null_string, 'abc', 'abc'}, lst2tbl(l)) + eq({null_string, 'abc', 'abc'}, lst2tbl(l)) end) it('writes string ending with NL', function() local l = list() eq(0, encode_list_write(l, 'abc\n')) - eq({[type_key]=list_type, 'abc', null_string}, lst2tbl(l)) + eq({'abc', null_string}, lst2tbl(l)) end) it('writes string ending with NL twice', function() local l = list() eq(0, encode_list_write(l, 'abc\n')) - eq({[type_key]=list_type, 'abc', null_string}, lst2tbl(l)) + eq({'abc', null_string}, lst2tbl(l)) eq(0, encode_list_write(l, 'abc\n')) - eq({[type_key]=list_type, 'abc', 'abc', null_string}, lst2tbl(l)) + eq({'abc', 'abc', null_string}, lst2tbl(l)) end) it('writes string starting, ending and containing NL twice', function() local l = list() eq(0, encode_list_write(l, '\na\nb\n')) - eq({[type_key]=list_type, null_string, 'a', 'b', null_string}, lst2tbl(l)) + eq({null_string, 'a', 'b', null_string}, lst2tbl(l)) eq(0, encode_list_write(l, '\na\nb\n')) - eq({[type_key]=list_type, null_string, 'a', 'b', null_string, 'a', 'b', null_string}, lst2tbl(l)) + eq({null_string, 'a', 'b', null_string, 'a', 'b', null_string}, lst2tbl(l)) end) it('writes string starting, ending and containing NUL with NL between twice', function() local l = list() eq(0, encode_list_write(l, '\0\n\0\n\0')) - eq({[type_key]=list_type, '\n', '\n', '\n'}, lst2tbl(l)) + eq({'\n', '\n', '\n'}, lst2tbl(l)) eq(0, encode_list_write(l, '\0\n\0\n\0')) - eq({[type_key]=list_type, '\n', '\n', '\n\n', '\n', '\n'}, lst2tbl(l)) + eq({'\n', '\n', '\n\n', '\n', '\n'}, lst2tbl(l)) end) it('writes string starting, ending and containing NL with NUL between twice', function() local l = list() eq(0, encode_list_write(l, '\n\0\n\0\n')) - eq({[type_key]=list_type, null_string, '\n', '\n', null_string}, lst2tbl(l)) + eq({null_string, '\n', '\n', null_string}, lst2tbl(l)) eq(0, encode_list_write(l, '\n\0\n\0\n')) - eq({[type_key]=list_type, null_string, '\n', '\n', null_string, '\n', '\n', null_string}, lst2tbl(l)) + eq({null_string, '\n', '\n', null_string, '\n', '\n', null_string}, lst2tbl(l)) end) it('writes string containing a single NL twice', function() local l = list() eq(0, encode_list_write(l, '\n')) - eq({[type_key]=list_type, null_string, null_string}, lst2tbl(l)) + eq({null_string, null_string}, lst2tbl(l)) eq(0, encode_list_write(l, '\n')) - eq({[type_key]=list_type, null_string, null_string, null_string}, lst2tbl(l)) + eq({null_string, null_string, null_string}, lst2tbl(l)) end) it('writes string containing a few NLs twice', function() local l = list() eq(0, encode_list_write(l, '\n\n\n')) - eq({[type_key]=list_type, null_string, null_string, null_string, null_string}, lst2tbl(l)) + eq({null_string, null_string, null_string, null_string}, lst2tbl(l)) eq(0, encode_list_write(l, '\n\n\n')) - eq({[type_key]=list_type, null_string, null_string, null_string, null_string, null_string, null_string, null_string}, lst2tbl(l)) + eq({null_string, null_string, null_string, null_string, null_string, null_string, null_string}, lst2tbl(l)) end) end) diff --git a/test/unit/eval/helpers.lua b/test/unit/eval/helpers.lua index 2367f03e0d..45fbf8da5c 100644 --- a/test/unit/eval/helpers.lua +++ b/test/unit/eval/helpers.lua @@ -11,6 +11,12 @@ local null_string = {[true]='NULL string'} local null_list = {[true]='NULL list'} local type_key = {[true]='type key'} local list_type = {[true]='list type'} +local dict_type = {[true]='dict type'} +local func_type = {[true]='func type'} +local int_type = {[true]='int type'} +local flt_type = {[true]='flt type'} + +local nil_value = {[true]='nil'} local function list(...) local ret = ffi.gc(eval.list_alloc(), eval.list_unref) @@ -37,7 +43,53 @@ local function list(...) return ret end -local lst2tbl = function(l) +local special_tab = { + [eval.kSpecialVarFalse] = false, + [eval.kSpecialVarNull] = nil_value, + [eval.kSpecialVarTrue] = true, +} + +local lst2tbl +local dct2tbl + +local typvalt2lua_tab + +typvalt2lua_tab = { + [tonumber(eval.VAR_SPECIAL)] = function(t) + return special_tab[t.vval.v_special] + end, + [tonumber(eval.VAR_NUMBER)] = function(t) + return {[type_key]=int_type, value=tonumber(t.vval.v_number)} + end, + [tonumber(eval.VAR_FLOAT)] = function(t) + return tonumber(t.vval.v_float) + end, + [tonumber(eval.VAR_STRING)] = function(t) + local str = t.vval.v_string + if str == nil then + return null_string + else + return ffi.string(str) + end + end, + [tonumber(eval.VAR_LIST)] = function(t) + return lst2tbl(t.vval.v_list) + end, + [tonumber(eval.VAR_DICT)] = function(t) + return dct2tbl(t.vval.v_dict) + end, + [tonumber(eval.VAR_FUNC)] = function(t) + return {[type_key]=func_type, value=typvalt2lua_tab[eval.VAR_STRING](t)} + end, +} + +local typvalt2lua = function(t) + return ((typvalt2lua_tab[tonumber(t.v_type)] or function(t_inner) + assert(false, 'Converting ' .. tonumber(t_inner.v_type) .. ' was not implemented yet') + end)(t)) +end + +lst2tbl = function(l) local ret = {[type_key]=list_type} if l == nil then return ret @@ -45,28 +97,119 @@ local lst2tbl = function(l) local li = l.lv_first -- (listitem_T *) NULL is equal to nil, but yet it is not false. while li ~= nil do - local typ = li.li_tv.v_type - if typ == eval.VAR_STRING then - local str = li.li_tv.vval.v_string - if str == nil then - ret[#ret + 1] = null_string - else - ret[#ret + 1] = ffi.string(str) + ret[#ret + 1] = typvalt2lua(li.li_tv) + li = li.li_next + end + if ret[1] then + ret[type_key] = nil + end + return ret +end + +dct2tbl = function(d) + local ret = {d=d} + assert(false, 'Converting dictionaries is not implemented yet') + return ret +end + +local lua2typvalt + +local typvalt = function(typ, vval) + if type(typ) == 'string' then + typ = eval[typ] + end + return ffi.gc(ffi.new('typval_T', {v_type=typ, vval=vval}), eval.clear_tv) +end + +local lua2typvalt_type_tab = { + [int_type] = function(l, _) + return typvalt(eval.VAR_NUMBER, {v_number=l.value}) + end, + [flt_type] = function(l, processed) + return lua2typvalt(l.value, processed) + end, + [list_type] = function(l, processed) + if processed[l] then + processed[l].lv_refcount = processed[l].lv_refcount + 1 + return typvalt(eval.VAR_LIST, {v_list=processed[l]}) + end + local lst = eval.list_alloc() + lst.lv_refcount = 1 + processed[l] = lst + local ret = typvalt(eval.VAR_LIST, {v_list=lst}) + for i = 1, #l do + local item_tv = ffi.gc(lua2typvalt(l[i], processed), nil) + eval.list_append_tv(lst, item_tv) + eval.clear_tv(item_tv) + end + return ret + end, + [dict_type] = function(l, processed) + if processed[l] then + processed[l].dv_refcount = processed[l].dv_refcount + 1 + return typvalt(eval.VAR_DICT, {v_dict=processed[l]}) + end + local dct = eval.dict_alloc() + dct.dv_refcount = 1 + processed[l] = dct + local ret = typvalt(eval.VAR_DICT, {v_dict=dct}) + for k, v in pairs(l) do + if type(k) == 'string' then + local di = eval.dictitem_alloc(to_cstr(k)) + local val_tv = ffi.gc(lua2typvalt(v, processed), nil) + eval.copy_tv(val_tv, di.di_tv) + eval.clear_tv(val_tv) + eval.dict_add(dct, di) end + end + return ret + end, +} + +lua2typvalt = function(l, processed) + processed = processed or {} + if l == nil or l == nil_value then + return typvalt(eval.VAR_SPECIAL, {v_special=eval.kSpecialVarNull}) + elseif type(l) == 'table' then + if l[type_key] then + return lua2typvalt_type_tab[l[type_key]](l, processed) else - assert(false, 'Not implemented yet') + if l[1] then + return lua2typvalt_type_tab[list_type](l, processed) + else + return lua2typvalt_type_tab[dict_type](l, processed) + end end - li = li.li_next + elseif type(l) == 'number' then + return typvalt(eval.VAR_FLOAT, {v_float=l}) + elseif type(l) == 'boolean' then + return typvalt(eval.VAR_SPECIAL, { + v_special=(l and eval.kSpecialVarTrue or eval.kSpecialVarFalse) + }) + elseif type(l) == 'string' then + return typvalt(eval.VAR_STRING, {v_string=eval.xmemdupz(to_cstr(l), #l)}) end - return ret end return { null_string=null_string, null_list=null_list, list_type=list_type, + dict_type=dict_type, + func_type=func_type, + int_type=int_type, + flt_type=flt_type, + + nil_value=nil_value, + type_key=type_key, list=list, lst2tbl=lst2tbl, + dct2tbl=dct2tbl, + + lua2typvalt=lua2typvalt, + typvalt2lua=typvalt2lua, + + typvalt=typvalt, } diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua index 426ae2d9e0..91da459393 100644 --- a/test/unit/helpers.lua +++ b/test/unit/helpers.lua @@ -1,9 +1,13 @@ -local assert = require('luassert') local ffi = require('ffi') local formatc = require('test.unit.formatc') local Set = require('test.unit.set') local Preprocess = require('test.unit.preprocess') local Paths = require('test.config.paths') +local global_helpers = require('test.helpers') + +local neq = global_helpers.neq +local eq = global_helpers.eq +local ok = global_helpers.ok -- add some standard header locations for _, p in ipairs(Paths.include_paths) do @@ -31,7 +35,8 @@ local function filter_complex_blocks(body) if not (string.find(line, "(^)", 1, true) ~= nil or string.find(line, "_ISwupper", 1, true) or string.find(line, "msgpack_zone_push_finalizer") - or string.find(line, "msgpack_unpacker_reserve_buffer")) then + or string.find(line, "msgpack_unpacker_reserve_buffer") + or string.find(line, "inline _Bool")) then result[#result + 1] = line end end @@ -153,12 +158,9 @@ return { cimport = cimport, cppimport = cppimport, internalize = internalize, - eq = function(expected, actual) - return assert.are.same(expected, actual) - end, - neq = function(expected, actual) - return assert.are_not.same(expected, actual) - end, + ok = ok, + eq = eq, + neq = neq, ffi = ffi, lib = libnvim, cstr = cstr, diff --git a/test/unit/os/fileio_spec.lua b/test/unit/os/fileio_spec.lua new file mode 100644 index 0000000000..5358022422 --- /dev/null +++ b/test/unit/os/fileio_spec.lua @@ -0,0 +1,365 @@ +local lfs = require('lfs') + +local helpers = require('test.unit.helpers') + +local eq = helpers.eq +local ffi = helpers.ffi +local cimport = helpers.cimport + +local m = cimport('./src/nvim/os/fileio.h') + +local fcontents = '' +for i = 0, 255 do + fcontents = fcontents .. (i == 0 and '\0' or ('%c'):format(i)) +end +fcontents = fcontents:rep(16) + +local dir = 'Xtest-unit-file_spec.d' +local file1 = dir .. '/file1.dat' +local file2 = dir .. '/file2.dat' +local linkf = dir .. '/file.lnk' +local linkb = dir .. '/broken.lnk' +local filec = dir .. '/created-file.dat' + +before_each(function() + lfs.mkdir(dir); + + local f1 = io.open(file1, 'w') + f1:write(fcontents) + f1:close() + + local f2 = io.open(file2, 'w') + f2:write(fcontents) + f2:close() + + lfs.link('file1.dat', linkf, true) + lfs.link('broken.dat', linkb, true) +end) + +after_each(function() + os.remove(file1) + os.remove(file2) + os.remove(linkf) + os.remove(linkb) + os.remove(filec) + lfs.rmdir(dir) +end) + +local function file_open(fname, flags, mode) + local ret2 = ffi.new('FileDescriptor') + local ret1 = m.file_open(ret2, fname, flags, mode) + return ret1, ret2 +end + +local function file_open_new(fname, flags, mode) + local ret1 = ffi.new('int[?]', 1, {0}) + local ret2 = ffi.gc(m.file_open_new(ret1, fname, flags, mode), nil) + return ret1[0], ret2 +end + +local function file_write(fp, buf) + return m.file_write(fp, buf, #buf) +end + +local function file_read(fp, size) + local buf = nil + if size == nil then + size = 0 + else + -- For some reason if length of NUL-bytes-string is the same as `char[?]` + -- size luajit garbage collector crashes. But it does not do so in + -- os_read[v] tests in os/fs_spec.lua. + buf = ffi.new('char[?]', size + 1, ('\0'):rep(size)) + end + local ret1 = m.file_read(fp, buf, size) + local ret2 = '' + if buf ~= nil then + ret2 = ffi.string(buf, size) + end + return ret1, ret2 +end + +local function file_fsync(fp) + return m.file_fsync(fp) +end + +local function file_skip(fp, size) + return m.file_skip(fp, size) +end + +describe('file_open', function() + it('can create a rwx------ file with kFileCreate', function() + local err, fp = file_open(filec, m.kFileCreate, 448) + eq(0, err) + local attrs = lfs.attributes(filec) + eq('rwx------', attrs.permissions) + eq(0, m.file_close(fp)) + end) + + it('can create a rw------- file with kFileCreate', function() + local err, fp = file_open(filec, m.kFileCreate, 384) + eq(0, err) + local attrs = lfs.attributes(filec) + eq('rw-------', attrs.permissions) + eq(0, m.file_close(fp)) + end) + + it('can create a rwx------ file with kFileCreateOnly', function() + local err, fp = file_open(filec, m.kFileCreateOnly, 448) + eq(0, err) + local attrs = lfs.attributes(filec) + eq('rwx------', attrs.permissions) + eq(0, m.file_close(fp)) + end) + + it('can create a rw------- file with kFileCreateOnly', function() + local err, fp = file_open(filec, m.kFileCreateOnly, 384) + eq(0, err) + local attrs = lfs.attributes(filec) + eq('rw-------', attrs.permissions) + eq(0, m.file_close(fp)) + end) + + it('fails to open an existing file with kFileCreateOnly', function() + local err, _ = file_open(file1, m.kFileCreateOnly, 384) + eq(m.UV_EEXIST, err) + end) + + it('fails to open an symlink with kFileNoSymlink', function() + local err, _ = file_open(linkf, m.kFileNoSymlink, 384) + -- err is UV_EMLINK in FreeBSD, but if I use `ok(err == m.UV_ELOOP or err == + -- m.UV_EMLINK)`, then I loose the ability to see actual `err` value. + if err ~= m.UV_ELOOP then eq(m.UV_EMLINK, err) end + end) + + it('can open an existing file write-only with kFileCreate', function() + local err, fp = file_open(file1, m.kFileCreate, 384) + eq(0, err) + eq(true, fp.wr) + eq(0, m.file_close(fp)) + end) + + it('can open an existing file read-only with zero', function() + local err, fp = file_open(file1, 0, 384) + eq(0, err) + eq(false, fp.wr) + eq(0, m.file_close(fp)) + end) + + it('can open an existing file read-only with kFileReadOnly', function() + local err, fp = file_open(file1, m.kFileReadOnly, 384) + eq(0, err) + eq(false, fp.wr) + eq(0, m.file_close(fp)) + end) + + it('can open an existing file read-only with kFileNoSymlink', function() + local err, fp = file_open(file1, m.kFileNoSymlink, 384) + eq(0, err) + eq(false, fp.wr) + eq(0, m.file_close(fp)) + end) + + it('can truncate an existing file with kFileTruncate', function() + local err, fp = file_open(file1, m.kFileTruncate, 384) + eq(0, err) + eq(true, fp.wr) + eq(0, m.file_close(fp)) + local attrs = lfs.attributes(file1) + eq(0, attrs.size) + end) + + it('can open an existing file write-only with kFileWriteOnly', function() + local err, fp = file_open(file1, m.kFileWriteOnly, 384) + eq(0, err) + eq(true, fp.wr) + eq(0, m.file_close(fp)) + local attrs = lfs.attributes(file1) + eq(4096, attrs.size) + end) + + it('fails to create a file with just kFileWriteOnly', function() + local err, _ = file_open(filec, m.kFileWriteOnly, 384) + eq(m.UV_ENOENT, err) + local attrs = lfs.attributes(filec) + eq(nil, attrs) + end) + + it('can truncate an existing file with kFileTruncate when opening a symlink', + function() + local err, fp = file_open(linkf, m.kFileTruncate, 384) + eq(0, err) + eq(true, fp.wr) + eq(0, m.file_close(fp)) + local attrs = lfs.attributes(file1) + eq(0, attrs.size) + end) + + it('fails to open a directory write-only', function() + local err, _ = file_open(dir, m.kFileWriteOnly, 384) + eq(m.UV_EISDIR, err) + end) + + it('fails to open a broken symbolic link write-only', function() + local err, _ = file_open(linkb, m.kFileWriteOnly, 384) + eq(m.UV_ENOENT, err) + end) + + it('fails to open a broken symbolic link read-only', function() + local err, _ = file_open(linkb, m.kFileReadOnly, 384) + eq(m.UV_ENOENT, err) + end) +end) + +describe('file_open_new', function() + it('can open a file read-only', function() + local err, fp = file_open_new(file1, 0, 384) + eq(0, err) + eq(false, fp.wr) + eq(0, m.file_free(fp)) + end) + + it('fails to open an existing file with kFileCreateOnly', function() + local err, fp = file_open_new(file1, m.kFileCreateOnly, 384) + eq(m.UV_EEXIST, err) + eq(nil, fp) + end) +end) + +-- file_close is called above, so it is not tested directly + +describe('file_fsync', function() + it('can flush writes to disk', function() + local err, fp = file_open(filec, m.kFileCreateOnly, 384) + eq(0, file_fsync(fp)) + eq(0, err) + eq(0, lfs.attributes(filec).size) + local wsize = file_write(fp, 'test') + eq(4, wsize) + eq(0, lfs.attributes(filec).size) + eq(0, file_fsync(fp)) + eq(wsize, lfs.attributes(filec).size) + eq(0, m.file_close(fp)) + end) +end) + +describe('file_read', function() + it('can read small chunks of input until eof', function() + local err, fp = file_open(file1, 0, 384) + eq(0, err) + eq(false, fp.wr) + local shift = 0 + while shift < #fcontents do + local size = 3 + local exp_err = size + local exp_s = fcontents:sub(shift + 1, shift + size) + if shift + size >= #fcontents then + exp_err = #fcontents - shift + exp_s = (fcontents:sub(shift + 1, shift + size) + .. (('\0'):rep(size - exp_err))) + end + eq({exp_err, exp_s}, {file_read(fp, size)}) + shift = shift + size + end + eq(0, m.file_close(fp)) + end) + + it('can read the whole file at once', function() + local err, fp = file_open(file1, 0, 384) + eq(0, err) + eq(false, fp.wr) + eq({#fcontents, fcontents}, {file_read(fp, #fcontents)}) + eq({0, ('\0'):rep(#fcontents)}, {file_read(fp, #fcontents)}) + eq(0, m.file_close(fp)) + end) + + it('can read more then 1024 bytes after reading a small chunk', function() + local err, fp = file_open(file1, 0, 384) + eq(0, err) + eq(false, fp.wr) + eq({5, fcontents:sub(1, 5)}, {file_read(fp, 5)}) + eq({#fcontents - 5, fcontents:sub(6) .. (('\0'):rep(5))}, + {file_read(fp, #fcontents)}) + eq(0, m.file_close(fp)) + end) + + it('can read file by 768-byte-chunks', function() + local err, fp = file_open(file1, 0, 384) + eq(0, err) + eq(false, fp.wr) + local shift = 0 + while shift < #fcontents do + local size = 768 + local exp_err = size + local exp_s = fcontents:sub(shift + 1, shift + size) + if shift + size >= #fcontents then + exp_err = #fcontents - shift + exp_s = (fcontents:sub(shift + 1, shift + size) + .. (('\0'):rep(size - exp_err))) + end + eq({exp_err, exp_s}, {file_read(fp, size)}) + shift = shift + size + end + eq(0, m.file_close(fp)) + end) +end) + +describe('file_write', function() + it('can write the whole file at once', function() + local err, fp = file_open(filec, m.kFileCreateOnly, 384) + eq(0, err) + eq(true, fp.wr) + local wr = file_write(fp, fcontents) + eq(#fcontents, wr) + eq(0, m.file_close(fp)) + eq(wr, lfs.attributes(filec).size) + eq(fcontents, io.open(filec):read('*a')) + end) + + it('can write the whole file by small chunks', function() + local err, fp = file_open(filec, m.kFileCreateOnly, 384) + eq(0, err) + eq(true, fp.wr) + local shift = 0 + while shift < #fcontents do + local size = 3 + local s = fcontents:sub(shift + 1, shift + size) + local wr = file_write(fp, s) + eq(wr, #s) + shift = shift + size + end + eq(0, m.file_close(fp)) + eq(#fcontents, lfs.attributes(filec).size) + eq(fcontents, io.open(filec):read('*a')) + end) + + it('can write the whole file by 768-byte-chunks', function() + local err, fp = file_open(filec, m.kFileCreateOnly, 384) + eq(0, err) + eq(true, fp.wr) + local shift = 0 + while shift < #fcontents do + local size = 768 + local s = fcontents:sub(shift + 1, shift + size) + local wr = file_write(fp, s) + eq(wr, #s) + shift = shift + size + end + eq(0, m.file_close(fp)) + eq(#fcontents, lfs.attributes(filec).size) + eq(fcontents, io.open(filec):read('*a')) + end) +end) + +describe('file_skip', function() + it('can skip 3 bytes', function() + local err, fp = file_open(file1, 0, 384) + eq(0, err) + eq(false, fp.wr) + eq(3, file_skip(fp, 3)) + local rd, s = file_read(fp, 3) + eq(3, rd) + eq(fcontents:sub(4, 6), s) + eq(0, m.file_close(fp)) + end) +end) diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua index 857a5001f1..7e7eddb6fc 100644 --- a/test/unit/os/fs_spec.lua +++ b/test/unit/os/fs_spec.lua @@ -6,6 +6,7 @@ local helpers = require('test.unit.helpers') local cimport = helpers.cimport local cppimport = helpers.cppimport local internalize = helpers.internalize +local ok = helpers.ok local eq = helpers.eq local neq = helpers.neq local ffi = helpers.ffi @@ -27,6 +28,12 @@ cppimport('sys/stat.h') cppimport('fcntl.h') cppimport('uv-errno.h') +local s = '' +for i = 0, 255 do + s = s .. (i == 0 and '\0' or ('%c'):format(i)) +end +local fcontents = s:rep(16) + local buffer = "" local directory = nil local absolute_executable = nil @@ -68,6 +75,8 @@ describe('fs function', function() io.open('unit-test-directory/test_2.file', 'w').close() lfs.link('test.file', 'unit-test-directory/test_link.file', true) + + lfs.link('non_existing_file.file', 'unit-test-directory/test_broken_link.file', true) -- Since the tests are executed, they are called by an executable. We use -- that executable for several asserts. absolute_executable = arg[0] @@ -81,6 +90,7 @@ describe('fs function', function() os.remove('unit-test-directory/test_2.file') os.remove('unit-test-directory/test_link.file') os.remove('unit-test-directory/test_hlink.file') + os.remove('unit-test-directory/test_broken_link.file') lfs.rmdir('unit-test-directory') end) @@ -150,11 +160,11 @@ describe('fs function', function() local function os_can_exe(name) local buf = ffi.new('char *[1]') buf[0] = NULL - local ok = fs.os_can_exe(to_cstr(name), buf, true) + local ce_ret = fs.os_can_exe(to_cstr(name), buf, true) -- When os_can_exe returns true, it must set the path. -- When it returns false, the path must be NULL. - if ok then + if ce_ret then neq(NULL, buf[0]) return internalize(buf[0]) else @@ -356,8 +366,8 @@ describe('fs function', function() end) describe('file operations', function() - local function os_file_exists(filename) - return fs.os_file_exists((to_cstr(filename))) + local function os_path_exists(filename) + return fs.os_path_exists((to_cstr(filename))) end local function os_rename(path, new_path) return fs.os_rename((to_cstr(path)), (to_cstr(new_path))) @@ -368,14 +378,67 @@ describe('fs function', function() local function os_open(path, flags, mode) return fs.os_open((to_cstr(path)), flags, mode) end + local function os_close(fd) + return fs.os_close(fd) + end + -- For some reason if length of NUL-bytes-string is the same as `char[?]` + -- size luajit crashes. Though it does not do so in this test suite, better + -- be cautios and allocate more elements then needed. I only did this to + -- strings. + local function os_read(fd, size) + local buf = nil + if size == nil then + size = 0 + else + buf = ffi.new('char[?]', size + 1, ('\0'):rep(size)) + end + local eof = ffi.new('bool[?]', 1, {true}) + local ret2 = fs.os_read(fd, eof, buf, size) + local ret1 = eof[0] + local ret3 = '' + if buf ~= nil then + ret3 = ffi.string(buf, size) + end + return ret1, ret2, ret3 + end + local function os_readv(fd, sizes) + local bufs = {} + for i, size in ipairs(sizes) do + bufs[i] = { + iov_base=ffi.new('char[?]', size + 1, ('\0'):rep(size)), + iov_len=size, + } + end + local iov = ffi.new('struct iovec[?]', #sizes, bufs) + local eof = ffi.new('bool[?]', 1, {true}) + local ret2 = fs.os_readv(fd, eof, iov, #sizes) + local ret1 = eof[0] + local ret3 = {} + for i = 1,#sizes do + -- Warning: iov may not be used. + ret3[i] = ffi.string(bufs[i].iov_base, bufs[i].iov_len) + end + return ret1, ret2, ret3 + end + local function os_write(fd, data) + return fs.os_write(fd, data, data and #data or 0) + end - describe('os_file_exists', function() + describe('os_path_exists', function() it('returns false when given a non-existing file', function() - eq(false, (os_file_exists('non-existing-file'))) + eq(false, (os_path_exists('non-existing-file'))) end) it('returns true when given an existing file', function() - eq(true, (os_file_exists('unit-test-directory/test.file'))) + eq(true, (os_path_exists('unit-test-directory/test.file'))) + end) + + it('returns false when given a broken symlink', function() + eq(false, (os_path_exists('unit-test-directory/test_broken_link.file'))) + end) + + it('returns true when given a directory', function() + eq(true, (os_path_exists('unit-test-directory'))) end) end) @@ -385,8 +448,8 @@ describe('fs function', function() it('can rename file if destination file does not exist', function() eq(OK, (os_rename(test, not_exist))) - eq(false, (os_file_exists(test))) - eq(true, (os_file_exists(not_exist))) + eq(false, (os_path_exists(test))) + eq(true, (os_path_exists(not_exist))) eq(OK, (os_rename(not_exist, test))) -- restore test file end) @@ -402,8 +465,8 @@ describe('fs function', function() file:close() eq(OK, (os_rename(other, test))) - eq(false, (os_file_exists(other))) - eq(true, (os_file_exists(test))) + eq(false, (os_path_exists(other))) + eq(true, (os_path_exists(test))) file = io.open(test, 'r') eq('other', (file:read('*all'))) file:close() @@ -432,30 +495,34 @@ describe('fs function', function() end) describe('os_open', function() + local new_file = 'test_new_file' + local existing_file = 'unit-test-directory/test_existing.file' + before_each(function() - io.open('unit-test-directory/test_existing.file', 'w').close() + (io.open(existing_file, 'w')):close() end) after_each(function() - os.remove('unit-test-directory/test_existing.file') - os.remove('test_new_file') + os.remove(existing_file) + os.remove(new_file) end) - local new_file = 'test_new_file' - local existing_file = 'unit-test-directory/test_existing.file' - it('returns UV_ENOENT for O_RDWR on a non-existing file', function() eq(ffi.C.UV_ENOENT, (os_open('non-existing-file', ffi.C.kO_RDWR, 0))) end) - it('returns non-negative for O_CREAT on a non-existing file', function() + it('returns non-negative for O_CREAT on a non-existing file which then can be closed', function() assert_file_does_not_exist(new_file) - assert.is_true(0 <= (os_open(new_file, ffi.C.kO_CREAT, 0))) + local fd = os_open(new_file, ffi.C.kO_CREAT, 0) + assert.is_true(0 <= fd) + eq(0, os_close(fd)) end) - it('returns non-negative for O_CREAT on a existing file', function() + it('returns non-negative for O_CREAT on a existing file which then can be closed', function() assert_file_exists(existing_file) - assert.is_true(0 <= (os_open(existing_file, ffi.C.kO_CREAT, 0))) + local fd = os_open(existing_file, ffi.C.kO_CREAT, 0) + assert.is_true(0 <= fd) + eq(0, os_close(fd)) end) it('returns UV_EEXIST for O_CREAT|O_EXCL on a existing file', function() @@ -463,24 +530,181 @@ describe('fs function', function() eq(ffi.C.kUV_EEXIST, (os_open(existing_file, (bit.bor(ffi.C.kO_CREAT, ffi.C.kO_EXCL)), 0))) end) - it('sets `rwx` permissions for O_CREAT 700', function() + it('sets `rwx` permissions for O_CREAT 700 which then can be closed', function() assert_file_does_not_exist(new_file) --create the file - os_open(new_file, ffi.C.kO_CREAT, tonumber("700", 8)) + local fd = os_open(new_file, ffi.C.kO_CREAT, tonumber("700", 8)) --verify permissions eq('rwx------', lfs.attributes(new_file)['permissions']) + eq(0, os_close(fd)) end) - it('sets `rw` permissions for O_CREAT 600', function() + it('sets `rw` permissions for O_CREAT 600 which then can be closed', function() assert_file_does_not_exist(new_file) --create the file - os_open(new_file, ffi.C.kO_CREAT, tonumber("600", 8)) + local fd = os_open(new_file, ffi.C.kO_CREAT, tonumber("600", 8)) --verify permissions eq('rw-------', lfs.attributes(new_file)['permissions']) + eq(0, os_close(fd)) + end) + + it('returns a non-negative file descriptor for an existing file which then can be closed', function() + local fd = os_open(existing_file, ffi.C.kO_RDWR, 0) + assert.is_true(0 <= fd) + eq(0, os_close(fd)) + end) + end) + + describe('os_close', function() + it('returns EBADF for negative file descriptors', function() + eq(ffi.C.UV_EBADF, os_close(-1)) + eq(ffi.C.UV_EBADF, os_close(-1000)) + end) + end) + + describe('os_read', function() + local file = 'test-unit-os-fs_spec-os_read.dat' + + before_each(function() + local f = io.open(file, 'w') + f:write(fcontents) + f:close() + end) + + after_each(function() + os.remove(file) + end) + + it('can read zero bytes from a file', function() + local fd = os_open(file, ffi.C.kO_RDONLY, 0) + ok(fd >= 0) + eq({false, 0, ''}, {os_read(fd, nil)}) + eq({false, 0, ''}, {os_read(fd, 0)}) + eq(0, os_close(fd)) + end) + + it('can read from a file multiple times', function() + local fd = os_open(file, ffi.C.kO_RDONLY, 0) + ok(fd >= 0) + eq({false, 2, '\000\001'}, {os_read(fd, 2)}) + eq({false, 2, '\002\003'}, {os_read(fd, 2)}) + eq(0, os_close(fd)) + end) + + it('can read the whole file at once and then report eof', function() + local fd = os_open(file, ffi.C.kO_RDONLY, 0) + ok(fd >= 0) + eq({false, #fcontents, fcontents}, {os_read(fd, #fcontents)}) + eq({true, 0, ('\0'):rep(#fcontents)}, {os_read(fd, #fcontents)}) + eq(0, os_close(fd)) + end) + + it('can read the whole file in two calls, one partially', function() + local fd = os_open(file, ffi.C.kO_RDONLY, 0) + ok(fd >= 0) + eq({false, #fcontents * 3/4, fcontents:sub(1, #fcontents * 3/4)}, + {os_read(fd, #fcontents * 3/4)}) + eq({true, + (#fcontents * 1/4), + fcontents:sub(#fcontents * 3/4 + 1) .. ('\0'):rep(#fcontents * 2/4)}, + {os_read(fd, #fcontents * 3/4)}) + eq(0, os_close(fd)) + end) + end) + + describe('os_readv', function() + -- Function may be absent + if not pcall(function() return fs.os_readv end) then + return + end + local file = 'test-unit-os-fs_spec-os_readv.dat' + + before_each(function() + local f = io.open(file, 'w') + f:write(fcontents) + f:close() + end) + + after_each(function() + os.remove(file) + end) + + it('can read zero bytes from a file', function() + local fd = os_open(file, ffi.C.kO_RDONLY, 0) + ok(fd >= 0) + eq({false, 0, {}}, {os_readv(fd, {})}) + eq({false, 0, {'', '', ''}}, {os_readv(fd, {0, 0, 0})}) + eq(0, os_close(fd)) + end) + + it('can read from a file multiple times to a differently-sized buffers', function() + local fd = os_open(file, ffi.C.kO_RDONLY, 0) + ok(fd >= 0) + eq({false, 2, {'\000\001'}}, {os_readv(fd, {2})}) + eq({false, 5, {'\002\003', '\004\005\006'}}, {os_readv(fd, {2, 3})}) + eq(0, os_close(fd)) + end) + + it('can read the whole file at once and then report eof', function() + local fd = os_open(file, ffi.C.kO_RDONLY, 0) + ok(fd >= 0) + eq({false, + #fcontents, + {fcontents:sub(1, #fcontents * 1/4), + fcontents:sub(#fcontents * 1/4 + 1, #fcontents * 3/4), + fcontents:sub(#fcontents * 3/4 + 1, #fcontents * 15/16), + fcontents:sub(#fcontents * 15/16 + 1, #fcontents)}}, + {os_readv(fd, {#fcontents * 1/4, + #fcontents * 2/4, + #fcontents * 3/16, + #fcontents * 1/16})}) + eq({true, 0, {'\0'}}, {os_readv(fd, {1})}) + eq(0, os_close(fd)) + end) + + it('can read the whole file in two calls, one partially', function() + local fd = os_open(file, ffi.C.kO_RDONLY, 0) + ok(fd >= 0) + eq({false, #fcontents * 3/4, {fcontents:sub(1, #fcontents * 3/4)}}, + {os_readv(fd, {#fcontents * 3/4})}) + eq({true, + (#fcontents * 1/4), + {fcontents:sub(#fcontents * 3/4 + 1) .. ('\0'):rep(#fcontents * 2/4)}}, + {os_readv(fd, {#fcontents * 3/4})}) + eq(0, os_close(fd)) + end) + end) + + describe('os_write', function() + -- Function may be absent + local file = 'test-unit-os-fs_spec-os_write.dat' + + before_each(function() + local f = io.open(file, 'w') + f:write(fcontents) + f:close() + end) + + after_each(function() + os.remove(file) + end) + + it('can write zero bytes to a file', function() + local fd = os_open(file, ffi.C.kO_WRONLY, 0) + ok(fd >= 0) + eq(0, os_write(fd, '')) + eq(0, os_write(fd, nil)) + eq(fcontents, io.open(file, 'r'):read('*a')) + eq(0, os_close(fd)) end) - it('returns a non-negative file descriptor for an existing file', function() - assert.is_true(0 <= (os_open(existing_file, ffi.C.kO_RDWR, 0))) + it('can write some data to a file', function() + local fd = os_open(file, ffi.C.kO_WRONLY, 0) + ok(fd >= 0) + eq(3, os_write(fd, 'abc')) + eq(4, os_write(fd, ' def')) + eq('abc def' .. fcontents:sub(8), io.open(file, 'r'):read('*a')) + eq(0, os_close(fd)) end) end) diff --git a/test/unit/os/shell_spec.lua b/test/unit/os/shell_spec.lua index 93103e4e8c..906f950308 100644 --- a/test/unit/os/shell_spec.lua +++ b/test/unit/os/shell_spec.lua @@ -30,10 +30,6 @@ describe('shell functions', function() cimported.p_shcf = to_cstr('-c') end) - teardown(function() - cimported.event_teardown() - end) - local function shell_build_argv(cmd, extra_args) local res = cimported.shell_build_argv( cmd and to_cstr(cmd), diff --git a/test/unit/strings_spec.lua b/test/unit/strings_spec.lua index e935d2af6a..0034670ee8 100644 --- a/test/unit/strings_spec.lua +++ b/test/unit/strings_spec.lua @@ -8,6 +8,38 @@ local to_cstr = helpers.to_cstr local strings = cimport('stdlib.h', './src/nvim/strings.h', './src/nvim/memory.h') +describe('vim_strsave_escaped()', function() + local vim_strsave_escaped = function(s, chars) + local res = strings.vim_strsave_escaped(to_cstr(s), to_cstr(chars)) + local ret = ffi.string(res) + + -- Explicitly free memory so we are sure it is allocated: if it was not it + -- will crash. + strings.xfree(res) + return ret + end + + it('precedes by a backslash all chars from second argument', function() + eq([[\a\b\c\d]], vim_strsave_escaped('abcd','abcd')) + end) + + it('precedes by a backslash chars only from second argument', function() + eq([[\a\bcd]], vim_strsave_escaped('abcd','ab')) + end) + + it('returns a copy of passed string if second argument is empty', function() + eq('text \n text', vim_strsave_escaped('text \n text','')) + end) + + it('returns an empty string if first argument is empty string', function() + eq('', vim_strsave_escaped('','\r')) + end) + + it('returns a copy of passed string if it does not contain chars from 2nd argument', function() + eq('some text', vim_strsave_escaped('some text', 'a')) + end) +end) + describe('vim_strnsave_unquoted()', function() local vim_strnsave_unquoted = function(s, len) local res = strings.vim_strnsave_unquoted(to_cstr(s), len or #s) diff --git a/test/unit/tempfile_spec.lua b/test/unit/tempfile_spec.lua index 7975d11aed..cf0d78b7a7 100644 --- a/test/unit/tempfile_spec.lua +++ b/test/unit/tempfile_spec.lua @@ -43,7 +43,7 @@ describe('tempfile related functions', function() it('generate name of non-existing file', function() local file = vim_tempname() assert.truthy(file) - assert.False(os.os_file_exists(file)) + assert.False(os.os_path_exists(file)) end) it('generate different names on each call', function() diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index f584815499..9fc1b2eb36 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -99,9 +99,9 @@ set(LIBTERMKEY_SHA256 239746de41c845af52bb3c14055558f743292dd6c24ac26c2d6567a5a6 set(LIBVTERM_URL https://github.com/neovim/libvterm/archive/a9c7c6fd20fa35e0ad3e0e98901ca12dfca9c25c.tar.gz) set(LIBVTERM_SHA256 1a4272be91d9614dc183a503786df83b6584e4afaab7feaaa5409f841afbd796) -set(JEMALLOC_URL https://github.com/jemalloc/jemalloc/releases/download/4.0.2/jemalloc-4.0.2.tar.bz2) -set(JEMALLOC_SHA256 0d8a9c8a98adb6983e0ccb521d45d9db1656ef3e71d0b14fb333f2c8138f4611) - +set(JEMALLOC_URL https://github.com/jemalloc/jemalloc/releases/download/4.2.1/jemalloc-4.2.1.tar.bz2) +set(JEMALLOC_SHA256 5630650d5c1caab95d2f0898de4fe5ab8519dc680b04963b38bb425ef6a42d57) + set(LUV_URL https://github.com/luvit/luv/archive/146f1ce4c08c3b67f604c9ee1e124b1cf5c15cf3.tar.gz) set(LUV_SHA256 3d537f8eb9fa5adb146a083eae22af886aee324ec268e2aa0fa75f2f1c52ca7a) diff --git a/unicode/CaseFolding.txt b/unicode/CaseFolding.txt index 0197a6c40f..372ee68bd8 100644 --- a/unicode/CaseFolding.txt +++ b/unicode/CaseFolding.txt @@ -1,10 +1,11 @@ -# CaseFolding-8.0.0.txt -# Date: 2015-01-13, 18:16:36 GMT [MD] +# CaseFolding-9.0.0.txt +# Date: 2016-03-02, 18:54:54 GMT +# © 2016 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # # Case Folding Properties # @@ -593,6 +594,15 @@ 13FB; C; 13F3; # CHEROKEE SMALL LETTER YU 13FC; C; 13F4; # CHEROKEE SMALL LETTER YV 13FD; C; 13F5; # CHEROKEE SMALL LETTER MV +1C80; C; 0432; # CYRILLIC SMALL LETTER ROUNDED VE +1C81; C; 0434; # CYRILLIC SMALL LETTER LONG-LEGGED DE +1C82; C; 043E; # CYRILLIC SMALL LETTER NARROW O +1C83; C; 0441; # CYRILLIC SMALL LETTER WIDE ES +1C84; C; 0442; # CYRILLIC SMALL LETTER TALL TE +1C85; C; 0442; # CYRILLIC SMALL LETTER THREE-LEGGED TE +1C86; C; 044A; # CYRILLIC SMALL LETTER TALL HARD SIGN +1C87; C; 0463; # CYRILLIC SMALL LETTER TALL YAT +1C88; C; A64B; # CYRILLIC SMALL LETTER UNBLENDED UK 1E00; C; 1E01; # LATIN CAPITAL LETTER A WITH RING BELOW 1E02; C; 1E03; # LATIN CAPITAL LETTER B WITH DOT ABOVE 1E04; C; 1E05; # LATIN CAPITAL LETTER B WITH DOT BELOW @@ -1163,6 +1173,7 @@ A7AA; C; 0266; # LATIN CAPITAL LETTER H WITH HOOK A7AB; C; 025C; # LATIN CAPITAL LETTER REVERSED OPEN E A7AC; C; 0261; # LATIN CAPITAL LETTER SCRIPT G A7AD; C; 026C; # LATIN CAPITAL LETTER L WITH BELT +A7AE; C; 026A; # LATIN CAPITAL LETTER SMALL CAPITAL I A7B0; C; 029E; # LATIN CAPITAL LETTER TURNED K A7B1; C; 0287; # LATIN CAPITAL LETTER TURNED T A7B2; C; 029D; # LATIN CAPITAL LETTER J WITH CROSSED-TAIL @@ -1327,6 +1338,42 @@ FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z 10425; C; 1044D; # DESERET CAPITAL LETTER ENG 10426; C; 1044E; # DESERET CAPITAL LETTER OI 10427; C; 1044F; # DESERET CAPITAL LETTER EW +104B0; C; 104D8; # OSAGE CAPITAL LETTER A +104B1; C; 104D9; # OSAGE CAPITAL LETTER AI +104B2; C; 104DA; # OSAGE CAPITAL LETTER AIN +104B3; C; 104DB; # OSAGE CAPITAL LETTER AH +104B4; C; 104DC; # OSAGE CAPITAL LETTER BRA +104B5; C; 104DD; # OSAGE CAPITAL LETTER CHA +104B6; C; 104DE; # OSAGE CAPITAL LETTER EHCHA +104B7; C; 104DF; # OSAGE CAPITAL LETTER E +104B8; C; 104E0; # OSAGE CAPITAL LETTER EIN +104B9; C; 104E1; # OSAGE CAPITAL LETTER HA +104BA; C; 104E2; # OSAGE CAPITAL LETTER HYA +104BB; C; 104E3; # OSAGE CAPITAL LETTER I +104BC; C; 104E4; # OSAGE CAPITAL LETTER KA +104BD; C; 104E5; # OSAGE CAPITAL LETTER EHKA +104BE; C; 104E6; # OSAGE CAPITAL LETTER KYA +104BF; C; 104E7; # OSAGE CAPITAL LETTER LA +104C0; C; 104E8; # OSAGE CAPITAL LETTER MA +104C1; C; 104E9; # OSAGE CAPITAL LETTER NA +104C2; C; 104EA; # OSAGE CAPITAL LETTER O +104C3; C; 104EB; # OSAGE CAPITAL LETTER OIN +104C4; C; 104EC; # OSAGE CAPITAL LETTER PA +104C5; C; 104ED; # OSAGE CAPITAL LETTER EHPA +104C6; C; 104EE; # OSAGE CAPITAL LETTER SA +104C7; C; 104EF; # OSAGE CAPITAL LETTER SHA +104C8; C; 104F0; # OSAGE CAPITAL LETTER TA +104C9; C; 104F1; # OSAGE CAPITAL LETTER EHTA +104CA; C; 104F2; # OSAGE CAPITAL LETTER TSA +104CB; C; 104F3; # OSAGE CAPITAL LETTER EHTSA +104CC; C; 104F4; # OSAGE CAPITAL LETTER TSHA +104CD; C; 104F5; # OSAGE CAPITAL LETTER DHA +104CE; C; 104F6; # OSAGE CAPITAL LETTER U +104CF; C; 104F7; # OSAGE CAPITAL LETTER WA +104D0; C; 104F8; # OSAGE CAPITAL LETTER KHA +104D1; C; 104F9; # OSAGE CAPITAL LETTER GHA +104D2; C; 104FA; # OSAGE CAPITAL LETTER ZA +104D3; C; 104FB; # OSAGE CAPITAL LETTER ZHA 10C80; C; 10CC0; # OLD HUNGARIAN CAPITAL LETTER A 10C81; C; 10CC1; # OLD HUNGARIAN CAPITAL LETTER AA 10C82; C; 10CC2; # OLD HUNGARIAN CAPITAL LETTER EB @@ -1410,5 +1457,39 @@ FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z 118BD; C; 118DD; # WARANG CITI CAPITAL LETTER SSUU 118BE; C; 118DE; # WARANG CITI CAPITAL LETTER SII 118BF; C; 118DF; # WARANG CITI CAPITAL LETTER VIYO +1E900; C; 1E922; # ADLAM CAPITAL LETTER ALIF +1E901; C; 1E923; # ADLAM CAPITAL LETTER DAALI +1E902; C; 1E924; # ADLAM CAPITAL LETTER LAAM +1E903; C; 1E925; # ADLAM CAPITAL LETTER MIIM +1E904; C; 1E926; # ADLAM CAPITAL LETTER BA +1E905; C; 1E927; # ADLAM CAPITAL LETTER SINNYIIYHE +1E906; C; 1E928; # ADLAM CAPITAL LETTER PE +1E907; C; 1E929; # ADLAM CAPITAL LETTER BHE +1E908; C; 1E92A; # ADLAM CAPITAL LETTER RA +1E909; C; 1E92B; # ADLAM CAPITAL LETTER E +1E90A; C; 1E92C; # ADLAM CAPITAL LETTER FA +1E90B; C; 1E92D; # ADLAM CAPITAL LETTER I +1E90C; C; 1E92E; # ADLAM CAPITAL LETTER O +1E90D; C; 1E92F; # ADLAM CAPITAL LETTER DHA +1E90E; C; 1E930; # ADLAM CAPITAL LETTER YHE +1E90F; C; 1E931; # ADLAM CAPITAL LETTER WAW +1E910; C; 1E932; # ADLAM CAPITAL LETTER NUN +1E911; C; 1E933; # ADLAM CAPITAL LETTER KAF +1E912; C; 1E934; # ADLAM CAPITAL LETTER YA +1E913; C; 1E935; # ADLAM CAPITAL LETTER U +1E914; C; 1E936; # ADLAM CAPITAL LETTER JIIM +1E915; C; 1E937; # ADLAM CAPITAL LETTER CHI +1E916; C; 1E938; # ADLAM CAPITAL LETTER HA +1E917; C; 1E939; # ADLAM CAPITAL LETTER QAAF +1E918; C; 1E93A; # ADLAM CAPITAL LETTER GA +1E919; C; 1E93B; # ADLAM CAPITAL LETTER NYA +1E91A; C; 1E93C; # ADLAM CAPITAL LETTER TU +1E91B; C; 1E93D; # ADLAM CAPITAL LETTER NHA +1E91C; C; 1E93E; # ADLAM CAPITAL LETTER VA +1E91D; C; 1E93F; # ADLAM CAPITAL LETTER KHA +1E91E; C; 1E940; # ADLAM CAPITAL LETTER GBE +1E91F; C; 1E941; # ADLAM CAPITAL LETTER ZAL +1E920; C; 1E942; # ADLAM CAPITAL LETTER KPO +1E921; C; 1E943; # ADLAM CAPITAL LETTER SHA # # EOF diff --git a/unicode/EastAsianWidth.txt b/unicode/EastAsianWidth.txt index b72970e171..5a2ede5d59 100644 --- a/unicode/EastAsianWidth.txt +++ b/unicode/EastAsianWidth.txt @@ -1,35 +1,34 @@ -# EastAsianWidth-8.0.0.txt -# Date: 2015-02-10, 21:00:00 GMT [KW, LI] +# EastAsianWidth-9.0.0.txt +# Date: 2016-05-27, 17:00:00 GMT [KW, LI] +# © 2016 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ # # East_Asian_Width Property # # This file is an informative contributory data file in the # Unicode Character Database. # -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# # The format is two fields separated by a semicolon. # Field 0: Unicode code point value or range of code point values # Field 1: East_Asian_Width property, consisting of one of the following values: -# "N", "A", "H", "W", "F", "Na" +# "A", "F", "H", "N", "Na", "W" # - All code points, assigned or unassigned, that are not listed -# explicitly are given the value "N". -# The unassigned code points that default to "W" include ranges in the -# following blocks: -# CJK Unified Ideographs Extension A: U+3400..U+4DBF -# CJK Unified Ideographs: U+4E00..U+9FFF -# CJK Compatibility Ideographs: U+F900..U+FAFF -# CJK Unified Ideographs Extension B: U+20000..U+2A6DF -# CJK Unified Ideographs Extension C: U+2A700..U+2B73F -# CJK Unified Ideographs Extension D: U+2B740..U+2B81F -# CJK Unified Ideographs Extension E: U+2B820..U+2CEAF -# CJK Compatibility Ideographs Supplement: U+2F800..U+2FA1F -# and any other reserved code points on -# Planes 2 and 3: U+20000..U+2FFFD -# U+30000..U+3FFFD -# - Character ranges are specified as for other property files in -# the Unicode Character Database. +# explicitly are given the value "N". +# - The unassigned code points in the following blocks default to "W": +# CJK Unified Ideographs Extension A: U+3400..U+4DBF +# CJK Unified Ideographs: U+4E00..U+9FFF +# CJK Compatibility Ideographs: U+F900..U+FAFF +# - All undesignated code points in Planes 2 and 3, whether inside or +# outside of allocated blocks, default to "W": +# Plane 2: U+20000..U+2FFFD +# Plane 3: U+30000..U+3FFFD +# +# Character ranges are specified as for other property files in the +# Unicode Character Database. # # For legacy reasons, there are no spaces before or after the semicolon # which separates the two fields. The comments following the number sign @@ -330,6 +329,9 @@ 0859..085B;N # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK 085E;N # Po MANDAIC PUNCTUATION 08A0..08B4;N # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW +08B6..08BD;N # Lo [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON +08D4..08E1;N # Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA +08E2;N # Cf ARABIC DISPUTED END OF AYAH 08E3..08FF;N # Mn [29] ARABIC TURNED DAMMA BELOW..ARABIC MARK SIDEWAYS NOON GHUNNA 0900..0902;N # Mn [3] DEVANAGARI SIGN INVERTED CANDRABINDU..DEVANAGARI SIGN ANUSVARA 0903;N # Mc DEVANAGARI SIGN VISARGA @@ -491,6 +493,7 @@ 0C66..0C6F;N # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE 0C78..0C7E;N # No [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR 0C7F;N # So TELUGU SIGN TUUMU +0C80;N # Lo KANNADA SIGN SPACING CANDRABINDU 0C81;N # Mn KANNADA SIGN CANDRABINDU 0C82..0C83;N # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA 0C85..0C8C;N # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L @@ -525,11 +528,14 @@ 0D4A..0D4C;N # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU 0D4D;N # Mn MALAYALAM SIGN VIRAMA 0D4E;N # Lo MALAYALAM LETTER DOT REPH +0D4F;N # So MALAYALAM SIGN PARA +0D54..0D56;N # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL 0D57;N # Mc MALAYALAM AU LENGTH MARK +0D58..0D5E;N # No [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH 0D5F..0D61;N # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL 0D62..0D63;N # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL 0D66..0D6F;N # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE -0D70..0D75;N # No [6] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE QUARTERS +0D70..0D78;N # No [9] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE SIXTEENTHS 0D79;N # So MALAYALAM DATE MARK 0D7A..0D7F;N # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K 0D82..0D83;N # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA @@ -732,7 +738,9 @@ 1820..1842;N # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI 1843;N # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN 1844..1877;N # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA -1880..18A8;N # Lo [41] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER MANCHU ALI GALI BHA +1880..1884;N # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA +1885..1886;N # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA +1887..18A8;N # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA 18A9;N # Mn MONGOLIAN LETTER ALI GALI DAGALGA 18AA;N # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA 18B0..18F5;N # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S @@ -832,6 +840,7 @@ 1C5A..1C77;N # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D;N # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD 1C7E..1C7F;N # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD +1C80..1C88;N # Ll [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK 1CC0..1CC7;N # Po [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA 1CD0..1CD2;N # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA 1CD3;N # Po VEDIC SIGN NIHSHVASA @@ -853,7 +862,7 @@ 1D80..1D9A;N # Ll [27] LATIN SMALL LETTER B WITH PALATAL HOOK..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK 1D9B..1DBF;N # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA 1DC0..1DF5;N # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE -1DFC..1DFF;N # Mn [4] COMBINING DOUBLE INVERTED BREVE BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +1DFB..1DFF;N # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW 1E00..1EFF;N # L& [256] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER Y WITH LOOP 1F00..1F15;N # L& [22] GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA 1F18..1F1D;N # Lu [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA @@ -1092,7 +1101,9 @@ 230B;N # Pe RIGHT FLOOR 230C..2311;N # So [6] BOTTOM RIGHT CROP..SQUARE LOZENGE 2312;A # So ARC -2313..231F;N # So [13] SEGMENT..BOTTOM RIGHT CORNER +2313..2319;N # So [7] SEGMENT..TURNED NOT SIGN +231A..231B;W # So [2] WATCH..HOURGLASS +231C..231F;N # So [4] TOP LEFT CORNER..BOTTOM RIGHT CORNER 2320..2321;N # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL 2322..2328;N # So [7] FROWN..KEYBOARD 2329;W # Ps LEFT-POINTING ANGLE BRACKET @@ -1103,7 +1114,13 @@ 239B..23B3;N # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM 23B4..23DB;N # So [40] TOP SQUARE BRACKET..FUSE 23DC..23E1;N # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET -23E2..23FA;N # So [25] WHITE TRAPEZIUM..BLACK CIRCLE FOR RECORD +23E2..23E8;N # So [7] WHITE TRAPEZIUM..DECIMAL EXPONENT SYMBOL +23E9..23EC;W # So [4] BLACK RIGHT-POINTING DOUBLE TRIANGLE..BLACK DOWN-POINTING DOUBLE TRIANGLE +23ED..23EF;N # So [3] BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR..BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR +23F0;W # So ALARM CLOCK +23F1..23F2;N # So [2] STOPWATCH..TIMER CLOCK +23F3;W # So HOURGLASS WITH FLOWING SAND +23F4..23FE;N # So [11] BLACK MEDIUM LEFT-POINTING TRIANGLE..POWER SLEEP SYMBOL 2400..2426;N # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO 2440..244A;N # So [11] OCR HOOK..OCR DOUBLE BACKSLASH 2460..249B;A # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP @@ -1142,7 +1159,9 @@ 25E6..25EE;N # So [9] WHITE BULLET..UP-POINTING TRIANGLE WITH RIGHT HALF BLACK 25EF;A # So LARGE CIRCLE 25F0..25F7;N # So [8] WHITE SQUARE WITH UPPER LEFT QUADRANT..WHITE CIRCLE WITH UPPER RIGHT QUADRANT -25F8..25FF;N # Sm [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE +25F8..25FC;N # Sm [5] UPPER LEFT TRIANGLE..BLACK MEDIUM SQUARE +25FD..25FE;W # Sm [2] WHITE MEDIUM SMALL SQUARE..BLACK MEDIUM SMALL SQUARE +25FF;N # Sm LOWER RIGHT TRIANGLE 2600..2604;N # So [5] BLACK SUN WITH RAYS..COMET 2605..2606;A # So [2] BLACK STAR..WHITE STAR 2607..2608;N # So [2] LIGHTNING..THUNDERSTORM @@ -1150,7 +1169,7 @@ 260A..260D;N # So [4] ASCENDING NODE..OPPOSITION 260E..260F;A # So [2] BLACK TELEPHONE..WHITE TELEPHONE 2610..2613;N # So [4] BALLOT BOX..SALTIRE -2614..2615;A # So [2] UMBRELLA WITH RAIN DROPS..HOT BEVERAGE +2614..2615;W # So [2] UMBRELLA WITH RAIN DROPS..HOT BEVERAGE 2616..261B;N # So [6] WHITE SHOGI PIECE..BLACK RIGHT POINTING INDEX 261C;A # So WHITE LEFT POINTING INDEX 261D;N # So WHITE UP POINTING INDEX @@ -1159,7 +1178,9 @@ 2640;A # So FEMALE SIGN 2641;N # So EARTH 2642;A # So MALE SIGN -2643..265F;N # So [29] JUPITER..BLACK CHESS PAWN +2643..2647;N # So [5] JUPITER..PLUTO +2648..2653;W # So [12] ARIES..PISCES +2654..265F;N # So [12] WHITE CHESS KING..BLACK CHESS PAWN 2660..2661;A # So [2] BLACK SPADE SUIT..WHITE HEART SUIT 2662;N # So WHITE DIAMOND SUIT 2663..2665;A # So [3] BLACK CLUB SUIT..BLACK HEART SUIT @@ -1169,22 +1190,56 @@ 266C..266D;A # So [2] BEAMED SIXTEENTH NOTES..MUSIC FLAT SIGN 266E;N # So MUSIC NATURAL SIGN 266F;A # Sm MUSIC SHARP SIGN -2670..269D;N # So [46] WEST SYRIAC CROSS..OUTLINED WHITE STAR +2670..267E;N # So [15] WEST SYRIAC CROSS..PERMANENT PAPER SIGN +267F;W # So WHEELCHAIR SYMBOL +2680..2692;N # So [19] DIE FACE-1..HAMMER AND PICK +2693;W # So ANCHOR +2694..269D;N # So [10] CROSSED SWORDS..OUTLINED WHITE STAR 269E..269F;A # So [2] THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT -26A0..26BD;N # So [30] WARNING SIGN..SOCCER BALL -26BE..26BF;A # So [2] BASEBALL..SQUARED KEY +26A0;N # So WARNING SIGN +26A1;W # So HIGH VOLTAGE SIGN +26A2..26A9;N # So [8] DOUBLED FEMALE SIGN..HORIZONTAL MALE WITH STROKE SIGN +26AA..26AB;W # So [2] MEDIUM WHITE CIRCLE..MEDIUM BLACK CIRCLE +26AC..26BC;N # So [17] MEDIUM SMALL WHITE CIRCLE..SESQUIQUADRATE +26BD..26BE;W # So [2] SOCCER BALL..BASEBALL +26BF;A # So SQUARED KEY 26C0..26C3;N # So [4] WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING -26C4..26CD;A # So [10] SNOWMAN WITHOUT SNOW..DISABLED CAR -26CE;N # So OPHIUCHUS -26CF..26E1;A # So [19] PICK..RESTRICTED LEFT ENTRY-2 +26C4..26C5;W # So [2] SNOWMAN WITHOUT SNOW..SUN BEHIND CLOUD +26C6..26CD;A # So [8] RAIN..DISABLED CAR +26CE;W # So OPHIUCHUS +26CF..26D3;A # So [5] PICK..CHAINS +26D4;W # So NO ENTRY +26D5..26E1;A # So [13] ALTERNATE ONE-WAY LEFT WAY TRAFFIC..RESTRICTED LEFT ENTRY-2 26E2;N # So ASTRONOMICAL SYMBOL FOR URANUS 26E3;A # So HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE 26E4..26E7;N # So [4] PENTAGRAM..INVERTED PENTAGRAM -26E8..26FF;A # So [24] BLACK CROSS ON SHIELD..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE -2700..273C;N # So [61] BLACK SAFETY SCISSORS..OPEN CENTRE TEARDROP-SPOKED ASTERISK +26E8..26E9;A # So [2] BLACK CROSS ON SHIELD..SHINTO SHRINE +26EA;W # So CHURCH +26EB..26F1;A # So [7] CASTLE..UMBRELLA ON GROUND +26F2..26F3;W # So [2] FOUNTAIN..FLAG IN HOLE +26F4;A # So FERRY +26F5;W # So SAILBOAT +26F6..26F9;A # So [4] SQUARE FOUR CORNERS..PERSON WITH BALL +26FA;W # So TENT +26FB..26FC;A # So [2] JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL +26FD;W # So FUEL PUMP +26FE..26FF;A # So [2] CUP ON BLACK SQUARE..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE +2700..2704;N # So [5] BLACK SAFETY SCISSORS..WHITE SCISSORS +2705;W # So WHITE HEAVY CHECK MARK +2706..2709;N # So [4] TELEPHONE LOCATION SIGN..ENVELOPE +270A..270B;W # So [2] RAISED FIST..RAISED HAND +270C..2727;N # So [28] VICTORY HAND..WHITE FOUR POINTED STAR +2728;W # So SPARKLES +2729..273C;N # So [20] STRESS OUTLINED WHITE STAR..OPEN CENTRE TEARDROP-SPOKED ASTERISK 273D;A # So HEAVY TEARDROP-SPOKED ASTERISK -273E..2756;N # So [25] SIX PETALLED BLACK AND WHITE FLORETTE..BLACK DIAMOND MINUS WHITE X -2757;A # So HEAVY EXCLAMATION MARK SYMBOL +273E..274B;N # So [14] SIX PETALLED BLACK AND WHITE FLORETTE..HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK +274C;W # So CROSS MARK +274D;N # So SHADOWED WHITE CIRCLE +274E;W # So NEGATIVE SQUARED CROSS MARK +274F..2752;N # So [4] LOWER RIGHT DROP-SHADOWED WHITE SQUARE..UPPER RIGHT SHADOWED WHITE SQUARE +2753..2755;W # So [3] BLACK QUESTION MARK ORNAMENT..WHITE EXCLAMATION MARK ORNAMENT +2756;N # So BLACK DIAMOND MINUS WHITE X +2757;W # So HEAVY EXCLAMATION MARK SYMBOL 2758..2767;N # So [16] LIGHT VERTICAL BAR..ROTATED FLORAL HEART BULLET 2768;N # Ps MEDIUM LEFT PARENTHESIS ORNAMENT 2769;N # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT @@ -1202,7 +1257,12 @@ 2775;N # Pe MEDIUM RIGHT CURLY BRACKET ORNAMENT 2776..277F;A # No [10] DINGBAT NEGATIVE CIRCLED DIGIT ONE..DINGBAT NEGATIVE CIRCLED NUMBER TEN 2780..2793;N # No [20] DINGBAT CIRCLED SANS-SERIF DIGIT ONE..DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN -2794..27BF;N # So [44] HEAVY WIDE-HEADED RIGHTWARDS ARROW..DOUBLE CURLY LOOP +2794;N # So HEAVY WIDE-HEADED RIGHTWARDS ARROW +2795..2797;W # So [3] HEAVY PLUS SIGN..HEAVY DIVISION SIGN +2798..27AF;N # So [24] HEAVY SOUTH EAST ARROW..NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27B0;W # So CURLY LOOP +27B1..27BE;N # So [14] NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW..OPEN-OUTLINED RIGHTWARDS ARROW +27BF;W # So DOUBLE CURLY LOOP 27C0..27C4;N # Sm [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET 27C5;N # Ps LEFT S-SHAPED BAG DELIMITER 27C6;N # Pe RIGHT S-SHAPED BAG DELIMITER @@ -1253,12 +1313,17 @@ 29FD;N # Pe RIGHT-POINTING CURVED ANGLE BRACKET 29FE..29FF;N # Sm [2] TINY..MINY 2A00..2AFF;N # Sm [256] N-ARY CIRCLED DOT OPERATOR..N-ARY WHITE VERTICAL BAR -2B00..2B2F;N # So [48] NORTH EAST WHITE ARROW..WHITE VERTICAL ELLIPSE +2B00..2B1A;N # So [27] NORTH EAST WHITE ARROW..DOTTED SQUARE +2B1B..2B1C;W # So [2] BLACK LARGE SQUARE..WHITE LARGE SQUARE +2B1D..2B2F;N # So [19] BLACK VERY SMALL SQUARE..WHITE VERTICAL ELLIPSE 2B30..2B44;N # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET 2B45..2B46;N # So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW 2B47..2B4C;N # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR -2B4D..2B54;N # So [8] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..WHITE RIGHT-POINTING PENTAGON -2B55..2B59;A # So [5] HEAVY LARGE CIRCLE..HEAVY CIRCLED SALTIRE +2B4D..2B4F;N # So [3] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..SHORT BACKSLANTED SOUTH ARROW +2B50;W # So WHITE MEDIUM STAR +2B51..2B54;N # So [4] BLACK SMALL STAR..WHITE RIGHT-POINTING PENTAGON +2B55;W # So HEAVY LARGE CIRCLE +2B56..2B59;A # So [4] HEAVY OVAL WITH OVAL INSIDE..HEAVY CIRCLED SALTIRE 2B5A..2B73;N # So [26] SLANTED NORTH ARROW WITH HOOKED HEAD..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR 2B76..2B95;N # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW 2B98..2BB9;N # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX @@ -1332,6 +1397,7 @@ 2E40;N # Pd DOUBLE HYPHEN 2E41;N # Po REVERSED COMMA 2E42;N # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK +2E43..2E44;N # Po [2] DASH WITH LEFT UPTURN..DOUBLE SUSPENSION MARK 2E80..2E99;W # So [26] CJK RADICAL REPEAT..CJK RADICAL RAP 2E9B..2EF3;W # So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE 2F00..2FD5;W # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE @@ -1450,7 +1516,7 @@ A788;N # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A789..A78A;N # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN A78B..A78E;N # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F;N # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7AD;N # L& [30] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER L WITH BELT +A790..A7AE;N # L& [31] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER SMALL CAPITAL I A7B0..A7B7;N # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA A7F7;N # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9;N # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -1476,7 +1542,7 @@ A874..A877;N # Po [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOUBLE SH A880..A881;N # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA A882..A8B3;N # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA A8B4..A8C3;N # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU -A8C4;N # Mn SAURASHTRA SIGN VIRAMA +A8C4..A8C5;N # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU A8CE..A8CF;N # Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA A8D0..A8D9;N # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE A8E0..A8F1;N # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA @@ -1726,7 +1792,7 @@ FFFD;A # So REPLACEMENT CHARACTER 10175..10178;N # No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN 10179..10189;N # So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN 1018A..1018B;N # No [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN -1018C;N # So GREEK SINUSOID SIGN +1018C..1018E;N # So [3] GREEK SINUSOID SIGN..NOMISMA SIGN 10190..1019B;N # So [12] ROMAN SEXTANS SIGN..ROMAN CENTURIAL SIGN 101A0;N # So GREEK SYMBOL TAU RHO 101D0..101FC;N # So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND @@ -1753,6 +1819,8 @@ FFFD;A # So REPLACEMENT CHARACTER 10450..1047F;N # Lo [48] SHAVIAN LETTER PEEP..SHAVIAN LETTER YEW 10480..1049D;N # Lo [30] OSMANYA LETTER ALEF..OSMANYA LETTER OO 104A0..104A9;N # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE +104B0..104D3;N # Lu [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA +104D8..104FB;N # Ll [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA 10500..10527;N # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE 10530..10563;N # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW 1056F;N # Po CAUCASIAN ALBANIAN CITATION MARK @@ -1880,6 +1948,7 @@ FFFD;A # So REPLACEMENT CHARACTER 11235;N # Mc KHOJKI SIGN VIRAMA 11236..11237;N # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA 11238..1123D;N # Po [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN +1123E;N # Mn KHOJKI SIGN SUKUN 11280..11286;N # Lo [7] MULTANI LETTER A..MULTANI LETTER GA 11288;N # Lo MULTANI LETTER GHA 1128A..1128D;N # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA @@ -1912,6 +1981,18 @@ FFFD;A # So REPLACEMENT CHARACTER 11362..11363;N # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL 11366..1136C;N # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374;N # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11400..11434;N # Lo [53] NEWA LETTER A..NEWA LETTER HA +11435..11437;N # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II +11438..1143F;N # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI +11440..11441;N # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU +11442..11444;N # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA +11445;N # Mc NEWA SIGN VISARGA +11446;N # Mn NEWA SIGN NUKTA +11447..1144A;N # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI +1144B..1144F;N # Po [5] NEWA DANDA..NEWA ABBREVIATION SIGN +11450..11459;N # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE +1145B;N # Po NEWA PLACEHOLDER MARK +1145D;N # Po NEWA INSERTION SIGN 11480..114AF;N # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA 114B0..114B2;N # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II 114B3..114B8;N # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL @@ -1945,6 +2026,7 @@ FFFD;A # So REPLACEMENT CHARACTER 11641..11643;N # Po [3] MODI DANDA..MODI ABBREVIATION SIGN 11644;N # Lo MODI SIGN HUVA 11650..11659;N # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE +11660..1166C;N # Po [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT 11680..116AA;N # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA 116AB;N # Mn TAKRI SIGN ANUSVARA 116AC;N # Mc TAKRI SIGN VISARGA @@ -1969,6 +2051,26 @@ FFFD;A # So REPLACEMENT CHARACTER 118EA..118F2;N # No [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY 118FF;N # Lo WARANG CITI OM 11AC0..11AF8;N # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL +11C00..11C08;N # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L +11C0A..11C2E;N # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA +11C2F;N # Mc BHAIKSUKI VOWEL SIGN AA +11C30..11C36;N # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L +11C38..11C3D;N # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA +11C3E;N # Mc BHAIKSUKI SIGN VISARGA +11C3F;N # Mn BHAIKSUKI SIGN VIRAMA +11C40;N # Lo BHAIKSUKI SIGN AVAGRAHA +11C41..11C45;N # Po [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2 +11C50..11C59;N # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE +11C5A..11C6C;N # No [19] BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK +11C70..11C71;N # Po [2] MARCHEN HEAD MARK..MARCHEN MARK SHAD +11C72..11C8F;N # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A +11C92..11CA7;N # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CA9;N # Mc MARCHEN SUBJOINED LETTER YA +11CAA..11CB0;N # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA +11CB1;N # Mc MARCHEN VOWEL SIGN I +11CB2..11CB3;N # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E +11CB4;N # Mc MARCHEN VOWEL SIGN O +11CB5..11CB6;N # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU 12000..12399;N # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U 12400..1246E;N # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM 12470..12474;N # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON @@ -1998,6 +2100,9 @@ FFFD;A # So REPLACEMENT CHARACTER 16F51..16F7E;N # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG 16F8F..16F92;N # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW 16F93..16F9F;N # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 +16FE0;W # Lm TANGUT ITERATION MARK +17000..187EC;W # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC +18800..18AF2;W # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755 1B000..1B001;W # Lo [2] KATAKANA LETTER ARCHAIC E..HIRAGANA LETTER ARCHAIC YE 1BC00..1BC6A;N # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M 1BC70..1BC7C;N # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK @@ -2079,9 +2184,18 @@ FFFD;A # So REPLACEMENT CHARACTER 1DA87..1DA8B;N # Po [5] SIGNWRITING COMMA..SIGNWRITING PARENTHESIS 1DA9B..1DA9F;N # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 1DAA1..1DAAF;N # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 +1E000..1E006;N # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E008..1E018;N # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E01B..1E021;N # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E023..1E024;N # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E026..1E02A;N # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA 1E800..1E8C4;N # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON 1E8C7..1E8CF;N # No [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE 1E8D0..1E8D6;N # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS +1E900..1E943;N # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA +1E944..1E94A;N # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA +1E950..1E959;N # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE +1E95E..1E95F;N # Po [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK 1EE00..1EE03;N # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL 1EE05..1EE1F;N # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF 1EE21..1EE22;N # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM @@ -2116,11 +2230,14 @@ FFFD;A # So REPLACEMENT CHARACTER 1EEA5..1EEA9;N # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH 1EEAB..1EEBB;N # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN 1EEF0..1EEF1;N # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL -1F000..1F02B;N # So [44] MAHJONG TILE EAST WIND..MAHJONG TILE BACK +1F000..1F003;N # So [4] MAHJONG TILE EAST WIND..MAHJONG TILE NORTH WIND +1F004;W # So MAHJONG TILE RED DRAGON +1F005..1F02B;N # So [39] MAHJONG TILE GREEN DRAGON..MAHJONG TILE BACK 1F030..1F093;N # So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06 1F0A0..1F0AE;N # So [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES 1F0B1..1F0BF;N # So [15] PLAYING CARD ACE OF HEARTS..PLAYING CARD RED JOKER -1F0C1..1F0CF;N # So [15] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD BLACK JOKER +1F0C1..1F0CE;N # So [14] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD KING OF DIAMONDS +1F0CF;W # So PLAYING CARD BLACK JOKER 1F0D1..1F0F5;N # So [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21 1F100..1F10A;A # No [11] DIGIT ZERO FULL STOP..DIGIT NINE COMMA 1F10B..1F10C;N # No [2] DINGBAT CIRCLED SANS-SERIF DIGIT ZERO..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO @@ -2128,22 +2245,64 @@ FFFD;A # So REPLACEMENT CHARACTER 1F12E;N # So CIRCLED WZ 1F130..1F169;A # So [58] SQUARED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 1F16A..1F16B;N # So [2] RAISED MC SIGN..RAISED MD SIGN -1F170..1F19A;A # So [43] NEGATIVE SQUARED LATIN CAPITAL LETTER A..SQUARED VS +1F170..1F18D;A # So [30] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED SA +1F18E;W # So NEGATIVE SQUARED AB +1F18F..1F190;A # So [2] NEGATIVE SQUARED WC..SQUARE DJ +1F191..1F19A;W # So [10] SQUARED CL..SQUARED VS +1F19B..1F1AC;A # So [18] SQUARED THREE D..SQUARED VOD 1F1E6..1F1FF;N # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z 1F200..1F202;W # So [3] SQUARE HIRAGANA HOKA..SQUARED KATAKANA SA -1F210..1F23A;W # So [43] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-55B6 +1F210..1F23B;W # So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D 1F240..1F248;W # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 1F250..1F251;W # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT -1F300..1F3FA;N # So [251] CYCLONE..AMPHORA -1F3FB..1F3FF;N # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 -1F400..1F579;N # So [378] RAT..JOYSTICK -1F57B..1F5A3;N # So [41] LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX -1F5A5..1F5FF;N # So [91] DESKTOP COMPUTER..MOYAI -1F600..1F64F;N # So [80] GRINNING FACE..PERSON WITH FOLDED HANDS +1F300..1F320;W # So [33] CYCLONE..SHOOTING STAR +1F321..1F32C;N # So [12] THERMOMETER..WIND BLOWING FACE +1F32D..1F335;W # So [9] HOT DOG..CACTUS +1F336;N # So HOT PEPPER +1F337..1F37C;W # So [70] TULIP..BABY BOTTLE +1F37D;N # So FORK AND KNIFE WITH PLATE +1F37E..1F393;W # So [22] BOTTLE WITH POPPING CORK..GRADUATION CAP +1F394..1F39F;N # So [12] HEART WITH TIP ON THE LEFT..ADMISSION TICKETS +1F3A0..1F3CA;W # So [43] CAROUSEL HORSE..SWIMMER +1F3CB..1F3CE;N # So [4] WEIGHT LIFTER..RACING CAR +1F3CF..1F3D3;W # So [5] CRICKET BAT AND BALL..TABLE TENNIS PADDLE AND BALL +1F3D4..1F3DF;N # So [12] SNOW CAPPED MOUNTAIN..STADIUM +1F3E0..1F3F0;W # So [17] HOUSE BUILDING..EUROPEAN CASTLE +1F3F1..1F3F3;N # So [3] WHITE PENNANT..WAVING WHITE FLAG +1F3F4;W # So WAVING BLACK FLAG +1F3F5..1F3F7;N # So [3] ROSETTE..LABEL +1F3F8..1F3FA;W # So [3] BADMINTON RACQUET AND SHUTTLECOCK..AMPHORA +1F3FB..1F3FF;W # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 +1F400..1F43E;W # So [63] RAT..PAW PRINTS +1F43F;N # So CHIPMUNK +1F440;W # So EYES +1F441;N # So EYE +1F442..1F4FC;W # So [187] EAR..VIDEOCASSETTE +1F4FD..1F4FE;N # So [2] FILM PROJECTOR..PORTABLE STEREO +1F4FF..1F53D;W # So [63] PRAYER BEADS..DOWN-POINTING SMALL RED TRIANGLE +1F53E..1F54A;N # So [13] LOWER RIGHT SHADOWED WHITE CIRCLE..DOVE OF PEACE +1F54B..1F54E;W # So [4] KAABA..MENORAH WITH NINE BRANCHES +1F54F;N # So BOWL OF HYGIEIA +1F550..1F567;W # So [24] CLOCK FACE ONE OCLOCK..CLOCK FACE TWELVE-THIRTY +1F568..1F579;N # So [18] RIGHT SPEAKER..JOYSTICK +1F57A;W # So MAN DANCING +1F57B..1F594;N # So [26] LEFT HAND TELEPHONE RECEIVER..REVERSED VICTORY HAND +1F595..1F596;W # So [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS +1F597..1F5A3;N # So [13] WHITE DOWN POINTING LEFT HAND INDEX..BLACK DOWN POINTING BACKHAND INDEX +1F5A4;W # So BLACK HEART +1F5A5..1F5FA;N # So [86] DESKTOP COMPUTER..WORLD MAP +1F5FB..1F5FF;W # So [5] MOUNT FUJI..MOYAI +1F600..1F64F;W # So [80] GRINNING FACE..PERSON WITH FOLDED HANDS 1F650..1F67F;N # So [48] NORTH WEST POINTING LEAF..REVERSE CHECKER BOARD -1F680..1F6D0;N # So [81] ROCKET..PLACE OF WORSHIP -1F6E0..1F6EC;N # So [13] HAMMER AND WRENCH..AIRPLANE ARRIVING +1F680..1F6C5;W # So [70] ROCKET..LEFT LUGGAGE +1F6C6..1F6CB;N # So [6] TRIANGLE WITH ROUNDED CORNERS..COUCH AND LAMP +1F6CC;W # So SLEEPING ACCOMMODATION +1F6CD..1F6CF;N # So [3] SHOPPING BAGS..BED +1F6D0..1F6D2;W # So [3] PLACE OF WORSHIP..SHOPPING TROLLEY +1F6E0..1F6EA;N # So [11] HAMMER AND WRENCH..NORTHEAST-POINTING AIRPLANE +1F6EB..1F6EC;W # So [2] AIRPLANE DEPARTURE..AIRPLANE ARRIVING 1F6F0..1F6F3;N # So [4] SATELLITE..PASSENGER SHIP +1F6F4..1F6F6;W # So [3] SCOOTER..CANOE 1F700..1F773;N # So [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE 1F780..1F7D4;N # So [85] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..HEAVY TWELVE POINTED PINWHEEL STAR 1F800..1F80B;N # So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD @@ -2151,9 +2310,14 @@ FFFD;A # So REPLACEMENT CHARACTER 1F850..1F859;N # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW 1F860..1F887;N # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW 1F890..1F8AD;N # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS -1F910..1F918;N # So [9] ZIPPER-MOUTH FACE..SIGN OF THE HORNS -1F980..1F984;N # So [5] CRAB..UNICORN FACE -1F9C0;N # So CHEESE WEDGE +1F910..1F91E;W # So [15] ZIPPER-MOUTH FACE..HAND WITH INDEX AND MIDDLE FINGERS CROSSED +1F920..1F927;W # So [8] FACE WITH COWBOY HAT..SNEEZING FACE +1F930;W # So PREGNANT WOMAN +1F933..1F93E;W # So [12] SELFIE..HANDBALL +1F940..1F94B;W # So [12] WILTED FLOWER..MARTIAL ARTS UNIFORM +1F950..1F95E;W # So [15] CROISSANT..PANCAKES +1F980..1F991;W # So [18] CRAB..SQUID +1F9C0;W # So CHEESE WEDGE 20000..2A6D6;W # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6 2A6D7..2A6FF;W # Cn [41] <reserved-2A6D7>..<reserved-2A6FF> 2A700..2B734;W # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 diff --git a/unicode/UnicodeData.txt b/unicode/UnicodeData.txt index aa0e914f84..a756976461 100644 --- a/unicode/UnicodeData.txt +++ b/unicode/UnicodeData.txt @@ -616,7 +616,7 @@ 0267;LATIN SMALL LETTER HENG WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER HENG HOOK;;;; 0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197 0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196 -026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;;; +026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;A7AE;;A7AE 026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;2C62;;2C62 026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;A7AD;;A7AD 026D;LATIN SMALL LETTER L WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER L RETROFLEX HOOK;;;; @@ -2093,6 +2093,29 @@ 08B2;ARABIC LETTER ZAIN WITH INVERTED V ABOVE;Lo;0;AL;;;;;N;;;;; 08B3;ARABIC LETTER AIN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; 08B4;ARABIC LETTER KAF WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +08B6;ARABIC LETTER BEH WITH SMALL MEEM ABOVE;Lo;0;AL;;;;;N;;;;; +08B7;ARABIC LETTER PEH WITH SMALL MEEM ABOVE;Lo;0;AL;;;;;N;;;;; +08B8;ARABIC LETTER TEH WITH SMALL TEH ABOVE;Lo;0;AL;;;;;N;;;;; +08B9;ARABIC LETTER REH WITH SMALL NOON ABOVE;Lo;0;AL;;;;;N;;;;; +08BA;ARABIC LETTER YEH WITH TWO DOTS BELOW AND SMALL NOON ABOVE;Lo;0;AL;;;;;N;;;;; +08BB;ARABIC LETTER AFRICAN FEH;Lo;0;AL;;;;;N;;;;; +08BC;ARABIC LETTER AFRICAN QAF;Lo;0;AL;;;;;N;;;;; +08BD;ARABIC LETTER AFRICAN NOON;Lo;0;AL;;;;;N;;;;; +08D4;ARABIC SMALL HIGH WORD AR-RUB;Mn;230;NSM;;;;;N;;;;; +08D5;ARABIC SMALL HIGH SAD;Mn;230;NSM;;;;;N;;;;; +08D6;ARABIC SMALL HIGH AIN;Mn;230;NSM;;;;;N;;;;; +08D7;ARABIC SMALL HIGH QAF;Mn;230;NSM;;;;;N;;;;; +08D8;ARABIC SMALL HIGH NOON WITH KASRA;Mn;230;NSM;;;;;N;;;;; +08D9;ARABIC SMALL LOW NOON WITH KASRA;Mn;230;NSM;;;;;N;;;;; +08DA;ARABIC SMALL HIGH WORD ATH-THALATHA;Mn;230;NSM;;;;;N;;;;; +08DB;ARABIC SMALL HIGH WORD AS-SAJDA;Mn;230;NSM;;;;;N;;;;; +08DC;ARABIC SMALL HIGH WORD AN-NISF;Mn;230;NSM;;;;;N;;;;; +08DD;ARABIC SMALL HIGH WORD SAKTA;Mn;230;NSM;;;;;N;;;;; +08DE;ARABIC SMALL HIGH WORD QIF;Mn;230;NSM;;;;;N;;;;; +08DF;ARABIC SMALL HIGH WORD WAQFA;Mn;230;NSM;;;;;N;;;;; +08E0;ARABIC SMALL HIGH FOOTNOTE MARKER;Mn;230;NSM;;;;;N;;;;; +08E1;ARABIC SMALL HIGH SIGN SAFHA;Mn;230;NSM;;;;;N;;;;; +08E2;ARABIC DISPUTED END OF AYAH;Cf;0;AN;;;;;N;;;;; 08E3;ARABIC TURNED DAMMA BELOW;Mn;220;NSM;;;;;N;;;;; 08E4;ARABIC CURLY FATHA;Mn;230;NSM;;;;;N;;;;; 08E5;ARABIC CURLY DAMMA;Mn;230;NSM;;;;;N;;;;; @@ -2765,6 +2788,7 @@ 0C7D;TELUGU FRACTION DIGIT TWO FOR EVEN POWERS OF FOUR;No;0;ON;;;;2;N;;;;; 0C7E;TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR;No;0;ON;;;;3;N;;;;; 0C7F;TELUGU SIGN TUUMU;So;0;L;;;;;N;;;;; +0C80;KANNADA SIGN SPACING CANDRABINDU;Lo;0;L;;;;;N;;;;; 0C81;KANNADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -2923,7 +2947,18 @@ 0D4C;MALAYALAM VOWEL SIGN AU;Mc;0;L;0D46 0D57;;;;N;;;;; 0D4D;MALAYALAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 0D4E;MALAYALAM LETTER DOT REPH;Lo;0;L;;;;;N;;;;; +0D4F;MALAYALAM SIGN PARA;So;0;L;;;;;N;;;;; +0D54;MALAYALAM LETTER CHILLU M;Lo;0;L;;;;;N;;;;; +0D55;MALAYALAM LETTER CHILLU Y;Lo;0;L;;;;;N;;;;; +0D56;MALAYALAM LETTER CHILLU LLL;Lo;0;L;;;;;N;;;;; 0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +0D58;MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH;No;0;L;;;;1/160;N;;;;; +0D59;MALAYALAM FRACTION ONE FORTIETH;No;0;L;;;;1/40;N;;;;; +0D5A;MALAYALAM FRACTION THREE EIGHTIETHS;No;0;L;;;;3/80;N;;;;; +0D5B;MALAYALAM FRACTION ONE TWENTIETH;No;0;L;;;;1/20;N;;;;; +0D5C;MALAYALAM FRACTION ONE TENTH;No;0;L;;;;1/10;N;;;;; +0D5D;MALAYALAM FRACTION THREE TWENTIETHS;No;0;L;;;;3/20;N;;;;; +0D5E;MALAYALAM FRACTION ONE FIFTH;No;0;L;;;;1/5;N;;;;; 0D5F;MALAYALAM LETTER ARCHAIC II;Lo;0;L;;;;;N;;;;; 0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; @@ -2945,6 +2980,9 @@ 0D73;MALAYALAM FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;; 0D74;MALAYALAM FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;; 0D75;MALAYALAM FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;; +0D76;MALAYALAM FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;; +0D77;MALAYALAM FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;; +0D78;MALAYALAM FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;; 0D79;MALAYALAM DATE MARK;So;0;L;;;;;N;;;;; 0D7A;MALAYALAM LETTER CHILLU NN;Lo;0;L;;;;;N;;;;; 0D7B;MALAYALAM LETTER CHILLU N;Lo;0;L;;;;;N;;;;; @@ -5458,8 +5496,8 @@ 1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;; 1883;MONGOLIAN LETTER ALI GALI UBADAMA;Lo;0;L;;;;;N;;;;; 1884;MONGOLIAN LETTER ALI GALI INVERTED UBADAMA;Lo;0;L;;;;;N;;;;; -1885;MONGOLIAN LETTER ALI GALI BALUDA;Lo;0;L;;;;;N;;;;; -1886;MONGOLIAN LETTER ALI GALI THREE BALUDA;Lo;0;L;;;;;N;;;;; +1885;MONGOLIAN LETTER ALI GALI BALUDA;Mn;0;NSM;;;;;N;;;;; +1886;MONGOLIAN LETTER ALI GALI THREE BALUDA;Mn;0;NSM;;;;;N;;;;; 1887;MONGOLIAN LETTER ALI GALI A;Lo;0;L;;;;;N;;;;; 1888;MONGOLIAN LETTER ALI GALI I;Lo;0;L;;;;;N;;;;; 1889;MONGOLIAN LETTER ALI GALI KA;Lo;0;L;;;;;N;;;;; @@ -6319,6 +6357,15 @@ 1C7D;OL CHIKI AHAD;Lm;0;L;;;;;N;;;;; 1C7E;OL CHIKI PUNCTUATION MUCAAD;Po;0;L;;;;;N;;;;; 1C7F;OL CHIKI PUNCTUATION DOUBLE MUCAAD;Po;0;L;;;;;N;;;;; +1C80;CYRILLIC SMALL LETTER ROUNDED VE;Ll;0;L;;;;;N;;;0412;;0412 +1C81;CYRILLIC SMALL LETTER LONG-LEGGED DE;Ll;0;L;;;;;N;;;0414;;0414 +1C82;CYRILLIC SMALL LETTER NARROW O;Ll;0;L;;;;;N;;;041E;;041E +1C83;CYRILLIC SMALL LETTER WIDE ES;Ll;0;L;;;;;N;;;0421;;0421 +1C84;CYRILLIC SMALL LETTER TALL TE;Ll;0;L;;;;;N;;;0422;;0422 +1C85;CYRILLIC SMALL LETTER THREE-LEGGED TE;Ll;0;L;;;;;N;;;0422;;0422 +1C86;CYRILLIC SMALL LETTER TALL HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A +1C87;CYRILLIC SMALL LETTER TALL YAT;Ll;0;L;;;;;N;;;0462;;0462 +1C88;CYRILLIC SMALL LETTER UNBLENDED UK;Ll;0;L;;;;;N;;;A64A;;A64A 1CC0;SUNDANESE PUNCTUATION BINDU SURYA;Po;0;L;;;;;N;;;;; 1CC1;SUNDANESE PUNCTUATION BINDU PANGLONG;Po;0;L;;;;;N;;;;; 1CC2;SUNDANESE PUNCTUATION BINDU PURNAMA;Po;0;L;;;;;N;;;;; @@ -6614,6 +6661,7 @@ 1DF3;COMBINING LATIN SMALL LETTER O WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;; 1DF4;COMBINING LATIN SMALL LETTER U WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;; 1DF5;COMBINING UP TACK ABOVE;Mn;230;NSM;;;;;N;;;;; +1DFB;COMBINING DELETION MARK;Mn;230;NSM;;;;;N;;;;; 1DFC;COMBINING DOUBLE INVERTED BREVE BELOW;Mn;233;NSM;;;;;N;;;;; 1DFD;COMBINING ALMOST EQUAL TO BELOW;Mn;220;NSM;;;;;N;;;;; 1DFE;COMBINING LEFT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; @@ -8083,6 +8131,10 @@ 23F8;DOUBLE VERTICAL BAR;So;0;ON;;;;;N;;;;; 23F9;BLACK SQUARE FOR STOP;So;0;ON;;;;;N;;;;; 23FA;BLACK CIRCLE FOR RECORD;So;0;ON;;;;;N;;;;; +23FB;POWER SYMBOL;So;0;ON;;;;;N;;;;; +23FC;POWER ON-OFF SYMBOL;So;0;ON;;;;;N;;;;; +23FD;POWER ON SYMBOL;So;0;ON;;;;;N;;;;; +23FE;POWER SLEEP SYMBOL;So;0;ON;;;;;N;;;;; 2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;; 2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;; 2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;; @@ -10561,6 +10613,8 @@ 2E40;DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;; 2E41;REVERSED COMMA;Po;0;ON;;;;;N;;;;; 2E42;DOUBLE LOW-REVERSED-9 QUOTATION MARK;Ps;0;ON;;;;;N;;;;; +2E43;DASH WITH LEFT UPTURN;Po;0;ON;;;;;N;;;;; +2E44;DOUBLE SUSPENSION MARK;Po;0;ON;;;;;N;;;;; 2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;; 2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;; 2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;; @@ -13889,6 +13943,7 @@ A7AA;LATIN CAPITAL LETTER H WITH HOOK;Lu;0;L;;;;;N;;;;0266; A7AB;LATIN CAPITAL LETTER REVERSED OPEN E;Lu;0;L;;;;;N;;;;025C; A7AC;LATIN CAPITAL LETTER SCRIPT G;Lu;0;L;;;;;N;;;;0261; A7AD;LATIN CAPITAL LETTER L WITH BELT;Lu;0;L;;;;;N;;;;026C; +A7AE;LATIN CAPITAL LETTER SMALL CAPITAL I;Lu;0;L;;;;;N;;;;026A; A7B0;LATIN CAPITAL LETTER TURNED K;Lu;0;L;;;;;N;;;;029E; A7B1;LATIN CAPITAL LETTER TURNED T;Lu;0;L;;;;;N;;;;0287; A7B2;LATIN CAPITAL LETTER J WITH CROSSED-TAIL;Lu;0;L;;;;;N;;;;029D; @@ -14085,6 +14140,7 @@ A8C1;SAURASHTRA VOWEL SIGN O;Mc;0;L;;;;;N;;;;; A8C2;SAURASHTRA VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; A8C3;SAURASHTRA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; A8C4;SAURASHTRA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +A8C5;SAURASHTRA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; A8CE;SAURASHTRA DANDA;Po;0;L;;;;;N;;;;; A8CF;SAURASHTRA DOUBLE DANDA;Po;0;L;;;;;N;;;;; A8D0;SAURASHTRA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; @@ -16834,6 +16890,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1018A;GREEK ZERO SIGN;No;0;ON;;;;0;N;;;;; 1018B;GREEK ONE QUARTER SIGN;No;0;ON;;;;1/4;N;;;;; 1018C;GREEK SINUSOID SIGN;So;0;ON;;;;;N;;;;; +1018D;GREEK INDICTION SIGN;So;0;L;;;;;N;;;;; +1018E;NOMISMA SIGN;So;0;L;;;;;N;;;;; 10190;ROMAN SEXTANS SIGN;So;0;ON;;;;;N;;;;; 10191;ROMAN UNCIA SIGN;So;0;ON;;;;;N;;;;; 10192;ROMAN SEMUNCIA SIGN;So;0;ON;;;;;N;;;;; @@ -17354,6 +17412,78 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 104A7;OSMANYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 104A8;OSMANYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 104A9;OSMANYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +104B0;OSAGE CAPITAL LETTER A;Lu;0;L;;;;;N;;;;104D8; +104B1;OSAGE CAPITAL LETTER AI;Lu;0;L;;;;;N;;;;104D9; +104B2;OSAGE CAPITAL LETTER AIN;Lu;0;L;;;;;N;;;;104DA; +104B3;OSAGE CAPITAL LETTER AH;Lu;0;L;;;;;N;;;;104DB; +104B4;OSAGE CAPITAL LETTER BRA;Lu;0;L;;;;;N;;;;104DC; +104B5;OSAGE CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;104DD; +104B6;OSAGE CAPITAL LETTER EHCHA;Lu;0;L;;;;;N;;;;104DE; +104B7;OSAGE CAPITAL LETTER E;Lu;0;L;;;;;N;;;;104DF; +104B8;OSAGE CAPITAL LETTER EIN;Lu;0;L;;;;;N;;;;104E0; +104B9;OSAGE CAPITAL LETTER HA;Lu;0;L;;;;;N;;;;104E1; +104BA;OSAGE CAPITAL LETTER HYA;Lu;0;L;;;;;N;;;;104E2; +104BB;OSAGE CAPITAL LETTER I;Lu;0;L;;;;;N;;;;104E3; +104BC;OSAGE CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;104E4; +104BD;OSAGE CAPITAL LETTER EHKA;Lu;0;L;;;;;N;;;;104E5; +104BE;OSAGE CAPITAL LETTER KYA;Lu;0;L;;;;;N;;;;104E6; +104BF;OSAGE CAPITAL LETTER LA;Lu;0;L;;;;;N;;;;104E7; +104C0;OSAGE CAPITAL LETTER MA;Lu;0;L;;;;;N;;;;104E8; +104C1;OSAGE CAPITAL LETTER NA;Lu;0;L;;;;;N;;;;104E9; +104C2;OSAGE CAPITAL LETTER O;Lu;0;L;;;;;N;;;;104EA; +104C3;OSAGE CAPITAL LETTER OIN;Lu;0;L;;;;;N;;;;104EB; +104C4;OSAGE CAPITAL LETTER PA;Lu;0;L;;;;;N;;;;104EC; +104C5;OSAGE CAPITAL LETTER EHPA;Lu;0;L;;;;;N;;;;104ED; +104C6;OSAGE CAPITAL LETTER SA;Lu;0;L;;;;;N;;;;104EE; +104C7;OSAGE CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;104EF; +104C8;OSAGE CAPITAL LETTER TA;Lu;0;L;;;;;N;;;;104F0; +104C9;OSAGE CAPITAL LETTER EHTA;Lu;0;L;;;;;N;;;;104F1; +104CA;OSAGE CAPITAL LETTER TSA;Lu;0;L;;;;;N;;;;104F2; +104CB;OSAGE CAPITAL LETTER EHTSA;Lu;0;L;;;;;N;;;;104F3; +104CC;OSAGE CAPITAL LETTER TSHA;Lu;0;L;;;;;N;;;;104F4; +104CD;OSAGE CAPITAL LETTER DHA;Lu;0;L;;;;;N;;;;104F5; +104CE;OSAGE CAPITAL LETTER U;Lu;0;L;;;;;N;;;;104F6; +104CF;OSAGE CAPITAL LETTER WA;Lu;0;L;;;;;N;;;;104F7; +104D0;OSAGE CAPITAL LETTER KHA;Lu;0;L;;;;;N;;;;104F8; +104D1;OSAGE CAPITAL LETTER GHA;Lu;0;L;;;;;N;;;;104F9; +104D2;OSAGE CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;104FA; +104D3;OSAGE CAPITAL LETTER ZHA;Lu;0;L;;;;;N;;;;104FB; +104D8;OSAGE SMALL LETTER A;Ll;0;L;;;;;N;;;104B0;;104B0 +104D9;OSAGE SMALL LETTER AI;Ll;0;L;;;;;N;;;104B1;;104B1 +104DA;OSAGE SMALL LETTER AIN;Ll;0;L;;;;;N;;;104B2;;104B2 +104DB;OSAGE SMALL LETTER AH;Ll;0;L;;;;;N;;;104B3;;104B3 +104DC;OSAGE SMALL LETTER BRA;Ll;0;L;;;;;N;;;104B4;;104B4 +104DD;OSAGE SMALL LETTER CHA;Ll;0;L;;;;;N;;;104B5;;104B5 +104DE;OSAGE SMALL LETTER EHCHA;Ll;0;L;;;;;N;;;104B6;;104B6 +104DF;OSAGE SMALL LETTER E;Ll;0;L;;;;;N;;;104B7;;104B7 +104E0;OSAGE SMALL LETTER EIN;Ll;0;L;;;;;N;;;104B8;;104B8 +104E1;OSAGE SMALL LETTER HA;Ll;0;L;;;;;N;;;104B9;;104B9 +104E2;OSAGE SMALL LETTER HYA;Ll;0;L;;;;;N;;;104BA;;104BA +104E3;OSAGE SMALL LETTER I;Ll;0;L;;;;;N;;;104BB;;104BB +104E4;OSAGE SMALL LETTER KA;Ll;0;L;;;;;N;;;104BC;;104BC +104E5;OSAGE SMALL LETTER EHKA;Ll;0;L;;;;;N;;;104BD;;104BD +104E6;OSAGE SMALL LETTER KYA;Ll;0;L;;;;;N;;;104BE;;104BE +104E7;OSAGE SMALL LETTER LA;Ll;0;L;;;;;N;;;104BF;;104BF +104E8;OSAGE SMALL LETTER MA;Ll;0;L;;;;;N;;;104C0;;104C0 +104E9;OSAGE SMALL LETTER NA;Ll;0;L;;;;;N;;;104C1;;104C1 +104EA;OSAGE SMALL LETTER O;Ll;0;L;;;;;N;;;104C2;;104C2 +104EB;OSAGE SMALL LETTER OIN;Ll;0;L;;;;;N;;;104C3;;104C3 +104EC;OSAGE SMALL LETTER PA;Ll;0;L;;;;;N;;;104C4;;104C4 +104ED;OSAGE SMALL LETTER EHPA;Ll;0;L;;;;;N;;;104C5;;104C5 +104EE;OSAGE SMALL LETTER SA;Ll;0;L;;;;;N;;;104C6;;104C6 +104EF;OSAGE SMALL LETTER SHA;Ll;0;L;;;;;N;;;104C7;;104C7 +104F0;OSAGE SMALL LETTER TA;Ll;0;L;;;;;N;;;104C8;;104C8 +104F1;OSAGE SMALL LETTER EHTA;Ll;0;L;;;;;N;;;104C9;;104C9 +104F2;OSAGE SMALL LETTER TSA;Ll;0;L;;;;;N;;;104CA;;104CA +104F3;OSAGE SMALL LETTER EHTSA;Ll;0;L;;;;;N;;;104CB;;104CB +104F4;OSAGE SMALL LETTER TSHA;Ll;0;L;;;;;N;;;104CC;;104CC +104F5;OSAGE SMALL LETTER DHA;Ll;0;L;;;;;N;;;104CD;;104CD +104F6;OSAGE SMALL LETTER U;Ll;0;L;;;;;N;;;104CE;;104CE +104F7;OSAGE SMALL LETTER WA;Ll;0;L;;;;;N;;;104CF;;104CF +104F8;OSAGE SMALL LETTER KHA;Ll;0;L;;;;;N;;;104D0;;104D0 +104F9;OSAGE SMALL LETTER GHA;Ll;0;L;;;;;N;;;104D1;;104D1 +104FA;OSAGE SMALL LETTER ZA;Ll;0;L;;;;;N;;;104D2;;104D2 +104FB;OSAGE SMALL LETTER ZHA;Ll;0;L;;;;;N;;;104D3;;104D3 10500;ELBASAN LETTER A;Lo;0;L;;;;;N;;;;; 10501;ELBASAN LETTER BE;Lo;0;L;;;;;N;;;;; 10502;ELBASAN LETTER CE;Lo;0;L;;;;;N;;;;; @@ -19180,6 +19310,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1123B;KHOJKI SECTION MARK;Po;0;L;;;;;N;;;;; 1123C;KHOJKI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;; 1123D;KHOJKI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +1123E;KHOJKI SIGN SUKUN;Mn;0;NSM;;;;;N;;;;; 11280;MULTANI LETTER A;Lo;0;L;;;;;N;;;;; 11281;MULTANI LETTER I;Lo;0;L;;;;;N;;;;; 11282;MULTANI LETTER U;Lo;0;L;;;;;N;;;;; @@ -19372,6 +19503,98 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11372;COMBINING GRANTHA LETTER NA;Mn;230;NSM;;;;;N;;;;; 11373;COMBINING GRANTHA LETTER VI;Mn;230;NSM;;;;;N;;;;; 11374;COMBINING GRANTHA LETTER PA;Mn;230;NSM;;;;;N;;;;; +11400;NEWA LETTER A;Lo;0;L;;;;;N;;;;; +11401;NEWA LETTER AA;Lo;0;L;;;;;N;;;;; +11402;NEWA LETTER I;Lo;0;L;;;;;N;;;;; +11403;NEWA LETTER II;Lo;0;L;;;;;N;;;;; +11404;NEWA LETTER U;Lo;0;L;;;;;N;;;;; +11405;NEWA LETTER UU;Lo;0;L;;;;;N;;;;; +11406;NEWA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11407;NEWA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11408;NEWA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +11409;NEWA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1140A;NEWA LETTER E;Lo;0;L;;;;;N;;;;; +1140B;NEWA LETTER AI;Lo;0;L;;;;;N;;;;; +1140C;NEWA LETTER O;Lo;0;L;;;;;N;;;;; +1140D;NEWA LETTER AU;Lo;0;L;;;;;N;;;;; +1140E;NEWA LETTER KA;Lo;0;L;;;;;N;;;;; +1140F;NEWA LETTER KHA;Lo;0;L;;;;;N;;;;; +11410;NEWA LETTER GA;Lo;0;L;;;;;N;;;;; +11411;NEWA LETTER GHA;Lo;0;L;;;;;N;;;;; +11412;NEWA LETTER NGA;Lo;0;L;;;;;N;;;;; +11413;NEWA LETTER NGHA;Lo;0;L;;;;;N;;;;; +11414;NEWA LETTER CA;Lo;0;L;;;;;N;;;;; +11415;NEWA LETTER CHA;Lo;0;L;;;;;N;;;;; +11416;NEWA LETTER JA;Lo;0;L;;;;;N;;;;; +11417;NEWA LETTER JHA;Lo;0;L;;;;;N;;;;; +11418;NEWA LETTER NYA;Lo;0;L;;;;;N;;;;; +11419;NEWA LETTER NYHA;Lo;0;L;;;;;N;;;;; +1141A;NEWA LETTER TTA;Lo;0;L;;;;;N;;;;; +1141B;NEWA LETTER TTHA;Lo;0;L;;;;;N;;;;; +1141C;NEWA LETTER DDA;Lo;0;L;;;;;N;;;;; +1141D;NEWA LETTER DDHA;Lo;0;L;;;;;N;;;;; +1141E;NEWA LETTER NNA;Lo;0;L;;;;;N;;;;; +1141F;NEWA LETTER TA;Lo;0;L;;;;;N;;;;; +11420;NEWA LETTER THA;Lo;0;L;;;;;N;;;;; +11421;NEWA LETTER DA;Lo;0;L;;;;;N;;;;; +11422;NEWA LETTER DHA;Lo;0;L;;;;;N;;;;; +11423;NEWA LETTER NA;Lo;0;L;;;;;N;;;;; +11424;NEWA LETTER NHA;Lo;0;L;;;;;N;;;;; +11425;NEWA LETTER PA;Lo;0;L;;;;;N;;;;; +11426;NEWA LETTER PHA;Lo;0;L;;;;;N;;;;; +11427;NEWA LETTER BA;Lo;0;L;;;;;N;;;;; +11428;NEWA LETTER BHA;Lo;0;L;;;;;N;;;;; +11429;NEWA LETTER MA;Lo;0;L;;;;;N;;;;; +1142A;NEWA LETTER MHA;Lo;0;L;;;;;N;;;;; +1142B;NEWA LETTER YA;Lo;0;L;;;;;N;;;;; +1142C;NEWA LETTER RA;Lo;0;L;;;;;N;;;;; +1142D;NEWA LETTER RHA;Lo;0;L;;;;;N;;;;; +1142E;NEWA LETTER LA;Lo;0;L;;;;;N;;;;; +1142F;NEWA LETTER LHA;Lo;0;L;;;;;N;;;;; +11430;NEWA LETTER WA;Lo;0;L;;;;;N;;;;; +11431;NEWA LETTER SHA;Lo;0;L;;;;;N;;;;; +11432;NEWA LETTER SSA;Lo;0;L;;;;;N;;;;; +11433;NEWA LETTER SA;Lo;0;L;;;;;N;;;;; +11434;NEWA LETTER HA;Lo;0;L;;;;;N;;;;; +11435;NEWA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11436;NEWA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +11437;NEWA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +11438;NEWA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11439;NEWA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +1143A;NEWA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +1143B;NEWA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +1143C;NEWA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +1143D;NEWA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +1143E;NEWA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +1143F;NEWA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11440;NEWA VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +11441;NEWA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +11442;NEWA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +11443;NEWA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11444;NEWA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11445;NEWA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11446;NEWA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +11447;NEWA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +11448;NEWA SIGN FINAL ANUSVARA;Lo;0;L;;;;;N;;;;; +11449;NEWA OM;Lo;0;L;;;;;N;;;;; +1144A;NEWA SIDDHI;Lo;0;L;;;;;N;;;;; +1144B;NEWA DANDA;Po;0;L;;;;;N;;;;; +1144C;NEWA DOUBLE DANDA;Po;0;L;;;;;N;;;;; +1144D;NEWA COMMA;Po;0;L;;;;;N;;;;; +1144E;NEWA GAP FILLER;Po;0;L;;;;;N;;;;; +1144F;NEWA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +11450;NEWA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11451;NEWA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11452;NEWA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11453;NEWA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11454;NEWA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11455;NEWA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11456;NEWA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11457;NEWA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11458;NEWA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11459;NEWA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1145B;NEWA PLACEHOLDER MARK;Po;0;L;;;;;N;;;;; +1145D;NEWA INSERTION SIGN;Po;0;L;;;;;N;;;;; 11480;TIRHUTA ANJI;Lo;0;L;;;;;N;;;;; 11481;TIRHUTA LETTER A;Lo;0;L;;;;;N;;;;; 11482;TIRHUTA LETTER AA;Lo;0;L;;;;;N;;;;; @@ -19625,6 +19848,19 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11657;MODI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 11658;MODI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 11659;MODI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11660;MONGOLIAN BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +11661;MONGOLIAN ROTATED BIRGA;Po;0;ON;;;;;N;;;;; +11662;MONGOLIAN DOUBLE BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +11663;MONGOLIAN TRIPLE BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +11664;MONGOLIAN BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; +11665;MONGOLIAN ROTATED BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +11666;MONGOLIAN ROTATED BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; +11667;MONGOLIAN INVERTED BIRGA;Po;0;ON;;;;;N;;;;; +11668;MONGOLIAN INVERTED BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; +11669;MONGOLIAN SWIRL BIRGA;Po;0;ON;;;;;N;;;;; +1166A;MONGOLIAN SWIRL BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +1166B;MONGOLIAN SWIRL BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; +1166C;MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; 11680;TAKRI LETTER A;Lo;0;L;;;;;N;;;;; 11681;TAKRI LETTER AA;Lo;0;L;;;;;N;;;;; 11682;TAKRI LETTER I;Lo;0;L;;;;;N;;;;; @@ -19889,6 +20125,171 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11AF6;PAU CIN HAU LOW-FALLING TONE LONG FINAL;Lo;0;L;;;;;N;;;;; 11AF7;PAU CIN HAU LOW-FALLING TONE FINAL;Lo;0;L;;;;;N;;;;; 11AF8;PAU CIN HAU GLOTTAL STOP FINAL;Lo;0;L;;;;;N;;;;; +11C00;BHAIKSUKI LETTER A;Lo;0;L;;;;;N;;;;; +11C01;BHAIKSUKI LETTER AA;Lo;0;L;;;;;N;;;;; +11C02;BHAIKSUKI LETTER I;Lo;0;L;;;;;N;;;;; +11C03;BHAIKSUKI LETTER II;Lo;0;L;;;;;N;;;;; +11C04;BHAIKSUKI LETTER U;Lo;0;L;;;;;N;;;;; +11C05;BHAIKSUKI LETTER UU;Lo;0;L;;;;;N;;;;; +11C06;BHAIKSUKI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11C07;BHAIKSUKI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11C08;BHAIKSUKI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +11C0A;BHAIKSUKI LETTER E;Lo;0;L;;;;;N;;;;; +11C0B;BHAIKSUKI LETTER AI;Lo;0;L;;;;;N;;;;; +11C0C;BHAIKSUKI LETTER O;Lo;0;L;;;;;N;;;;; +11C0D;BHAIKSUKI LETTER AU;Lo;0;L;;;;;N;;;;; +11C0E;BHAIKSUKI LETTER KA;Lo;0;L;;;;;N;;;;; +11C0F;BHAIKSUKI LETTER KHA;Lo;0;L;;;;;N;;;;; +11C10;BHAIKSUKI LETTER GA;Lo;0;L;;;;;N;;;;; +11C11;BHAIKSUKI LETTER GHA;Lo;0;L;;;;;N;;;;; +11C12;BHAIKSUKI LETTER NGA;Lo;0;L;;;;;N;;;;; +11C13;BHAIKSUKI LETTER CA;Lo;0;L;;;;;N;;;;; +11C14;BHAIKSUKI LETTER CHA;Lo;0;L;;;;;N;;;;; +11C15;BHAIKSUKI LETTER JA;Lo;0;L;;;;;N;;;;; +11C16;BHAIKSUKI LETTER JHA;Lo;0;L;;;;;N;;;;; +11C17;BHAIKSUKI LETTER NYA;Lo;0;L;;;;;N;;;;; +11C18;BHAIKSUKI LETTER TTA;Lo;0;L;;;;;N;;;;; +11C19;BHAIKSUKI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11C1A;BHAIKSUKI LETTER DDA;Lo;0;L;;;;;N;;;;; +11C1B;BHAIKSUKI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11C1C;BHAIKSUKI LETTER NNA;Lo;0;L;;;;;N;;;;; +11C1D;BHAIKSUKI LETTER TA;Lo;0;L;;;;;N;;;;; +11C1E;BHAIKSUKI LETTER THA;Lo;0;L;;;;;N;;;;; +11C1F;BHAIKSUKI LETTER DA;Lo;0;L;;;;;N;;;;; +11C20;BHAIKSUKI LETTER DHA;Lo;0;L;;;;;N;;;;; +11C21;BHAIKSUKI LETTER NA;Lo;0;L;;;;;N;;;;; +11C22;BHAIKSUKI LETTER PA;Lo;0;L;;;;;N;;;;; +11C23;BHAIKSUKI LETTER PHA;Lo;0;L;;;;;N;;;;; +11C24;BHAIKSUKI LETTER BA;Lo;0;L;;;;;N;;;;; +11C25;BHAIKSUKI LETTER BHA;Lo;0;L;;;;;N;;;;; +11C26;BHAIKSUKI LETTER MA;Lo;0;L;;;;;N;;;;; +11C27;BHAIKSUKI LETTER YA;Lo;0;L;;;;;N;;;;; +11C28;BHAIKSUKI LETTER RA;Lo;0;L;;;;;N;;;;; +11C29;BHAIKSUKI LETTER LA;Lo;0;L;;;;;N;;;;; +11C2A;BHAIKSUKI LETTER VA;Lo;0;L;;;;;N;;;;; +11C2B;BHAIKSUKI LETTER SHA;Lo;0;L;;;;;N;;;;; +11C2C;BHAIKSUKI LETTER SSA;Lo;0;L;;;;;N;;;;; +11C2D;BHAIKSUKI LETTER SA;Lo;0;L;;;;;N;;;;; +11C2E;BHAIKSUKI LETTER HA;Lo;0;L;;;;;N;;;;; +11C2F;BHAIKSUKI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11C30;BHAIKSUKI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11C31;BHAIKSUKI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +11C32;BHAIKSUKI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11C33;BHAIKSUKI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +11C34;BHAIKSUKI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +11C35;BHAIKSUKI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +11C36;BHAIKSUKI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +11C38;BHAIKSUKI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11C39;BHAIKSUKI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11C3A;BHAIKSUKI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11C3B;BHAIKSUKI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +11C3C;BHAIKSUKI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11C3D;BHAIKSUKI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11C3E;BHAIKSUKI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11C3F;BHAIKSUKI SIGN VIRAMA;Mn;9;L;;;;;N;;;;; +11C40;BHAIKSUKI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +11C41;BHAIKSUKI DANDA;Po;0;L;;;;;N;;;;; +11C42;BHAIKSUKI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +11C43;BHAIKSUKI WORD SEPARATOR;Po;0;L;;;;;N;;;;; +11C44;BHAIKSUKI GAP FILLER-1;Po;0;L;;;;;N;;;;; +11C45;BHAIKSUKI GAP FILLER-2;Po;0;L;;;;;N;;;;; +11C50;BHAIKSUKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11C51;BHAIKSUKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11C52;BHAIKSUKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11C53;BHAIKSUKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11C54;BHAIKSUKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11C55;BHAIKSUKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11C56;BHAIKSUKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11C57;BHAIKSUKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11C58;BHAIKSUKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11C59;BHAIKSUKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11C5A;BHAIKSUKI NUMBER ONE;No;0;L;;;;1;N;;;;; +11C5B;BHAIKSUKI NUMBER TWO;No;0;L;;;;2;N;;;;; +11C5C;BHAIKSUKI NUMBER THREE;No;0;L;;;;3;N;;;;; +11C5D;BHAIKSUKI NUMBER FOUR;No;0;L;;;;4;N;;;;; +11C5E;BHAIKSUKI NUMBER FIVE;No;0;L;;;;5;N;;;;; +11C5F;BHAIKSUKI NUMBER SIX;No;0;L;;;;6;N;;;;; +11C60;BHAIKSUKI NUMBER SEVEN;No;0;L;;;;7;N;;;;; +11C61;BHAIKSUKI NUMBER EIGHT;No;0;L;;;;8;N;;;;; +11C62;BHAIKSUKI NUMBER NINE;No;0;L;;;;9;N;;;;; +11C63;BHAIKSUKI NUMBER TEN;No;0;L;;;;10;N;;;;; +11C64;BHAIKSUKI NUMBER TWENTY;No;0;L;;;;20;N;;;;; +11C65;BHAIKSUKI NUMBER THIRTY;No;0;L;;;;30;N;;;;; +11C66;BHAIKSUKI NUMBER FORTY;No;0;L;;;;40;N;;;;; +11C67;BHAIKSUKI NUMBER FIFTY;No;0;L;;;;50;N;;;;; +11C68;BHAIKSUKI NUMBER SIXTY;No;0;L;;;;60;N;;;;; +11C69;BHAIKSUKI NUMBER SEVENTY;No;0;L;;;;70;N;;;;; +11C6A;BHAIKSUKI NUMBER EIGHTY;No;0;L;;;;80;N;;;;; +11C6B;BHAIKSUKI NUMBER NINETY;No;0;L;;;;90;N;;;;; +11C6C;BHAIKSUKI HUNDREDS UNIT MARK;No;0;L;;;;100;N;;;;; +11C70;MARCHEN HEAD MARK;Po;0;L;;;;;N;;;;; +11C71;MARCHEN MARK SHAD;Po;0;L;;;;;N;;;;; +11C72;MARCHEN LETTER KA;Lo;0;L;;;;;N;;;;; +11C73;MARCHEN LETTER KHA;Lo;0;L;;;;;N;;;;; +11C74;MARCHEN LETTER GA;Lo;0;L;;;;;N;;;;; +11C75;MARCHEN LETTER NGA;Lo;0;L;;;;;N;;;;; +11C76;MARCHEN LETTER CA;Lo;0;L;;;;;N;;;;; +11C77;MARCHEN LETTER CHA;Lo;0;L;;;;;N;;;;; +11C78;MARCHEN LETTER JA;Lo;0;L;;;;;N;;;;; +11C79;MARCHEN LETTER NYA;Lo;0;L;;;;;N;;;;; +11C7A;MARCHEN LETTER TA;Lo;0;L;;;;;N;;;;; +11C7B;MARCHEN LETTER THA;Lo;0;L;;;;;N;;;;; +11C7C;MARCHEN LETTER DA;Lo;0;L;;;;;N;;;;; +11C7D;MARCHEN LETTER NA;Lo;0;L;;;;;N;;;;; +11C7E;MARCHEN LETTER PA;Lo;0;L;;;;;N;;;;; +11C7F;MARCHEN LETTER PHA;Lo;0;L;;;;;N;;;;; +11C80;MARCHEN LETTER BA;Lo;0;L;;;;;N;;;;; +11C81;MARCHEN LETTER MA;Lo;0;L;;;;;N;;;;; +11C82;MARCHEN LETTER TSA;Lo;0;L;;;;;N;;;;; +11C83;MARCHEN LETTER TSHA;Lo;0;L;;;;;N;;;;; +11C84;MARCHEN LETTER DZA;Lo;0;L;;;;;N;;;;; +11C85;MARCHEN LETTER WA;Lo;0;L;;;;;N;;;;; +11C86;MARCHEN LETTER ZHA;Lo;0;L;;;;;N;;;;; +11C87;MARCHEN LETTER ZA;Lo;0;L;;;;;N;;;;; +11C88;MARCHEN LETTER -A;Lo;0;L;;;;;N;;;;; +11C89;MARCHEN LETTER YA;Lo;0;L;;;;;N;;;;; +11C8A;MARCHEN LETTER RA;Lo;0;L;;;;;N;;;;; +11C8B;MARCHEN LETTER LA;Lo;0;L;;;;;N;;;;; +11C8C;MARCHEN LETTER SHA;Lo;0;L;;;;;N;;;;; +11C8D;MARCHEN LETTER SA;Lo;0;L;;;;;N;;;;; +11C8E;MARCHEN LETTER HA;Lo;0;L;;;;;N;;;;; +11C8F;MARCHEN LETTER A;Lo;0;L;;;;;N;;;;; +11C92;MARCHEN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;; +11C93;MARCHEN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;; +11C94;MARCHEN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;; +11C95;MARCHEN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;; +11C96;MARCHEN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;; +11C97;MARCHEN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;; +11C98;MARCHEN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;; +11C99;MARCHEN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;; +11C9A;MARCHEN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;; +11C9B;MARCHEN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;; +11C9C;MARCHEN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;; +11C9D;MARCHEN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;; +11C9E;MARCHEN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;; +11C9F;MARCHEN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;; +11CA0;MARCHEN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;; +11CA1;MARCHEN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;; +11CA2;MARCHEN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;; +11CA3;MARCHEN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;; +11CA4;MARCHEN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;; +11CA5;MARCHEN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;;;; +11CA6;MARCHEN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;; +11CA7;MARCHEN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;; +11CA9;MARCHEN SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;; +11CAA;MARCHEN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;;;; +11CAB;MARCHEN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;; +11CAC;MARCHEN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;; +11CAD;MARCHEN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;; +11CAE;MARCHEN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;; +11CAF;MARCHEN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;; +11CB0;MARCHEN VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +11CB1;MARCHEN VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +11CB2;MARCHEN VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11CB3;MARCHEN VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11CB4;MARCHEN VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +11CB5;MARCHEN SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11CB6;MARCHEN SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 12000;CUNEIFORM SIGN A;Lo;0;L;;;;;N;;;;; 12001;CUNEIFORM SIGN A TIMES A;Lo;0;L;;;;;N;;;;; 12002;CUNEIFORM SIGN A TIMES BAD;Lo;0;L;;;;;N;;;;; @@ -23685,6 +24086,764 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 16F9D;MIAO LETTER REFORMED TONE-5;Lm;0;L;;;;;N;;;;; 16F9E;MIAO LETTER REFORMED TONE-6;Lm;0;L;;;;;N;;;;; 16F9F;MIAO LETTER REFORMED TONE-8;Lm;0;L;;;;;N;;;;; +16FE0;TANGUT ITERATION MARK;Lm;0;L;;;;;N;;;;; +17000;<Tangut Ideograph, First>;Lo;0;L;;;;;N;;;;; +187EC;<Tangut Ideograph, Last>;Lo;0;L;;;;;N;;;;; +18800;TANGUT COMPONENT-001;Lo;0;L;;;;;N;;;;; +18801;TANGUT COMPONENT-002;Lo;0;L;;;;;N;;;;; +18802;TANGUT COMPONENT-003;Lo;0;L;;;;;N;;;;; +18803;TANGUT COMPONENT-004;Lo;0;L;;;;;N;;;;; +18804;TANGUT COMPONENT-005;Lo;0;L;;;;;N;;;;; +18805;TANGUT COMPONENT-006;Lo;0;L;;;;;N;;;;; +18806;TANGUT COMPONENT-007;Lo;0;L;;;;;N;;;;; +18807;TANGUT COMPONENT-008;Lo;0;L;;;;;N;;;;; +18808;TANGUT COMPONENT-009;Lo;0;L;;;;;N;;;;; +18809;TANGUT COMPONENT-010;Lo;0;L;;;;;N;;;;; +1880A;TANGUT COMPONENT-011;Lo;0;L;;;;;N;;;;; +1880B;TANGUT COMPONENT-012;Lo;0;L;;;;;N;;;;; +1880C;TANGUT COMPONENT-013;Lo;0;L;;;;;N;;;;; +1880D;TANGUT COMPONENT-014;Lo;0;L;;;;;N;;;;; +1880E;TANGUT COMPONENT-015;Lo;0;L;;;;;N;;;;; +1880F;TANGUT COMPONENT-016;Lo;0;L;;;;;N;;;;; +18810;TANGUT COMPONENT-017;Lo;0;L;;;;;N;;;;; +18811;TANGUT COMPONENT-018;Lo;0;L;;;;;N;;;;; +18812;TANGUT COMPONENT-019;Lo;0;L;;;;;N;;;;; +18813;TANGUT COMPONENT-020;Lo;0;L;;;;;N;;;;; +18814;TANGUT COMPONENT-021;Lo;0;L;;;;;N;;;;; +18815;TANGUT COMPONENT-022;Lo;0;L;;;;;N;;;;; +18816;TANGUT COMPONENT-023;Lo;0;L;;;;;N;;;;; +18817;TANGUT COMPONENT-024;Lo;0;L;;;;;N;;;;; +18818;TANGUT COMPONENT-025;Lo;0;L;;;;;N;;;;; +18819;TANGUT COMPONENT-026;Lo;0;L;;;;;N;;;;; +1881A;TANGUT COMPONENT-027;Lo;0;L;;;;;N;;;;; +1881B;TANGUT COMPONENT-028;Lo;0;L;;;;;N;;;;; +1881C;TANGUT COMPONENT-029;Lo;0;L;;;;;N;;;;; +1881D;TANGUT COMPONENT-030;Lo;0;L;;;;;N;;;;; +1881E;TANGUT COMPONENT-031;Lo;0;L;;;;;N;;;;; +1881F;TANGUT COMPONENT-032;Lo;0;L;;;;;N;;;;; +18820;TANGUT COMPONENT-033;Lo;0;L;;;;;N;;;;; +18821;TANGUT COMPONENT-034;Lo;0;L;;;;;N;;;;; +18822;TANGUT COMPONENT-035;Lo;0;L;;;;;N;;;;; +18823;TANGUT COMPONENT-036;Lo;0;L;;;;;N;;;;; +18824;TANGUT COMPONENT-037;Lo;0;L;;;;;N;;;;; +18825;TANGUT COMPONENT-038;Lo;0;L;;;;;N;;;;; +18826;TANGUT COMPONENT-039;Lo;0;L;;;;;N;;;;; +18827;TANGUT COMPONENT-040;Lo;0;L;;;;;N;;;;; +18828;TANGUT COMPONENT-041;Lo;0;L;;;;;N;;;;; +18829;TANGUT COMPONENT-042;Lo;0;L;;;;;N;;;;; +1882A;TANGUT COMPONENT-043;Lo;0;L;;;;;N;;;;; +1882B;TANGUT COMPONENT-044;Lo;0;L;;;;;N;;;;; +1882C;TANGUT COMPONENT-045;Lo;0;L;;;;;N;;;;; +1882D;TANGUT COMPONENT-046;Lo;0;L;;;;;N;;;;; +1882E;TANGUT COMPONENT-047;Lo;0;L;;;;;N;;;;; +1882F;TANGUT COMPONENT-048;Lo;0;L;;;;;N;;;;; +18830;TANGUT COMPONENT-049;Lo;0;L;;;;;N;;;;; +18831;TANGUT COMPONENT-050;Lo;0;L;;;;;N;;;;; +18832;TANGUT COMPONENT-051;Lo;0;L;;;;;N;;;;; +18833;TANGUT COMPONENT-052;Lo;0;L;;;;;N;;;;; +18834;TANGUT COMPONENT-053;Lo;0;L;;;;;N;;;;; +18835;TANGUT COMPONENT-054;Lo;0;L;;;;;N;;;;; +18836;TANGUT COMPONENT-055;Lo;0;L;;;;;N;;;;; +18837;TANGUT COMPONENT-056;Lo;0;L;;;;;N;;;;; +18838;TANGUT COMPONENT-057;Lo;0;L;;;;;N;;;;; +18839;TANGUT COMPONENT-058;Lo;0;L;;;;;N;;;;; +1883A;TANGUT COMPONENT-059;Lo;0;L;;;;;N;;;;; +1883B;TANGUT COMPONENT-060;Lo;0;L;;;;;N;;;;; +1883C;TANGUT COMPONENT-061;Lo;0;L;;;;;N;;;;; +1883D;TANGUT COMPONENT-062;Lo;0;L;;;;;N;;;;; +1883E;TANGUT COMPONENT-063;Lo;0;L;;;;;N;;;;; +1883F;TANGUT COMPONENT-064;Lo;0;L;;;;;N;;;;; +18840;TANGUT COMPONENT-065;Lo;0;L;;;;;N;;;;; +18841;TANGUT COMPONENT-066;Lo;0;L;;;;;N;;;;; +18842;TANGUT COMPONENT-067;Lo;0;L;;;;;N;;;;; +18843;TANGUT COMPONENT-068;Lo;0;L;;;;;N;;;;; +18844;TANGUT COMPONENT-069;Lo;0;L;;;;;N;;;;; +18845;TANGUT COMPONENT-070;Lo;0;L;;;;;N;;;;; +18846;TANGUT COMPONENT-071;Lo;0;L;;;;;N;;;;; +18847;TANGUT COMPONENT-072;Lo;0;L;;;;;N;;;;; +18848;TANGUT COMPONENT-073;Lo;0;L;;;;;N;;;;; +18849;TANGUT COMPONENT-074;Lo;0;L;;;;;N;;;;; +1884A;TANGUT COMPONENT-075;Lo;0;L;;;;;N;;;;; +1884B;TANGUT COMPONENT-076;Lo;0;L;;;;;N;;;;; +1884C;TANGUT COMPONENT-077;Lo;0;L;;;;;N;;;;; +1884D;TANGUT COMPONENT-078;Lo;0;L;;;;;N;;;;; +1884E;TANGUT COMPONENT-079;Lo;0;L;;;;;N;;;;; +1884F;TANGUT COMPONENT-080;Lo;0;L;;;;;N;;;;; +18850;TANGUT COMPONENT-081;Lo;0;L;;;;;N;;;;; +18851;TANGUT COMPONENT-082;Lo;0;L;;;;;N;;;;; +18852;TANGUT COMPONENT-083;Lo;0;L;;;;;N;;;;; +18853;TANGUT COMPONENT-084;Lo;0;L;;;;;N;;;;; +18854;TANGUT COMPONENT-085;Lo;0;L;;;;;N;;;;; +18855;TANGUT COMPONENT-086;Lo;0;L;;;;;N;;;;; +18856;TANGUT COMPONENT-087;Lo;0;L;;;;;N;;;;; +18857;TANGUT COMPONENT-088;Lo;0;L;;;;;N;;;;; +18858;TANGUT COMPONENT-089;Lo;0;L;;;;;N;;;;; +18859;TANGUT COMPONENT-090;Lo;0;L;;;;;N;;;;; +1885A;TANGUT COMPONENT-091;Lo;0;L;;;;;N;;;;; +1885B;TANGUT COMPONENT-092;Lo;0;L;;;;;N;;;;; +1885C;TANGUT COMPONENT-093;Lo;0;L;;;;;N;;;;; +1885D;TANGUT COMPONENT-094;Lo;0;L;;;;;N;;;;; +1885E;TANGUT COMPONENT-095;Lo;0;L;;;;;N;;;;; +1885F;TANGUT COMPONENT-096;Lo;0;L;;;;;N;;;;; +18860;TANGUT COMPONENT-097;Lo;0;L;;;;;N;;;;; +18861;TANGUT COMPONENT-098;Lo;0;L;;;;;N;;;;; +18862;TANGUT COMPONENT-099;Lo;0;L;;;;;N;;;;; +18863;TANGUT COMPONENT-100;Lo;0;L;;;;;N;;;;; +18864;TANGUT COMPONENT-101;Lo;0;L;;;;;N;;;;; +18865;TANGUT COMPONENT-102;Lo;0;L;;;;;N;;;;; +18866;TANGUT COMPONENT-103;Lo;0;L;;;;;N;;;;; +18867;TANGUT COMPONENT-104;Lo;0;L;;;;;N;;;;; +18868;TANGUT COMPONENT-105;Lo;0;L;;;;;N;;;;; +18869;TANGUT COMPONENT-106;Lo;0;L;;;;;N;;;;; +1886A;TANGUT COMPONENT-107;Lo;0;L;;;;;N;;;;; +1886B;TANGUT COMPONENT-108;Lo;0;L;;;;;N;;;;; +1886C;TANGUT COMPONENT-109;Lo;0;L;;;;;N;;;;; +1886D;TANGUT COMPONENT-110;Lo;0;L;;;;;N;;;;; +1886E;TANGUT COMPONENT-111;Lo;0;L;;;;;N;;;;; +1886F;TANGUT COMPONENT-112;Lo;0;L;;;;;N;;;;; +18870;TANGUT COMPONENT-113;Lo;0;L;;;;;N;;;;; +18871;TANGUT COMPONENT-114;Lo;0;L;;;;;N;;;;; +18872;TANGUT COMPONENT-115;Lo;0;L;;;;;N;;;;; +18873;TANGUT COMPONENT-116;Lo;0;L;;;;;N;;;;; +18874;TANGUT COMPONENT-117;Lo;0;L;;;;;N;;;;; +18875;TANGUT COMPONENT-118;Lo;0;L;;;;;N;;;;; +18876;TANGUT COMPONENT-119;Lo;0;L;;;;;N;;;;; +18877;TANGUT COMPONENT-120;Lo;0;L;;;;;N;;;;; +18878;TANGUT COMPONENT-121;Lo;0;L;;;;;N;;;;; +18879;TANGUT COMPONENT-122;Lo;0;L;;;;;N;;;;; +1887A;TANGUT COMPONENT-123;Lo;0;L;;;;;N;;;;; +1887B;TANGUT COMPONENT-124;Lo;0;L;;;;;N;;;;; +1887C;TANGUT COMPONENT-125;Lo;0;L;;;;;N;;;;; +1887D;TANGUT COMPONENT-126;Lo;0;L;;;;;N;;;;; +1887E;TANGUT COMPONENT-127;Lo;0;L;;;;;N;;;;; +1887F;TANGUT COMPONENT-128;Lo;0;L;;;;;N;;;;; +18880;TANGUT COMPONENT-129;Lo;0;L;;;;;N;;;;; +18881;TANGUT COMPONENT-130;Lo;0;L;;;;;N;;;;; +18882;TANGUT COMPONENT-131;Lo;0;L;;;;;N;;;;; +18883;TANGUT COMPONENT-132;Lo;0;L;;;;;N;;;;; +18884;TANGUT COMPONENT-133;Lo;0;L;;;;;N;;;;; +18885;TANGUT COMPONENT-134;Lo;0;L;;;;;N;;;;; +18886;TANGUT COMPONENT-135;Lo;0;L;;;;;N;;;;; +18887;TANGUT COMPONENT-136;Lo;0;L;;;;;N;;;;; +18888;TANGUT COMPONENT-137;Lo;0;L;;;;;N;;;;; +18889;TANGUT COMPONENT-138;Lo;0;L;;;;;N;;;;; +1888A;TANGUT COMPONENT-139;Lo;0;L;;;;;N;;;;; +1888B;TANGUT COMPONENT-140;Lo;0;L;;;;;N;;;;; +1888C;TANGUT COMPONENT-141;Lo;0;L;;;;;N;;;;; +1888D;TANGUT COMPONENT-142;Lo;0;L;;;;;N;;;;; +1888E;TANGUT COMPONENT-143;Lo;0;L;;;;;N;;;;; +1888F;TANGUT COMPONENT-144;Lo;0;L;;;;;N;;;;; +18890;TANGUT COMPONENT-145;Lo;0;L;;;;;N;;;;; +18891;TANGUT COMPONENT-146;Lo;0;L;;;;;N;;;;; +18892;TANGUT COMPONENT-147;Lo;0;L;;;;;N;;;;; +18893;TANGUT COMPONENT-148;Lo;0;L;;;;;N;;;;; +18894;TANGUT COMPONENT-149;Lo;0;L;;;;;N;;;;; +18895;TANGUT COMPONENT-150;Lo;0;L;;;;;N;;;;; +18896;TANGUT COMPONENT-151;Lo;0;L;;;;;N;;;;; +18897;TANGUT COMPONENT-152;Lo;0;L;;;;;N;;;;; +18898;TANGUT COMPONENT-153;Lo;0;L;;;;;N;;;;; +18899;TANGUT COMPONENT-154;Lo;0;L;;;;;N;;;;; +1889A;TANGUT COMPONENT-155;Lo;0;L;;;;;N;;;;; +1889B;TANGUT COMPONENT-156;Lo;0;L;;;;;N;;;;; +1889C;TANGUT COMPONENT-157;Lo;0;L;;;;;N;;;;; +1889D;TANGUT COMPONENT-158;Lo;0;L;;;;;N;;;;; +1889E;TANGUT COMPONENT-159;Lo;0;L;;;;;N;;;;; +1889F;TANGUT COMPONENT-160;Lo;0;L;;;;;N;;;;; +188A0;TANGUT COMPONENT-161;Lo;0;L;;;;;N;;;;; +188A1;TANGUT COMPONENT-162;Lo;0;L;;;;;N;;;;; +188A2;TANGUT COMPONENT-163;Lo;0;L;;;;;N;;;;; +188A3;TANGUT COMPONENT-164;Lo;0;L;;;;;N;;;;; +188A4;TANGUT COMPONENT-165;Lo;0;L;;;;;N;;;;; +188A5;TANGUT COMPONENT-166;Lo;0;L;;;;;N;;;;; +188A6;TANGUT COMPONENT-167;Lo;0;L;;;;;N;;;;; +188A7;TANGUT COMPONENT-168;Lo;0;L;;;;;N;;;;; +188A8;TANGUT COMPONENT-169;Lo;0;L;;;;;N;;;;; +188A9;TANGUT COMPONENT-170;Lo;0;L;;;;;N;;;;; +188AA;TANGUT COMPONENT-171;Lo;0;L;;;;;N;;;;; +188AB;TANGUT COMPONENT-172;Lo;0;L;;;;;N;;;;; +188AC;TANGUT COMPONENT-173;Lo;0;L;;;;;N;;;;; +188AD;TANGUT COMPONENT-174;Lo;0;L;;;;;N;;;;; +188AE;TANGUT COMPONENT-175;Lo;0;L;;;;;N;;;;; +188AF;TANGUT COMPONENT-176;Lo;0;L;;;;;N;;;;; +188B0;TANGUT COMPONENT-177;Lo;0;L;;;;;N;;;;; +188B1;TANGUT COMPONENT-178;Lo;0;L;;;;;N;;;;; +188B2;TANGUT COMPONENT-179;Lo;0;L;;;;;N;;;;; +188B3;TANGUT COMPONENT-180;Lo;0;L;;;;;N;;;;; +188B4;TANGUT COMPONENT-181;Lo;0;L;;;;;N;;;;; +188B5;TANGUT COMPONENT-182;Lo;0;L;;;;;N;;;;; +188B6;TANGUT COMPONENT-183;Lo;0;L;;;;;N;;;;; +188B7;TANGUT COMPONENT-184;Lo;0;L;;;;;N;;;;; +188B8;TANGUT COMPONENT-185;Lo;0;L;;;;;N;;;;; +188B9;TANGUT COMPONENT-186;Lo;0;L;;;;;N;;;;; +188BA;TANGUT COMPONENT-187;Lo;0;L;;;;;N;;;;; +188BB;TANGUT COMPONENT-188;Lo;0;L;;;;;N;;;;; +188BC;TANGUT COMPONENT-189;Lo;0;L;;;;;N;;;;; +188BD;TANGUT COMPONENT-190;Lo;0;L;;;;;N;;;;; +188BE;TANGUT COMPONENT-191;Lo;0;L;;;;;N;;;;; +188BF;TANGUT COMPONENT-192;Lo;0;L;;;;;N;;;;; +188C0;TANGUT COMPONENT-193;Lo;0;L;;;;;N;;;;; +188C1;TANGUT COMPONENT-194;Lo;0;L;;;;;N;;;;; +188C2;TANGUT COMPONENT-195;Lo;0;L;;;;;N;;;;; +188C3;TANGUT COMPONENT-196;Lo;0;L;;;;;N;;;;; +188C4;TANGUT COMPONENT-197;Lo;0;L;;;;;N;;;;; +188C5;TANGUT COMPONENT-198;Lo;0;L;;;;;N;;;;; +188C6;TANGUT COMPONENT-199;Lo;0;L;;;;;N;;;;; +188C7;TANGUT COMPONENT-200;Lo;0;L;;;;;N;;;;; +188C8;TANGUT COMPONENT-201;Lo;0;L;;;;;N;;;;; +188C9;TANGUT COMPONENT-202;Lo;0;L;;;;;N;;;;; +188CA;TANGUT COMPONENT-203;Lo;0;L;;;;;N;;;;; +188CB;TANGUT COMPONENT-204;Lo;0;L;;;;;N;;;;; +188CC;TANGUT COMPONENT-205;Lo;0;L;;;;;N;;;;; +188CD;TANGUT COMPONENT-206;Lo;0;L;;;;;N;;;;; +188CE;TANGUT COMPONENT-207;Lo;0;L;;;;;N;;;;; +188CF;TANGUT COMPONENT-208;Lo;0;L;;;;;N;;;;; +188D0;TANGUT COMPONENT-209;Lo;0;L;;;;;N;;;;; +188D1;TANGUT COMPONENT-210;Lo;0;L;;;;;N;;;;; +188D2;TANGUT COMPONENT-211;Lo;0;L;;;;;N;;;;; +188D3;TANGUT COMPONENT-212;Lo;0;L;;;;;N;;;;; +188D4;TANGUT COMPONENT-213;Lo;0;L;;;;;N;;;;; +188D5;TANGUT COMPONENT-214;Lo;0;L;;;;;N;;;;; +188D6;TANGUT COMPONENT-215;Lo;0;L;;;;;N;;;;; +188D7;TANGUT COMPONENT-216;Lo;0;L;;;;;N;;;;; +188D8;TANGUT COMPONENT-217;Lo;0;L;;;;;N;;;;; +188D9;TANGUT COMPONENT-218;Lo;0;L;;;;;N;;;;; +188DA;TANGUT COMPONENT-219;Lo;0;L;;;;;N;;;;; +188DB;TANGUT COMPONENT-220;Lo;0;L;;;;;N;;;;; +188DC;TANGUT COMPONENT-221;Lo;0;L;;;;;N;;;;; +188DD;TANGUT COMPONENT-222;Lo;0;L;;;;;N;;;;; +188DE;TANGUT COMPONENT-223;Lo;0;L;;;;;N;;;;; +188DF;TANGUT COMPONENT-224;Lo;0;L;;;;;N;;;;; +188E0;TANGUT COMPONENT-225;Lo;0;L;;;;;N;;;;; +188E1;TANGUT COMPONENT-226;Lo;0;L;;;;;N;;;;; +188E2;TANGUT COMPONENT-227;Lo;0;L;;;;;N;;;;; +188E3;TANGUT COMPONENT-228;Lo;0;L;;;;;N;;;;; +188E4;TANGUT COMPONENT-229;Lo;0;L;;;;;N;;;;; +188E5;TANGUT COMPONENT-230;Lo;0;L;;;;;N;;;;; +188E6;TANGUT COMPONENT-231;Lo;0;L;;;;;N;;;;; +188E7;TANGUT COMPONENT-232;Lo;0;L;;;;;N;;;;; +188E8;TANGUT COMPONENT-233;Lo;0;L;;;;;N;;;;; +188E9;TANGUT COMPONENT-234;Lo;0;L;;;;;N;;;;; +188EA;TANGUT COMPONENT-235;Lo;0;L;;;;;N;;;;; +188EB;TANGUT COMPONENT-236;Lo;0;L;;;;;N;;;;; +188EC;TANGUT COMPONENT-237;Lo;0;L;;;;;N;;;;; +188ED;TANGUT COMPONENT-238;Lo;0;L;;;;;N;;;;; +188EE;TANGUT COMPONENT-239;Lo;0;L;;;;;N;;;;; +188EF;TANGUT COMPONENT-240;Lo;0;L;;;;;N;;;;; +188F0;TANGUT COMPONENT-241;Lo;0;L;;;;;N;;;;; +188F1;TANGUT COMPONENT-242;Lo;0;L;;;;;N;;;;; +188F2;TANGUT COMPONENT-243;Lo;0;L;;;;;N;;;;; +188F3;TANGUT COMPONENT-244;Lo;0;L;;;;;N;;;;; +188F4;TANGUT COMPONENT-245;Lo;0;L;;;;;N;;;;; +188F5;TANGUT COMPONENT-246;Lo;0;L;;;;;N;;;;; +188F6;TANGUT COMPONENT-247;Lo;0;L;;;;;N;;;;; +188F7;TANGUT COMPONENT-248;Lo;0;L;;;;;N;;;;; +188F8;TANGUT COMPONENT-249;Lo;0;L;;;;;N;;;;; +188F9;TANGUT COMPONENT-250;Lo;0;L;;;;;N;;;;; +188FA;TANGUT COMPONENT-251;Lo;0;L;;;;;N;;;;; +188FB;TANGUT COMPONENT-252;Lo;0;L;;;;;N;;;;; +188FC;TANGUT COMPONENT-253;Lo;0;L;;;;;N;;;;; +188FD;TANGUT COMPONENT-254;Lo;0;L;;;;;N;;;;; +188FE;TANGUT COMPONENT-255;Lo;0;L;;;;;N;;;;; +188FF;TANGUT COMPONENT-256;Lo;0;L;;;;;N;;;;; +18900;TANGUT COMPONENT-257;Lo;0;L;;;;;N;;;;; +18901;TANGUT COMPONENT-258;Lo;0;L;;;;;N;;;;; +18902;TANGUT COMPONENT-259;Lo;0;L;;;;;N;;;;; +18903;TANGUT COMPONENT-260;Lo;0;L;;;;;N;;;;; +18904;TANGUT COMPONENT-261;Lo;0;L;;;;;N;;;;; +18905;TANGUT COMPONENT-262;Lo;0;L;;;;;N;;;;; +18906;TANGUT COMPONENT-263;Lo;0;L;;;;;N;;;;; +18907;TANGUT COMPONENT-264;Lo;0;L;;;;;N;;;;; +18908;TANGUT COMPONENT-265;Lo;0;L;;;;;N;;;;; +18909;TANGUT COMPONENT-266;Lo;0;L;;;;;N;;;;; +1890A;TANGUT COMPONENT-267;Lo;0;L;;;;;N;;;;; +1890B;TANGUT COMPONENT-268;Lo;0;L;;;;;N;;;;; +1890C;TANGUT COMPONENT-269;Lo;0;L;;;;;N;;;;; +1890D;TANGUT COMPONENT-270;Lo;0;L;;;;;N;;;;; +1890E;TANGUT COMPONENT-271;Lo;0;L;;;;;N;;;;; +1890F;TANGUT COMPONENT-272;Lo;0;L;;;;;N;;;;; +18910;TANGUT COMPONENT-273;Lo;0;L;;;;;N;;;;; +18911;TANGUT COMPONENT-274;Lo;0;L;;;;;N;;;;; +18912;TANGUT COMPONENT-275;Lo;0;L;;;;;N;;;;; +18913;TANGUT COMPONENT-276;Lo;0;L;;;;;N;;;;; +18914;TANGUT COMPONENT-277;Lo;0;L;;;;;N;;;;; +18915;TANGUT COMPONENT-278;Lo;0;L;;;;;N;;;;; +18916;TANGUT COMPONENT-279;Lo;0;L;;;;;N;;;;; +18917;TANGUT COMPONENT-280;Lo;0;L;;;;;N;;;;; +18918;TANGUT COMPONENT-281;Lo;0;L;;;;;N;;;;; +18919;TANGUT COMPONENT-282;Lo;0;L;;;;;N;;;;; +1891A;TANGUT COMPONENT-283;Lo;0;L;;;;;N;;;;; +1891B;TANGUT COMPONENT-284;Lo;0;L;;;;;N;;;;; +1891C;TANGUT COMPONENT-285;Lo;0;L;;;;;N;;;;; +1891D;TANGUT COMPONENT-286;Lo;0;L;;;;;N;;;;; +1891E;TANGUT COMPONENT-287;Lo;0;L;;;;;N;;;;; +1891F;TANGUT COMPONENT-288;Lo;0;L;;;;;N;;;;; +18920;TANGUT COMPONENT-289;Lo;0;L;;;;;N;;;;; +18921;TANGUT COMPONENT-290;Lo;0;L;;;;;N;;;;; +18922;TANGUT COMPONENT-291;Lo;0;L;;;;;N;;;;; +18923;TANGUT COMPONENT-292;Lo;0;L;;;;;N;;;;; +18924;TANGUT COMPONENT-293;Lo;0;L;;;;;N;;;;; +18925;TANGUT COMPONENT-294;Lo;0;L;;;;;N;;;;; +18926;TANGUT COMPONENT-295;Lo;0;L;;;;;N;;;;; +18927;TANGUT COMPONENT-296;Lo;0;L;;;;;N;;;;; +18928;TANGUT COMPONENT-297;Lo;0;L;;;;;N;;;;; +18929;TANGUT COMPONENT-298;Lo;0;L;;;;;N;;;;; +1892A;TANGUT COMPONENT-299;Lo;0;L;;;;;N;;;;; +1892B;TANGUT COMPONENT-300;Lo;0;L;;;;;N;;;;; +1892C;TANGUT COMPONENT-301;Lo;0;L;;;;;N;;;;; +1892D;TANGUT COMPONENT-302;Lo;0;L;;;;;N;;;;; +1892E;TANGUT COMPONENT-303;Lo;0;L;;;;;N;;;;; +1892F;TANGUT COMPONENT-304;Lo;0;L;;;;;N;;;;; +18930;TANGUT COMPONENT-305;Lo;0;L;;;;;N;;;;; +18931;TANGUT COMPONENT-306;Lo;0;L;;;;;N;;;;; +18932;TANGUT COMPONENT-307;Lo;0;L;;;;;N;;;;; +18933;TANGUT COMPONENT-308;Lo;0;L;;;;;N;;;;; +18934;TANGUT COMPONENT-309;Lo;0;L;;;;;N;;;;; +18935;TANGUT COMPONENT-310;Lo;0;L;;;;;N;;;;; +18936;TANGUT COMPONENT-311;Lo;0;L;;;;;N;;;;; +18937;TANGUT COMPONENT-312;Lo;0;L;;;;;N;;;;; +18938;TANGUT COMPONENT-313;Lo;0;L;;;;;N;;;;; +18939;TANGUT COMPONENT-314;Lo;0;L;;;;;N;;;;; +1893A;TANGUT COMPONENT-315;Lo;0;L;;;;;N;;;;; +1893B;TANGUT COMPONENT-316;Lo;0;L;;;;;N;;;;; +1893C;TANGUT COMPONENT-317;Lo;0;L;;;;;N;;;;; +1893D;TANGUT COMPONENT-318;Lo;0;L;;;;;N;;;;; +1893E;TANGUT COMPONENT-319;Lo;0;L;;;;;N;;;;; +1893F;TANGUT COMPONENT-320;Lo;0;L;;;;;N;;;;; +18940;TANGUT COMPONENT-321;Lo;0;L;;;;;N;;;;; +18941;TANGUT COMPONENT-322;Lo;0;L;;;;;N;;;;; +18942;TANGUT COMPONENT-323;Lo;0;L;;;;;N;;;;; +18943;TANGUT COMPONENT-324;Lo;0;L;;;;;N;;;;; +18944;TANGUT COMPONENT-325;Lo;0;L;;;;;N;;;;; +18945;TANGUT COMPONENT-326;Lo;0;L;;;;;N;;;;; +18946;TANGUT COMPONENT-327;Lo;0;L;;;;;N;;;;; +18947;TANGUT COMPONENT-328;Lo;0;L;;;;;N;;;;; +18948;TANGUT COMPONENT-329;Lo;0;L;;;;;N;;;;; +18949;TANGUT COMPONENT-330;Lo;0;L;;;;;N;;;;; +1894A;TANGUT COMPONENT-331;Lo;0;L;;;;;N;;;;; +1894B;TANGUT COMPONENT-332;Lo;0;L;;;;;N;;;;; +1894C;TANGUT COMPONENT-333;Lo;0;L;;;;;N;;;;; +1894D;TANGUT COMPONENT-334;Lo;0;L;;;;;N;;;;; +1894E;TANGUT COMPONENT-335;Lo;0;L;;;;;N;;;;; +1894F;TANGUT COMPONENT-336;Lo;0;L;;;;;N;;;;; +18950;TANGUT COMPONENT-337;Lo;0;L;;;;;N;;;;; +18951;TANGUT COMPONENT-338;Lo;0;L;;;;;N;;;;; +18952;TANGUT COMPONENT-339;Lo;0;L;;;;;N;;;;; +18953;TANGUT COMPONENT-340;Lo;0;L;;;;;N;;;;; +18954;TANGUT COMPONENT-341;Lo;0;L;;;;;N;;;;; +18955;TANGUT COMPONENT-342;Lo;0;L;;;;;N;;;;; +18956;TANGUT COMPONENT-343;Lo;0;L;;;;;N;;;;; +18957;TANGUT COMPONENT-344;Lo;0;L;;;;;N;;;;; +18958;TANGUT COMPONENT-345;Lo;0;L;;;;;N;;;;; +18959;TANGUT COMPONENT-346;Lo;0;L;;;;;N;;;;; +1895A;TANGUT COMPONENT-347;Lo;0;L;;;;;N;;;;; +1895B;TANGUT COMPONENT-348;Lo;0;L;;;;;N;;;;; +1895C;TANGUT COMPONENT-349;Lo;0;L;;;;;N;;;;; +1895D;TANGUT COMPONENT-350;Lo;0;L;;;;;N;;;;; +1895E;TANGUT COMPONENT-351;Lo;0;L;;;;;N;;;;; +1895F;TANGUT COMPONENT-352;Lo;0;L;;;;;N;;;;; +18960;TANGUT COMPONENT-353;Lo;0;L;;;;;N;;;;; +18961;TANGUT COMPONENT-354;Lo;0;L;;;;;N;;;;; +18962;TANGUT COMPONENT-355;Lo;0;L;;;;;N;;;;; +18963;TANGUT COMPONENT-356;Lo;0;L;;;;;N;;;;; +18964;TANGUT COMPONENT-357;Lo;0;L;;;;;N;;;;; +18965;TANGUT COMPONENT-358;Lo;0;L;;;;;N;;;;; +18966;TANGUT COMPONENT-359;Lo;0;L;;;;;N;;;;; +18967;TANGUT COMPONENT-360;Lo;0;L;;;;;N;;;;; +18968;TANGUT COMPONENT-361;Lo;0;L;;;;;N;;;;; +18969;TANGUT COMPONENT-362;Lo;0;L;;;;;N;;;;; +1896A;TANGUT COMPONENT-363;Lo;0;L;;;;;N;;;;; +1896B;TANGUT COMPONENT-364;Lo;0;L;;;;;N;;;;; +1896C;TANGUT COMPONENT-365;Lo;0;L;;;;;N;;;;; +1896D;TANGUT COMPONENT-366;Lo;0;L;;;;;N;;;;; +1896E;TANGUT COMPONENT-367;Lo;0;L;;;;;N;;;;; +1896F;TANGUT COMPONENT-368;Lo;0;L;;;;;N;;;;; +18970;TANGUT COMPONENT-369;Lo;0;L;;;;;N;;;;; +18971;TANGUT COMPONENT-370;Lo;0;L;;;;;N;;;;; +18972;TANGUT COMPONENT-371;Lo;0;L;;;;;N;;;;; +18973;TANGUT COMPONENT-372;Lo;0;L;;;;;N;;;;; +18974;TANGUT COMPONENT-373;Lo;0;L;;;;;N;;;;; +18975;TANGUT COMPONENT-374;Lo;0;L;;;;;N;;;;; +18976;TANGUT COMPONENT-375;Lo;0;L;;;;;N;;;;; +18977;TANGUT COMPONENT-376;Lo;0;L;;;;;N;;;;; +18978;TANGUT COMPONENT-377;Lo;0;L;;;;;N;;;;; +18979;TANGUT COMPONENT-378;Lo;0;L;;;;;N;;;;; +1897A;TANGUT COMPONENT-379;Lo;0;L;;;;;N;;;;; +1897B;TANGUT COMPONENT-380;Lo;0;L;;;;;N;;;;; +1897C;TANGUT COMPONENT-381;Lo;0;L;;;;;N;;;;; +1897D;TANGUT COMPONENT-382;Lo;0;L;;;;;N;;;;; +1897E;TANGUT COMPONENT-383;Lo;0;L;;;;;N;;;;; +1897F;TANGUT COMPONENT-384;Lo;0;L;;;;;N;;;;; +18980;TANGUT COMPONENT-385;Lo;0;L;;;;;N;;;;; +18981;TANGUT COMPONENT-386;Lo;0;L;;;;;N;;;;; +18982;TANGUT COMPONENT-387;Lo;0;L;;;;;N;;;;; +18983;TANGUT COMPONENT-388;Lo;0;L;;;;;N;;;;; +18984;TANGUT COMPONENT-389;Lo;0;L;;;;;N;;;;; +18985;TANGUT COMPONENT-390;Lo;0;L;;;;;N;;;;; +18986;TANGUT COMPONENT-391;Lo;0;L;;;;;N;;;;; +18987;TANGUT COMPONENT-392;Lo;0;L;;;;;N;;;;; +18988;TANGUT COMPONENT-393;Lo;0;L;;;;;N;;;;; +18989;TANGUT COMPONENT-394;Lo;0;L;;;;;N;;;;; +1898A;TANGUT COMPONENT-395;Lo;0;L;;;;;N;;;;; +1898B;TANGUT COMPONENT-396;Lo;0;L;;;;;N;;;;; +1898C;TANGUT COMPONENT-397;Lo;0;L;;;;;N;;;;; +1898D;TANGUT COMPONENT-398;Lo;0;L;;;;;N;;;;; +1898E;TANGUT COMPONENT-399;Lo;0;L;;;;;N;;;;; +1898F;TANGUT COMPONENT-400;Lo;0;L;;;;;N;;;;; +18990;TANGUT COMPONENT-401;Lo;0;L;;;;;N;;;;; +18991;TANGUT COMPONENT-402;Lo;0;L;;;;;N;;;;; +18992;TANGUT COMPONENT-403;Lo;0;L;;;;;N;;;;; +18993;TANGUT COMPONENT-404;Lo;0;L;;;;;N;;;;; +18994;TANGUT COMPONENT-405;Lo;0;L;;;;;N;;;;; +18995;TANGUT COMPONENT-406;Lo;0;L;;;;;N;;;;; +18996;TANGUT COMPONENT-407;Lo;0;L;;;;;N;;;;; +18997;TANGUT COMPONENT-408;Lo;0;L;;;;;N;;;;; +18998;TANGUT COMPONENT-409;Lo;0;L;;;;;N;;;;; +18999;TANGUT COMPONENT-410;Lo;0;L;;;;;N;;;;; +1899A;TANGUT COMPONENT-411;Lo;0;L;;;;;N;;;;; +1899B;TANGUT COMPONENT-412;Lo;0;L;;;;;N;;;;; +1899C;TANGUT COMPONENT-413;Lo;0;L;;;;;N;;;;; +1899D;TANGUT COMPONENT-414;Lo;0;L;;;;;N;;;;; +1899E;TANGUT COMPONENT-415;Lo;0;L;;;;;N;;;;; +1899F;TANGUT COMPONENT-416;Lo;0;L;;;;;N;;;;; +189A0;TANGUT COMPONENT-417;Lo;0;L;;;;;N;;;;; +189A1;TANGUT COMPONENT-418;Lo;0;L;;;;;N;;;;; +189A2;TANGUT COMPONENT-419;Lo;0;L;;;;;N;;;;; +189A3;TANGUT COMPONENT-420;Lo;0;L;;;;;N;;;;; +189A4;TANGUT COMPONENT-421;Lo;0;L;;;;;N;;;;; +189A5;TANGUT COMPONENT-422;Lo;0;L;;;;;N;;;;; +189A6;TANGUT COMPONENT-423;Lo;0;L;;;;;N;;;;; +189A7;TANGUT COMPONENT-424;Lo;0;L;;;;;N;;;;; +189A8;TANGUT COMPONENT-425;Lo;0;L;;;;;N;;;;; +189A9;TANGUT COMPONENT-426;Lo;0;L;;;;;N;;;;; +189AA;TANGUT COMPONENT-427;Lo;0;L;;;;;N;;;;; +189AB;TANGUT COMPONENT-428;Lo;0;L;;;;;N;;;;; +189AC;TANGUT COMPONENT-429;Lo;0;L;;;;;N;;;;; +189AD;TANGUT COMPONENT-430;Lo;0;L;;;;;N;;;;; +189AE;TANGUT COMPONENT-431;Lo;0;L;;;;;N;;;;; +189AF;TANGUT COMPONENT-432;Lo;0;L;;;;;N;;;;; +189B0;TANGUT COMPONENT-433;Lo;0;L;;;;;N;;;;; +189B1;TANGUT COMPONENT-434;Lo;0;L;;;;;N;;;;; +189B2;TANGUT COMPONENT-435;Lo;0;L;;;;;N;;;;; +189B3;TANGUT COMPONENT-436;Lo;0;L;;;;;N;;;;; +189B4;TANGUT COMPONENT-437;Lo;0;L;;;;;N;;;;; +189B5;TANGUT COMPONENT-438;Lo;0;L;;;;;N;;;;; +189B6;TANGUT COMPONENT-439;Lo;0;L;;;;;N;;;;; +189B7;TANGUT COMPONENT-440;Lo;0;L;;;;;N;;;;; +189B8;TANGUT COMPONENT-441;Lo;0;L;;;;;N;;;;; +189B9;TANGUT COMPONENT-442;Lo;0;L;;;;;N;;;;; +189BA;TANGUT COMPONENT-443;Lo;0;L;;;;;N;;;;; +189BB;TANGUT COMPONENT-444;Lo;0;L;;;;;N;;;;; +189BC;TANGUT COMPONENT-445;Lo;0;L;;;;;N;;;;; +189BD;TANGUT COMPONENT-446;Lo;0;L;;;;;N;;;;; +189BE;TANGUT COMPONENT-447;Lo;0;L;;;;;N;;;;; +189BF;TANGUT COMPONENT-448;Lo;0;L;;;;;N;;;;; +189C0;TANGUT COMPONENT-449;Lo;0;L;;;;;N;;;;; +189C1;TANGUT COMPONENT-450;Lo;0;L;;;;;N;;;;; +189C2;TANGUT COMPONENT-451;Lo;0;L;;;;;N;;;;; +189C3;TANGUT COMPONENT-452;Lo;0;L;;;;;N;;;;; +189C4;TANGUT COMPONENT-453;Lo;0;L;;;;;N;;;;; +189C5;TANGUT COMPONENT-454;Lo;0;L;;;;;N;;;;; +189C6;TANGUT COMPONENT-455;Lo;0;L;;;;;N;;;;; +189C7;TANGUT COMPONENT-456;Lo;0;L;;;;;N;;;;; +189C8;TANGUT COMPONENT-457;Lo;0;L;;;;;N;;;;; +189C9;TANGUT COMPONENT-458;Lo;0;L;;;;;N;;;;; +189CA;TANGUT COMPONENT-459;Lo;0;L;;;;;N;;;;; +189CB;TANGUT COMPONENT-460;Lo;0;L;;;;;N;;;;; +189CC;TANGUT COMPONENT-461;Lo;0;L;;;;;N;;;;; +189CD;TANGUT COMPONENT-462;Lo;0;L;;;;;N;;;;; +189CE;TANGUT COMPONENT-463;Lo;0;L;;;;;N;;;;; +189CF;TANGUT COMPONENT-464;Lo;0;L;;;;;N;;;;; +189D0;TANGUT COMPONENT-465;Lo;0;L;;;;;N;;;;; +189D1;TANGUT COMPONENT-466;Lo;0;L;;;;;N;;;;; +189D2;TANGUT COMPONENT-467;Lo;0;L;;;;;N;;;;; +189D3;TANGUT COMPONENT-468;Lo;0;L;;;;;N;;;;; +189D4;TANGUT COMPONENT-469;Lo;0;L;;;;;N;;;;; +189D5;TANGUT COMPONENT-470;Lo;0;L;;;;;N;;;;; +189D6;TANGUT COMPONENT-471;Lo;0;L;;;;;N;;;;; +189D7;TANGUT COMPONENT-472;Lo;0;L;;;;;N;;;;; +189D8;TANGUT COMPONENT-473;Lo;0;L;;;;;N;;;;; +189D9;TANGUT COMPONENT-474;Lo;0;L;;;;;N;;;;; +189DA;TANGUT COMPONENT-475;Lo;0;L;;;;;N;;;;; +189DB;TANGUT COMPONENT-476;Lo;0;L;;;;;N;;;;; +189DC;TANGUT COMPONENT-477;Lo;0;L;;;;;N;;;;; +189DD;TANGUT COMPONENT-478;Lo;0;L;;;;;N;;;;; +189DE;TANGUT COMPONENT-479;Lo;0;L;;;;;N;;;;; +189DF;TANGUT COMPONENT-480;Lo;0;L;;;;;N;;;;; +189E0;TANGUT COMPONENT-481;Lo;0;L;;;;;N;;;;; +189E1;TANGUT COMPONENT-482;Lo;0;L;;;;;N;;;;; +189E2;TANGUT COMPONENT-483;Lo;0;L;;;;;N;;;;; +189E3;TANGUT COMPONENT-484;Lo;0;L;;;;;N;;;;; +189E4;TANGUT COMPONENT-485;Lo;0;L;;;;;N;;;;; +189E5;TANGUT COMPONENT-486;Lo;0;L;;;;;N;;;;; +189E6;TANGUT COMPONENT-487;Lo;0;L;;;;;N;;;;; +189E7;TANGUT COMPONENT-488;Lo;0;L;;;;;N;;;;; +189E8;TANGUT COMPONENT-489;Lo;0;L;;;;;N;;;;; +189E9;TANGUT COMPONENT-490;Lo;0;L;;;;;N;;;;; +189EA;TANGUT COMPONENT-491;Lo;0;L;;;;;N;;;;; +189EB;TANGUT COMPONENT-492;Lo;0;L;;;;;N;;;;; +189EC;TANGUT COMPONENT-493;Lo;0;L;;;;;N;;;;; +189ED;TANGUT COMPONENT-494;Lo;0;L;;;;;N;;;;; +189EE;TANGUT COMPONENT-495;Lo;0;L;;;;;N;;;;; +189EF;TANGUT COMPONENT-496;Lo;0;L;;;;;N;;;;; +189F0;TANGUT COMPONENT-497;Lo;0;L;;;;;N;;;;; +189F1;TANGUT COMPONENT-498;Lo;0;L;;;;;N;;;;; +189F2;TANGUT COMPONENT-499;Lo;0;L;;;;;N;;;;; +189F3;TANGUT COMPONENT-500;Lo;0;L;;;;;N;;;;; +189F4;TANGUT COMPONENT-501;Lo;0;L;;;;;N;;;;; +189F5;TANGUT COMPONENT-502;Lo;0;L;;;;;N;;;;; +189F6;TANGUT COMPONENT-503;Lo;0;L;;;;;N;;;;; +189F7;TANGUT COMPONENT-504;Lo;0;L;;;;;N;;;;; +189F8;TANGUT COMPONENT-505;Lo;0;L;;;;;N;;;;; +189F9;TANGUT COMPONENT-506;Lo;0;L;;;;;N;;;;; +189FA;TANGUT COMPONENT-507;Lo;0;L;;;;;N;;;;; +189FB;TANGUT COMPONENT-508;Lo;0;L;;;;;N;;;;; +189FC;TANGUT COMPONENT-509;Lo;0;L;;;;;N;;;;; +189FD;TANGUT COMPONENT-510;Lo;0;L;;;;;N;;;;; +189FE;TANGUT COMPONENT-511;Lo;0;L;;;;;N;;;;; +189FF;TANGUT COMPONENT-512;Lo;0;L;;;;;N;;;;; +18A00;TANGUT COMPONENT-513;Lo;0;L;;;;;N;;;;; +18A01;TANGUT COMPONENT-514;Lo;0;L;;;;;N;;;;; +18A02;TANGUT COMPONENT-515;Lo;0;L;;;;;N;;;;; +18A03;TANGUT COMPONENT-516;Lo;0;L;;;;;N;;;;; +18A04;TANGUT COMPONENT-517;Lo;0;L;;;;;N;;;;; +18A05;TANGUT COMPONENT-518;Lo;0;L;;;;;N;;;;; +18A06;TANGUT COMPONENT-519;Lo;0;L;;;;;N;;;;; +18A07;TANGUT COMPONENT-520;Lo;0;L;;;;;N;;;;; +18A08;TANGUT COMPONENT-521;Lo;0;L;;;;;N;;;;; +18A09;TANGUT COMPONENT-522;Lo;0;L;;;;;N;;;;; +18A0A;TANGUT COMPONENT-523;Lo;0;L;;;;;N;;;;; +18A0B;TANGUT COMPONENT-524;Lo;0;L;;;;;N;;;;; +18A0C;TANGUT COMPONENT-525;Lo;0;L;;;;;N;;;;; +18A0D;TANGUT COMPONENT-526;Lo;0;L;;;;;N;;;;; +18A0E;TANGUT COMPONENT-527;Lo;0;L;;;;;N;;;;; +18A0F;TANGUT COMPONENT-528;Lo;0;L;;;;;N;;;;; +18A10;TANGUT COMPONENT-529;Lo;0;L;;;;;N;;;;; +18A11;TANGUT COMPONENT-530;Lo;0;L;;;;;N;;;;; +18A12;TANGUT COMPONENT-531;Lo;0;L;;;;;N;;;;; +18A13;TANGUT COMPONENT-532;Lo;0;L;;;;;N;;;;; +18A14;TANGUT COMPONENT-533;Lo;0;L;;;;;N;;;;; +18A15;TANGUT COMPONENT-534;Lo;0;L;;;;;N;;;;; +18A16;TANGUT COMPONENT-535;Lo;0;L;;;;;N;;;;; +18A17;TANGUT COMPONENT-536;Lo;0;L;;;;;N;;;;; +18A18;TANGUT COMPONENT-537;Lo;0;L;;;;;N;;;;; +18A19;TANGUT COMPONENT-538;Lo;0;L;;;;;N;;;;; +18A1A;TANGUT COMPONENT-539;Lo;0;L;;;;;N;;;;; +18A1B;TANGUT COMPONENT-540;Lo;0;L;;;;;N;;;;; +18A1C;TANGUT COMPONENT-541;Lo;0;L;;;;;N;;;;; +18A1D;TANGUT COMPONENT-542;Lo;0;L;;;;;N;;;;; +18A1E;TANGUT COMPONENT-543;Lo;0;L;;;;;N;;;;; +18A1F;TANGUT COMPONENT-544;Lo;0;L;;;;;N;;;;; +18A20;TANGUT COMPONENT-545;Lo;0;L;;;;;N;;;;; +18A21;TANGUT COMPONENT-546;Lo;0;L;;;;;N;;;;; +18A22;TANGUT COMPONENT-547;Lo;0;L;;;;;N;;;;; +18A23;TANGUT COMPONENT-548;Lo;0;L;;;;;N;;;;; +18A24;TANGUT COMPONENT-549;Lo;0;L;;;;;N;;;;; +18A25;TANGUT COMPONENT-550;Lo;0;L;;;;;N;;;;; +18A26;TANGUT COMPONENT-551;Lo;0;L;;;;;N;;;;; +18A27;TANGUT COMPONENT-552;Lo;0;L;;;;;N;;;;; +18A28;TANGUT COMPONENT-553;Lo;0;L;;;;;N;;;;; +18A29;TANGUT COMPONENT-554;Lo;0;L;;;;;N;;;;; +18A2A;TANGUT COMPONENT-555;Lo;0;L;;;;;N;;;;; +18A2B;TANGUT COMPONENT-556;Lo;0;L;;;;;N;;;;; +18A2C;TANGUT COMPONENT-557;Lo;0;L;;;;;N;;;;; +18A2D;TANGUT COMPONENT-558;Lo;0;L;;;;;N;;;;; +18A2E;TANGUT COMPONENT-559;Lo;0;L;;;;;N;;;;; +18A2F;TANGUT COMPONENT-560;Lo;0;L;;;;;N;;;;; +18A30;TANGUT COMPONENT-561;Lo;0;L;;;;;N;;;;; +18A31;TANGUT COMPONENT-562;Lo;0;L;;;;;N;;;;; +18A32;TANGUT COMPONENT-563;Lo;0;L;;;;;N;;;;; +18A33;TANGUT COMPONENT-564;Lo;0;L;;;;;N;;;;; +18A34;TANGUT COMPONENT-565;Lo;0;L;;;;;N;;;;; +18A35;TANGUT COMPONENT-566;Lo;0;L;;;;;N;;;;; +18A36;TANGUT COMPONENT-567;Lo;0;L;;;;;N;;;;; +18A37;TANGUT COMPONENT-568;Lo;0;L;;;;;N;;;;; +18A38;TANGUT COMPONENT-569;Lo;0;L;;;;;N;;;;; +18A39;TANGUT COMPONENT-570;Lo;0;L;;;;;N;;;;; +18A3A;TANGUT COMPONENT-571;Lo;0;L;;;;;N;;;;; +18A3B;TANGUT COMPONENT-572;Lo;0;L;;;;;N;;;;; +18A3C;TANGUT COMPONENT-573;Lo;0;L;;;;;N;;;;; +18A3D;TANGUT COMPONENT-574;Lo;0;L;;;;;N;;;;; +18A3E;TANGUT COMPONENT-575;Lo;0;L;;;;;N;;;;; +18A3F;TANGUT COMPONENT-576;Lo;0;L;;;;;N;;;;; +18A40;TANGUT COMPONENT-577;Lo;0;L;;;;;N;;;;; +18A41;TANGUT COMPONENT-578;Lo;0;L;;;;;N;;;;; +18A42;TANGUT COMPONENT-579;Lo;0;L;;;;;N;;;;; +18A43;TANGUT COMPONENT-580;Lo;0;L;;;;;N;;;;; +18A44;TANGUT COMPONENT-581;Lo;0;L;;;;;N;;;;; +18A45;TANGUT COMPONENT-582;Lo;0;L;;;;;N;;;;; +18A46;TANGUT COMPONENT-583;Lo;0;L;;;;;N;;;;; +18A47;TANGUT COMPONENT-584;Lo;0;L;;;;;N;;;;; +18A48;TANGUT COMPONENT-585;Lo;0;L;;;;;N;;;;; +18A49;TANGUT COMPONENT-586;Lo;0;L;;;;;N;;;;; +18A4A;TANGUT COMPONENT-587;Lo;0;L;;;;;N;;;;; +18A4B;TANGUT COMPONENT-588;Lo;0;L;;;;;N;;;;; +18A4C;TANGUT COMPONENT-589;Lo;0;L;;;;;N;;;;; +18A4D;TANGUT COMPONENT-590;Lo;0;L;;;;;N;;;;; +18A4E;TANGUT COMPONENT-591;Lo;0;L;;;;;N;;;;; +18A4F;TANGUT COMPONENT-592;Lo;0;L;;;;;N;;;;; +18A50;TANGUT COMPONENT-593;Lo;0;L;;;;;N;;;;; +18A51;TANGUT COMPONENT-594;Lo;0;L;;;;;N;;;;; +18A52;TANGUT COMPONENT-595;Lo;0;L;;;;;N;;;;; +18A53;TANGUT COMPONENT-596;Lo;0;L;;;;;N;;;;; +18A54;TANGUT COMPONENT-597;Lo;0;L;;;;;N;;;;; +18A55;TANGUT COMPONENT-598;Lo;0;L;;;;;N;;;;; +18A56;TANGUT COMPONENT-599;Lo;0;L;;;;;N;;;;; +18A57;TANGUT COMPONENT-600;Lo;0;L;;;;;N;;;;; +18A58;TANGUT COMPONENT-601;Lo;0;L;;;;;N;;;;; +18A59;TANGUT COMPONENT-602;Lo;0;L;;;;;N;;;;; +18A5A;TANGUT COMPONENT-603;Lo;0;L;;;;;N;;;;; +18A5B;TANGUT COMPONENT-604;Lo;0;L;;;;;N;;;;; +18A5C;TANGUT COMPONENT-605;Lo;0;L;;;;;N;;;;; +18A5D;TANGUT COMPONENT-606;Lo;0;L;;;;;N;;;;; +18A5E;TANGUT COMPONENT-607;Lo;0;L;;;;;N;;;;; +18A5F;TANGUT COMPONENT-608;Lo;0;L;;;;;N;;;;; +18A60;TANGUT COMPONENT-609;Lo;0;L;;;;;N;;;;; +18A61;TANGUT COMPONENT-610;Lo;0;L;;;;;N;;;;; +18A62;TANGUT COMPONENT-611;Lo;0;L;;;;;N;;;;; +18A63;TANGUT COMPONENT-612;Lo;0;L;;;;;N;;;;; +18A64;TANGUT COMPONENT-613;Lo;0;L;;;;;N;;;;; +18A65;TANGUT COMPONENT-614;Lo;0;L;;;;;N;;;;; +18A66;TANGUT COMPONENT-615;Lo;0;L;;;;;N;;;;; +18A67;TANGUT COMPONENT-616;Lo;0;L;;;;;N;;;;; +18A68;TANGUT COMPONENT-617;Lo;0;L;;;;;N;;;;; +18A69;TANGUT COMPONENT-618;Lo;0;L;;;;;N;;;;; +18A6A;TANGUT COMPONENT-619;Lo;0;L;;;;;N;;;;; +18A6B;TANGUT COMPONENT-620;Lo;0;L;;;;;N;;;;; +18A6C;TANGUT COMPONENT-621;Lo;0;L;;;;;N;;;;; +18A6D;TANGUT COMPONENT-622;Lo;0;L;;;;;N;;;;; +18A6E;TANGUT COMPONENT-623;Lo;0;L;;;;;N;;;;; +18A6F;TANGUT COMPONENT-624;Lo;0;L;;;;;N;;;;; +18A70;TANGUT COMPONENT-625;Lo;0;L;;;;;N;;;;; +18A71;TANGUT COMPONENT-626;Lo;0;L;;;;;N;;;;; +18A72;TANGUT COMPONENT-627;Lo;0;L;;;;;N;;;;; +18A73;TANGUT COMPONENT-628;Lo;0;L;;;;;N;;;;; +18A74;TANGUT COMPONENT-629;Lo;0;L;;;;;N;;;;; +18A75;TANGUT COMPONENT-630;Lo;0;L;;;;;N;;;;; +18A76;TANGUT COMPONENT-631;Lo;0;L;;;;;N;;;;; +18A77;TANGUT COMPONENT-632;Lo;0;L;;;;;N;;;;; +18A78;TANGUT COMPONENT-633;Lo;0;L;;;;;N;;;;; +18A79;TANGUT COMPONENT-634;Lo;0;L;;;;;N;;;;; +18A7A;TANGUT COMPONENT-635;Lo;0;L;;;;;N;;;;; +18A7B;TANGUT COMPONENT-636;Lo;0;L;;;;;N;;;;; +18A7C;TANGUT COMPONENT-637;Lo;0;L;;;;;N;;;;; +18A7D;TANGUT COMPONENT-638;Lo;0;L;;;;;N;;;;; +18A7E;TANGUT COMPONENT-639;Lo;0;L;;;;;N;;;;; +18A7F;TANGUT COMPONENT-640;Lo;0;L;;;;;N;;;;; +18A80;TANGUT COMPONENT-641;Lo;0;L;;;;;N;;;;; +18A81;TANGUT COMPONENT-642;Lo;0;L;;;;;N;;;;; +18A82;TANGUT COMPONENT-643;Lo;0;L;;;;;N;;;;; +18A83;TANGUT COMPONENT-644;Lo;0;L;;;;;N;;;;; +18A84;TANGUT COMPONENT-645;Lo;0;L;;;;;N;;;;; +18A85;TANGUT COMPONENT-646;Lo;0;L;;;;;N;;;;; +18A86;TANGUT COMPONENT-647;Lo;0;L;;;;;N;;;;; +18A87;TANGUT COMPONENT-648;Lo;0;L;;;;;N;;;;; +18A88;TANGUT COMPONENT-649;Lo;0;L;;;;;N;;;;; +18A89;TANGUT COMPONENT-650;Lo;0;L;;;;;N;;;;; +18A8A;TANGUT COMPONENT-651;Lo;0;L;;;;;N;;;;; +18A8B;TANGUT COMPONENT-652;Lo;0;L;;;;;N;;;;; +18A8C;TANGUT COMPONENT-653;Lo;0;L;;;;;N;;;;; +18A8D;TANGUT COMPONENT-654;Lo;0;L;;;;;N;;;;; +18A8E;TANGUT COMPONENT-655;Lo;0;L;;;;;N;;;;; +18A8F;TANGUT COMPONENT-656;Lo;0;L;;;;;N;;;;; +18A90;TANGUT COMPONENT-657;Lo;0;L;;;;;N;;;;; +18A91;TANGUT COMPONENT-658;Lo;0;L;;;;;N;;;;; +18A92;TANGUT COMPONENT-659;Lo;0;L;;;;;N;;;;; +18A93;TANGUT COMPONENT-660;Lo;0;L;;;;;N;;;;; +18A94;TANGUT COMPONENT-661;Lo;0;L;;;;;N;;;;; +18A95;TANGUT COMPONENT-662;Lo;0;L;;;;;N;;;;; +18A96;TANGUT COMPONENT-663;Lo;0;L;;;;;N;;;;; +18A97;TANGUT COMPONENT-664;Lo;0;L;;;;;N;;;;; +18A98;TANGUT COMPONENT-665;Lo;0;L;;;;;N;;;;; +18A99;TANGUT COMPONENT-666;Lo;0;L;;;;;N;;;;; +18A9A;TANGUT COMPONENT-667;Lo;0;L;;;;;N;;;;; +18A9B;TANGUT COMPONENT-668;Lo;0;L;;;;;N;;;;; +18A9C;TANGUT COMPONENT-669;Lo;0;L;;;;;N;;;;; +18A9D;TANGUT COMPONENT-670;Lo;0;L;;;;;N;;;;; +18A9E;TANGUT COMPONENT-671;Lo;0;L;;;;;N;;;;; +18A9F;TANGUT COMPONENT-672;Lo;0;L;;;;;N;;;;; +18AA0;TANGUT COMPONENT-673;Lo;0;L;;;;;N;;;;; +18AA1;TANGUT COMPONENT-674;Lo;0;L;;;;;N;;;;; +18AA2;TANGUT COMPONENT-675;Lo;0;L;;;;;N;;;;; +18AA3;TANGUT COMPONENT-676;Lo;0;L;;;;;N;;;;; +18AA4;TANGUT COMPONENT-677;Lo;0;L;;;;;N;;;;; +18AA5;TANGUT COMPONENT-678;Lo;0;L;;;;;N;;;;; +18AA6;TANGUT COMPONENT-679;Lo;0;L;;;;;N;;;;; +18AA7;TANGUT COMPONENT-680;Lo;0;L;;;;;N;;;;; +18AA8;TANGUT COMPONENT-681;Lo;0;L;;;;;N;;;;; +18AA9;TANGUT COMPONENT-682;Lo;0;L;;;;;N;;;;; +18AAA;TANGUT COMPONENT-683;Lo;0;L;;;;;N;;;;; +18AAB;TANGUT COMPONENT-684;Lo;0;L;;;;;N;;;;; +18AAC;TANGUT COMPONENT-685;Lo;0;L;;;;;N;;;;; +18AAD;TANGUT COMPONENT-686;Lo;0;L;;;;;N;;;;; +18AAE;TANGUT COMPONENT-687;Lo;0;L;;;;;N;;;;; +18AAF;TANGUT COMPONENT-688;Lo;0;L;;;;;N;;;;; +18AB0;TANGUT COMPONENT-689;Lo;0;L;;;;;N;;;;; +18AB1;TANGUT COMPONENT-690;Lo;0;L;;;;;N;;;;; +18AB2;TANGUT COMPONENT-691;Lo;0;L;;;;;N;;;;; +18AB3;TANGUT COMPONENT-692;Lo;0;L;;;;;N;;;;; +18AB4;TANGUT COMPONENT-693;Lo;0;L;;;;;N;;;;; +18AB5;TANGUT COMPONENT-694;Lo;0;L;;;;;N;;;;; +18AB6;TANGUT COMPONENT-695;Lo;0;L;;;;;N;;;;; +18AB7;TANGUT COMPONENT-696;Lo;0;L;;;;;N;;;;; +18AB8;TANGUT COMPONENT-697;Lo;0;L;;;;;N;;;;; +18AB9;TANGUT COMPONENT-698;Lo;0;L;;;;;N;;;;; +18ABA;TANGUT COMPONENT-699;Lo;0;L;;;;;N;;;;; +18ABB;TANGUT COMPONENT-700;Lo;0;L;;;;;N;;;;; +18ABC;TANGUT COMPONENT-701;Lo;0;L;;;;;N;;;;; +18ABD;TANGUT COMPONENT-702;Lo;0;L;;;;;N;;;;; +18ABE;TANGUT COMPONENT-703;Lo;0;L;;;;;N;;;;; +18ABF;TANGUT COMPONENT-704;Lo;0;L;;;;;N;;;;; +18AC0;TANGUT COMPONENT-705;Lo;0;L;;;;;N;;;;; +18AC1;TANGUT COMPONENT-706;Lo;0;L;;;;;N;;;;; +18AC2;TANGUT COMPONENT-707;Lo;0;L;;;;;N;;;;; +18AC3;TANGUT COMPONENT-708;Lo;0;L;;;;;N;;;;; +18AC4;TANGUT COMPONENT-709;Lo;0;L;;;;;N;;;;; +18AC5;TANGUT COMPONENT-710;Lo;0;L;;;;;N;;;;; +18AC6;TANGUT COMPONENT-711;Lo;0;L;;;;;N;;;;; +18AC7;TANGUT COMPONENT-712;Lo;0;L;;;;;N;;;;; +18AC8;TANGUT COMPONENT-713;Lo;0;L;;;;;N;;;;; +18AC9;TANGUT COMPONENT-714;Lo;0;L;;;;;N;;;;; +18ACA;TANGUT COMPONENT-715;Lo;0;L;;;;;N;;;;; +18ACB;TANGUT COMPONENT-716;Lo;0;L;;;;;N;;;;; +18ACC;TANGUT COMPONENT-717;Lo;0;L;;;;;N;;;;; +18ACD;TANGUT COMPONENT-718;Lo;0;L;;;;;N;;;;; +18ACE;TANGUT COMPONENT-719;Lo;0;L;;;;;N;;;;; +18ACF;TANGUT COMPONENT-720;Lo;0;L;;;;;N;;;;; +18AD0;TANGUT COMPONENT-721;Lo;0;L;;;;;N;;;;; +18AD1;TANGUT COMPONENT-722;Lo;0;L;;;;;N;;;;; +18AD2;TANGUT COMPONENT-723;Lo;0;L;;;;;N;;;;; +18AD3;TANGUT COMPONENT-724;Lo;0;L;;;;;N;;;;; +18AD4;TANGUT COMPONENT-725;Lo;0;L;;;;;N;;;;; +18AD5;TANGUT COMPONENT-726;Lo;0;L;;;;;N;;;;; +18AD6;TANGUT COMPONENT-727;Lo;0;L;;;;;N;;;;; +18AD7;TANGUT COMPONENT-728;Lo;0;L;;;;;N;;;;; +18AD8;TANGUT COMPONENT-729;Lo;0;L;;;;;N;;;;; +18AD9;TANGUT COMPONENT-730;Lo;0;L;;;;;N;;;;; +18ADA;TANGUT COMPONENT-731;Lo;0;L;;;;;N;;;;; +18ADB;TANGUT COMPONENT-732;Lo;0;L;;;;;N;;;;; +18ADC;TANGUT COMPONENT-733;Lo;0;L;;;;;N;;;;; +18ADD;TANGUT COMPONENT-734;Lo;0;L;;;;;N;;;;; +18ADE;TANGUT COMPONENT-735;Lo;0;L;;;;;N;;;;; +18ADF;TANGUT COMPONENT-736;Lo;0;L;;;;;N;;;;; +18AE0;TANGUT COMPONENT-737;Lo;0;L;;;;;N;;;;; +18AE1;TANGUT COMPONENT-738;Lo;0;L;;;;;N;;;;; +18AE2;TANGUT COMPONENT-739;Lo;0;L;;;;;N;;;;; +18AE3;TANGUT COMPONENT-740;Lo;0;L;;;;;N;;;;; +18AE4;TANGUT COMPONENT-741;Lo;0;L;;;;;N;;;;; +18AE5;TANGUT COMPONENT-742;Lo;0;L;;;;;N;;;;; +18AE6;TANGUT COMPONENT-743;Lo;0;L;;;;;N;;;;; +18AE7;TANGUT COMPONENT-744;Lo;0;L;;;;;N;;;;; +18AE8;TANGUT COMPONENT-745;Lo;0;L;;;;;N;;;;; +18AE9;TANGUT COMPONENT-746;Lo;0;L;;;;;N;;;;; +18AEA;TANGUT COMPONENT-747;Lo;0;L;;;;;N;;;;; +18AEB;TANGUT COMPONENT-748;Lo;0;L;;;;;N;;;;; +18AEC;TANGUT COMPONENT-749;Lo;0;L;;;;;N;;;;; +18AED;TANGUT COMPONENT-750;Lo;0;L;;;;;N;;;;; +18AEE;TANGUT COMPONENT-751;Lo;0;L;;;;;N;;;;; +18AEF;TANGUT COMPONENT-752;Lo;0;L;;;;;N;;;;; +18AF0;TANGUT COMPONENT-753;Lo;0;L;;;;;N;;;;; +18AF1;TANGUT COMPONENT-754;Lo;0;L;;;;;N;;;;; +18AF2;TANGUT COMPONENT-755;Lo;0;L;;;;;N;;;;; 1B000;KATAKANA LETTER ARCHAIC E;Lo;0;L;;;;;N;;;;; 1B001;HIRAGANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;; 1BC00;DUPLOYAN LETTER H;Lo;0;L;;;;;N;;;;; @@ -26154,6 +27313,44 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1DAAD;SIGNWRITING ROTATION MODIFIER-14;Mn;0;NSM;;;;;N;;;;; 1DAAE;SIGNWRITING ROTATION MODIFIER-15;Mn;0;NSM;;;;;N;;;;; 1DAAF;SIGNWRITING ROTATION MODIFIER-16;Mn;0;NSM;;;;;N;;;;; +1E000;COMBINING GLAGOLITIC LETTER AZU;Mn;230;NSM;;;;;N;;;;; +1E001;COMBINING GLAGOLITIC LETTER BUKY;Mn;230;NSM;;;;;N;;;;; +1E002;COMBINING GLAGOLITIC LETTER VEDE;Mn;230;NSM;;;;;N;;;;; +1E003;COMBINING GLAGOLITIC LETTER GLAGOLI;Mn;230;NSM;;;;;N;;;;; +1E004;COMBINING GLAGOLITIC LETTER DOBRO;Mn;230;NSM;;;;;N;;;;; +1E005;COMBINING GLAGOLITIC LETTER YESTU;Mn;230;NSM;;;;;N;;;;; +1E006;COMBINING GLAGOLITIC LETTER ZHIVETE;Mn;230;NSM;;;;;N;;;;; +1E008;COMBINING GLAGOLITIC LETTER ZEMLJA;Mn;230;NSM;;;;;N;;;;; +1E009;COMBINING GLAGOLITIC LETTER IZHE;Mn;230;NSM;;;;;N;;;;; +1E00A;COMBINING GLAGOLITIC LETTER INITIAL IZHE;Mn;230;NSM;;;;;N;;;;; +1E00B;COMBINING GLAGOLITIC LETTER I;Mn;230;NSM;;;;;N;;;;; +1E00C;COMBINING GLAGOLITIC LETTER DJERVI;Mn;230;NSM;;;;;N;;;;; +1E00D;COMBINING GLAGOLITIC LETTER KAKO;Mn;230;NSM;;;;;N;;;;; +1E00E;COMBINING GLAGOLITIC LETTER LJUDIJE;Mn;230;NSM;;;;;N;;;;; +1E00F;COMBINING GLAGOLITIC LETTER MYSLITE;Mn;230;NSM;;;;;N;;;;; +1E010;COMBINING GLAGOLITIC LETTER NASHI;Mn;230;NSM;;;;;N;;;;; +1E011;COMBINING GLAGOLITIC LETTER ONU;Mn;230;NSM;;;;;N;;;;; +1E012;COMBINING GLAGOLITIC LETTER POKOJI;Mn;230;NSM;;;;;N;;;;; +1E013;COMBINING GLAGOLITIC LETTER RITSI;Mn;230;NSM;;;;;N;;;;; +1E014;COMBINING GLAGOLITIC LETTER SLOVO;Mn;230;NSM;;;;;N;;;;; +1E015;COMBINING GLAGOLITIC LETTER TVRIDO;Mn;230;NSM;;;;;N;;;;; +1E016;COMBINING GLAGOLITIC LETTER UKU;Mn;230;NSM;;;;;N;;;;; +1E017;COMBINING GLAGOLITIC LETTER FRITU;Mn;230;NSM;;;;;N;;;;; +1E018;COMBINING GLAGOLITIC LETTER HERU;Mn;230;NSM;;;;;N;;;;; +1E01B;COMBINING GLAGOLITIC LETTER SHTA;Mn;230;NSM;;;;;N;;;;; +1E01C;COMBINING GLAGOLITIC LETTER TSI;Mn;230;NSM;;;;;N;;;;; +1E01D;COMBINING GLAGOLITIC LETTER CHRIVI;Mn;230;NSM;;;;;N;;;;; +1E01E;COMBINING GLAGOLITIC LETTER SHA;Mn;230;NSM;;;;;N;;;;; +1E01F;COMBINING GLAGOLITIC LETTER YERU;Mn;230;NSM;;;;;N;;;;; +1E020;COMBINING GLAGOLITIC LETTER YERI;Mn;230;NSM;;;;;N;;;;; +1E021;COMBINING GLAGOLITIC LETTER YATI;Mn;230;NSM;;;;;N;;;;; +1E023;COMBINING GLAGOLITIC LETTER YU;Mn;230;NSM;;;;;N;;;;; +1E024;COMBINING GLAGOLITIC LETTER SMALL YUS;Mn;230;NSM;;;;;N;;;;; +1E026;COMBINING GLAGOLITIC LETTER YO;Mn;230;NSM;;;;;N;;;;; +1E027;COMBINING GLAGOLITIC LETTER IOTATED SMALL YUS;Mn;230;NSM;;;;;N;;;;; +1E028;COMBINING GLAGOLITIC LETTER BIG YUS;Mn;230;NSM;;;;;N;;;;; +1E029;COMBINING GLAGOLITIC LETTER IOTATED BIG YUS;Mn;230;NSM;;;;;N;;;;; +1E02A;COMBINING GLAGOLITIC LETTER FITA;Mn;230;NSM;;;;;N;;;;; 1E800;MENDE KIKAKUI SYLLABLE M001 KI;Lo;0;R;;;;;N;;;;; 1E801;MENDE KIKAKUI SYLLABLE M002 KA;Lo;0;R;;;;;N;;;;; 1E802;MENDE KIKAKUI SYLLABLE M003 KU;Lo;0;R;;;;;N;;;;; @@ -26367,6 +27564,93 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1E8D4;MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS;Mn;220;NSM;;;;;N;;;;; 1E8D5;MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS;Mn;220;NSM;;;;;N;;;;; 1E8D6;MENDE KIKAKUI COMBINING NUMBER MILLIONS;Mn;220;NSM;;;;;N;;;;; +1E900;ADLAM CAPITAL LETTER ALIF;Lu;0;R;;;;;N;;;;1E922; +1E901;ADLAM CAPITAL LETTER DAALI;Lu;0;R;;;;;N;;;;1E923; +1E902;ADLAM CAPITAL LETTER LAAM;Lu;0;R;;;;;N;;;;1E924; +1E903;ADLAM CAPITAL LETTER MIIM;Lu;0;R;;;;;N;;;;1E925; +1E904;ADLAM CAPITAL LETTER BA;Lu;0;R;;;;;N;;;;1E926; +1E905;ADLAM CAPITAL LETTER SINNYIIYHE;Lu;0;R;;;;;N;;;;1E927; +1E906;ADLAM CAPITAL LETTER PE;Lu;0;R;;;;;N;;;;1E928; +1E907;ADLAM CAPITAL LETTER BHE;Lu;0;R;;;;;N;;;;1E929; +1E908;ADLAM CAPITAL LETTER RA;Lu;0;R;;;;;N;;;;1E92A; +1E909;ADLAM CAPITAL LETTER E;Lu;0;R;;;;;N;;;;1E92B; +1E90A;ADLAM CAPITAL LETTER FA;Lu;0;R;;;;;N;;;;1E92C; +1E90B;ADLAM CAPITAL LETTER I;Lu;0;R;;;;;N;;;;1E92D; +1E90C;ADLAM CAPITAL LETTER O;Lu;0;R;;;;;N;;;;1E92E; +1E90D;ADLAM CAPITAL LETTER DHA;Lu;0;R;;;;;N;;;;1E92F; +1E90E;ADLAM CAPITAL LETTER YHE;Lu;0;R;;;;;N;;;;1E930; +1E90F;ADLAM CAPITAL LETTER WAW;Lu;0;R;;;;;N;;;;1E931; +1E910;ADLAM CAPITAL LETTER NUN;Lu;0;R;;;;;N;;;;1E932; +1E911;ADLAM CAPITAL LETTER KAF;Lu;0;R;;;;;N;;;;1E933; +1E912;ADLAM CAPITAL LETTER YA;Lu;0;R;;;;;N;;;;1E934; +1E913;ADLAM CAPITAL LETTER U;Lu;0;R;;;;;N;;;;1E935; +1E914;ADLAM CAPITAL LETTER JIIM;Lu;0;R;;;;;N;;;;1E936; +1E915;ADLAM CAPITAL LETTER CHI;Lu;0;R;;;;;N;;;;1E937; +1E916;ADLAM CAPITAL LETTER HA;Lu;0;R;;;;;N;;;;1E938; +1E917;ADLAM CAPITAL LETTER QAAF;Lu;0;R;;;;;N;;;;1E939; +1E918;ADLAM CAPITAL LETTER GA;Lu;0;R;;;;;N;;;;1E93A; +1E919;ADLAM CAPITAL LETTER NYA;Lu;0;R;;;;;N;;;;1E93B; +1E91A;ADLAM CAPITAL LETTER TU;Lu;0;R;;;;;N;;;;1E93C; +1E91B;ADLAM CAPITAL LETTER NHA;Lu;0;R;;;;;N;;;;1E93D; +1E91C;ADLAM CAPITAL LETTER VA;Lu;0;R;;;;;N;;;;1E93E; +1E91D;ADLAM CAPITAL LETTER KHA;Lu;0;R;;;;;N;;;;1E93F; +1E91E;ADLAM CAPITAL LETTER GBE;Lu;0;R;;;;;N;;;;1E940; +1E91F;ADLAM CAPITAL LETTER ZAL;Lu;0;R;;;;;N;;;;1E941; +1E920;ADLAM CAPITAL LETTER KPO;Lu;0;R;;;;;N;;;;1E942; +1E921;ADLAM CAPITAL LETTER SHA;Lu;0;R;;;;;N;;;;1E943; +1E922;ADLAM SMALL LETTER ALIF;Ll;0;R;;;;;N;;;1E900;;1E900 +1E923;ADLAM SMALL LETTER DAALI;Ll;0;R;;;;;N;;;1E901;;1E901 +1E924;ADLAM SMALL LETTER LAAM;Ll;0;R;;;;;N;;;1E902;;1E902 +1E925;ADLAM SMALL LETTER MIIM;Ll;0;R;;;;;N;;;1E903;;1E903 +1E926;ADLAM SMALL LETTER BA;Ll;0;R;;;;;N;;;1E904;;1E904 +1E927;ADLAM SMALL LETTER SINNYIIYHE;Ll;0;R;;;;;N;;;1E905;;1E905 +1E928;ADLAM SMALL LETTER PE;Ll;0;R;;;;;N;;;1E906;;1E906 +1E929;ADLAM SMALL LETTER BHE;Ll;0;R;;;;;N;;;1E907;;1E907 +1E92A;ADLAM SMALL LETTER RA;Ll;0;R;;;;;N;;;1E908;;1E908 +1E92B;ADLAM SMALL LETTER E;Ll;0;R;;;;;N;;;1E909;;1E909 +1E92C;ADLAM SMALL LETTER FA;Ll;0;R;;;;;N;;;1E90A;;1E90A +1E92D;ADLAM SMALL LETTER I;Ll;0;R;;;;;N;;;1E90B;;1E90B +1E92E;ADLAM SMALL LETTER O;Ll;0;R;;;;;N;;;1E90C;;1E90C +1E92F;ADLAM SMALL LETTER DHA;Ll;0;R;;;;;N;;;1E90D;;1E90D +1E930;ADLAM SMALL LETTER YHE;Ll;0;R;;;;;N;;;1E90E;;1E90E +1E931;ADLAM SMALL LETTER WAW;Ll;0;R;;;;;N;;;1E90F;;1E90F +1E932;ADLAM SMALL LETTER NUN;Ll;0;R;;;;;N;;;1E910;;1E910 +1E933;ADLAM SMALL LETTER KAF;Ll;0;R;;;;;N;;;1E911;;1E911 +1E934;ADLAM SMALL LETTER YA;Ll;0;R;;;;;N;;;1E912;;1E912 +1E935;ADLAM SMALL LETTER U;Ll;0;R;;;;;N;;;1E913;;1E913 +1E936;ADLAM SMALL LETTER JIIM;Ll;0;R;;;;;N;;;1E914;;1E914 +1E937;ADLAM SMALL LETTER CHI;Ll;0;R;;;;;N;;;1E915;;1E915 +1E938;ADLAM SMALL LETTER HA;Ll;0;R;;;;;N;;;1E916;;1E916 +1E939;ADLAM SMALL LETTER QAAF;Ll;0;R;;;;;N;;;1E917;;1E917 +1E93A;ADLAM SMALL LETTER GA;Ll;0;R;;;;;N;;;1E918;;1E918 +1E93B;ADLAM SMALL LETTER NYA;Ll;0;R;;;;;N;;;1E919;;1E919 +1E93C;ADLAM SMALL LETTER TU;Ll;0;R;;;;;N;;;1E91A;;1E91A +1E93D;ADLAM SMALL LETTER NHA;Ll;0;R;;;;;N;;;1E91B;;1E91B +1E93E;ADLAM SMALL LETTER VA;Ll;0;R;;;;;N;;;1E91C;;1E91C +1E93F;ADLAM SMALL LETTER KHA;Ll;0;R;;;;;N;;;1E91D;;1E91D +1E940;ADLAM SMALL LETTER GBE;Ll;0;R;;;;;N;;;1E91E;;1E91E +1E941;ADLAM SMALL LETTER ZAL;Ll;0;R;;;;;N;;;1E91F;;1E91F +1E942;ADLAM SMALL LETTER KPO;Ll;0;R;;;;;N;;;1E920;;1E920 +1E943;ADLAM SMALL LETTER SHA;Ll;0;R;;;;;N;;;1E921;;1E921 +1E944;ADLAM ALIF LENGTHENER;Mn;230;NSM;;;;;N;;;;; +1E945;ADLAM VOWEL LENGTHENER;Mn;230;NSM;;;;;N;;;;; +1E946;ADLAM GEMINATION MARK;Mn;230;NSM;;;;;N;;;;; +1E947;ADLAM HAMZA;Mn;230;NSM;;;;;N;;;;; +1E948;ADLAM CONSONANT MODIFIER;Mn;230;NSM;;;;;N;;;;; +1E949;ADLAM GEMINATE CONSONANT MODIFIER;Mn;230;NSM;;;;;N;;;;; +1E94A;ADLAM NUKTA;Mn;7;NSM;;;;;N;;;;; +1E950;ADLAM DIGIT ZERO;Nd;0;R;;0;0;0;N;;;;; +1E951;ADLAM DIGIT ONE;Nd;0;R;;1;1;1;N;;;;; +1E952;ADLAM DIGIT TWO;Nd;0;R;;2;2;2;N;;;;; +1E953;ADLAM DIGIT THREE;Nd;0;R;;3;3;3;N;;;;; +1E954;ADLAM DIGIT FOUR;Nd;0;R;;4;4;4;N;;;;; +1E955;ADLAM DIGIT FIVE;Nd;0;R;;5;5;5;N;;;;; +1E956;ADLAM DIGIT SIX;Nd;0;R;;6;6;6;N;;;;; +1E957;ADLAM DIGIT SEVEN;Nd;0;R;;7;7;7;N;;;;; +1E958;ADLAM DIGIT EIGHT;Nd;0;R;;8;8;8;N;;;;; +1E959;ADLAM DIGIT NINE;Nd;0;R;;9;9;9;N;;;;; +1E95E;ADLAM INITIAL EXCLAMATION MARK;Po;0;R;;;;;N;;;;; +1E95F;ADLAM INITIAL QUESTION MARK;Po;0;R;;;;;N;;;;; 1EE00;ARABIC MATHEMATICAL ALEF;Lo;0;AL;<font> 0627;;;;N;;;;; 1EE01;ARABIC MATHEMATICAL BEH;Lo;0;AL;<font> 0628;;;;N;;;;; 1EE02;ARABIC MATHEMATICAL JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; @@ -26883,6 +28167,24 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F198;SQUARED SOS;So;0;L;;;;;N;;;;; 1F199;SQUARED UP WITH EXCLAMATION MARK;So;0;L;;;;;N;;;;; 1F19A;SQUARED VS;So;0;L;;;;;N;;;;; +1F19B;SQUARED THREE D;So;0;L;;;;;N;;;;; +1F19C;SQUARED SECOND SCREEN;So;0;L;;;;;N;;;;; +1F19D;SQUARED TWO K;So;0;L;;;;;N;;;;; +1F19E;SQUARED FOUR K;So;0;L;;;;;N;;;;; +1F19F;SQUARED EIGHT K;So;0;L;;;;;N;;;;; +1F1A0;SQUARED FIVE POINT ONE;So;0;L;;;;;N;;;;; +1F1A1;SQUARED SEVEN POINT ONE;So;0;L;;;;;N;;;;; +1F1A2;SQUARED TWENTY-TWO POINT TWO;So;0;L;;;;;N;;;;; +1F1A3;SQUARED SIXTY P;So;0;L;;;;;N;;;;; +1F1A4;SQUARED ONE HUNDRED TWENTY P;So;0;L;;;;;N;;;;; +1F1A5;SQUARED LATIN SMALL LETTER D;So;0;L;;;;;N;;;;; +1F1A6;SQUARED HC;So;0;L;;;;;N;;;;; +1F1A7;SQUARED HDR;So;0;L;;;;;N;;;;; +1F1A8;SQUARED HI-RES;So;0;L;;;;;N;;;;; +1F1A9;SQUARED LOSSLESS;So;0;L;;;;;N;;;;; +1F1AA;SQUARED SHV;So;0;L;;;;;N;;;;; +1F1AB;SQUARED UHD;So;0;L;;;;;N;;;;; +1F1AC;SQUARED VOD;So;0;L;;;;;N;;;;; 1F1E6;REGIONAL INDICATOR SYMBOL LETTER A;So;0;L;;;;;N;;;;; 1F1E7;REGIONAL INDICATOR SYMBOL LETTER B;So;0;L;;;;;N;;;;; 1F1E8;REGIONAL INDICATOR SYMBOL LETTER C;So;0;L;;;;;N;;;;; @@ -26955,6 +28257,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F238;SQUARED CJK UNIFIED IDEOGRAPH-7533;So;0;L;<square> 7533;;;;N;;;;; 1F239;SQUARED CJK UNIFIED IDEOGRAPH-5272;So;0;L;<square> 5272;;;;N;;;;; 1F23A;SQUARED CJK UNIFIED IDEOGRAPH-55B6;So;0;L;<square> 55B6;;;;N;;;;; +1F23B;SQUARED CJK UNIFIED IDEOGRAPH-914D;So;0;L;<square> 914D;;;;N;;;;; 1F240;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C;So;0;L;<compat> 3014 672C 3015;;;;N;;;;; 1F241;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09;So;0;L;<compat> 3014 4E09 3015;;;;N;;;;; 1F242;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8C;So;0;L;<compat> 3014 4E8C 3015;;;;N;;;;; @@ -27600,6 +28903,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F577;SPIDER;So;0;ON;;;;;N;;;;; 1F578;SPIDER WEB;So;0;ON;;;;;N;;;;; 1F579;JOYSTICK;So;0;ON;;;;;N;;;;; +1F57A;MAN DANCING;So;0;ON;;;;;N;;;;; 1F57B;LEFT HAND TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;; 1F57C;TELEPHONE RECEIVER WITH PAGE;So;0;ON;;;;;N;;;;; 1F57D;RIGHT HAND TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;; @@ -27641,6 +28945,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F5A1;SIDEWAYS BLACK DOWN POINTING INDEX;So;0;ON;;;;;N;;;;; 1F5A2;BLACK UP POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; 1F5A3;BLACK DOWN POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F5A4;BLACK HEART;So;0;ON;;;;;N;;;;; 1F5A5;DESKTOP COMPUTER;So;0;ON;;;;;N;;;;; 1F5A6;KEYBOARD AND MOUSE;So;0;ON;;;;;N;;;;; 1F5A7;THREE NETWORKED COMPUTERS;So;0;ON;;;;;N;;;;; @@ -27941,6 +29246,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F6CE;BELLHOP BELL;So;0;ON;;;;;N;;;;; 1F6CF;BED;So;0;ON;;;;;N;;;;; 1F6D0;PLACE OF WORSHIP;So;0;ON;;;;;N;;;;; +1F6D1;OCTAGONAL SIGN;So;0;ON;;;;;N;;;;; +1F6D2;SHOPPING TROLLEY;So;0;ON;;;;;N;;;;; 1F6E0;HAMMER AND WRENCH;So;0;ON;;;;;N;;;;; 1F6E1;SHIELD;So;0;ON;;;;;N;;;;; 1F6E2;OIL DRUM;So;0;ON;;;;;N;;;;; @@ -27958,6 +29265,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F6F1;ONCOMING FIRE ENGINE;So;0;ON;;;;;N;;;;; 1F6F2;DIESEL LOCOMOTIVE;So;0;ON;;;;;N;;;;; 1F6F3;PASSENGER SHIP;So;0;ON;;;;;N;;;;; +1F6F4;SCOOTER;So;0;ON;;;;;N;;;;; +1F6F5;MOTOR SCOOTER;So;0;ON;;;;;N;;;;; +1F6F6;CANOE;So;0;ON;;;;;N;;;;; 1F700;ALCHEMICAL SYMBOL FOR QUINTESSENCE;So;0;ON;;;;;N;;;;; 1F701;ALCHEMICAL SYMBOL FOR AIR;So;0;ON;;;;;N;;;;; 1F702;ALCHEMICAL SYMBOL FOR FIRE;So;0;ON;;;;;N;;;;; @@ -28316,11 +29626,78 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F916;ROBOT FACE;So;0;ON;;;;;N;;;;; 1F917;HUGGING FACE;So;0;ON;;;;;N;;;;; 1F918;SIGN OF THE HORNS;So;0;ON;;;;;N;;;;; +1F919;CALL ME HAND;So;0;ON;;;;;N;;;;; +1F91A;RAISED BACK OF HAND;So;0;ON;;;;;N;;;;; +1F91B;LEFT-FACING FIST;So;0;ON;;;;;N;;;;; +1F91C;RIGHT-FACING FIST;So;0;ON;;;;;N;;;;; +1F91D;HANDSHAKE;So;0;ON;;;;;N;;;;; +1F91E;HAND WITH INDEX AND MIDDLE FINGERS CROSSED;So;0;ON;;;;;N;;;;; +1F920;FACE WITH COWBOY HAT;So;0;ON;;;;;N;;;;; +1F921;CLOWN FACE;So;0;ON;;;;;N;;;;; +1F922;NAUSEATED FACE;So;0;ON;;;;;N;;;;; +1F923;ROLLING ON THE FLOOR LAUGHING;So;0;ON;;;;;N;;;;; +1F924;DROOLING FACE;So;0;ON;;;;;N;;;;; +1F925;LYING FACE;So;0;ON;;;;;N;;;;; +1F926;FACE PALM;So;0;ON;;;;;N;;;;; +1F927;SNEEZING FACE;So;0;ON;;;;;N;;;;; +1F930;PREGNANT WOMAN;So;0;ON;;;;;N;;;;; +1F933;SELFIE;So;0;ON;;;;;N;;;;; +1F934;PRINCE;So;0;ON;;;;;N;;;;; +1F935;MAN IN TUXEDO;So;0;ON;;;;;N;;;;; +1F936;MOTHER CHRISTMAS;So;0;ON;;;;;N;;;;; +1F937;SHRUG;So;0;ON;;;;;N;;;;; +1F938;PERSON DOING CARTWHEEL;So;0;ON;;;;;N;;;;; +1F939;JUGGLING;So;0;ON;;;;;N;;;;; +1F93A;FENCER;So;0;ON;;;;;N;;;;; +1F93B;MODERN PENTATHLON;So;0;ON;;;;;N;;;;; +1F93C;WRESTLERS;So;0;ON;;;;;N;;;;; +1F93D;WATER POLO;So;0;ON;;;;;N;;;;; +1F93E;HANDBALL;So;0;ON;;;;;N;;;;; +1F940;WILTED FLOWER;So;0;ON;;;;;N;;;;; +1F941;DRUM WITH DRUMSTICKS;So;0;ON;;;;;N;;;;; +1F942;CLINKING GLASSES;So;0;ON;;;;;N;;;;; +1F943;TUMBLER GLASS;So;0;ON;;;;;N;;;;; +1F944;SPOON;So;0;ON;;;;;N;;;;; +1F945;GOAL NET;So;0;ON;;;;;N;;;;; +1F946;RIFLE;So;0;ON;;;;;N;;;;; +1F947;FIRST PLACE MEDAL;So;0;ON;;;;;N;;;;; +1F948;SECOND PLACE MEDAL;So;0;ON;;;;;N;;;;; +1F949;THIRD PLACE MEDAL;So;0;ON;;;;;N;;;;; +1F94A;BOXING GLOVE;So;0;ON;;;;;N;;;;; +1F94B;MARTIAL ARTS UNIFORM;So;0;ON;;;;;N;;;;; +1F950;CROISSANT;So;0;ON;;;;;N;;;;; +1F951;AVOCADO;So;0;ON;;;;;N;;;;; +1F952;CUCUMBER;So;0;ON;;;;;N;;;;; +1F953;BACON;So;0;ON;;;;;N;;;;; +1F954;POTATO;So;0;ON;;;;;N;;;;; +1F955;CARROT;So;0;ON;;;;;N;;;;; +1F956;BAGUETTE BREAD;So;0;ON;;;;;N;;;;; +1F957;GREEN SALAD;So;0;ON;;;;;N;;;;; +1F958;SHALLOW PAN OF FOOD;So;0;ON;;;;;N;;;;; +1F959;STUFFED FLATBREAD;So;0;ON;;;;;N;;;;; +1F95A;EGG;So;0;ON;;;;;N;;;;; +1F95B;GLASS OF MILK;So;0;ON;;;;;N;;;;; +1F95C;PEANUTS;So;0;ON;;;;;N;;;;; +1F95D;KIWIFRUIT;So;0;ON;;;;;N;;;;; +1F95E;PANCAKES;So;0;ON;;;;;N;;;;; 1F980;CRAB;So;0;ON;;;;;N;;;;; 1F981;LION FACE;So;0;ON;;;;;N;;;;; 1F982;SCORPION;So;0;ON;;;;;N;;;;; 1F983;TURKEY;So;0;ON;;;;;N;;;;; 1F984;UNICORN FACE;So;0;ON;;;;;N;;;;; +1F985;EAGLE;So;0;ON;;;;;N;;;;; +1F986;DUCK;So;0;ON;;;;;N;;;;; +1F987;BAT;So;0;ON;;;;;N;;;;; +1F988;SHARK;So;0;ON;;;;;N;;;;; +1F989;OWL;So;0;ON;;;;;N;;;;; +1F98A;FOX FACE;So;0;ON;;;;;N;;;;; +1F98B;BUTTERFLY;So;0;ON;;;;;N;;;;; +1F98C;DEER;So;0;ON;;;;;N;;;;; +1F98D;GORILLA;So;0;ON;;;;;N;;;;; +1F98E;LIZARD;So;0;ON;;;;;N;;;;; +1F98F;RHINOCEROS;So;0;ON;;;;;N;;;;; +1F990;SHRIMP;So;0;ON;;;;;N;;;;; +1F991;SQUID;So;0;ON;;;;;N;;;;; 1F9C0;CHEESE WEDGE;So;0;ON;;;;;N;;;;; 20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;; 2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;; |