diff options
232 files changed, 5141 insertions, 4591 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index d9b67eafe7..0d58d2bd85 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,7 +1,7 @@ env: CIRRUS_CLONE_DEPTH: '2' LANG: en_US.UTF-8 - CMAKE_EXTRA_FLAGS: -DCI_BUILD=ON -DMIN_LOG_LEVEL=3 + CMAKE_EXTRA_FLAGS: -DCI_BUILD=ON freebsd_task: name: FreeBSD diff --git a/.clang-tidy b/.clang-tidy index 1fe87ba501..1c7d13e2b0 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,3 +1,4 @@ +WarningsAsErrors: '*' Checks: > -*, diff --git a/.gitattributes b/.gitattributes index 1770c9b164..a1aa7e155f 100755 --- a/.gitattributes +++ b/.gitattributes @@ -11,6 +11,3 @@ src/unicode/** linguist-vendored src/nvim/testdir/test42.in diff .github/ export-ignore -.travis.yml export-ignore -codecov.yml export-ignore -.builds/ export-ignore diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml index 858045c02a..819380f351 100644 --- a/.github/actions/cache/action.yml +++ b/.github/actions/cache/action.yml @@ -3,7 +3,7 @@ description: "This action caches neovim dependencies" runs: using: "composite" steps: - - run: echo "CACHE_KEY=${{ github.job }}-${{ github.base_ref }}" >> $GITHUB_ENV + - run: echo "CACHE_KEY=${{ github.job }}" >> $GITHUB_ENV shell: bash - if: ${{ matrix }} @@ -16,7 +16,7 @@ runs: # files to search through. - uses: actions/cache@v3 with: - path: ${{ env.CACHE_NVIM_DEPS_DIR }} + path: ${{ env.DEPS_BUILD_DIR }} key: ${{ env.CACHE_KEY }}-${{ hashFiles('cmake**', 'ci/**', '.github/workflows/ci.yml', 'CMakeLists.txt', 'runtime/CMakeLists.txt', 'src/nvim/**/CMakeLists.txt') }} diff --git a/.github/scripts/build_universal_macos.sh b/.github/scripts/build_universal_macos.sh new file mode 100755 index 0000000000..392eec62ac --- /dev/null +++ b/.github/scripts/build_universal_macos.sh @@ -0,0 +1,36 @@ +#!/bin/bash -e + +echo "Provision universal libintl" +GETTEXT_PREFIX="$(brew --prefix gettext)" +printf 'GETTEXT_PREFIX=%s\n' "$GETTEXT_PREFIX" >> $GITHUB_ENV +bottle_tag="arm64_big_sur" +brew fetch --bottle-tag="$bottle_tag" gettext +cd "$(mktemp -d)" +tar xf "$(brew --cache)"/**/*gettext*${bottle_tag}*.tar.gz +lipo gettext/*/lib/libintl.a "${GETTEXT_PREFIX}/lib/libintl.a" -create -output libintl.a +mv -f libintl.a /usr/local/lib/ + +echo "Ensure static linkage to libintl" +# We're about to mangle `gettext`, so let's remove any potentially broken +# installs (e.g. curl, git) as those could interfere with our build. +brew uninstall $(brew uses --installed --recursive gettext) +brew unlink gettext +ln -sf "$(brew --prefix)/opt/$(readlink "${GETTEXT_PREFIX}")/bin"/* /usr/local/bin/ +ln -sf "$(brew --prefix)/opt/$(readlink "${GETTEXT_PREFIX}")/include"/* /usr/local/include/ +rm -f "$GETTEXT_PREFIX" + +echo "Build release" +cd "$GITHUB_WORKSPACE" +MACOSX_DEPLOYMENT_TARGET="$(sw_vers -productVersion | cut -f1 -d.)" +export MACOSX_DEPLOYMENT_TARGET +cmake -S cmake.deps -B .deps -G Ninja -D CMAKE_BUILD_TYPE=${NVIM_BUILD_TYPE} -D CMAKE_OSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} -D CMAKE_OSX_ARCHITECTURES=arm64\;x86_64 +cmake --build .deps +cmake -B build -G Ninja -D CMAKE_BUILD_TYPE=${NVIM_BUILD_TYPE} -D CMAKE_OSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} -D CMAKE_OSX_ARCHITECTURES=arm64\;x86_64 +cmake --build build +cmake --install build --prefix build/release/nvim-macos +cd build +# Make sure we build everything for M1 as well +for macho in bin/* lib/nvim/parser/*.so; do + lipo -info "$macho" | grep -q arm64 || exit 1 +done +cpack -C "$NVIM_BUILD_TYPE" diff --git a/.github/scripts/install_deps.sh b/.github/scripts/install_deps.sh new file mode 100755 index 0000000000..4727b5d08d --- /dev/null +++ b/.github/scripts/install_deps.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +os=$(uname -s) +if [[ $os == Linux ]]; then + sudo apt-get update + sudo apt-get install -y autoconf automake build-essential cmake curl gettext libtool-bin locales-all ninja-build pkg-config unzip "$@" +elif [[ $os == Darwin ]]; then + brew update --quiet + brew install automake ninja "$@" +fi diff --git a/.github/scripts/install_deps_ubuntu.sh b/.github/scripts/install_deps_ubuntu.sh deleted file mode 100755 index 012409ba4a..0000000000 --- a/.github/scripts/install_deps_ubuntu.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -PACKAGES=( - autoconf - automake - build-essential - cmake - cpanminus - curl - gettext - libtool-bin - locales-all - ninja-build - pkg-config - unzip -) - -sudo apt-get update -sudo apt-get install -y "${PACKAGES[@]}" diff --git a/.github/scripts/reviews.js b/.github/scripts/reviews.js index cc6aaa1e8b..0ed382ac30 100644 --- a/.github/scripts/reviews.js +++ b/.github/scripts/reviews.js @@ -69,10 +69,6 @@ module.exports = async ({github, context}) => { reviewers.add("justinmk") } - if (labels.includes('refactor')) { - reviewers.add("bfredl") - } - if (labels.includes('test')) { reviewers.add("justinmk") } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 83ee4f0358..4814e89a69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,13 +11,21 @@ on: paths-ignore: - 'contrib/**' -# Cancel any in-progress CI runs for a PR if it is updated concurrency: group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }} cancel-in-progress: true env: - UNCRUSTIFY_VERSION: uncrustify-0.75.0 + ASAN_OPTIONS: detect_leaks=1:check_initialization_order=1:handle_abort=1:handle_sigill=1:log_path=${{ github.workspace }}/build/log/asan:intercept_tls_get_addr=0 + BIN_DIR: ${{ github.workspace }}/bin + BUILD_DIR: ${{ github.workspace }}/build + DEPS_BUILD_DIR: ${{ github.workspace }}/nvim-deps + INSTALL_PREFIX: ${{ github.workspace }}/nvim-install + LOG_DIR: ${{ github.workspace }}/build/log + NVIM_LOG_FILE: ${{ github.workspace }}/build/.nvimlog + TSAN_OPTIONS: log_path=${{ github.workspace }}/build/log/tsan + UBSAN_OPTIONS: "print_stacktrace=1 log_path=${{ github.workspace }}/build/log/ubsan" + VALGRIND_LOG: ${{ github.workspace }}/build/log/valgrind-%p.log # TEST_FILE: test/functional/core/startup_spec.lua # TEST_FILTER: foo @@ -27,17 +35,13 @@ jobs: runs-on: ubuntu-22.04 timeout-minutes: 10 env: - CC: gcc + CACHE_UNCRUSTIFY: ${{ github.workspace }}/.cache/uncrustify + UNCRUSTIFY_VERSION: uncrustify-0.75.0 steps: - uses: actions/checkout@v3 - - name: Setup common environment variables - run: ./.github/workflows/env.sh lint - - - name: Install apt packages - run: | - ./.github/scripts/install_deps_ubuntu.sh - sudo apt-get install -y lua-check + - name: Install dependencies + run: ./.github/scripts/install_deps.sh lua-check - name: Cache uncrustify id: cache-uncrustify @@ -59,15 +63,17 @@ jobs: run: | source_dir=uncrustify build_dir=uncrustify/build - cmake -S $source_dir -B $build_dir -G Ninja -DCMAKE_BUILD_TYPE=Release + cmake -S $source_dir -B $build_dir -G Ninja -D CMAKE_BUILD_TYPE=Release cmake --build $build_dir - mkdir -p $HOME/.cache + mkdir -p .cache cp $build_dir/uncrustify ${{ env.CACHE_UNCRUSTIFY }} - uses: ./.github/actions/cache - name: Build third-party deps - run: ./ci/before_script.sh + run: | + cmake -S cmake.deps -B $DEPS_BUILD_DIR -G Ninja + cmake --build $DEPS_BUILD_DIR - if: "!cancelled()" name: Determine if run should be aborted @@ -85,12 +91,12 @@ jobs: - if: success() || failure() && steps.abort_job.outputs.status == 'success' name: luacheck run: | - cmake -B $BUILD_DIR -G Ninja - cmake --build $BUILD_DIR --target lintlua-luacheck + cmake -B build -G Ninja + cmake --build build --target lintlua-luacheck - if: success() || failure() && steps.abort_job.outputs.status == 'success' name: lintsh - run: make lintsh + run: cmake --build build --target lintsh - if: success() || failure() && steps.abort_job.outputs.status == 'success' name: uncrustify @@ -107,11 +113,7 @@ jobs: - if: success() || failure() && steps.abort_job.outputs.status == 'success' name: check uncrustify - run: | - git diff --color --exit-code - - - name: Cache dependencies - run: ./ci/before_cache.sh + run: git diff --color --exit-code lintc: # This job tests two things: it lints the code but also builds neovim using @@ -122,18 +124,13 @@ jobs: if: (github.event_name == 'pull_request' && github.base_ref == 'master') || (github.event_name == 'push' && github.ref == 'refs/heads/master') runs-on: ubuntu-22.04 timeout-minutes: 10 - env: - CC: gcc steps: - uses: actions/checkout@v3 - - name: Setup common environment variables - run: ./.github/workflows/env.sh lintc - - - name: Install apt packages + - name: Install dependencies run: | sudo add-apt-repository ppa:neovim-ppa/stable - ./.github/scripts/install_deps_ubuntu.sh + ./.github/scripts/install_deps.sh sudo apt-get install -y \ libluajit-5.1-dev \ libmsgpack-dev \ @@ -151,15 +148,23 @@ jobs: # lua-luv-dev # Remove comments from packages once we start using these external - # dependencies. See env.sh for more context. + # dependencies. - uses: ./.github/actions/cache - name: Build third-party deps - run: ./ci/before_script.sh + run: | + # Ideally all dependencies should external for this job, but some + # dependencies don't have the required version available. We use the + # bundled versions for these with the hopes of being able to remove them + # later on. + cmake -S cmake.deps -B $DEPS_BUILD_DIR -G Ninja -D USE_BUNDLED=OFF -D USE_BUNDLED_LUV=ON -D USE_BUNDLED_LIBVTERM=ON + cmake --build $DEPS_BUILD_DIR - - name: Build nvim - run: make + - name: Build + run: | + cmake -B build -G Ninja + cmake --build build - if: "!cancelled()" name: Determine if run should be aborted @@ -171,11 +176,7 @@ jobs: run: cmake --build build --target lintc-clint - if: success() || failure() && steps.abort_job.outputs.status == 'success' - name: check-single-includes - run: make check-single-includes - - - name: Cache dependencies - run: ./ci/before_cache.sh + run: cmake --build build --target clang-tidy posix: name: ${{ matrix.runner }} ${{ matrix.flavor }} (cc=${{ matrix.cc }}) @@ -186,79 +187,75 @@ jobs: - flavor: asan cc: clang runner: ubuntu-22.04 - os: linux + flags: -D CLANG_ASAN_UBSAN=ON - flavor: tsan cc: clang runner: ubuntu-22.04 - os: linux + flags: -D CLANG_TSAN=ON - flavor: uchar cc: gcc runner: ubuntu-22.04 - os: linux + flags: -D UNSIGNED_CHAR=ON - cc: clang runner: macos-12 - os: osx # functionaltest-lua is our dumping ground for non-mainline configurations. # 1. Check that the tests pass with PUC Lua instead of LuaJIT. - # 2. Use as oldest/minimum versions of dependencies/build tools we - # still explicitly support so we don't accidentally rely on - # features that is only available on later versions. - # 3. No treesitter parsers installed. + # 2. No treesitter parsers installed. - flavor: functionaltest-lua cc: gcc runner: ubuntu-22.04 - os: linux - cmake: minimum_required + deps_flags: -D USE_BUNDLED_LUAJIT=OFF -D USE_BUNDLED_LUA=ON + flags: -D PREFER_LUA=ON runs-on: ${{ matrix.runner }} timeout-minutes: 45 env: CC: ${{ matrix.cc }} - CI_OS_NAME: ${{ matrix.os }} steps: - uses: actions/checkout@v3 - - name: Setup common environment variables - run: ./.github/workflows/env.sh ${{ matrix.flavor }} + - name: Set up environment + run: | + ulimit -c unlimited + echo "$BIN_DIR" >> $GITHUB_PATH - - name: Install apt packages - if: matrix.os == 'linux' - run: ./.github/scripts/install_deps_ubuntu.sh + - name: Create log dir + run: mkdir -p "$LOG_DIR" - - name: Install minimum required version of cmake - if: matrix.cmake == 'minimum_required' - env: - CMAKE_URL: 'https://cmake.org/files/v3.10/cmake-3.10.0-Linux-x86_64.sh' - CMAKE_VERSION: '3.10.0' - shell: bash - run: | - curl --retry 5 --silent --show-error --fail -o /tmp/cmake-installer.sh "$CMAKE_URL" - mkdir -p "$HOME/.local/bin" /opt/cmake-custom - chmod a+x /tmp/cmake-installer.sh - /tmp/cmake-installer.sh --prefix=/opt/cmake-custom --skip-license - ln -sfn /opt/cmake-custom/bin/cmake "$HOME/.local/bin/cmake" - cmake_version="$(cmake --version | head -1)" - echo "$cmake_version" | grep -qF "cmake version $CMAKE_VERSION" || { - echo "Unexpected CMake version: $cmake_version" - exit 1 - } + - name: Install dependencies + run: ./.github/scripts/install_deps.sh cpanminus - - name: Install brew packages - if: matrix.os == 'osx' + - name: Setup interpreter packages run: | - brew update --quiet - brew install automake cpanminus ninja + # Use default CC to avoid compilation problems when installing Python modules. + echo "Install neovim module for Python." + CC=cc python3 -m pip -q install --user --upgrade pynvim - - name: Setup interpreter packages - run: ./ci/install.sh + echo "Install neovim RubyGem." + gem install --no-document --bindir "$BIN_DIR" --user-install --pre neovim + + echo "Install neovim npm package" + npm install -g neovim + npm link neovim + + if [[ $RUNNER_OS != macOS ]]; then + sudo cpanm -n Neovim::Ext || cat "$HOME/.cpanm/build.log" + perl -W -e 'use Neovim::Ext; print $Neovim::Ext::VERSION' + fi + + - run: echo "DEPS_BUILD_DIR=$HOME/nvim-deps" >> $GITHUB_ENV - uses: ./.github/actions/cache - name: Build third-party deps - run: ./ci/before_script.sh + run: | + cmake -S cmake.deps -B $DEPS_BUILD_DIR -G Ninja ${{ matrix.deps_flags }} + cmake --build $DEPS_BUILD_DIR - name: Build - run: ./ci/run_tests.sh build_nvim + run: | + cmake -B build -G Ninja -D CI_BUILD=ON -D CMAKE_INSTALL_PREFIX:PATH=$INSTALL_PREFIX ${{ matrix.flags }} + cmake --build build - if: "!cancelled()" name: Determine if run should be aborted @@ -266,48 +263,158 @@ jobs: run: echo "status=${{ job.status }}" >> $GITHUB_OUTPUT - if: matrix.flavor != 'tsan' && matrix.flavor != 'functionaltest-lua' && (success() || failure() && steps.abort_job.outputs.status == 'success') - name: Unittests - run: ./ci/run_tests.sh unittests + name: Unittest + timeout-minutes: 5 + run: cmake --build build --target unittest - - if: success() || failure() && steps.abort_job.outputs.status == 'success' - name: Functionaltests - run: ./ci/run_tests.sh functionaltests + - if: matrix.flavor != 'functionaltest-lua' && (success() || failure() && steps.abort_job.outputs.status == 'success') + name: Functionaltest + timeout-minutes: 15 + run: cmake --build build --target functionaltest + + - if: matrix.flavor == 'functionaltest-lua' && (success() || failure() && steps.abort_job.outputs.status == 'success') + name: Functionaltest with PUC Lua + timeout-minutes: 15 + run: cmake --build build --target functionaltest-lua - if: matrix.flavor != 'tsan' && (success() || failure() && steps.abort_job.outputs.status == 'success') - name: Oldtests - run: ./ci/run_tests.sh oldtests + name: Oldtest + run: make oldtest + + - if: success() || failure() && steps.abort_job.outputs.status == 'success' + name: Install + run: cmake --install build - if: success() || failure() && steps.abort_job.outputs.status == 'success' - name: Install nvim - run: ./ci/run_tests.sh install_nvim + name: Installtests + run: | + "$INSTALL_PREFIX/bin/nvim" --version + if ! "$INSTALL_PREFIX/bin/nvim" -u NONE -e -c ':help' -c ':qall'; then + echo "Running ':help' in the installed nvim failed." + echo "Maybe the helptags have not been generated properly." + echo 'Failed running :help' + exit 1 + fi + + # Check that all runtime files were installed + for file in $(git -C runtime ls-files '*.vim' '*.ps' '*.dict' '*.py' '*.tutor'); do + if ! test -e "$INSTALL_PREFIX/share/nvim/runtime/$file"; then + printf "%s%s" 'It appears that %s is not installed.' "$file" + exit 1 + fi + done + + # Check that some runtime files are installed and are executables + for file in $(git -C runtime ls-files '*.awk' '*.sh' '*.bat'); do + if ! test -x "$INSTALL_PREFIX/share/nvim/runtime/$file"; then + printf "%s%s" 'It appears that %s is not installed or is not executable.' "$file" + exit 1 + fi + done + + # Check that generated syntax file has function names, #5060. + genvimsynf=syntax/vim/generated.vim + gpat='syn keyword vimFuncName .*eval' + if ! grep -q "$gpat" "$INSTALL_PREFIX/share/nvim/runtime/$genvimsynf"; then + echo "It appears that $genvimsynf does not contain $gpat." + exit 1 + fi + + - if: success() || failure() && steps.abort_job.outputs.status == 'success' + name: Show logs + run: cat $(find "$LOG_DIR" -type f) + + - if: success() || failure() && steps.abort_job.outputs.status == 'success' + name: Show core dumps + run: | + # TODO(dundargoc): app should be luajit for unittests + app="build/bin/nvim" + if test "$RUNNER_OS" = macOS; then + cores="$(find /cores/ -type f -print)" + else + cores="$(find ./ -type f \( -name 'core.*' -o -name core -o -name nvim.core \) -print)" + fi + + if test -z "$cores"; then + exit 0 + fi + for core in $cores; do + if test "$RUNNER_OS" = macOS; then + lldb -Q -o "bt all" -f "$app" -c "$core" + else + gdb -n -batch -ex 'thread apply all bt full' "$app" -c "$core" + fi + done + echo 'Core dumps found' + exit 1 + + old_cmake: + name: Test oldest supported cmake + runs-on: ubuntu-22.04 + timeout-minutes: 15 + env: + CMAKE_URL: 'https://cmake.org/files/v3.10/cmake-3.10.0-Linux-x86_64.sh' + CMAKE_VERSION: '3.10.0' + steps: + - uses: actions/checkout@v3 + + - name: Set up environment + run: echo "$BIN_DIR" >> $GITHUB_PATH - - name: Cache dependencies - run: ./ci/before_cache.sh + - name: Install dependencies + run: ./.github/scripts/install_deps.sh + + - name: Install minimum required version of cmake + run: | + curl --retry 5 --silent --show-error --fail -o /tmp/cmake-installer.sh "$CMAKE_URL" + mkdir -p "$BIN_DIR" /opt/cmake-custom + chmod a+x /tmp/cmake-installer.sh + /tmp/cmake-installer.sh --prefix=/opt/cmake-custom --skip-license + ln -sfn /opt/cmake-custom/bin/cmake "$BIN_DIR/cmake" + cmake_version="$(cmake --version | head -1)" + echo "$cmake_version" | grep -qF "cmake version $CMAKE_VERSION" || { + echo "Unexpected CMake version: $cmake_version" + exit 1 + } + + - uses: ./.github/actions/cache + + - name: Build dependencies + run: make deps + + - name: Build + run: make CMAKE_FLAGS="-D CI_BUILD=ON -D CMAKE_INSTALL_PREFIX:PATH=$INSTALL_PREFIX" + + - name: Install + run: make install windows: runs-on: windows-2019 timeout-minutes: 45 - env: - DEPS_BUILD_DIR: ${{ github.workspace }}/nvim-deps - CACHE_NVIM_DEPS_DIR: ${{ github.workspace }}/nvim-deps - DEPS_PREFIX: ${{ github.workspace }}/nvim-deps/usr - name: windows (MSVC_64) + name: windows steps: - uses: actions/checkout@v3 - uses: ./.github/actions/cache - name: Set env - run: ./.github/workflows/env.ps1 + run: | + $installationPath = vswhere.exe -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath + if ($installationPath -and (Test-Path "$installationPath\Common7\Tools\vsdevcmd.bat")) { + & "${env:COMSPEC}" /s /c "`"$installationPath\Common7\Tools\vsdevcmd.bat`" -arch=x64 -no_logo && set" | ForEach-Object { + $name, $value = $_ -split '=', 2 + "$name=$value" >> $env:GITHUB_ENV + } + } - name: Build deps run: | - cmake -S cmake.deps -B $env:DEPS_BUILD_DIR -G Ninja -DCMAKE_BUILD_TYPE='RelWithDebInfo' + cmake -S cmake.deps -B $env:DEPS_BUILD_DIR -G Ninja -D CMAKE_BUILD_TYPE='RelWithDebInfo' cmake --build $env:DEPS_BUILD_DIR - - name: Build nvim + - name: Build run: | - cmake -B build -G Ninja -DCMAKE_BUILD_TYPE='RelWithDebInfo' -DDEPS_PREFIX="$env:DEPS_PREFIX" -DCI_BUILD=ON + cmake -B build -G Ninja -D CMAKE_BUILD_TYPE='RelWithDebInfo' -D CI_BUILD=ON cmake --build build - name: Install test deps @@ -340,14 +447,15 @@ jobs: "status=${{ job.status }}" >> $env:GITHUB_OUTPUT - if: success() || failure() && steps.abort_job.outputs.status == 'success' - name: Run functionaltests + name: Run functionaltest + timeout-minutes: 15 run: cmake --build build --target functionaltest - if: success() || failure() && steps.abort_job.outputs.status == 'success' - name: Run oldtests + name: Run oldtest run: | # Add MSYS to path, required for e.g. `find` used in test scripts. - # But would break functionaltests, where its `more` would be used then. + # But would break functionaltest, where its `more` would be used then. $OldPath = $env:PATH $env:PATH = "C:\msys64\usr\bin;$env:PATH" & "C:\msys64\mingw64\bin\mingw32-make.exe" -C $(Convert-Path src\nvim\testdir) VERBOSE=1 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a11a87f93a..497a79d2d1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,28 +13,19 @@ jobs: contents: read security-events: write - strategy: - fail-fast: false - matrix: - language: [ 'cpp' ] - steps: - name: Checkout repository uses: actions/checkout@v3 - - name: Setup common environment variables - run: ./.github/workflows/env.sh - - - name: Install apt packages - run: ./.github/scripts/install_deps_ubuntu.sh + - name: Install dependencies + run: ./.github/scripts/install_deps.sh - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: - languages: ${{ matrix.language }} + languages: cpp - - if: matrix.language == 'cpp' - run: make + - run: make - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 87e2cb1453..e63f119958 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -11,9 +11,7 @@ jobs: - uses: actions/checkout@v3 - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install -y autoconf automake build-essential cmake gettext libtool-bin locales ninja-build pkg-config unzip + run: ./.github/scripts/install_deps.sh - name: Download Coverity run: | diff --git a/.github/workflows/env.ps1 b/.github/workflows/env.ps1 deleted file mode 100644 index 8ac267f2f9..0000000000 --- a/.github/workflows/env.ps1 +++ /dev/null @@ -1,7 +0,0 @@ -$installationPath = vswhere.exe -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath -if ($installationPath -and (Test-Path "$installationPath\Common7\Tools\vsdevcmd.bat")) { - & "${env:COMSPEC}" /s /c "`"$installationPath\Common7\Tools\vsdevcmd.bat`" -arch=x64 -no_logo && set" | ForEach-Object { - $name, $value = $_ -split '=', 2 - "$name=$value" >> $env:GITHUB_ENV - } -} diff --git a/.github/workflows/env.sh b/.github/workflows/env.sh deleted file mode 100755 index 42a355da44..0000000000 --- a/.github/workflows/env.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash -set -e -u - -FLAVOR=${1:-} - -cat <<EOF >> "$GITHUB_PATH" -$HOME/.local/bin -EOF - -cat <<EOF >> "$GITHUB_ENV" -CI_BUILD_DIR=$GITHUB_WORKSPACE -BUILD_DIR=$GITHUB_WORKSPACE/build -DEPS_BUILD_DIR=$HOME/nvim-deps -INSTALL_PREFIX=$HOME/nvim-install -LOG_DIR=$GITHUB_WORKSPACE/build/log -NVIM_LOG_FILE=$GITHUB_WORKSPACE/build/.nvimlog -VALGRIND_LOG=$GITHUB_WORKSPACE/build/log/valgrind-%p.log -CACHE_NVIM_DEPS_DIR=$HOME/.cache/nvim-deps -CACHE_MARKER=$HOME/.cache/nvim-deps/.ci_cache_marker -CACHE_UNCRUSTIFY=$HOME/.cache/uncrustify -EOF - -DEPS_CMAKE_FLAGS= -FUNCTIONALTEST=functionaltest -BUILD_FLAGS="CMAKE_FLAGS=-DCI_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX:PATH=$HOME/nvim-install -DBUSTED_OUTPUT_TYPE=nvim -DDEPS_PREFIX=$HOME/nvim-deps/usr -DMIN_LOG_LEVEL=3" - -case "$FLAVOR" in - asan) - cat <<EOF >> "$GITHUB_ENV" -CLANG_SANITIZER=ASAN_UBSAN -ASAN_OPTIONS=detect_leaks=1:check_initialization_order=1:log_path=$GITHUB_WORKSPACE/build/log/asan:intercept_tls_get_addr=0 -UBSAN_OPTIONS=print_stacktrace=1 log_path=$GITHUB_WORKSPACE/build/log/ubsan -EOF - ;; - tsan) - cat <<EOF >> "$GITHUB_ENV" -TSAN_OPTIONS=log_path=$GITHUB_WORKSPACE/build/log/tsan -CLANG_SANITIZER=TSAN -EOF - ;; - uchar) - cat <<EOF >> "$GITHUB_ENV" -BUILD_UCHAR=1 -EOF - ;; - lintc) -# Re-enable once system deps are available -# BUILD_FLAGS="$BUILD_FLAGS -DLIBLUV_LIBRARY:FILEPATH=/usr/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/lua/5.1/luv.so -DLIBLUV_INCLUDE_DIR:PATH=/usr/include/lua5.1" - - # Ideally all dependencies should external for this job, but some - # dependencies don't have the required version available. We use the - # bundled versions for these with the hopes of being able to remove them - # later on. - DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -DUSE_BUNDLED=OFF -DUSE_BUNDLED_LUV=ON -DUSE_BUNDLED_LIBVTERM=ON" - ;; - functionaltest-lua) - BUILD_FLAGS="$BUILD_FLAGS -DPREFER_LUA=ON" - FUNCTIONALTEST=functionaltest-lua - DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -DUSE_BUNDLED_LUAJIT=OFF" - ;; - *) - ;; -esac - -cat <<EOF >> "$GITHUB_ENV" -$BUILD_FLAGS -DEPS_CMAKE_FLAGS=$DEPS_CMAKE_FLAGS -FUNCTIONALTEST=$FUNCTIONALTEST -EOF diff --git a/.github/workflows/lintcommit.yml b/.github/workflows/lintcommit.yml index a7a227865d..afedbe0b12 100644 --- a/.github/workflows/lintcommit.yml +++ b/.github/workflows/lintcommit.yml @@ -15,9 +15,7 @@ jobs: with: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} - path: pr_nvim - uses: rhysd/action-setup-vim@v1 with: neovim: true - - run: wget https://raw.githubusercontent.com/neovim/neovim/master/scripts/lintcommit.lua - - run: nvim --clean -es +"cd pr_nvim" +"lua dofile('../lintcommit.lua').main({trace=true})" + - run: nvim --clean -es +"lua require('scripts.lintcommit').main({trace=false})" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1df33962e5..a05038f32a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -101,40 +101,8 @@ jobs: run: printf 'NVIM_BUILD_TYPE=Release\n' >> $GITHUB_ENV - if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag_name == 'nightly') run: printf 'NVIM_BUILD_TYPE=RelWithDebInfo\n' >> $GITHUB_ENV - - name: Provision universal `libintl` - run: | - GETTEXT_PREFIX="$(brew --prefix gettext)" - printf 'GETTEXT_PREFIX=%s\n' "$GETTEXT_PREFIX" >> $GITHUB_ENV - bottle_tag="arm64_big_sur" - brew fetch --bottle-tag="$bottle_tag" gettext - cd "$(mktemp -d)" - tar xf "$(brew --cache)"/**/*gettext*${bottle_tag}*.tar.gz - lipo gettext/*/lib/libintl.a "${GETTEXT_PREFIX}/lib/libintl.a" -create -output libintl.a - mv -f libintl.a /usr/local/lib/ - - name: Ensure static linkage to `libintl` - run: | - # We're about to mangle `gettext`, so let's remove any potentially broken - # installs (e.g. curl, git) as those could interfere with our build. - brew uninstall $(brew uses --installed --recursive gettext) - brew unlink gettext - ln -sf "$(brew --prefix)/opt/$(readlink "${GETTEXT_PREFIX}")/bin"/* /usr/local/bin/ - ln -sf "$(brew --prefix)/opt/$(readlink "${GETTEXT_PREFIX}")/include"/* /usr/local/include/ - rm -f "$GETTEXT_PREFIX" - - name: Build release - run: | - export MACOSX_DEPLOYMENT_TARGET="$(sw_vers -productVersion | cut -f1 -d.)" - OSX_FLAGS="-DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} -DCMAKE_OSX_ARCHITECTURES=arm64\;x86_64" - make CMAKE_BUILD_TYPE=${NVIM_BUILD_TYPE} \ - CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX:PATH= $OSX_FLAGS" \ - DEPS_CMAKE_FLAGS="$OSX_FLAGS" - make DESTDIR="$GITHUB_WORKSPACE/build/release/nvim-macos" install - cd "$GITHUB_WORKSPACE/build/" - # Make sure we build everything for M1 as well - for macho in bin/* lib/nvim/parser/*.so - do - lipo -info "$macho" | grep -q arm64 || exit 1 - done - cpack -C "$NVIM_BUILD_TYPE" + - name: Build universal binary + run: ./.github/scripts/build_universal_macos.sh - uses: actions/upload-artifact@v3 with: name: nvim-macos @@ -143,24 +111,27 @@ jobs: windows: runs-on: windows-2019 - env: - DEPS_BUILD_DIR: ${{ format('{0}/nvim-deps', github.workspace) }} - DEPS_PREFIX: ${{ format('{0}/nvim-deps/usr', github.workspace) }} - CMAKE_BUILD_TYPE: "RelWithDebInfo" name: windows (MSVC_64) steps: - uses: actions/checkout@v3 with: fetch-depth: 0 - name: Set env - run: ./.github/workflows/env.ps1 + run: | + $installationPath = vswhere.exe -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath + if ($installationPath -and (Test-Path "$installationPath\Common7\Tools\vsdevcmd.bat")) { + & "${env:COMSPEC}" /s /c "`"$installationPath\Common7\Tools\vsdevcmd.bat`" -arch=x64 -no_logo && set" | ForEach-Object { + $name, $value = $_ -split '=', 2 + "$name=$value" >> $env:GITHUB_ENV + } + } - name: Build deps run: | - cmake -S cmake.deps -B $env:DEPS_BUILD_DIR -G Ninja -DCMAKE_BUILD_TYPE='RelWithDebInfo' - cmake --build $env:DEPS_BUILD_DIR + cmake -S cmake.deps -B .deps -G Ninja -DCMAKE_BUILD_TYPE='RelWithDebInfo' + cmake --build .deps - name: build package run: | - cmake -B build -G Ninja -DCMAKE_BUILD_TYPE='RelWithDebInfo' -DDEPS_PREFIX="$env:DEPS_PREFIX" + cmake -B build -G Ninja -DCMAKE_BUILD_TYPE='RelWithDebInfo' cmake --build build --target package - uses: actions/upload-artifact@v3 with: diff --git a/.github/workflows/universal_macos.yml b/.github/workflows/universal_macos.yml new file mode 100644 index 0000000000..7ce66ea5fb --- /dev/null +++ b/.github/workflows/universal_macos.yml @@ -0,0 +1,34 @@ +name: macos-universal +on: + pull_request: + branches: + - 'master' + - 'release-[0-9]+.[0-9]+' + paths: + - '**.cmake' + - '**/CMakeLists.txt' + - '**/CMakePresets.json' + - 'cmake.*/**' + - '.github/scripts/build_universal_macos.sh' + - '.github/workflow/universal_macos.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref }} + cancel-in-progress: true + +jobs: + macos-universal: + runs-on: macos-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v3 + + - name: Install dependencies + run: | + brew update --quiet + brew install automake ninja + + - run: printf 'NVIM_BUILD_TYPE=Release\n' >> $GITHUB_ENV + + - name: Build universal binary + run: ./.github/scripts/build_universal_macos.sh diff --git a/.github/workflows/vim-patches.yml b/.github/workflows/vim-patches.yml index 159eb09e7c..305f8019f1 100644 --- a/.github/workflows/vim-patches.yml +++ b/.github/workflows/vim-patches.yml @@ -11,7 +11,7 @@ jobs: contents: write pull-requests: write env: - VIM_SOURCE_DIR: ${{ format('{0}/vim-src', github.workspace) }} + VIM_SOURCE_DIR: ${{ github.workspace }}/vim-src VERSION_BRANCH: marvim/ci-version-update GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: diff --git a/.luacheckrc b/.luacheckrc index 8ef4f5ea66..d1aca1cfd6 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -41,4 +41,5 @@ globals = { exclude_files = { 'test/functional/fixtures/lua/syntax_error.lua', + 'runtime/lua/vim/treesitter/_meta.lua' } diff --git a/CMakeLists.txt b/CMakeLists.txt index 8df9eb19f9..d12b71a651 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,15 +65,15 @@ else() file(MAKE_DIRECTORY ${DEPS_BUILD_DIR}) execute_process( COMMAND ${CMAKE_COMMAND} -G ${CMAKE_GENERATOR} - -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} - -DCMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG} - -DCMAKE_C_FLAGS_MINSIZEREL=${CMAKE_C_FLAGS_MINSIZEREL} - -DCMAKE_C_FLAGS_RELWITHDEBINFO=${CMAKE_C_FLAGS_RELWITHDEBINFO} - -DCMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE} - -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} + -D CMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} + -D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -D CMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -D CMAKE_C_FLAGS=${CMAKE_C_FLAGS} + -D CMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG} + -D CMAKE_C_FLAGS_MINSIZEREL=${CMAKE_C_FLAGS_MINSIZEREL} + -D CMAKE_C_FLAGS_RELWITHDEBINFO=${CMAKE_C_FLAGS_RELWITHDEBINFO} + -D CMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE} + -D CMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} ${PROJECT_SOURCE_DIR}/cmake.deps WORKING_DIRECTORY ${DEPS_BUILD_DIR}) execute_process( @@ -244,9 +244,9 @@ endif() # Lint # find_program(LUACHECK_PRG luacheck) +find_program(SHELLCHECK_PRG shellcheck) find_program(STYLUA_PRG stylua) find_program(UNCRUSTIFY_PRG uncrustify) -find_program(SHELLCHECK_PRG shellcheck) add_glob_target( REQUIRED @@ -276,8 +276,6 @@ add_glob_target( GLOB_PAT *.sh EXCLUDE scripts/pvscheck.sh - ci/common - ci/snap TOUCH_STRATEGY SINGLE) add_custom_target(lintcommit @@ -287,7 +285,7 @@ add_custom_target(lintcommit add_dependencies(lintcommit nvim) add_custom_target(lint) -add_dependencies(lint check-single-includes lintc lintlua lintsh lintcommit) +add_dependencies(lint clang-tidy lintc lintlua lintsh lintcommit) # # Format @@ -306,113 +304,22 @@ install_helper( FILES ${CMAKE_SOURCE_DIR}/src/man/nvim.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) -# -# Go down the tree. -# +if(EXISTS "${DEPS_PREFIX}/share/nvim-qt") + option(USE_BUNDLED_NVIMQT "Bundle neovim-qt" ON) +else() + option(USE_BUNDLED_NVIMQT "Bundle neovim-qt" OFF) +endif() add_subdirectory(src/nvim) add_subdirectory(cmake.config) -add_subdirectory(test/functional/fixtures) # compile test programs add_subdirectory(runtime) -get_directory_property(GENERATED_HELP_TAGS DIRECTORY runtime DEFINITION GENERATED_HELP_TAGS) -if(WIN32) +add_subdirectory(test) +if(WIN32 AND USE_BUNDLED_NVIMQT) install_helper( FILES ${DEPS_PREFIX}/share/nvim-qt/runtime/plugin/nvim_gui_shim.vim DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/nvim-qt/runtime/plugin) endif() -# Setup busted. -find_program(BUSTED_PRG NAMES busted busted.bat) -find_program(BUSTED_LUA_PRG busted-lua) -if(NOT BUSTED_OUTPUT_TYPE) - set(BUSTED_OUTPUT_TYPE "nvim") -endif() - -# Setup some test-related bits. We do this after going down the tree because we -# need some of the targets. -if(BUSTED_PRG) - get_target_property(TEST_INCLUDE_DIRS main_lib INTERFACE_INCLUDE_DIRECTORIES) - - set(UNITTEST_PREREQS nvim) - set(FUNCTIONALTEST_PREREQS nvim printenv-test printargs-test shell-test pwsh-test streams-test tty-test ${GENERATED_HELP_TAGS}) - set(BENCHMARK_PREREQS nvim tty-test) - - check_lua_module(${LUA_PRG} "ffi" LUA_HAS_FFI) - if(LUA_HAS_FFI) - add_custom_target(unittest - 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} - -DTEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test - -DBUILD_DIR=${CMAKE_BINARY_DIR} - -DTEST_TYPE=unit - -DCIRRUS_CI=$ENV{CIRRUS_CI} - -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake - DEPENDS ${UNITTEST_PREREQS} - USES_TERMINAL) - set_target_properties(unittest PROPERTIES FOLDER test) - else() - message(WARNING "disabling unit tests: no Luajit FFI in ${LUA_PRG}") - endif() - - configure_file( - ${CMAKE_SOURCE_DIR}/test/cmakeconfig/paths.lua.in - ${CMAKE_BINARY_DIR}/test/cmakeconfig/paths.lua) - - 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} - -DTEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test - -DBUILD_DIR=${CMAKE_BINARY_DIR} - -DTEST_TYPE=functional - -DCIRRUS_CI=$ENV{CIRRUS_CI} - -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake - DEPENDS ${FUNCTIONALTEST_PREREQS} - USES_TERMINAL) - set_target_properties(functionaltest PROPERTIES FOLDER test) - - 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} - -DTEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test - -DBUILD_DIR=${CMAKE_BINARY_DIR} - -DTEST_TYPE=benchmark - -DCIRRUS_CI=$ENV{CIRRUS_CI} - -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake - DEPENDS ${BENCHMARK_PREREQS} - USES_TERMINAL) - set_target_properties(benchmark PROPERTIES FOLDER test) -endif() - -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} - -DTEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test - -DBUILD_DIR=${CMAKE_BINARY_DIR} - -DTEST_TYPE=functional - -DCIRRUS_CI=$ENV{CIRRUS_CI} - -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake - DEPENDS ${FUNCTIONALTEST_PREREQS} - USES_TERMINAL) - set_target_properties(functionaltest-lua PROPERTIES FOLDER test) -endif() - add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/UninstallHelper.cmake) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f1c7ca1cb3..fe2cdb8a36 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -98,7 +98,7 @@ the VCS/git logs more valuable. The general structure of a commit message is: ``` - Prefix the commit subject with one of these [_types_](https://github.com/commitizen/conventional-commit-types/blob/master/index.json): - - `build`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `test`, `vim-patch`, `dist` + - `build`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `test`, `vim-patch` - You can **ignore this for "fixup" commits** or any commits you expect to be squashed. - Append optional scope to _type_ such as `(lsp)`, `(treesitter)`, `(float)`, … - _Description_ shouldn't start with a capital letter or end in a period. @@ -187,7 +187,7 @@ master build. To view the defects, just request access; you will be approved. ``` - When running Neovim, use ``` - UBSAN_OPTIONS=print_stacktrace=1 ASAN_OPTIONS=log_path=/tmp/nvim_asan nvim args... + UBSAN_OPTIONS=print_stacktrace=1 ASAN_OPTIONS=log_path=/tmp/nvim_asan,handle_abort=1,handle_sigill=1 nvim args... ``` - If Neovim exits unexpectedly, check `/tmp/nvim_asan.{PID}` (or your preferred `log_path`) for log files with error messages. diff --git a/MAINTAIN.md b/MAINTAIN.md index 95a3916535..1b3176f4ff 100644 --- a/MAINTAIN.md +++ b/MAINTAIN.md @@ -69,6 +69,7 @@ Some can be auto-bumped by `scripts/bump_deps.lua`. * [LuaJIT](https://github.com/LuaJIT/LuaJIT) * [Lua](https://www.lua.org/download.html) * [Luv](https://github.com/luvit/luv) + * When bumping, also sync [our bundled documentation](https://github.com/neovim/neovim/blob/master/runtime/doc/luvref.txt) with [the upstream documentation](https://github.com/luvit/luv/blob/master/docs.md). * [gettext](https://ftp.gnu.org/pub/gnu/gettext/) * [libiconv](https://ftp.gnu.org/pub/gnu/libiconv) * [libtermkey](https://github.com/neovim/libtermkey) @@ -130,7 +130,7 @@ functionaltest-lua: | nvim $(BUILD_TOOL) -C build $@ FORMAT=formatc formatlua format -LINT=lintlua lintsh lintc check-single-includes lintcommit lint +LINT=lintlua lintsh lintc clang-tidy lintcommit lint TEST=functionaltest unittest generated-sources benchmark uninstall $(FORMAT) $(LINT) $(TEST): | build/.ran-cmake $(CMAKE_PRG) --build build --target $@ diff --git a/ci/before_cache.sh b/ci/before_cache.sh deleted file mode 100755 index 3daeb04793..0000000000 --- a/ci/before_cache.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -o pipefail - -CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source-path=SCRIPTDIR -source "${CI_DIR}/common/build.sh" -# shellcheck source-path=SCRIPTDIR -source "${CI_DIR}/common/suite.sh" - -mkdir -p "${HOME}/.cache" - -echo "before_cache.sh: cache size" -du -chd 1 "${HOME}/.cache" | sort -rh | head -20 - -# Update the third-party dependency cache only if the build was successful. -if ended_successfully && [ -d "${DEPS_BUILD_DIR}" ]; then - # Do not cache downloads. They should not be needed with up-to-date deps. - rm -rf "${DEPS_BUILD_DIR}/build/downloads" - rm -rf "${CACHE_NVIM_DEPS_DIR}" - mv "${DEPS_BUILD_DIR}" "${CACHE_NVIM_DEPS_DIR}" - - touch "${CACHE_MARKER}" - echo "Updated third-party dependencies (timestamp: $(_stat "${CACHE_MARKER}"))." -fi diff --git a/ci/before_script.sh b/ci/before_script.sh deleted file mode 100755 index 066789af36..0000000000 --- a/ci/before_script.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -o pipefail - -CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source-path=SCRIPTDIR -source "${CI_DIR}/common/build.sh" - -# Test some of the configuration variables. -if [[ -n "${GCOV}" ]] && [[ ! $(type -P "${GCOV}") ]]; then - echo "\$GCOV: '${GCOV}' is not executable." - exit 1 -fi -if [[ -n "${LLVM_SYMBOLIZER}" ]] && [[ ! $(type -P "${LLVM_SYMBOLIZER}") ]]; then - echo "\$LLVM_SYMBOLIZER: '${LLVM_SYMBOLIZER}' is not executable." - exit 1 -fi - -# Compile dependencies. -build_deps - -# Install cluacov for Lua coverage. -if [[ "$USE_LUACOV" == 1 ]]; then - "${DEPS_BUILD_DIR}/usr/bin/luarocks" install cluacov -fi - -rm -rf "${LOG_DIR}" -mkdir -p "${LOG_DIR}" diff --git a/ci/common/build.sh b/ci/common/build.sh deleted file mode 100644 index 95972aab13..0000000000 --- a/ci/common/build.sh +++ /dev/null @@ -1,78 +0,0 @@ -_stat() { - if test "${CI_OS_NAME}" = osx ; then - stat -f %Sm "${@}" - else - stat -c %y "${@}" - fi -} - -top_make() { - printf '%78s\n' ' ' | tr ' ' '=' - ninja "$@" -} - -build_make() { - top_make -C "${BUILD_DIR}" "$@" -} - -build_deps() { - if test "${FUNCTIONALTEST}" = "functionaltest-lua" ; then - DEPS_CMAKE_FLAGS="${DEPS_CMAKE_FLAGS} -DUSE_BUNDLED_LUA=ON" - fi - - mkdir -p "${DEPS_BUILD_DIR}" - - # Use cached dependencies if $CACHE_MARKER exists. - if test -f "${CACHE_MARKER}"; then - echo "Using third-party dependencies from cache (last update: $(_stat "${CACHE_MARKER}"))." - cp -a "${CACHE_NVIM_DEPS_DIR}"/. "${DEPS_BUILD_DIR}" - fi - - # Even if we're using cached dependencies, run CMake and make to - # update CMake configuration and update to newer deps versions. - cd "${DEPS_BUILD_DIR}" - echo "Configuring with '${DEPS_CMAKE_FLAGS}'." - # shellcheck disable=SC2086 - CC= cmake -G Ninja ${DEPS_CMAKE_FLAGS} "${CI_BUILD_DIR}/cmake.deps/" - - if ! top_make; then - exit 1 - fi - - cd "${CI_BUILD_DIR}" -} - -build_nvim() { - check_core_dumps --delete quiet - - if test -n "${CLANG_SANITIZER}" ; then - CMAKE_FLAGS="${CMAKE_FLAGS} -DCLANG_${CLANG_SANITIZER}=ON" - fi - - mkdir -p "${BUILD_DIR}" - cd "${BUILD_DIR}" - echo "Configuring with '${CMAKE_FLAGS} $*'." - # shellcheck disable=SC2086 - cmake -G Ninja ${CMAKE_FLAGS} "$@" "${CI_BUILD_DIR}" - - echo "Building nvim." - if ! top_make nvim ; then - exit 1 - fi - - if test "$CLANG_SANITIZER" != "TSAN" ; then - echo "Building libnvim." - if ! top_make libnvim ; then - exit 1 - fi - fi - - # Invoke nvim to trigger *San early. - if ! (bin/nvim --version && bin/nvim -u NONE -e -cq | cat -vet) ; then - check_sanitizer "${LOG_DIR}" - exit 1 - fi - check_sanitizer "${LOG_DIR}" - - cd "${CI_BUILD_DIR}" -} diff --git a/ci/common/submit_coverage.sh b/ci/common/submit_coverage.sh deleted file mode 100755 index f781ca8e5e..0000000000 --- a/ci/common/submit_coverage.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh -# Collect and submit coverage reports. -# -# Args: -# $1: Flag(s) for codecov, separated by comma. - -set -e - -# Change to grandparent dir (POSIXly). -CDPATH='' cd -P -- "$(dirname -- "$0")/../.." || exit - -echo "=== running submit_coverage in $PWD: $* ===" -"$GCOV" --version - -# Download/install codecov-bash and gcovr once. -codecov_sh="${TEMP:-/tmp}/codecov.bash" -if ! [ -f "$codecov_sh" ]; then - curl --retry 5 --silent --fail -o "$codecov_sh" https://codecov.io/bash - chmod +x "$codecov_sh" - - python -m pip install --quiet --user gcovr -fi - -( - cd build - python -m gcovr --branches --exclude-unreachable-branches --print-summary -j 2 --exclude '.*/auto/.*' --root .. --delete -o ../coverage.xml --xml -) - -# Upload to codecov. -# -X gcov: disable gcov, done manually above. -# -X fix: disable fixing of reports (not necessary, rather slow) -# -Z: exit non-zero on failure -# -F: flag(s) -# NOTE: ignoring flags for now, since this causes timeouts on codecov.io then, -# which they know about for about a year already... -# Flags must match pattern ^[\w\,]+$ ("," as separator). -codecov_flags="$(uname -s),${1}" -codecov_flags=$(echo "$codecov_flags" | sed 's/[^,_a-zA-Z0-9]/_/g') -if ! "$codecov_sh" -f coverage.xml -X gcov -X fix -Z -F "${codecov_flags}"; then - echo "codecov upload failed." -fi - -# Cleanup always, especially collected data. -find . \( -name '*.gcov' -o -name '*.gcda' \) -ls -delete | wc -l -rm -f coverage.xml - -# Upload Lua coverage (generated manually on AppVeyor/Windows). -if [ "$USE_LUACOV" = 1 ] && [ "$1" != "oldtest" ]; then - if [ -x "${DEPS_BUILD_DIR}/usr/bin/luacov" ]; then - "${DEPS_BUILD_DIR}/usr/bin/luacov" - fi - if ! "$codecov_sh" -f luacov.report.out -X gcov -X fix -Z -F "lua,${codecov_flags}"; then - echo "codecov upload failed." - fi - rm luacov.stats.out -fi diff --git a/ci/common/suite.sh b/ci/common/suite.sh deleted file mode 100644 index c81261d2e7..0000000000 --- a/ci/common/suite.sh +++ /dev/null @@ -1,41 +0,0 @@ -# Test success marker. If END_MARKER file exists, we know that all tests -# finished. If FAIL_SUMMARY_FILE exists we know that some tests failed, this -# file will contain information about failed tests. Build is considered -# successful if tests ended without any of them failing. -END_MARKER="$BUILD_DIR/.tests_finished" -FAIL_SUMMARY_FILE="$BUILD_DIR/.test_errors" - -fail() { - local test_name="$1" - local message="$2" - - : "${message:=Test $test_name failed}" - - local full_msg="$test_name :: $message" - echo "${full_msg}" >> "${FAIL_SUMMARY_FILE}" - echo "Failed: $full_msg" - export FAILED=1 -} - -ended_successfully() { - if test -f "${FAIL_SUMMARY_FILE}" ; then - echo 'Test failed, complete summary:' - cat "${FAIL_SUMMARY_FILE}" - - if [[ "$GITHUB_ACTIONS" == "true" ]]; then - rm -f "$FAIL_SUMMARY_FILE" - fi - - return 1 - fi - if ! test -f "${END_MARKER}" ; then - echo 'ended_successfully called before end marker was touched' - return 1 - fi - return 0 -} - -end_tests() { - touch "${END_MARKER}" - ended_successfully -} diff --git a/ci/common/test.sh b/ci/common/test.sh deleted file mode 100644 index 326ec162c3..0000000000 --- a/ci/common/test.sh +++ /dev/null @@ -1,175 +0,0 @@ -. "${CI_DIR}/common/build.sh" -. "${CI_DIR}/common/suite.sh" - -submit_coverage() { - if [ -n "${GCOV}" ]; then - "${CI_DIR}/common/submit_coverage.sh" "$@" || echo 'codecov upload failed.' - fi -} - -print_core() { - local app="$1" - local core="$2" - if test "$app" = quiet ; then - echo "Found core $core" - return 0 - fi - echo "======= Core file $core =======" - if test "${CI_OS_NAME}" = osx ; then - lldb -Q -o "bt all" -f "${app}" -c "${core}" - else - gdb -n -batch -ex 'thread apply all bt full' "${app}" -c "${core}" - fi -} - -check_core_dumps() { - local del= - if test "$1" = "--delete" ; then - del=1 - shift - fi - local app="${1:-${BUILD_DIR}/bin/nvim}" - local cores - if test "${CI_OS_NAME}" = osx ; then - cores="$(find /cores/ -type f -print)" - local _sudo='sudo' - else - cores="$(find ./ -type f \( -name 'core.*' -o -name core -o -name nvim.core \) -print)" - local _sudo= - fi - - if test -z "${cores}" ; then - return - fi - local core - for core in $cores; do - if test "$del" = "1" ; then - print_core "$app" "$core" >&2 - "$_sudo" rm "$core" - else - print_core "$app" "$core" - fi - done - if test "$app" != quiet ; then - fail 'cores' 'Core dumps found' - fi -} - -check_logs() { - # Iterate through each log to remove an useless warning. - # shellcheck disable=SC2044 - for log in $(find "${1}" -type f -name "${2}"); do - sed -i "${log}" \ - -e '/Warning: noted but unhandled ioctl/d' \ - -e '/could cause spurious value errors to appear/d' \ - -e '/See README_MISSING_SYSCALL_OR_IOCTL for guidance/d' - done - - # Now do it again, but only consider files with size > 0. - local err="" - # shellcheck disable=SC2044 - for log in $(find "${1}" -type f -name "${2}" -size +0); do - cat "${log}" - err=1 - rm "${log}" - done - if test -n "${err}" ; then - fail 'logs' 'Runtime errors detected.' - fi -} - -valgrind_check() { - check_logs "${1}" "valgrind-*" -} - -check_sanitizer() { - if test -n "${CLANG_SANITIZER}"; then - check_logs "${1}" "*san.*" | ${SYMBOLIZER:-cat} - fi -} - -unittests() {( - ulimit -c unlimited || true - if ! build_make unittest ; then - fail 'unittests' 'Unit tests failed' - fi - submit_coverage unittest - check_core_dumps "$(command -v luajit)" -)} - -functionaltests() {( - ulimit -c unlimited || true - if ! build_make "${FUNCTIONALTEST}"; then - fail 'functionaltests' 'Functional tests failed' - fi - submit_coverage functionaltest - check_sanitizer "${LOG_DIR}" - valgrind_check "${LOG_DIR}" - check_core_dumps -)} - -oldtests() {( - ulimit -c unlimited || true - if ! make oldtest; then - reset - fail 'oldtests' 'Legacy tests failed' - fi - submit_coverage oldtest - check_sanitizer "${LOG_DIR}" - valgrind_check "${LOG_DIR}" - check_core_dumps -)} - -check_runtime_files() {( - local test_name="$1" ; shift - local message="$1" ; shift - local tst="$1" ; shift - - cd runtime - for file in $(git ls-files "$@") ; do - # Check that test is not trying to work with files with spaces/etc - # Prefer failing the build over using more robust construct because files - # with IFS are not welcome. - if ! test -e "$file" ; then - fail "$test_name" "It appears that $file is only a part of the file name" - fi - if ! test "$tst" "$INSTALL_PREFIX/share/nvim/runtime/$file" ; then - fail "$test_name" "$(printf "%s%s" "$message" "$file")" - fi - done -)} - -install_nvim() {( - if ! build_make install ; then - fail 'install' 'make install failed' - exit 1 - fi - - "${INSTALL_PREFIX}/bin/nvim" --version - if ! "${INSTALL_PREFIX}/bin/nvim" -u NONE -e -c ':help' -c ':qall' ; then - echo "Running ':help' in the installed nvim failed." - echo "Maybe the helptags have not been generated properly." - fail 'help' 'Failed running :help' - fi - - # Check that all runtime files were installed - check_runtime_files \ - 'runtime-install' \ - 'It appears that %s is not installed.' \ - -e \ - '*.vim' '*.ps' '*.dict' '*.py' '*.tutor' - - # Check that some runtime files are installed and are executables - check_runtime_files \ - 'not-exe' \ - 'It appears that %s is not installed or is not executable.' \ - -x \ - '*.awk' '*.sh' '*.bat' - - # Check that generated syntax file has function names, #5060. - local genvimsynf=syntax/vim/generated.vim - local gpat='syn keyword vimFuncName .*eval' - if ! grep -q "$gpat" "${INSTALL_PREFIX}/share/nvim/runtime/$genvimsynf" ; then - fail 'funcnames' "It appears that $genvimsynf does not contain $gpat." - fi -)} diff --git a/ci/install.sh b/ci/install.sh deleted file mode 100755 index 5925cc7b02..0000000000 --- a/ci/install.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -o pipefail - -# Use default CC to avoid compilation problems when installing Python modules. -echo "Install neovim module for Python." -CC=cc python3 -m pip -q install --user --upgrade pynvim - -echo "Install neovim RubyGem." -gem install --no-document --bindir "$HOME/.local/bin" --user-install --pre neovim - -echo "Install neovim npm package" -npm install -g neovim -npm link neovim - -if [[ $CI_OS_NAME != osx ]]; then - sudo cpanm -n Neovim::Ext || cat "$HOME/.cpanm/build.log" - perl -W -e 'use Neovim::Ext; print $Neovim::Ext::VERSION' -fi diff --git a/ci/run_tests.sh b/ci/run_tests.sh deleted file mode 100755 index 0ef7080628..0000000000 --- a/ci/run_tests.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -o pipefail - -CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source-path=SCRIPTDIR -source "${CI_DIR}/common/build.sh" -# shellcheck source-path=SCRIPTDIR -source "${CI_DIR}/common/test.sh" -# shellcheck source-path=SCRIPTDIR -source "${CI_DIR}/common/suite.sh" - -rm -f "$END_MARKER" - -# Run all tests (with some caveats) if no input argument is given -if (($# == 0)); then - tests=('build_nvim') - - # Additional threads aren't created in the unit/old tests - if test "$CLANG_SANITIZER" != "TSAN"; then - if test "${FUNCTIONALTEST}" != "functionaltest-lua"; then - tests+=('unittests') - fi - tests+=('oldtests') - fi - - tests+=('functionaltests' 'install_nvim') -else - tests=("$@") -fi - -for i in "${tests[@]}"; do - eval "$i" || fail "$i" -done - -end_tests - -if [[ -s "${GCOV_ERROR_FILE}" ]]; then - echo '=== Unexpected gcov errors: ===' - cat "${GCOV_ERROR_FILE}" - exit 1 -fi diff --git a/cmake.config/CMakeLists.txt b/cmake.config/CMakeLists.txt index 29d7622c01..da7b2b9b45 100644 --- a/cmake.config/CMakeLists.txt +++ b/cmake.config/CMakeLists.txt @@ -156,7 +156,6 @@ if (NOT "${HAVE_BE64TOH}") endif() endif() -# generate configuration header and update include directories configure_file ( "${PROJECT_SOURCE_DIR}/cmake.config/config.h.in" "${PROJECT_BINARY_DIR}/cmake.config/auto/config.h" @@ -176,21 +175,21 @@ file(GENERATE OUTPUT "${PROJECT_BINARY_DIR}/cmake.config/auto/versiondef.h" INPUT "${PROJECT_BINARY_DIR}/cmake.config/auto/versiondef.h.gen") -# generate pathdef.c -find_program(WHOAMI_PROG whoami) -find_program(HOSTNAME_PROG hostname) +find_program(WHOAMI_PRG whoami) +find_program(HOSTNAME_PRG hostname) +mark_as_advanced(HOSTNAME_PRG WHOAMI_PRG) if (DEFINED ENV{USERNAME}) set(USERNAME $ENV{USERNAME}) -elseif (NOT DEFINED USERNAME AND EXISTS ${WHOAMI_PROG}) - execute_process(COMMAND ${WHOAMI_PROG} +elseif (NOT DEFINED USERNAME AND EXISTS ${WHOAMI_PRG}) + execute_process(COMMAND ${WHOAMI_PRG} OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE USERNAME) endif() if (DEFINED ENV{HOSTNAME}) set(HOSTNAME $ENV{HOSTNAME}) -elseif (EXISTS ${HOSTNAME_PROG}) - execute_process(COMMAND ${HOSTNAME_PROG} +elseif (EXISTS ${HOSTNAME_PRG}) + execute_process(COMMAND ${HOSTNAME_PRG} OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE HOSTNAME) endif() diff --git a/cmake.deps/CMakeLists.txt b/cmake.deps/CMakeLists.txt index 90ae91463d..bc395017c0 100644 --- a/cmake.deps/CMakeLists.txt +++ b/cmake.deps/CMakeLists.txt @@ -13,10 +13,10 @@ include(CheckCCompilerFlag) include(Util) set(DEPS_CMAKE_ARGS - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - -DCMAKE_GENERATOR=${CMAKE_GENERATOR} - -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM} - -DCMAKE_POSITION_INDEPENDENT_CODE=ON) + -D CMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -D CMAKE_GENERATOR=${CMAKE_GENERATOR} + -D CMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM} + -D CMAKE_POSITION_INDEPENDENT_CODE=ON) set(DEPS_CMAKE_CACHE_ARGS -DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES}) @@ -24,7 +24,7 @@ set_default_buildtype() get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(NOT isMultiConfig) - list(APPEND DEPS_CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}) + list(APPEND DEPS_CMAKE_ARGS -D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}) endif() set(DEFAULT_MAKE_CFLAGS CFLAGS+=-g) @@ -45,7 +45,7 @@ else() set(DEPS_INSTALL_DIR "${CMAKE_BINARY_DIR}/usr" CACHE PATH "Dependencies install directory.") endif() -list(APPEND DEPS_CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}) +list(APPEND DEPS_CMAKE_ARGS -D CMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}) set(DEPS_BIN_DIR "${DEPS_INSTALL_DIR}/bin" CACHE PATH "Dependencies binary install directory.") set(DEPS_LIB_DIR "${DEPS_INSTALL_DIR}/lib" CACHE PATH "Dependencies library install directory.") @@ -76,6 +76,10 @@ else() option(USE_BUNDLED_LIBICONV "Use the bundled version of libiconv." OFF) endif() +if(WIN32) + option(USE_BUNDLED_NVIMQT "Bundle neovim-qt" ON) +endif() + option(USE_EXISTING_SRC_DIR "Skip download of deps sources in case of existing source directory." OFF) find_package(Git) @@ -137,8 +141,8 @@ endif() include(ExternalProject) set_directory_properties(PROPERTIES EP_PREFIX "${DEPS_BUILD_DIR}") -set(LIBUV_URL https://github.com/libuv/libuv/archive/f610339f74f7f0fcd183533d2c965ce1468b44c6.tar.gz) -set(LIBUV_SHA256 d5f22303ba44ac60d3232b1977b404d23a349ae4e8cb83f00e7122fafe38d8c9) +set(LIBUV_URL https://github.com/libuv/libuv/archive/62c2374a8c005ce9e42088965f8f8af2532c177b.tar.gz) +set(LIBUV_SHA256 c7e89137da65a1cb550ba96b892dfeeabea982bf33b9237bcf9bbcd90f2e70a1) set(MSGPACK_URL https://github.com/msgpack/msgpack-c/releases/download/c-4.0.0/msgpack-c-4.0.0.tar.gz) set(MSGPACK_SHA256 420fe35e7572f2a168d17e660ef981a589c9cbe77faa25eb34a520e1fcc032c8) @@ -163,8 +167,8 @@ set(LIBVTERM_URL https://www.leonerd.org.uk/code/libvterm/libvterm-0.3.1.tar.gz) set(LIBVTERM_SHA256 25a8ad9c15485368dfd0a8a9dca1aec8fea5c27da3fa74ec518d5d3787f0c397) set(LUV_VERSION 1.44.2-1) -set(LUV_URL https://github.com/luvit/luv/archive/80c8c00baebe3e994d1616d4b54097c2d6e14834.tar.gz) -set(LUV_SHA256 bcd3ffc7bc80053ab0ec87f0fe83c7632c7619879b2eb75fba88ddb3bee620e8) +set(LUV_URL https://github.com/luvit/luv/archive/e8e7b7e13225348a8806118a3ea9e021383a9536.tar.gz) +set(LUV_SHA256 531dfbcb6fffe3fdfa806860b39035e54b07ee1ff3bb2af813e175febf7e9ccc) set(LUA_COMPAT53_URL https://github.com/keplerproject/lua-compat-5.3/archive/v0.9.tar.gz) set(LUA_COMPAT53_SHA256 ad05540d2d96a48725bb79a1def35cf6652a4e2ec26376e2617c8ce2baa6f416) @@ -261,9 +265,11 @@ if(WIN32) GetBinaryDep(TARGET wintools INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory . ${DEPS_INSTALL_DIR}/bin) - GetBinaryDep(TARGET wingui - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory bin ${DEPS_INSTALL_DIR}/bin + if(USE_BUNDLED_NVIMQT) + GetBinaryDep(TARGET wingui + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory bin ${DEPS_INSTALL_DIR}/bin COMMAND ${CMAKE_COMMAND} -E copy_directory share ${DEPS_INSTALL_DIR}/share) + endif() GetBinaryDep(TARGET win32yank_X86_64 INSTALL_COMMAND ${CMAKE_COMMAND} -E copy win32yank.exe ${DEPS_INSTALL_DIR}/bin) @@ -276,7 +282,7 @@ if (MSVC) else() add_custom_target(clean-shared-libraries COMMAND ${CMAKE_COMMAND} - -DREMOVE_FILE_GLOB=${DEPS_INSTALL_DIR}/lib/${CMAKE_SHARED_LIBRARY_PREFIX}*${CMAKE_SHARED_LIBRARY_SUFFIX}* + -D REMOVE_FILE_GLOB=${DEPS_INSTALL_DIR}/lib/${CMAKE_SHARED_LIBRARY_PREFIX}*${CMAKE_SHARED_LIBRARY_SUFFIX}* -P ${PROJECT_SOURCE_DIR}/cmake/RemoveFiles.cmake DEPENDS ${THIRD_PARTY_DEPS} ) diff --git a/cmake.deps/cmake/BuildGettext.cmake b/cmake.deps/cmake/BuildGettext.cmake index 1f9fd38702..31d84b76e4 100644 --- a/cmake.deps/cmake/BuildGettext.cmake +++ b/cmake.deps/cmake/BuildGettext.cmake @@ -11,8 +11,8 @@ if(MSVC) ${CMAKE_CURRENT_SOURCE_DIR}/cmake/GettextCMakeLists.txt ${DEPS_BUILD_DIR}/src/gettext/CMakeLists.txt CMAKE_ARGS ${DEPS_CMAKE_ARGS} - -DLIBICONV_INCLUDE_DIRS=${DEPS_INSTALL_DIR}/include - -DLIBICONV_LIBRARIES=${DEPS_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}libcharset${CMAKE_STATIC_LIBRARY_SUFFIX}$<SEMICOLON>${DEPS_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}libiconv${CMAKE_STATIC_LIBRARY_SUFFIX} + -D LIBICONV_INCLUDE_DIRS=${DEPS_INSTALL_DIR}/include + -D LIBICONV_LIBRARIES=${DEPS_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}libcharset${CMAKE_STATIC_LIBRARY_SUFFIX}$<SEMICOLON>${DEPS_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}libiconv${CMAKE_STATIC_LIBRARY_SUFFIX} CMAKE_CACHE_ARGS ${DEPS_CMAKE_CACHE_ARGS}) else() message(FATAL_ERROR "Trying to build gettext in an unsupported system ${CMAKE_SYSTEM_NAME}/${CMAKE_C_COMPILER_ID}") diff --git a/cmake.deps/cmake/BuildLibtermkey.cmake b/cmake.deps/cmake/BuildLibtermkey.cmake index 6457a864ba..5836b05494 100644 --- a/cmake.deps/cmake/BuildLibtermkey.cmake +++ b/cmake.deps/cmake/BuildLibtermkey.cmake @@ -10,9 +10,9 @@ ExternalProject_Add(libtermkey ${CMAKE_CURRENT_SOURCE_DIR}/cmake/libtermkeyCMakeLists.txt ${DEPS_BUILD_DIR}/src/libtermkey/CMakeLists.txt CMAKE_ARGS ${DEPS_CMAKE_ARGS} - -DCMAKE_SHARED_LIBRARY_LINK_C_FLAGS="" # Hack to avoid -rdynamic in Mingw - -DUNIBILIUM_INCLUDE_DIRS=${DEPS_INSTALL_DIR}/include - -DUNIBILIUM_LIBRARIES=${DEPS_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}unibilium${CMAKE_STATIC_LIBRARY_SUFFIX} + -D CMAKE_SHARED_LIBRARY_LINK_C_FLAGS="" # Hack to avoid -rdynamic in Mingw + -D UNIBILIUM_INCLUDE_DIRS=${DEPS_INSTALL_DIR}/include + -D UNIBILIUM_LIBRARIES=${DEPS_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}unibilium${CMAKE_STATIC_LIBRARY_SUFFIX} CMAKE_CACHE_ARGS ${DEPS_CMAKE_CACHE_ARGS}) list(APPEND THIRD_PARTY_DEPS libtermkey) diff --git a/cmake.deps/cmake/BuildLibuv.cmake b/cmake.deps/cmake/BuildLibuv.cmake index eb88458644..6b3c8643a0 100644 --- a/cmake.deps/cmake/BuildLibuv.cmake +++ b/cmake.deps/cmake/BuildLibuv.cmake @@ -7,9 +7,9 @@ ExternalProject_Add(libuv DOWNLOAD_NO_PROGRESS TRUE DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/libuv CMAKE_ARGS ${DEPS_CMAKE_ARGS} - -DCMAKE_INSTALL_LIBDIR=lib - -DBUILD_TESTING=OFF - -DLIBUV_BUILD_SHARED=OFF + -D CMAKE_INSTALL_LIBDIR=lib + -D BUILD_TESTING=OFF + -D LIBUV_BUILD_SHARED=OFF CMAKE_CACHE_ARGS ${DEPS_CMAKE_CACHE_ARGS}) list(APPEND THIRD_PARTY_DEPS libuv) diff --git a/cmake.deps/cmake/BuildLuarocks.cmake b/cmake.deps/cmake/BuildLuarocks.cmake index b84ce34d45..e50f50798a 100644 --- a/cmake.deps/cmake/BuildLuarocks.cmake +++ b/cmake.deps/cmake/BuildLuarocks.cmake @@ -158,23 +158,14 @@ if(USE_BUNDLED_BUSTED) DEPENDS busted) add_custom_target(luacheck DEPENDS ${LUACHECK_EXE}) - # luv - set(LUV_DEPS luacheck) - if(USE_BUNDLED_LUV) - set(NVIM_CLIENT_DEPS luacheck luv-static lua-compat-5.3) - else() - add_custom_command(OUTPUT ${ROCKS_DIR}/luv - COMMAND ${LUAROCKS_BINARY} build luv ${LUV_VERSION} ${LUAROCKS_BUILDARGS} - DEPENDS luacheck) - add_custom_target(luv DEPENDS ${ROCKS_DIR}/luv) - set(NVIM_CLIENT_DEPS luv) + if (NOT USE_BUNDLED_LUAJIT) + # coxpcall + add_custom_command(OUTPUT ${ROCKS_DIR}/coxpcall + COMMAND ${LUAROCKS_BINARY} build coxpcall 1.16.0-1 ${LUAROCKS_BUILDARGS} + DEPENDS luarocks) + add_custom_target(coxpcall DEPENDS ${ROCKS_DIR}/coxpcall) + list(APPEND THIRD_PARTY_DEPS coxpcall) endif() - # nvim-client: https://github.com/neovim/lua-client - add_custom_command(OUTPUT ${ROCKS_DIR}/nvim-client - COMMAND ${LUAROCKS_BINARY} build nvim-client 0.2.4-1 ${LUAROCKS_BUILDARGS} - DEPENDS ${NVIM_CLIENT_DEPS}) - add_custom_target(nvim-client DEPENDS ${ROCKS_DIR}/nvim-client) - - list(APPEND THIRD_PARTY_DEPS busted luacheck nvim-client) + list(APPEND THIRD_PARTY_DEPS busted luacheck) endif() diff --git a/cmake.deps/cmake/BuildLuv.cmake b/cmake.deps/cmake/BuildLuv.cmake index 38c0503c5b..155d6ced4e 100644 --- a/cmake.deps/cmake/BuildLuv.cmake +++ b/cmake.deps/cmake/BuildLuv.cmake @@ -2,37 +2,37 @@ set(LUV_INCLUDE_FLAGS "-I${DEPS_INSTALL_DIR}/include -I${DEPS_INSTALL_DIR}/include/luajit-2.1") set(LUV_CMAKE_ARGS - -DLUA_BUILD_TYPE=System - -DLUA_COMPAT53_DIR=${DEPS_BUILD_DIR}/src/lua-compat-5.3 - -DWITH_SHARED_LIBUV=ON - -DBUILD_SHARED_LIBS=OFF - -DBUILD_STATIC_LIBS=ON - -DBUILD_MODULE=OFF) + -D LUA_BUILD_TYPE=System + -D LUA_COMPAT53_DIR=${DEPS_BUILD_DIR}/src/lua-compat-5.3 + -D WITH_SHARED_LIBUV=ON + -D BUILD_SHARED_LIBS=OFF + -D BUILD_STATIC_LIBS=ON + -D BUILD_MODULE=OFF) if(USE_BUNDLED_LUAJIT) - list(APPEND LUV_CMAKE_ARGS -DWITH_LUA_ENGINE=LuaJit) + list(APPEND LUV_CMAKE_ARGS -D WITH_LUA_ENGINE=LuaJit) elseif(USE_BUNDLED_LUA) - list(APPEND LUV_CMAKE_ARGS -DWITH_LUA_ENGINE=Lua) + list(APPEND LUV_CMAKE_ARGS -D WITH_LUA_ENGINE=Lua) else() find_package(LuaJit) if(LUAJIT_FOUND) - list(APPEND LUV_CMAKE_ARGS -DWITH_LUA_ENGINE=LuaJit) + list(APPEND LUV_CMAKE_ARGS -D WITH_LUA_ENGINE=LuaJit) else() - list(APPEND LUV_CMAKE_ARGS -DWITH_LUA_ENGINE=Lua) + list(APPEND LUV_CMAKE_ARGS -D WITH_LUA_ENGINE=Lua) endif() endif() if(USE_BUNDLED_LIBUV) list(APPEND LUV_CMAKE_ARGS - -DCMAKE_PREFIX_PATH=${DEPS_INSTALL_DIR} - -DLIBUV_LIBRARIES=uv_a) + -D CMAKE_PREFIX_PATH=${DEPS_INSTALL_DIR} + -D LIBUV_LIBRARIES=uv_a) endif() list(APPEND LUV_CMAKE_ARGS "-DCMAKE_C_FLAGS:STRING=${LUV_INCLUDE_FLAGS}") if(CMAKE_GENERATOR MATCHES "Unix Makefiles" AND (CMAKE_SYSTEM_NAME MATCHES ".*BSD" OR CMAKE_SYSTEM_NAME MATCHES "DragonFly")) - list(APPEND LUV_CMAKE_ARGS -DCMAKE_MAKE_PROGRAM=gmake) + list(APPEND LUV_CMAKE_ARGS -D CMAKE_MAKE_PROGRAM=gmake) endif() if(USE_EXISTING_SRC_DIR) diff --git a/cmake.deps/cmake/BuildMsgpack.cmake b/cmake.deps/cmake/BuildMsgpack.cmake index 431420fb62..b1a77ee835 100644 --- a/cmake.deps/cmake/BuildMsgpack.cmake +++ b/cmake.deps/cmake/BuildMsgpack.cmake @@ -7,8 +7,8 @@ ExternalProject_Add(msgpack DOWNLOAD_NO_PROGRESS TRUE DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/msgpack CMAKE_ARGS ${DEPS_CMAKE_ARGS} - -DMSGPACK_BUILD_TESTS=OFF - -DMSGPACK_BUILD_EXAMPLES=OFF + -D MSGPACK_BUILD_TESTS=OFF + -D MSGPACK_BUILD_EXAMPLES=OFF CMAKE_CACHE_ARGS ${DEPS_CMAKE_CACHE_ARGS}) list(APPEND THIRD_PARTY_DEPS msgpack) diff --git a/cmake.deps/cmake/BuildTreesitterParsers.cmake b/cmake.deps/cmake/BuildTreesitterParsers.cmake index d62b19d97d..fcfcb71036 100644 --- a/cmake.deps/cmake/BuildTreesitterParsers.cmake +++ b/cmake.deps/cmake/BuildTreesitterParsers.cmake @@ -12,7 +12,7 @@ function(BuildTSParser LANG TS_URL TS_SHA256 TS_CMAKE_FILE) ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${TS_CMAKE_FILE} ${DEPS_BUILD_DIR}/src/${NAME}/CMakeLists.txt CMAKE_ARGS ${DEPS_CMAKE_ARGS} - -DPARSERLANG=${LANG} + -D PARSERLANG=${LANG} CMAKE_CACHE_ARGS ${DEPS_CMAKE_CACHE_ARGS}) endfunction() diff --git a/cmake/FindIconv.cmake b/cmake/FindIconv.cmake index 63290fe889..a164abfea8 100644 --- a/cmake/FindIconv.cmake +++ b/cmake/FindIconv.cmake @@ -19,3 +19,5 @@ if(ICONV_LIBRARY) endif() libfind_process(Iconv) + +mark_as_advanced(ICONV_LIBRARY) diff --git a/cmake/FindLibUV.cmake b/cmake/FindLibUV.cmake index d6c4e9cbef..e4946bee3f 100644 --- a/cmake/FindLibUV.cmake +++ b/cmake/FindLibUV.cmake @@ -13,7 +13,7 @@ endif() find_path(LIBUV_INCLUDE_DIR uv.h HINTS ${PC_LIBUV_INCLUDEDIR} ${PC_LIBUV_INCLUDE_DIRS}) -list(APPEND LIBUV_NAMES uv_a uv) +list(APPEND LIBUV_NAMES uv_a uv libuv) find_library(LIBUV_LIBRARY NAMES ${LIBUV_NAMES} HINTS ${PC_LIBUV_LIBDIR} ${PC_LIBUV_LIBRARY_DIRS}) diff --git a/cmake/FindMsgpack.cmake b/cmake/FindMsgpack.cmake index 26eb19d498..2429c49706 100644 --- a/cmake/FindMsgpack.cmake +++ b/cmake/FindMsgpack.cmake @@ -50,4 +50,3 @@ include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Msgpack REQUIRED_VARS MSGPACK_LIBRARY MSGPACK_INCLUDE_DIR VERSION_VAR MSGPACK_VERSION_STRING) - diff --git a/cmake/Findlibvterm.cmake b/cmake/Findlibvterm.cmake index d8536ca894..4a2ae48ffa 100644 --- a/cmake/Findlibvterm.cmake +++ b/cmake/Findlibvterm.cmake @@ -16,5 +16,7 @@ find_package_handle_standard_args(libvterm VERSION_VAR VTERM_VERSION) add_library(libvterm INTERFACE) -target_include_directories(libvterm SYSTEM BEFORE INTERFACE INTERFACE ${LIBVTERM_INCLUDE_DIR}) +target_include_directories(libvterm SYSTEM BEFORE INTERFACE ${LIBVTERM_INCLUDE_DIR}) target_link_libraries(libvterm INTERFACE ${LIBVTERM_LIBRARY}) + +mark_as_advanced(LIBVTERM_INCLUDE_DIR LIBVTERM_LIBRARY) diff --git a/cmake/Findunibilium.cmake b/cmake/Findunibilium.cmake index 7bfbcba942..3dbac31b5b 100644 --- a/cmake/Findunibilium.cmake +++ b/cmake/Findunibilium.cmake @@ -25,3 +25,5 @@ list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${UNIBILIUM_LIBRARY}") if(UNIBI_HAS_VAR_FROM) target_compile_definitions(unibilium INTERFACE NVIM_UNIBI_HAS_VAR_FROM) endif() + +mark_as_advanced(UNIBILIUM_INCLUDE_DIR UNIBILIUM_LIBRARY) diff --git a/cmake/RunTests.cmake b/cmake/RunTests.cmake index d724f43a5f..fe346661b5 100644 --- a/cmake/RunTests.cmake +++ b/cmake/RunTests.cmake @@ -1,13 +1,5 @@ # Set LC_ALL to meet expectations of some locale-sensitive tests. set(ENV{LC_ALL} "en_US.UTF-8") - -if(POLICY CMP0012) - # Avoid policy warning due to CI=true. This is needed even if the main - # project has already set this policy as project settings aren't inherited - # when using cmake script mode (-P). - cmake_policy(SET CMP0012 NEW) -endif() - set(ENV{VIMRUNTIME} ${WORKING_DIR}/runtime) set(ENV{NVIM_RPLUGIN_MANIFEST} ${BUILD_DIR}/Xtest_rplugin_manifest) set(ENV{XDG_CONFIG_HOME} ${BUILD_DIR}/Xtest_xdg/config) @@ -71,16 +63,10 @@ if(NOT DEFINED ENV{TEST_TIMEOUT} OR "$ENV{TEST_TIMEOUT}" STREQUAL "") endif() set(ENV{SYSTEM_NAME} ${CMAKE_HOST_SYSTEM_NAME}) # used by test/helpers.lua. - -# TODO: eventually always use NVIM_PRG as the runner -if("${TEST_TYPE}" STREQUAL "unit") - set(RUNNER_PRG ${NVIM_PRG} -ll ${WORKING_DIR}/test/busted_runner.lua) -else() - set(RUNNER_PRG ${BUSTED_PRG}) -endif() +set(ENV{DEPS_PREFIX} ${DEPS_PREFIX}) # used by test/busted_runner.lua on windows execute_process( - COMMAND ${RUNNER_PRG} -v -o test.busted.outputHandlers.${BUSTED_OUTPUT_TYPE} + COMMAND ${NVIM_PRG} -ll ${WORKING_DIR}/test/busted_runner.lua -v -o test.busted.outputHandlers.${BUSTED_OUTPUT_TYPE} --lazy --helper=${TEST_DIR}/${TEST_TYPE}/preload.lua --lpath=${BUILD_DIR}/?.lua --lpath=${WORKING_DIR}/runtime/lua/?.lua @@ -105,7 +91,7 @@ if(NOT res EQUAL 0) endif() # Dump the logfile on CI (if not displayed and moved already). - if($ENV{CI}) + if(CI_BUILD) if(EXISTS $ENV{NVIM_LOG_FILE} AND NOT EXISTS $ENV{NVIM_LOG_FILE}.displayed) file(READ $ENV{NVIM_LOG_FILE} out) message(STATUS "$NVIM_LOG_FILE: $ENV{NVIM_LOG_FILE}\n${out}") diff --git a/cmake/WindowsDllCopy.cmake b/cmake/WindowsDllCopy.cmake index fbbabf3a0c..c07dc51b8a 100644 --- a/cmake/WindowsDllCopy.cmake +++ b/cmake/WindowsDllCopy.cmake @@ -6,13 +6,13 @@ # - CMAKE_PREFIX_PATH: A list of directories to search for dependencies if(NOT DEFINED BINARY) - message(FATAL_ERROR "Missing required argument -DBINARY=") + message(FATAL_ERROR "Missing required argument -D BINARY=") endif() if(NOT DEFINED DST) - message(FATAL_ERROR "Missing required arguments -DDST=") + message(FATAL_ERROR "Missing required arguments -D DST=") endif() if(NOT DEFINED CMAKE_PREFIX_PATH) - message(FATAL_ERROR "Missing required arguments -DCMAKE_PREFIX_PATH=") + message(FATAL_ERROR "Missing required arguments -D CMAKE_PREFIX_PATH=") endif() include(GetPrerequisites) diff --git a/codecov.yml b/codecov.yml deleted file mode 100644 index a83fd916ee..0000000000 --- a/codecov.yml +++ /dev/null @@ -1,27 +0,0 @@ -# To validate: -# cat codecov.yml | curl --data-binary @- https://codecov.io/validate - -codecov: - notify: - require_ci_to_pass: no - ci: - - appveyor - - travis - - !neovim-qb.szakmeister.net - -coverage: - precision: 2 - round: down - range: "70...100" - - status: - project: - default: - threshold: 1 - patch: - default: - threshold: 1 - only_pulls: true - changes: no - -comment: off diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 47249a484b..0472c11a15 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -1362,7 +1362,8 @@ defer_fn({fn}, {timeout}) *vim.defer_fn()* Parameters: ~ • {fn} (function) Callback to call once `timeout` expires - • {timeout} integer Number of milliseconds to wait before calling `fn` + • {timeout} (integer) Number of milliseconds to wait before calling + `fn` Return: ~ (table) timer luv timer object diff --git a/runtime/doc/luvref.txt b/runtime/doc/luvref.txt index 859e75e4af..66cee0649c 100644 --- a/runtime/doc/luvref.txt +++ b/runtime/doc/luvref.txt @@ -24,7 +24,7 @@ be used in other Lua environments. More information about the core libuv library can be found at the original libuv documentation page (https://docs.libuv.org/). -TCP Echo Server Example~ +TCP Echo Server Example ~ Here is a small example showing a TCP echo server: @@ -51,15 +51,15 @@ Here is a small example showing a TCP echo server: uv.run() -- an explicit run call is necessary outside of luvit < -Module Layout~ +Module Layout ~ The luv library contains a single Lua module referred to hereafter as `uv` for simplicity. This module consists mostly of functions with names corresponding to their original libuv versions. For example, the libuv function -`uv_tcp_bind` has a luv version at |uv.tcp_bind()|. Currently, only one -non-function field exists: `uv.constants`, which is a table. +`uv_tcp_bind` has a luv version at |uv.tcp_bind()|. Currently, only two +non-function fields exists: `uv.constants` and `uv.errno`, which are tables. -Functions vs Methods~ +Functions vs Methods ~ In addition to having simple functions, luv provides an optional method-style API. For example, `uv.tcp_bind(server, host, port)` can alternatively be @@ -67,7 +67,7 @@ called as `server:bind(host, port)` . Note that the first argument `server` becomes the object and `tcp_` is removed from the function name. Method forms are documented below where they exist. -Synchronous vs Asynchronous Functions~ +Synchronous vs Asynchronous Functions ~ Functions that accept a callback are asynchronous. These functions may immediately return results to the caller to indicate their initial status, but @@ -82,7 +82,7 @@ Some (generally FS and DNS) functions can behave either synchronously or asynchronously. If a callback is provided to these functions, they behave asynchronously; if no callback is provided, they behave synchronously. -Pseudo-Types~ +Pseudo-Types ~ Some unique types are defined. These are not actual types in Lua, but they are used here to facilitate documenting consistent behavior: @@ -133,10 +133,10 @@ module. ============================================================================== ERROR HANDLING *luv-error-handling* -In libuv, errors are negative numbered constants; however, these errors and -the functions used to handle them are not exposed to luv users. Instead, if an -internal error is encountered, the luv function will return to the caller an -assertable `nil, err, name` tuple. +In libuv, errors are negative numbered constants; however, while those errors +are exposed through `uv.errno`, the functions used to handle them are not +exposed to luv users. Instead, if an internal error is encountered, the luv +function will return to the caller an assertable `nil, err, name` tuple. - `nil` idiomatically indicates failure - `err` is a string with the format `{name}: {message}` @@ -151,6 +151,94 @@ When a function is called successfully, it will return either a value that is relevant to the operation of the function, or the integer `0` to indicate success, or sometimes nothing at all. These cases are documented below. +`uv.errno` *uv.errno* + +A table value which exposes error constants as a map, where the key is the +error name (without the `UV_` prefix) and its value is a negative number. +See Libuv's "Error constants" page for further details. +(https://docs.libuv.org/en/v1.x/errors.html#error-constants) + +- `E2BIG`: argument list too long. +- `EACCES`: permission denied. +- `EADDRINUSE`: address already in use. +- `EADDRNOTAVAIL`: address not available. +- `EAFNOSUPPORT`: address family not supported. +- `EAGAIN`: resource temporarily unavailable. +- `EAI_ADDRFAMILY`: address family not supported. +- `EAI_AGAIN`: temporary failure. +- `EAI_BADFLAGS`: bad ai_flags value. +- `EAI_BADHINTS`: invalid value for hints. +- `EAI_CANCELED`: request canceled. +- `EAI_FAIL`: permanent failure. +- `EAI_FAMILY`: ai_family not supported. +- `EAI_MEMORY`: out of memory. +- `EAI_NODATA`: no address. +- `EAI_NONAME`: unknown node or service. +- `EAI_OVERFLOW`: argument buffer overflow. +- `EAI_PROTOCOL`: resolved protocol is unknown. +- `EAI_SERVICE`: service not available for socket type. +- `EAI_SOCKTYPE`: socket type not supported. +- `EALREADY`: connection already in progress. +- `EBADF`: bad file descriptor. +- `EBUSY`: resource busy or locked. +- `ECANCELED`: operation canceled. +- `ECHARSET`: invalid Unicode character. +- `ECONNABORTED`: software caused connection abort. +- `ECONNREFUSED`: connection refused. +- `ECONNRESET`: connection reset by peer. +- `EDESTADDRREQ`: destination address required. +- `EEXIST`: file already exists. +- `EFAULT`: bad address in system call argument. +- `EFBIG`: file too large. +- `EHOSTUNREACH`: host is unreachable. +- `EINTR`: interrupted system call. +- `EINVAL`: invalid argument. +- `EIO`: i/o error. +- `EISCONN`: socket is already connected. +- `EISDIR`: illegal operation on a directory. +- `ELOOP`: too many symbolic links encountered. +- `EMFILE`: too many open files. +- `EMSGSIZE`: message too long. +- `ENAMETOOLONG`: name too long. +- `ENETDOWN`: network is down. +- `ENETUNREACH`: network is unreachable. +- `ENFILE`: file table overflow. +- `ENOBUFS`: no buffer space available. +- `ENODEV`: no such device. +- `ENOENT`: no such file or directory. +- `ENOMEM`: not enough memory. +- `ENONET`: machine is not on the network. +- `ENOPROTOOPT`: protocol not available. +- `ENOSPC`: no space left on device. +- `ENOSYS`: function not implemented. +- `ENOTCONN`: socket is not connected. +- `ENOTDIR`: not a directory. +- `ENOTEMPTY`: directory not empty. +- `ENOTSOCK`: socket operation on non-socket. +- `ENOTSUP`: operation not supported on socket. +- `EOVERFLOW`: value too large for defined data type. +- `EPERM`: operation not permitted. +- `EPIPE`: broken pipe. +- `EPROTO`: protocol error. +- `EPROTONOSUPPORT`: protocol not supported. +- `EPROTOTYPE`: protocol wrong type for socket. +- `ERANGE`: result too large. +- `EROFS`: read-only file system. +- `ESHUTDOWN`: cannot send after transport endpoint shutdown. +- `ESPIPE`: invalid seek. +- `ESRCH`: no such process. +- `ETIMEDOUT`: connection timed out. +- `ETXTBSY`: text file is busy. +- `EXDEV`: cross-device link not permitted. +- `UNKNOWN`: unknown error. +- `EOF`: end of file. +- `ENXIO`: no such device or address. +- `EMLINK`: too many links. +- `ENOTTY`: inappropriate ioctl for device. +- `EFTYPE`: inappropriate file type or format. +- `EILSEQ`: illegal byte sequence. +- `ESOCKTNOSUPPORT`: socket type not supported. + ============================================================================== VERSION CHECKING *luv-version-checking* @@ -3888,11 +3976,11 @@ uv.metrics_idle_time() *uv.metrics_idle_time()* ============================================================================== CREDITS *luv-credits* -This document is a reformatted version of the LUV documentation, based on -commit c51e705 (5 May 2022) of the luv repository -https://github.com/luvit/luv/commit/c51e7052ec4f0a25058f70c1b4ee99dd36180e59. +This document is a reformatted version of the LUV documentation, up-to-date +with commit e8e7b7e (3 Feb 2023) of the luv repository +https://github.com/luvit/luv/commit/e8e7b7e13225348a8806118a3ea9e021383a9536. -Included from https://github.com/nanotee/luv-vimdocs with kind permission. +Based on https://github.com/nanotee/luv-vimdocs with kind permission. vim:tw=78:ts=8:ft=help:norl: diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 5c234677ef..2afb22bb43 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -47,6 +47,9 @@ The following changes may require adaptations in user config or plugins. • libiconv is now a required build dependency. +• Unsaved changes are now preserved rather than discarded when |channel-stdio| + is closed. + ============================================================================== NEW FEATURES *news-features* @@ -63,7 +66,7 @@ The following new APIs or features were added. < (or the Vimscript equivalent) to their |config| file. -• Run Lua scripts from your shell using |-l|. > +• Added support for running Lua scripts from shell using |-l|. > nvim -l foo.lua --arg1 --arg2 < Also works with stdin: > echo "print(42)" | nvim -l - @@ -151,6 +154,12 @@ The following new APIs or features were added. • |:highlight| now supports an additional attribute "altfont". +• Treesitter captures can now be transformed by directives. This will allow + more complicated dynamic language injections. + +• |vim.treesitter.query.get_node_text()| now accepts a `metadata` option for + writing custom directives using |vim.treesitter.query.add_directive()|. + ============================================================================== CHANGED FEATURES *news-changes* diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 1f91b89322..e4106358f1 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -4765,7 +4765,7 @@ A jump table for the options with a short description can be found at |Q_op|. Flags to change the way redrawing works, for debugging purposes. Most useful with 'writedelay' set to some reasonable value. Supports the following flags: - compositor Indicate what redraws come from the compositor + compositor Indicate each redraw event handled by the compositor by briefly flashing the redrawn regions in colors indicating the redraw type. These are the highlight groups used (and their default colors): @@ -4777,6 +4777,11 @@ A jump table for the options with a short description can be found at |Q_op|. RedrawDebugRecompose guibg=Red redraw generated by the compositor itself, due to a grid being moved or deleted. + line introduce a delay after each line drawn on the screen. + When using the TUI or another single-grid UI, "compositor" + gives more information and should be preferred (every + line is processed as a separate event by the compositor) + flush introduce a delay after each "flush" event. nothrottle Turn off throttling of the message grid. This is an optimization that joins many small scrolls to one larger scroll when drawing the message area (with @@ -4786,7 +4791,7 @@ A jump table for the options with a short description can be found at |Q_op|. useful when running nvim inside a debugger (and the test suite). nodelta Send all internally redrawn cells to the UI, even if - they are unchanged from the already displayed state. + they are unchanged from the already displayed state. *'redrawtime'* *'rdt'* 'redrawtime' 'rdt' number (default 2000) @@ -6196,8 +6201,10 @@ A jump table for the options with a short description can be found at |Q_op|. this label. < - Where to truncate line if too long. Default is at the start. No width fields allowed. - = - Separation point between alignment sections. Each section will - be separated by an equal number of spaces. + = - Separation point between alignment sections. Each section will + be separated by an equal number of spaces. With one %= what + comes after it will be right-aligned. With two %= there is a + middle part, with white space left and right of it. No width fields allowed. # - Set highlight group. The name must follow and then a # again. Thus use %#HLname# for highlight group HLname. The same @@ -7372,8 +7379,7 @@ A jump table for the options with a short description can be found at |Q_op|. *'writedelay'* *'wd'* 'writedelay' 'wd' number (default 0) global - The number of milliseconds to wait for each character sent to the - screen. When positive, characters are sent to the UI one by one. - See 'redrawdebug' for more options. For debugging purposes. + Only takes effect toghether with 'redrawdebug'. + The number of milliseconds to wait after each line or each flush vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/spell.txt b/runtime/doc/spell.txt index 98a6af1b8b..c6c4da2dea 100644 --- a/runtime/doc/spell.txt +++ b/runtime/doc/spell.txt @@ -440,9 +440,9 @@ find these functions useful: SETTING 'spellcapcheck' AUTOMATICALLY *set-spc-auto* After the 'spelllang' option has been set successfully, Vim will source the -files "spell/LANG.vim" in 'runtimepath'. "LANG" is the value of 'spelllang' -up to the first comma, dot or underscore. This can be used to set options -specifically for the language, especially 'spellcapcheck'. +files "spell/LANG.vim" and "spell/LANG.lua" in 'runtimepath'. "LANG" is the +value of 'spelllang' up to the first comma, dot or underscore. This can be +used to set options specifically for the language, especially 'spellcapcheck'. The distribution includes a few of these files. Use this command to see what they do: > diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 9bfdc0b94e..693804497d 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -66,102 +66,102 @@ See |lua-treesitter-languagetree| for the list of available methods. ============================================================================== TREESITTER TREES *treesitter-tree* - *tstree* + *TSTree* A "treesitter tree" represents the parsed contents of a buffer, which can be used to perform further analysis. It is a |luaref-userdata| reference to an object held by the tree-sitter library. -An instance `tstree` of a treesitter tree supports the following methods. +An instance `TSTree` of a treesitter tree supports the following methods. -tstree:root() *tstree:root()* +TSTree:root() *TSTree:root()* Return the root node of this tree. -tstree:copy() *tstree:copy()* - Returns a copy of the `tstree`. +TSTree:copy() *TSTree:copy()* + Returns a copy of the `TSTree`. ============================================================================== TREESITTER NODES *treesitter-node* - *tsnode* + *TSNode* A "treesitter node" represents one specific element of the parsed contents of a buffer, which can be captured by a |Query| for, e.g., highlighting. It is a |luaref-userdata| reference to an object held by the tree-sitter library. -An instance `tsnode` of a treesitter node supports the following methods. +An instance `TSNode` of a treesitter node supports the following methods. -tsnode:parent() *tsnode:parent()* +TSNode:parent() *TSNode:parent()* Get the node's immediate parent. -tsnode:next_sibling() *tsnode:next_sibling()* +TSNode:next_sibling() *TSNode:next_sibling()* Get the node's next sibling. -tsnode:prev_sibling() *tsnode:prev_sibling()* +TSNode:prev_sibling() *TSNode:prev_sibling()* Get the node's previous sibling. -tsnode:next_named_sibling() *tsnode:next_named_sibling()* +TSNode:next_named_sibling() *TSNode:next_named_sibling()* Get the node's next named sibling. -tsnode:prev_named_sibling() *tsnode:prev_named_sibling()* +TSNode:prev_named_sibling() *TSNode:prev_named_sibling()* Get the node's previous named sibling. -tsnode:iter_children() *tsnode:iter_children()* - Iterates over all the direct children of {tsnode}, regardless of whether +TSNode:iter_children() *TSNode:iter_children()* + Iterates over all the direct children of {TSNode}, regardless of whether they are named or not. Returns the child node plus the eventual field name corresponding to this child node. -tsnode:field({name}) *tsnode:field()* +TSNode:field({name}) *TSNode:field()* Returns a table of the nodes corresponding to the {name} field. -tsnode:child_count() *tsnode:child_count()* +TSNode:child_count() *TSNode:child_count()* Get the node's number of children. -tsnode:child({index}) *tsnode:child()* +TSNode:child({index}) *TSNode:child()* Get the node's child at the given {index}, where zero represents the first child. -tsnode:named_child_count() *tsnode:named_child_count()* +TSNode:named_child_count() *TSNode:named_child_count()* Get the node's number of named children. -tsnode:named_child({index}) *tsnode:named_child()* +TSNode:named_child({index}) *TSNode:named_child()* Get the node's named child at the given {index}, where zero represents the first named child. -tsnode:start() *tsnode:start()* +TSNode:start() *TSNode:start()* Get the node's start position. Return three values: the row, column and total byte count (all zero-based). -tsnode:end_() *tsnode:end_()* +TSNode:end_() *TSNode:end_()* Get the node's end position. Return three values: the row, column and total byte count (all zero-based). -tsnode:range() *tsnode:range()* +TSNode:range() *TSNode:range()* Get the range of the node. Return four values: the row, column of the start position, then the row, column of the end position. -tsnode:type() *tsnode:type()* +TSNode:type() *TSNode:type()* Get the node's type as a string. -tsnode:symbol() *tsnode:symbol()* +TSNode:symbol() *TSNode:symbol()* Get the node's type as a numerical id. -tsnode:named() *tsnode:named()* +TSNode:named() *TSNode:named()* Check if the node is named. Named nodes correspond to named rules in the grammar, whereas anonymous nodes correspond to string literals in the grammar. -tsnode:missing() *tsnode:missing()* +TSNode:missing() *TSNode:missing()* Check if the node is missing. Missing nodes are inserted by the parser in order to recover from certain kinds of syntax errors. -tsnode:has_error() *tsnode:has_error()* +TSNode:has_error() *TSNode:has_error()* Check if the node is a syntax error or contains any syntax errors. -tsnode:sexpr() *tsnode:sexpr()* +TSNode:sexpr() *TSNode:sexpr()* Get an S-expression representing the node as a string. -tsnode:id() *tsnode:id()* +TSNode:id() *TSNode:id()* Get an unique identifier for the node inside its own tree. No guarantees are made about this identifier's internal representation, @@ -171,20 +171,20 @@ tsnode:id() *tsnode:id()* Note: The `id` is not guaranteed to be unique for nodes from different trees. - *tsnode:descendant_for_range()* -tsnode:descendant_for_range({start_row}, {start_col}, {end_row}, {end_col}) + *TSNode:descendant_for_range()* +TSNode:descendant_for_range({start_row}, {start_col}, {end_row}, {end_col}) Get the smallest node within this node that spans the given range of (row, column) positions - *tsnode:named_descendant_for_range()* -tsnode:named_descendant_for_range({start_row}, {start_col}, {end_row}, {end_col}) + *TSNode:named_descendant_for_range()* +TSNode:named_descendant_for_range({start_row}, {start_col}, {end_row}, {end_col}) Get the smallest named node within this node that spans the given range of (row, column) positions ============================================================================== TREESITTER QUERIES *treesitter-query* -Treesitter queries are a way to extract information about a parsed |tstree|, +Treesitter queries are a way to extract information about a parsed |TSTree|, e.g., for the purpose of highlighting. Briefly, a `query` consists of one or more patterns. A `pattern` is defined over node types in the syntax tree. A `match` corresponds to specific elements of the syntax tree which match a @@ -336,7 +336,7 @@ repeated, for example, the following two modeline blocks are both valid: > TREESITTER SYNTAX HIGHLIGHTING *treesitter-highlight* Syntax highlighting is specified through queries named `highlights.scm`, -which match a |tsnode| in the parsed |tstree| to a `capture` that can be +which match a |TSNode| in the parsed |TSTree| to a `capture` that can be assigned a highlight group. For example, the query > (parameters (identifier) @parameter) @@ -486,7 +486,7 @@ get_captures_at_cursor({winnr}) Returns a list of highlight capture names under the cursor Parameters: ~ - • {winnr} (number|nil) Window handle or 0 for current window (default) + • {winnr} (integer|nil) Window handle or 0 for current window (default) Return: ~ string[] List of capture names @@ -500,9 +500,9 @@ get_captures_at_pos({bufnr}, {row}, {col}) if none are defined). Parameters: ~ - • {bufnr} (number) Buffer number (0 for current buffer) - • {row} (number) Position row - • {col} (number) Position column + • {bufnr} (integer) Buffer number (0 for current buffer) + • {row} (integer) Position row + • {col} (integer) Position column Return: ~ table[] List of captures `{ capture = "capture name", metadata = { ... @@ -512,7 +512,7 @@ get_node_at_cursor({winnr}) *vim.treesitter.get_node_at_cursor()* Returns the smallest named node under the cursor Parameters: ~ - • {winnr} (number|nil) Window handle or 0 for current window (default) + • {winnr} (integer|nil) Window handle or 0 for current window (default) Return: ~ (string) Name of node under the cursor @@ -522,25 +522,28 @@ get_node_at_pos({bufnr}, {row}, {col}, {opts}) Returns the smallest named node at the given position Parameters: ~ - • {bufnr} (number) Buffer number (0 for current buffer) - • {row} (number) Position row - • {col} (number) Position column + • {bufnr} (integer) Buffer number (0 for current buffer) + • {row} (integer) Position row + • {col} (integer) Position column • {opts} (table) Optional keyword arguments: • lang string|nil Parser language • ignore_injections boolean Ignore injected languages (default true) Return: ~ - userdata|nil |tsnode| under the cursor + |TSNode||nil under the cursor get_node_range({node_or_range}) *vim.treesitter.get_node_range()* Returns the node's range or an unpacked range table Parameters: ~ - • {node_or_range} (userdata|table) |tsnode| or table of positions + • {node_or_range} (|TSNode||table) Node or table of positions Return: ~ - (table) `{ start_row, start_col, end_row, end_col }` + (integer) start_row + (integer) start_col + (integer) end_row + (integer) end_col get_parser({bufnr}, {lang}, {opts}) *vim.treesitter.get_parser()* Returns the parser for a specific buffer and filetype and attaches it to @@ -549,14 +552,14 @@ get_parser({bufnr}, {lang}, {opts}) *vim.treesitter.get_parser()* If needed, this will create the parser. Parameters: ~ - • {bufnr} (number|nil) Buffer the parser should be tied to (default: + • {bufnr} (integer|nil) Buffer the parser should be tied to (default: current buffer) • {lang} (string|nil) Filetype of this parser (default: buffer filetype) • {opts} (table|nil) Options to pass to the created language tree Return: ~ - LanguageTree |LanguageTree| object to use for parsing + |LanguageTree| object to use for parsing *vim.treesitter.get_string_parser()* get_string_parser({str}, {lang}, {opts}) @@ -568,14 +571,14 @@ get_string_parser({str}, {lang}, {opts}) • {opts} (table|nil) Options to pass to the created language tree Return: ~ - LanguageTree |LanguageTree| object to use for parsing + |LanguageTree| object to use for parsing is_ancestor({dest}, {source}) *vim.treesitter.is_ancestor()* Determines whether a node is the ancestor of another Parameters: ~ - • {dest} userdata Possible ancestor |tsnode| - • {source} userdata Possible descendant |tsnode| + • {dest} |TSNode| Possible ancestor + • {source} |TSNode| Possible descendant Return: ~ (boolean) True if {dest} is an ancestor of {source} @@ -585,9 +588,9 @@ is_in_node_range({node}, {line}, {col}) Determines whether (line, col) position is in node range Parameters: ~ - • {node} userdata |tsnode| defining the range - • {line} (number) Line (0-based) - • {col} (number) Column (0-based) + • {node} |TSNode| defining the range + • {line} (integer) Line (0-based) + • {col} (integer) Column (0-based) Return: ~ (boolean) True if the position is in node range @@ -596,7 +599,7 @@ node_contains({node}, {range}) *vim.treesitter.node_contains()* Determines if a node contains a range Parameters: ~ - • {node} userdata |tsnode| + • {node} |TSNode| • {range} (table) Return: ~ @@ -615,14 +618,14 @@ show_tree({opts}) *vim.treesitter.show_tree()* keys: • lang (string|nil): The language of the source buffer. If omitted, the filetype of the source buffer is used. - • bufnr (number|nil): Buffer to draw the tree into. If + • bufnr (integer|nil): Buffer to draw the tree into. If omitted, a new buffer is created. - • winid (number|nil): Window id to display the tree buffer in. - If omitted, a new window is created with {command}. + • winid (integer|nil): Window id to display the tree buffer + in. If omitted, a new window is created with {command}. • command (string|nil): Vimscript command to create the window. Default value is "topleft 60vnew". Only used when {winid} is nil. - • title (string|fun(bufnr:number):string|nil): Title of the + • title (string|fun(bufnr:integer):string|nil): Title of the window. If a function, it accepts the buffer number of the source buffer as its only argument and should return a string. @@ -647,7 +650,7 @@ start({bufnr}, {lang}) *vim.treesitter.start()* < Parameters: ~ - • {bufnr} (number|nil) Buffer to be highlighted (default: current + • {bufnr} (integer|nil) Buffer to be highlighted (default: current buffer) • {lang} (string|nil) Language of the parser (default: buffer filetype) @@ -656,7 +659,7 @@ stop({bufnr}) *vim.treesitter.stop()* Stops treesitter highlighting for a buffer Parameters: ~ - • {bufnr} (number|nil) Buffer to stop highlighting (default: current + • {bufnr} (integer|nil) Buffer to stop highlighting (default: current buffer) @@ -709,8 +712,8 @@ add_directive({name}, {handler}, {force}) Parameters: ~ • {name} (string) Name of the directive, without leading # - • {handler} function(match:table, pattern:string, bufnr:number, - predicate:string[], metadata:table) + • {handler} function(match:table<string,|TSNode|>, pattern:string, + bufnr:number, predicate:string[], metadata:table) • match: see |treesitter-query| • node-level data are accessible via `match[capture_id]` @@ -718,6 +721,7 @@ add_directive({name}, {handler}, {force}) • predicate: list of strings containing the full directive being called, e.g. `(node (#set! conceal "-"))` would get the predicate `{ "#set!", "conceal", "-" }` + • {force} (boolean) *vim.treesitter.query.add_predicate()* add_predicate({name}, {handler}, {force}) @@ -725,25 +729,29 @@ add_predicate({name}, {handler}, {force}) Parameters: ~ • {name} (string) Name of the predicate, without leading # - • {handler} function(match:table, pattern:string, bufnr:number, - predicate:string[]) + • {handler} function(match:table<string,|TSNode|>, pattern:string, + bufnr:number, predicate:string[]) • see |vim.treesitter.query.add_directive()| for argument meanings + • {force} (boolean) *vim.treesitter.query.get_node_text()* get_node_text({node}, {source}, {opts}) Gets the text corresponding to a given node Parameters: ~ - • {node} userdata |tsnode| + • {node} |TSNode| • {source} (number|string) Buffer or string from which the {node} is extracted • {opts} (table|nil) Optional parameters. • concat: (boolean) Concatenate result in a string (default true) + • metadata (table) Metadata of a specific capture. This + would be set to `metadata[capture_id]` when using + |vim.treesitter.query.add_directive()|. Return: ~ - (string[]|string) + (string[]|string|nil) get_query({lang}, {query_name}) *vim.treesitter.query.get_query()* Returns the runtime query {query_name} for {lang}. @@ -753,7 +761,7 @@ get_query({lang}, {query_name}) *vim.treesitter.query.get_query()* • {query_name} (string) Name of the query (e.g. "highlights") Return: ~ - Query Parsed query + Query|nil Parsed query *vim.treesitter.query.get_query_files()* get_query_files({lang}, {query_name}, {is_included}) @@ -826,16 +834,15 @@ Query:iter_captures({self}, {node}, {source}, {start}, {stop}) < Parameters: ~ - • {node} userdata |tsnode| under which the search will occur - • {source} (number|string) Source buffer or string to extract text from + • {node} |TSNode| under which the search will occur + • {source} (integer|string) Source buffer or string to extract text + from • {start} (number) Starting line for the search • {stop} (number) Stopping line for the search (end-exclusive) • {self} Return: ~ - (number) capture Matching capture id - (table) capture_node Capture for {node} - (table) metadata for the {capture} + (fun(): integer, TSNode, TSMetadata ): capture id, capture node, metadata *Query:iter_matches()* Query:iter_matches({self}, {node}, {source}, {start}, {stop}) @@ -861,16 +868,15 @@ Query:iter_matches({self}, {node}, {source}, {start}, {stop}) < Parameters: ~ - • {node} userdata |tsnode| under which the search will occur - • {source} (number|string) Source buffer or string to search - • {start} (number) Starting line for the search - • {stop} (number) Stopping line for the search (end-exclusive) + • {node} |TSNode| under which the search will occur + • {source} (integer|string) Source buffer or string to search + • {start} (integer) Starting line for the search + • {stop} (integer) Stopping line for the search (end-exclusive) • {self} Return: ~ - (number) pattern id - (table) match - (table) metadata + (fun(): integer, table<integer,TSNode>, table): pattern id, match, + metadata *vim.treesitter.query.set_query()* set_query({lang}, {query_name}, {text}) @@ -892,7 +898,7 @@ new({tree}, {opts}) *vim.treesitter.highlighter.new()* Creates a new highlighter using Parameters: ~ - • {tree} LanguageTree |LanguageTree| parser object to use for highlighting + • {tree} |LanguageTree| parser object to use for highlighting • {opts} (table|nil) Configuration of the highlighter: • queries table overwrite queries used by the highlighter @@ -940,9 +946,9 @@ LanguageTree:for_each_child({self}, {fn}, {include_self}) Invokes the callback for each |LanguageTree| and its children recursively Parameters: ~ - • {fn} function(tree: LanguageTree, lang: string) - • {include_self} (boolean) Whether to include the invoking tree in the - results + • {fn} fun(tree: LanguageTree, lang: string) + • {include_self} (boolean|nil) Whether to include the invoking tree in + the results • {self} LanguageTree:for_each_tree({self}, {fn}) *LanguageTree:for_each_tree()* @@ -951,7 +957,7 @@ LanguageTree:for_each_tree({self}, {fn}) *LanguageTree:for_each_tree()* Note: This includes the invoking tree's child trees as well. Parameters: ~ - • {fn} function(tree: TSTree, languageTree: LanguageTree) + • {fn} fun(tree: TSTree, ltree: LanguageTree) • {self} LanguageTree:included_regions({self}) *LanguageTree:included_regions()* @@ -964,6 +970,7 @@ LanguageTree:invalidate({self}, {reload}) *LanguageTree:invalidate()* Invalidates this parser and all its children Parameters: ~ + • {reload} (boolean|nil) • {self} LanguageTree:is_valid({self}) *LanguageTree:is_valid()* @@ -987,7 +994,7 @@ LanguageTree:language_for_range({self}, {range}) • {self} Return: ~ - LanguageTree Managing {range} + |LanguageTree| Managing {range} *LanguageTree:named_node_for_range()* LanguageTree:named_node_for_range({self}, {range}, {opts}) @@ -1001,7 +1008,7 @@ LanguageTree:named_node_for_range({self}, {range}, {opts}) • {self} Return: ~ - userdata|nil Found |tsnode| + |TSNode||nil Found node LanguageTree:parse({self}) *LanguageTree:parse()* Parses all defined regions using a treesitter parser for the language this @@ -1012,8 +1019,8 @@ LanguageTree:parse({self}) *LanguageTree:parse()* • {self} Return: ~ - userdata[] Table of parsed |tstree| - (table) Change list + TSTree[] + (table|nil) Change list LanguageTree:register_cbs({self}, {cbs}) *LanguageTree:register_cbs()* Registers callbacks for the |LanguageTree|. @@ -1050,7 +1057,7 @@ LanguageTree:tree_for_range({self}, {range}, {opts}) • {self} Return: ~ - userdata|nil Contained |tstree| + TSTree|nil LanguageTree:trees({self}) *LanguageTree:trees()* Returns all trees this language tree contains. Does not include child @@ -1065,7 +1072,7 @@ new({source}, {lang}, {opts}) *vim.treesitter.languagetree.new()* may contain child languages themselves, hence the name). Parameters: ~ - • {source} (number|string) Buffer or a string of text to parse + • {source} (integer|string) Buffer or a string of text to parse • {lang} (string) Root language this tree represents • {opts} (table|nil) Optional keyword arguments: • injections table Mapping language to injection query @@ -1074,6 +1081,6 @@ new({source}, {lang}, {opts}) *vim.treesitter.languagetree.new()* per language. Return: ~ - LanguageTree |LanguageTree| parser object + |LanguageTree| parser object vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl: diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index bb3b670b24..97fc211c36 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -267,7 +267,6 @@ Options: 'pumblend' pseudo-transparent popupmenu 'scrollback' 'signcolumn' supports up to 9 dynamic/fixed columns - 'statusline' supports unlimited alignment sections 'tabline' %@Func@foo%X can call any function on mouse-click 'winblend' pseudo-transparency in floating windows |api-floatwin| 'winhighlight' window-local highlights @@ -292,6 +291,7 @@ These Nvim features were later integrated into Vim. - |WinScrolled| - |:sign-define| "numhl" argument - |:source| works with anonymous (no file) scripts +- 'statusline' supports unlimited alignment sections ============================================================================== 5. Changed features *nvim-features-changed* diff --git a/runtime/lua/nvim/health.lua b/runtime/lua/nvim/health.lua index f11899434e..b6d84404ec 100644 --- a/runtime/lua/nvim/health.lua +++ b/runtime/lua/nvim/health.lua @@ -183,7 +183,7 @@ local function check_rplugin_manifest() existing_rplugins[item.path] = 'python' end - for item in ipairs(vim.fn['remote#host#PluginsForHost']('python3')) do + for _, item in ipairs(vim.fn['remote#host#PluginsForHost']('python3')) do existing_rplugins[item.path] = 'python3' end @@ -200,7 +200,7 @@ local function check_rplugin_manifest() local scripts = vim.fn.glob(python_dir .. '/*.py', true, true) vim.list_extend(scripts, vim.fn.glob(python_dir .. '/*/__init__.py', true, true)) - for script in ipairs(scripts) do + for _, script in ipairs(scripts) do local contents = vim.fn.join(vim.fn.readfile(script)) if vim.regex([[\<\%(from\|import\)\s\+neovim\>]]):match_str(contents) then if vim.regex([[[\/]__init__\.py$]]):match_str(script) then @@ -384,7 +384,13 @@ local function check_terminal() ) end - for env_var in ipairs({ 'XTERM_VERSION', 'VTE_VERSION', 'TERM_PROGRAM', 'COLORTERM', 'SSH_TTY' }) do + for _, env_var in ipairs({ + 'XTERM_VERSION', + 'VTE_VERSION', + 'TERM_PROGRAM', + 'COLORTERM', + 'SSH_TTY', + }) do if vim.env[env_var] then health.report_info(vim.fn.printf('$%s="%s"', env_var, vim.env[env_var])) end diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 8144731b09..ca91f3f402 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -191,6 +191,7 @@ local extension = { qc = 'c', cabal = 'cabal', capnp = 'capnp', + cdc = 'cdc', cdl = 'cdl', toc = 'cdrtoc', cfc = 'cf', @@ -422,6 +423,7 @@ local extension = { fsh = 'fsh', fsi = 'fsharp', fsx = 'fsharp', + fc = 'func', fusion = 'fusion', gdb = 'gdb', gdmo = 'gdmo', @@ -690,6 +692,7 @@ local extension = { isc = 'monk', moo = 'moo', moon = 'moonscript', + move = 'move', mp = 'mp', mpiv = function(path, bufnr) return 'mp', function(b) @@ -870,6 +873,7 @@ local extension = { Snw = 'rnoweb', robot = 'robot', resource = 'robot', + ron = 'ron', rsc = 'routeros', x = 'rpcgen', rpl = 'rpl', @@ -1433,6 +1437,7 @@ local filename = { gnashrc = 'gnash', ['.gnuplot'] = 'gnuplot', ['go.sum'] = 'gosum', + ['go.work.sum'] = 'gosum', ['go.work'] = 'gowork', ['.gprc'] = 'gp', ['/.gnupg/gpg.conf'] = 'gpg', @@ -2444,6 +2449,7 @@ local function match_pattern(name, path, tail, pat) return false end end + -- If the pattern contains a / match against the full path, otherwise just the tail local fullpat = '^' .. pat .. '$' local matches @@ -2521,64 +2527,64 @@ function M.match(args) name = api.nvim_buf_get_name(bufnr) end - if name then - name = normalize_path(name) - end - local ft, on_detect - -- First check for the simple case where the full path exists as a key - local path = vim.fn.fnamemodify(name, ':p') - ft, on_detect = dispatch(filename[path], path, bufnr) - if ft then - return ft, on_detect - end + if name then + name = normalize_path(name) - -- Next check against just the file name - local tail = vim.fn.fnamemodify(name, ':t') - ft, on_detect = dispatch(filename[tail], path, bufnr) - if ft then - return ft, on_detect - end + -- First check for the simple case where the full path exists as a key + local path = vim.fn.fnamemodify(name, ':p') + ft, on_detect = dispatch(filename[path], path, bufnr) + if ft then + return ft, on_detect + end - -- Next, check the file path against available patterns with non-negative priority - local j = 1 - for i, v in ipairs(pattern_sorted) do - local k = next(v) - local opts = v[k][2] - if opts.priority < 0 then - j = i - break + -- Next check against just the file name + local tail = vim.fn.fnamemodify(name, ':t') + ft, on_detect = dispatch(filename[tail], path, bufnr) + if ft then + return ft, on_detect end - local filetype = v[k][1] - local matches = match_pattern(name, path, tail, k) - if matches then - ft, on_detect = dispatch(filetype, path, bufnr, matches) - if ft then - return ft, on_detect + -- Next, check the file path against available patterns with non-negative priority + local j = 1 + for i, v in ipairs(pattern_sorted) do + local k = next(v) + local opts = v[k][2] + if opts.priority < 0 then + j = i + break + end + + local filetype = v[k][1] + local matches = match_pattern(name, path, tail, k) + if matches then + ft, on_detect = dispatch(filetype, path, bufnr, matches) + if ft then + return ft, on_detect + end end end - end - -- Next, check file extension - local ext = vim.fn.fnamemodify(name, ':e') - ft, on_detect = dispatch(extension[ext], path, bufnr) - if ft then - return ft, on_detect - end + -- Next, check file extension + local ext = vim.fn.fnamemodify(name, ':e') + ft, on_detect = dispatch(extension[ext], path, bufnr) + if ft then + return ft, on_detect + end - -- Next, check patterns with negative priority - for i = j, #pattern_sorted do - local v = pattern_sorted[i] - local k = next(v) + -- Next, check patterns with negative priority + for i = j, #pattern_sorted do + local v = pattern_sorted[i] + local k = next(v) - local filetype = v[k][1] - local matches = match_pattern(name, path, tail, k) - if matches then - ft, on_detect = dispatch(filetype, path, bufnr, matches) - if ft then - return ft, on_detect + local filetype = v[k][1] + local matches = match_pattern(name, path, tail, k) + if matches then + ft, on_detect = dispatch(filetype, path, bufnr, matches) + if ft then + return ft, on_detect + end end end end @@ -2598,7 +2604,9 @@ function M.match(args) -- If the function tries to use the filename that is nil then it will fail, -- but this enables checks which do not need a filename to still work. local ok - ok, ft = pcall(require('vim.filetype.detect').match_contents, contents, name) + ok, ft = pcall(require('vim.filetype.detect').match_contents, contents, name, function(ext) + return dispatch(extension[ext], name, bufnr) + end) if ok and ft then return ft end diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index edffdde9c7..b3d9fedeae 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -1420,7 +1420,7 @@ local patterns_hashbang = { ---@private -- File starts with "#!". -local function match_from_hashbang(contents, path) +local function match_from_hashbang(contents, path, dispatch_extension) local first_line = contents[1] -- Check for a line like "#!/usr/bin/env {options} bash". Turn it into -- "#!/usr/bin/bash" to make matching easier. @@ -1473,6 +1473,11 @@ local function match_from_hashbang(contents, path) return ft end end + + -- If nothing matched, check the extension table. For a hashbang like + -- '#!/bin/env foo', this will set the filetype to 'fooscript' assuming + -- the filetype for the 'foo' extension is 'fooscript' in the extension table. + return dispatch_extension(name) end local patterns_text = { @@ -1652,10 +1657,10 @@ local function match_from_text(contents, path) return cvs_diff(path, contents) end -M.match_contents = function(contents, path) +function M.match_contents(contents, path, dispatch_extension) local first_line = contents[1] if first_line:find('^#!') then - return match_from_hashbang(contents, path) + return match_from_hashbang(contents, path, dispatch_extension) else return match_from_text(contents, path) end diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index 582922ecb6..4127198576 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -3,8 +3,11 @@ local query = require('vim.treesitter.query') local language = require('vim.treesitter.language') local LanguageTree = require('vim.treesitter.languagetree') +---@type table<integer,LanguageTree> local parsers = setmetatable({}, { __mode = 'v' }) +---@class TreesitterModule +---@field highlighter TSHighlighter local M = vim.tbl_extend('error', query, language) M.language_version = vim._ts_get_language_version() @@ -12,6 +15,7 @@ M.minimum_language_version = vim._ts_get_minimum_language_version() setmetatable(M, { __index = function(t, k) + ---@diagnostic disable:no-unknown if k == 'highlighter' then t[k] = require('vim.treesitter.highlighter') return t[k] @@ -29,21 +33,23 @@ setmetatable(M, { --- --- It is not recommended to use this; use |get_parser()| instead. --- ----@param bufnr string Buffer the parser will be tied to (0 for current buffer) +---@param bufnr integer Buffer the parser will be tied to (0 for current buffer) ---@param lang string Language of the parser ---@param opts (table|nil) Options to pass to the created language tree --- ----@return LanguageTree |LanguageTree| object to use for parsing +---@return LanguageTree object to use for parsing function M._create_parser(bufnr, lang, opts) language.require_language(lang) if bufnr == 0 then - bufnr = a.nvim_get_current_buf() + bufnr = vim.api.nvim_get_current_buf() end vim.fn.bufload(bufnr) local self = LanguageTree.new(bufnr, lang, opts) + ---@diagnostic disable:invisible + ---@private local function bytes_cb(_, ...) self:_on_bytes(...) @@ -58,12 +64,14 @@ function M._create_parser(bufnr, lang, opts) end ---@private - local function reload_cb(_, ...) - self:_on_reload(...) + local function reload_cb(_) + self:_on_reload() end + local source = self:source() --[[@as integer]] + a.nvim_buf_attach( - self:source(), + source, false, { on_bytes = bytes_cb, on_detach = detach_cb, on_reload = reload_cb, preview = true } ) @@ -77,22 +85,24 @@ end --- --- If needed, this will create the parser. --- ----@param bufnr (number|nil) Buffer the parser should be tied to (default: current buffer) +---@param bufnr (integer|nil) Buffer the parser should be tied to (default: current buffer) ---@param lang (string|nil) Filetype of this parser (default: buffer filetype) ---@param opts (table|nil) Options to pass to the created language tree --- ----@return LanguageTree |LanguageTree| object to use for parsing +---@return LanguageTree object to use for parsing function M.get_parser(bufnr, lang, opts) opts = opts or {} if bufnr == nil or bufnr == 0 then bufnr = a.nvim_get_current_buf() end - if lang == nil then - lang = a.nvim_buf_get_option(bufnr, 'filetype') - end - if parsers[bufnr] == nil or parsers[bufnr]:lang() ~= lang then + if parsers[bufnr] == nil then + lang = lang or a.nvim_buf_get_option(bufnr, 'filetype') + parsers[bufnr] = M._create_parser(bufnr, lang, opts) + elseif lang and parsers[bufnr]:lang() ~= lang then + -- Only try to create a new parser if lang is provided + -- and it doesn't match the stored parser parsers[bufnr] = M._create_parser(bufnr, lang, opts) end @@ -107,7 +117,7 @@ end ---@param lang string Language of this string ---@param opts (table|nil) Options to pass to the created language tree --- ----@return LanguageTree |LanguageTree| object to use for parsing +---@return LanguageTree object to use for parsing function M.get_string_parser(str, lang, opts) vim.validate({ str = { str, 'string' }, @@ -120,8 +130,8 @@ end --- Determines whether a node is the ancestor of another --- ----@param dest userdata Possible ancestor |tsnode| ----@param source userdata Possible descendant |tsnode| +---@param dest TSNode Possible ancestor +---@param source TSNode Possible descendant --- ---@return boolean True if {dest} is an ancestor of {source} function M.is_ancestor(dest, source) @@ -143,9 +153,12 @@ end --- Returns the node's range or an unpacked range table --- ----@param node_or_range (userdata|table) |tsnode| or table of positions +---@param node_or_range (TSNode|table) Node or table of positions --- ----@return table `{ start_row, start_col, end_row, end_col }` +---@return integer start_row +---@return integer start_col +---@return integer end_row +---@return integer end_col function M.get_node_range(node_or_range) if type(node_or_range) == 'table' then return unpack(node_or_range) @@ -156,9 +169,9 @@ end --- Determines whether (line, col) position is in node range --- ----@param node userdata |tsnode| defining the range ----@param line number Line (0-based) ----@param col number Column (0-based) +---@param node TSNode defining the range +---@param line integer Line (0-based) +---@param col integer Column (0-based) --- ---@return boolean True if the position is in node range function M.is_in_node_range(node, line, col) @@ -180,7 +193,7 @@ end --- Determines if a node contains a range --- ----@param node userdata |tsnode| +---@param node TSNode ---@param range table --- ---@return boolean True if the {node} contains the {range} @@ -197,9 +210,9 @@ end --- Each capture is represented by a table containing the capture name as a string as --- well as a table of metadata (`priority`, `conceal`, ...; empty if none are defined). --- ----@param bufnr number Buffer number (0 for current buffer) ----@param row number Position row ----@param col number Position column +---@param bufnr integer Buffer number (0 for current buffer) +---@param row integer Position row +---@param col integer Position column --- ---@return table[] List of captures `{ capture = "capture name", metadata = { ... } }` function M.get_captures_at_pos(bufnr, row, col) @@ -250,7 +263,7 @@ end --- Returns a list of highlight capture names under the cursor --- ----@param winnr (number|nil) Window handle or 0 for current window (default) +---@param winnr (integer|nil) Window handle or 0 for current window (default) --- ---@return string[] List of capture names function M.get_captures_at_cursor(winnr) @@ -271,14 +284,14 @@ end --- Returns the smallest named node at the given position --- ----@param bufnr number Buffer number (0 for current buffer) ----@param row number Position row ----@param col number Position column +---@param bufnr integer Buffer number (0 for current buffer) +---@param row integer Position row +---@param col integer Position column ---@param opts table Optional keyword arguments: --- - lang string|nil Parser language --- - ignore_injections boolean Ignore injected languages (default true) --- ----@return userdata|nil |tsnode| under the cursor +---@return TSNode|nil under the cursor function M.get_node_at_pos(bufnr, row, col, opts) if bufnr == 0 then bufnr = a.nvim_get_current_buf() @@ -295,7 +308,7 @@ end --- Returns the smallest named node under the cursor --- ----@param winnr (number|nil) Window handle or 0 for current window (default) +---@param winnr (integer|nil) Window handle or 0 for current window (default) --- ---@return string Name of node under the cursor function M.get_node_at_cursor(winnr) @@ -323,7 +336,7 @@ end --- }) --- </pre> --- ----@param bufnr (number|nil) Buffer to be highlighted (default: current buffer) +---@param bufnr (integer|nil) Buffer to be highlighted (default: current buffer) ---@param lang (string|nil) Language of the parser (default: buffer filetype) function M.start(bufnr, lang) bufnr = bufnr or a.nvim_get_current_buf() @@ -333,7 +346,7 @@ end --- Stops treesitter highlighting for a buffer --- ----@param bufnr (number|nil) Buffer to stop highlighting (default: current buffer) +---@param bufnr (integer|nil) Buffer to stop highlighting (default: current buffer) function M.stop(bufnr) bufnr = bufnr or a.nvim_get_current_buf() @@ -351,13 +364,13 @@ end ---@param opts table|nil Optional options table with the following possible keys: --- - lang (string|nil): The language of the source buffer. If omitted, the --- filetype of the source buffer is used. ---- - bufnr (number|nil): Buffer to draw the tree into. If omitted, a new +--- - bufnr (integer|nil): Buffer to draw the tree into. If omitted, a new --- buffer is created. ---- - winid (number|nil): Window id to display the tree buffer in. If omitted, +--- - winid (integer|nil): Window id to display the tree buffer in. If omitted, --- a new window is created with {command}. --- - command (string|nil): Vimscript command to create the window. Default --- value is "topleft 60vnew". Only used when {winid} is nil. ---- - title (string|fun(bufnr:number):string|nil): Title of the window. If a +--- - title (string|fun(bufnr:integer):string|nil): Title of the window. If a --- function, it accepts the buffer number of the source buffer as its only --- argument and should return a string. function M.show_tree(opts) @@ -400,6 +413,7 @@ function M.show_tree(opts) vim.bo[b].buflisted = false vim.bo[b].buftype = 'nofile' vim.bo[b].bufhidden = 'wipe' + vim.bo[b].filetype = 'query' local title = opts.title if not title then @@ -414,9 +428,6 @@ function M.show_tree(opts) pg:draw(b) - vim.fn.matchadd('Comment', '\\[[0-9:-]\\+\\]') - vim.fn.matchadd('String', '".*"') - a.nvim_buf_clear_namespace(buf, pg.ns, 0, -1) a.nvim_buf_set_keymap(b, 'n', '<CR>', '', { desc = 'Jump to the node under the cursor in the source buffer', @@ -456,6 +467,15 @@ function M.show_tree(opts) end_col = math.max(0, pos.end_col), hl_group = 'Visual', }) + + local topline, botline = vim.fn.line('w0', win), vim.fn.line('w$', win) + + -- Move the cursor if highlighted range is completely out of view + if pos.lnum < topline and pos.end_lnum < topline then + a.nvim_win_set_cursor(win, { pos.end_lnum + 1, 0 }) + elseif pos.lnum > botline and pos.end_lnum > botline then + a.nvim_win_set_cursor(win, { pos.lnum + 1, 0 }) + end end, }) diff --git a/runtime/lua/vim/treesitter/_meta.lua b/runtime/lua/vim/treesitter/_meta.lua new file mode 100644 index 0000000000..87b4560798 --- /dev/null +++ b/runtime/lua/vim/treesitter/_meta.lua @@ -0,0 +1,60 @@ +---@meta + +---@class TSNode +---@field id fun(self: TSNode): integer +---@field range fun(self: TSNode): integer, integer, integer, integer +---@field start fun(self: TSNode): integer, integer, integer +---@field end_ fun(self: TSNode): integer, integer, integer +---@field type fun(self: TSNode): string +---@field symbol fun(self: TSNode): integer +---@field named fun(self: TSNode): boolean +---@field missing fun(self: TSNode): boolean +---@field child_count fun(self: TSNode): integer +---@field named_child_count fun(self: TSNode): integer +---@field child fun(self: TSNode, integer): TSNode +---@field name_child fun(self: TSNode, integer): TSNode +---@field descendant_for_range fun(self: TSNode, integer, integer, integer, integer): TSNode +---@field named_descendant_for_range fun(self: TSNode, integer, integer, integer, integer): TSNode +---@field parent fun(self: TSNode): TSNode +---@field next_sibling fun(self: TSNode): TSNode +---@field prev_sibling fun(self: TSNode): TSNode +---@field next_named_sibling fun(self: TSNode): TSNode +---@field prev_named_sibling fun(self: TSNode): TSNode +---@field named_children fun(self: TSNode): TSNode[] +---@field has_error fun(self: TSNode): boolean +---@field iter_children fun(self: TSNode): fun(): TSNode, string +local TSNode = {} + +---@param query userdata +---@param captures true +---@param start integer +---@param end_ integer +---@return fun(): integer, TSNode, any +function TSNode:_rawquery(query, captures, start, end_) end + +---@param query userdata +---@param captures false +---@param start integer +---@param end_ integer +---@return fun(): string, any +function TSNode:_rawquery(query, captures, start, end_) end + +---@class TSParser +---@field parse fun(self: TSParser, tree, source: integer|string): TSTree, integer[] +---@field included_ranges fun(self: TSParser): integer[] +---@field set_included_ranges fun(self: TSParser, ranges: integer[][]) + +---@class TSTree +---@field root fun(self: TSTree): TSNode +---@field edit fun(self: TSTree, _: integer, _: integer, _: integer, _: integer, _: integer, _: integer, _: integer, _: integer, _:integer) +---@field copy fun(self: TSTree): TSTree + +---@return integer +vim._ts_get_language_version = function() end + +---@return integer +vim._ts_get_minimum_language_version = function() end + +---@param lang string +---@return TSParser +vim._create_ts_parser = function(lang) end diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index d77a0d0d03..8adaa4ef2f 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -1,13 +1,27 @@ local a = vim.api local query = require('vim.treesitter.query') --- support reload for quick experimentation +---@alias TSHlIter fun(): integer, TSNode, TSMetadata + +---@class TSHighlightState +---@field next_row integer +---@field iter TSHlIter|nil + ---@class TSHighlighter +---@field active table<integer,TSHighlighter> +---@field bufnr integer +---@field orig_spelloptions string +---@field _highlight_states table<TSTree,TSHighlightState> +---@field _queries table<string,TSHighlighterQuery> +---@field tree LanguageTree local TSHighlighter = rawget(vim.treesitter, 'TSHighlighter') or {} TSHighlighter.__index = TSHighlighter TSHighlighter.active = TSHighlighter.active or {} +---@class TSHighlighterQuery +---@field _query Query|nil +---@field hl_cache table<integer,integer> local TSHighlighterQuery = {} TSHighlighterQuery.__index = TSHighlighterQuery @@ -46,7 +60,7 @@ end --- Creates a new highlighter using @param tree --- ----@param tree LanguageTree |LanguageTree| parser object to use for highlighting +---@param tree LanguageTree parser object to use for highlighting ---@param opts (table|nil) Configuration of the highlighter: --- - queries table overwrite queries used by the highlighter ---@return TSHighlighter Created highlighter object @@ -57,9 +71,10 @@ function TSHighlighter.new(tree, opts) error('TSHighlighter can not be used with a string parser source.') end - opts = opts or {} + opts = opts or {} ---@type { queries: table<string,string> } self.tree = tree tree:register_cbs({ + ---@diagnostic disable:invisible on_changedtree = function(...) self:on_changedtree(...) end, @@ -67,17 +82,20 @@ function TSHighlighter.new(tree, opts) self:on_bytes(...) end, on_detach = function(...) + ---@diagnostic disable-next-line:redundant-parameter self:on_detach(...) end, }) - self.bufnr = tree:source() + self.bufnr = tree:source() --[[@as integer]] self.edit_count = 0 self.redraw_count = 0 self.line_count = {} -- A map of highlight states. -- This state is kept during rendering across each line update. self._highlight_states = {} + + ---@type table<string,TSHighlighterQuery> self._queries = {} -- Queries for a specific language can be overridden by a custom @@ -128,6 +146,8 @@ function TSHighlighter:destroy() end ---@private +---@param tstree TSTree +---@return TSHighlightState function TSHighlighter:get_highlight_state(tstree) if not self._highlight_states[tstree] then self._highlight_states[tstree] = { @@ -145,6 +165,8 @@ function TSHighlighter:reset_highlight_state() end ---@private +---@param start_row integer +---@param new_end integer function TSHighlighter:on_bytes(_, _, start_row, _, _, _, _, _, new_end) a.nvim__buf_redraw_range(self.bufnr, start_row, start_row + new_end + 1) end @@ -155,6 +177,7 @@ function TSHighlighter:on_detach() end ---@private +---@param changes integer[][]? function TSHighlighter:on_changedtree(changes) for _, ch in ipairs(changes or {}) do a.nvim__buf_redraw_range(self.bufnr, ch[1], ch[3] + 1) @@ -165,7 +188,7 @@ end -- ---@private ---@param lang string Language used by the highlighter. ----@return Query +---@return TSHighlighterQuery function TSHighlighter:get_query(lang) if not self._queries[lang] then self._queries[lang] = TSHighlighterQuery.new(lang) @@ -175,7 +198,12 @@ function TSHighlighter:get_query(lang) end ---@private +---@param self TSHighlighter +---@param buf integer +---@param line integer +---@param is_spell_nav boolean local function on_line_impl(self, buf, line, is_spell_nav) + ---@diagnostic disable:invisible self.tree:for_each_tree(function(tstree, tree) if not tstree then return @@ -213,7 +241,7 @@ local function on_line_impl(self, buf, line, is_spell_nav) local hl = highlighter_query.hl_cache[capture] local capture_name = highlighter_query:query().captures[capture] - local spell = nil + local spell = nil ---@type boolean? if capture_name == 'spell' then spell = true elseif capture_name == 'nospell' then @@ -242,6 +270,9 @@ local function on_line_impl(self, buf, line, is_spell_nav) end ---@private +---@param _win integer +---@param buf integer +---@param line integer function TSHighlighter._on_line(_, _win, buf, line, _) local self = TSHighlighter.active[buf] if not self then @@ -252,6 +283,9 @@ function TSHighlighter._on_line(_, _win, buf, line, _) end ---@private +---@param buf integer +---@param srow integer +---@param erow integer function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _) local self = TSHighlighter.active[buf] if not self then @@ -266,6 +300,7 @@ function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _) end ---@private +---@param buf integer function TSHighlighter._on_buf(_, buf) local self = TSHighlighter.active[buf] if self then @@ -274,6 +309,9 @@ function TSHighlighter._on_buf(_, buf) end ---@private +---@param _win integer +---@param buf integer +---@param _topline integer function TSHighlighter._on_win(_, _win, buf, _topline) local self = TSHighlighter.active[buf] if not self then diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index a1e96f8ef2..8255c6f4fe 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -2,20 +2,39 @@ local a = vim.api local query = require('vim.treesitter.query') local language = require('vim.treesitter.language') ----@class LanguageTree ----@field _callbacks function[] Callback handlers ----@field _children LanguageTree[] Injected languages ----@field _injection_query table Queries defining injected languages ----@field _opts table Options ----@field _parser userdata Parser for language ----@field _regions table List of regions this tree should manage and parse ----@field _lang string Language name ----@field _regions table ----@field _source (number|string) Buffer or string to parse ----@field _trees userdata[] Reference to parsed |tstree| (one for each language) ----@field _valid boolean If the parsed tree is valid +---@alias Range {[1]: integer, [2]: integer, [3]: integer, [4]: integer} +-- +---@alias TSCallbackName +---| 'changedtree' +---| 'bytes' +---| 'detach' +---| 'child_added' +---| 'child_removed' + +---@alias TSCallbackNameOn +---| 'on_changedtree' +---| 'on_bytes' +---| 'on_detach' +---| 'on_child_added' +---| 'on_child_removed' +---@class LanguageTree +---@field private _callbacks table<TSCallbackName,function[]> Callback handlers +---@field private _children table<string,LanguageTree> Injected languages +---@field private _injection_query Query Queries defining injected languages +---@field private _opts table Options +---@field private _parser TSParser Parser for language +---@field private _regions Range[][] List of regions this tree should manage and parse +---@field private _lang string Language name +---@field private _source (integer|string) Buffer or string to parse +---@field private _trees TSTree[] Reference to parsed tree (one for each language) +---@field private _valid boolean If the parsed tree is valid local LanguageTree = {} + +---@class LanguageTreeOpts +---@field queries table<string,string> -- Deprecated +---@field injections table<string,string> + LanguageTree.__index = LanguageTree --- A |LanguageTree| holds the treesitter parser for a given language {lang} used @@ -23,16 +42,17 @@ LanguageTree.__index = LanguageTree --- needs to store parsers for these child languages as well (which in turn may contain --- child languages themselves, hence the name). --- ----@param source (number|string) Buffer or a string of text to parse +---@param source (integer|string) Buffer or a string of text to parse ---@param lang string Root language this tree represents ---@param opts (table|nil) Optional keyword arguments: --- - injections table Mapping language to injection query strings. --- This is useful for overriding the built-in --- runtime file searching for the injection language --- query per language. ----@return LanguageTree |LanguageTree| parser object +---@return LanguageTree parser object function LanguageTree.new(source, lang, opts) language.require_language(lang) + ---@type LanguageTreeOpts opts = opts or {} if opts.queries then @@ -65,6 +85,7 @@ function LanguageTree.new(source, lang, opts) end --- Invalidates this parser and all its children +---@param reload boolean|nil function LanguageTree:invalidate(reload) self._valid = false @@ -73,7 +94,7 @@ function LanguageTree:invalidate(reload) self._trees = {} end - for _, child in ipairs(self._children) do + for _, child in pairs(self._children) do child:invalidate(reload) end end @@ -111,8 +132,8 @@ end --- This will run the injection query for this language to --- determine if any child languages should be created. --- ----@return userdata[] Table of parsed |tstree| ----@return table Change list +---@return TSTree[] +---@return table|nil Change list function LanguageTree:parse() if self._valid then return self._trees @@ -146,7 +167,7 @@ function LanguageTree:parse() end local injections_by_lang = self:_get_injections() - local seen_langs = {} + local seen_langs = {} ---@type table<string,boolean> for lang, injection_ranges in pairs(injections_by_lang) do local has_lang = language.require_language(lang, nil, true) @@ -188,8 +209,8 @@ end --- Invokes the callback for each |LanguageTree| and its children recursively --- ----@param fn function(tree: LanguageTree, lang: string) ----@param include_self boolean Whether to include the invoking tree in the results +---@param fn fun(tree: LanguageTree, lang: string) +---@param include_self boolean|nil Whether to include the invoking tree in the results function LanguageTree:for_each_child(fn, include_self) if include_self then fn(self, self._lang) @@ -204,7 +225,7 @@ end --- --- Note: This includes the invoking tree's child trees as well. --- ----@param fn function(tree: TSTree, languageTree: LanguageTree) +---@param fn fun(tree: TSTree, ltree: LanguageTree) function LanguageTree:for_each_tree(fn) for _, tree in ipairs(self._trees) do fn(tree, self) @@ -221,7 +242,7 @@ end --- ---@private ---@param lang string Language to add. ----@return LanguageTree Injected |LanguageTree| +---@return LanguageTree injected function LanguageTree:add_child(lang) if self._children[lang] then self:remove_child(lang) @@ -258,7 +279,7 @@ end --- `remove_child` must be called on the parent to remove it. function LanguageTree:destroy() -- Cleanup here - for _, child in ipairs(self._children) do + for _, child in pairs(self._children) do child:destroy() end end @@ -280,20 +301,22 @@ end --- Note: This call invalidates the tree and requires it to be parsed again. --- ---@private ----@param regions table List of regions this tree should manage and parse. +---@param regions integer[][][] List of regions this tree should manage and parse. function LanguageTree:set_included_regions(regions) -- Transform the tables from 4 element long to 6 element long (with byte offset) for _, region in ipairs(regions) do for i, range in ipairs(region) do if type(range) == 'table' and #range == 4 then + ---@diagnostic disable-next-line:no-unknown local start_row, start_col, end_row, end_col = unpack(range) local start_byte = 0 local end_byte = 0 + local source = self._source -- TODO(vigoux): proper byte computation here, and account for EOL ? - if type(self._source) == 'number' then + if type(source) == 'number' then -- Easy case, this is a buffer parser - start_byte = a.nvim_buf_get_offset(self._source, start_row) + start_col - end_byte = a.nvim_buf_get_offset(self._source, end_row) + end_col + start_byte = a.nvim_buf_get_offset(source, start_row) + start_col + end_byte = a.nvim_buf_get_offset(source, end_row) + end_col elseif type(self._source) == 'string' then -- string parser, single `\n` delimited string start_byte = vim.fn.byteidx(self._source, start_col) @@ -320,9 +343,13 @@ function LanguageTree:included_regions() end ---@private +---@param node TSNode +---@param id integer +---@param metadata TSMetadata +---@return Range local function get_range_from_metadata(node, id, metadata) if metadata[id] and metadata[id].range then - return metadata[id].range + return metadata[id].range --[[@as Range]] end return { node:range() } end @@ -334,11 +361,13 @@ end --- TODO: Allow for an offset predicate to tailor the injection range --- instead of using the entire nodes range. ---@private +---@return table<string, integer[][]> function LanguageTree:_get_injections() if not self._injection_query then return {} end + ---@type table<integer,table<string,table<integer,table>>> local injections = {} for tree_index, tree in ipairs(self._trees) do @@ -348,14 +377,14 @@ function LanguageTree:_get_injections() for pattern, match, metadata in self._injection_query:iter_matches(root_node, self._source, start_line, end_line + 1) do - local lang = nil - local ranges = {} - local combined = metadata.combined + local lang = nil ---@type string + local ranges = {} ---@type Range[] + local combined = metadata.combined ---@type boolean -- Directives can configure how injections are captured as well as actual node captures. -- This allows more advanced processing for determining ranges and language resolution. if metadata.content then - local content = metadata.content + local content = metadata.content ---@type any -- Allow for captured nodes to be used if type(content) == 'number' then @@ -368,7 +397,7 @@ function LanguageTree:_get_injections() end if metadata.language then - lang = metadata.language + lang = metadata.language ---@type string end -- You can specify the content and language together @@ -379,7 +408,7 @@ function LanguageTree:_get_injections() -- Lang should override any other language tag if name == 'language' and not lang then - lang = query.get_node_text(node, self._source) + lang = query.get_node_text(node, self._source, { metadata = metadata[id] }) elseif name == 'combined' then combined = true elseif name == 'content' and #ranges == 0 then @@ -417,6 +446,7 @@ function LanguageTree:_get_injections() end end + ---@type table<string,Range[][]> local result = {} -- Generate a map by lang of node lists. @@ -429,11 +459,13 @@ function LanguageTree:_get_injections() for _, entry in pairs(patterns) do if entry.combined then + ---@diagnostic disable-next-line:no-unknown local regions = vim.tbl_map(function(e) return vim.tbl_flatten(e) end, entry.regions) table.insert(result[lang], regions) else + ---@diagnostic disable-next-line:no-unknown for _, ranges in ipairs(entry.regions) do table.insert(result[lang], ranges) end @@ -446,6 +478,7 @@ function LanguageTree:_get_injections() end ---@private +---@param cb_name TSCallbackName function LanguageTree:_do_callback(cb_name, ...) for _, cb in ipairs(self._callbacks[cb_name]) do cb(...) @@ -453,6 +486,17 @@ function LanguageTree:_do_callback(cb_name, ...) end ---@private +---@param bufnr integer +---@param changed_tick integer +---@param start_row integer +---@param start_col integer +---@param start_byte integer +---@param old_row integer +---@param old_col integer +---@param old_byte integer +---@param new_row integer +---@param new_col integer +---@param new_byte integer function LanguageTree:_on_bytes( bufnr, changed_tick, @@ -523,6 +567,7 @@ end --- - `on_child_added` : emitted when a child is added to the tree. --- - `on_child_removed` : emitted when a child is removed from the tree. function LanguageTree:register_cbs(cbs) + ---@cast cbs table<TSCallbackNameOn,function> if not cbs then return end @@ -549,6 +594,9 @@ function LanguageTree:register_cbs(cbs) end ---@private +---@param tree TSTree +---@param range Range +---@return boolean local function tree_contains(tree, range) local start_row, start_col, end_row, end_col = tree:root():range() local start_fits = start_row < range[1] or (start_row == range[1] and start_col <= range[2]) @@ -559,7 +607,7 @@ end --- Determines whether {range} is contained in the |LanguageTree|. --- ----@param range table `{ start_line, start_col, end_line, end_col }` +---@param range Range `{ start_line, start_col, end_line, end_col }` ---@return boolean function LanguageTree:contains(range) for _, tree in pairs(self._trees) do @@ -573,10 +621,10 @@ end --- Gets the tree that contains {range}. --- ----@param range table `{ start_line, start_col, end_line, end_col }` +---@param range Range `{ start_line, start_col, end_line, end_col }` ---@param opts table|nil Optional keyword arguments: --- - ignore_injections boolean Ignore injected languages (default true) ----@return userdata|nil Contained |tstree| +---@return TSTree|nil function LanguageTree:tree_for_range(range, opts) opts = opts or {} local ignore = vim.F.if_nil(opts.ignore_injections, true) @@ -602,10 +650,10 @@ end --- Gets the smallest named node that contains {range}. --- ----@param range table `{ start_line, start_col, end_line, end_col }` +---@param range Range `{ start_line, start_col, end_line, end_col }` ---@param opts table|nil Optional keyword arguments: --- - ignore_injections boolean Ignore injected languages (default true) ----@return userdata|nil Found |tsnode| +---@return TSNode|nil Found node function LanguageTree:named_node_for_range(range, opts) local tree = self:tree_for_range(range, opts) if tree then @@ -615,7 +663,7 @@ end --- Gets the appropriate language that contains {range}. --- ----@param range table `{ start_line, start_col, end_line, end_col }` +---@param range Range `{ start_line, start_col, end_line, end_col }` ---@return LanguageTree Managing {range} function LanguageTree:language_for_range(range) for _, child in pairs(self._children) do diff --git a/runtime/lua/vim/treesitter/playground.lua b/runtime/lua/vim/treesitter/playground.lua index bb073290c6..001bc2d5bf 100644 --- a/runtime/lua/vim/treesitter/playground.lua +++ b/runtime/lua/vim/treesitter/playground.lua @@ -1,12 +1,13 @@ local api = vim.api -local M = {} - ----@class Playground +---@class TSPlayground ---@field ns number API namespace ---@field opts table Options table with the following keys: --- - anon (boolean): If true, display anonymous nodes --- - lang (boolean): If true, display the language alongside each node +---@field nodes Node[] +---@field named Node[] +local TSPlayground = {} --- ---@class Node ---@field id number Node id @@ -18,6 +19,7 @@ local M = {} ---@field end_lnum number Final line number of this node in the source buffer ---@field end_col number Final column number of this node in the source buffer ---@field lang string Source language of this node +---@field root TSNode --- Traverse all child nodes starting at {node}. --- @@ -31,10 +33,10 @@ local M = {} --- node of each of these trees is contained within a node in the primary tree. The {injections} --- table maps nodes in the primary tree to root nodes of injected trees. --- ----@param node userdata Starting node to begin traversal |tsnode| +---@param node TSNode Starting node to begin traversal |tsnode| ---@param depth number Current recursion depth ---@param lang string Language of the tree currently being traversed ----@param injections table Mapping of node ids to root nodes of injected language trees (see +---@param injections table<integer,Node> Mapping of node ids to root nodes of injected language trees (see --- explanation above) ---@param tree Node[] Output table containing a list of tables each representing a node in the tree ---@private @@ -48,7 +50,7 @@ local function traverse(node, depth, lang, injections, tree) local type = child:type() local lnum, col, end_lnum, end_col = child:range() local named = child:named() - local text + local text ---@type string if named then if field then text = string.format('%s: (%s)', field, type) @@ -79,14 +81,14 @@ end --- Create a new Playground object. --- ----@param bufnr number Source buffer number +---@param bufnr integer Source buffer number ---@param lang string|nil Language of source buffer --- ----@return Playground|nil +---@return TSPlayground|nil ---@return string|nil Error message, if any --- ---@private -function M.new(self, bufnr, lang) +function TSPlayground:new(bufnr, lang) local ok, parser = pcall(vim.treesitter.get_parser, bufnr or 0, lang) if not ok then return nil, 'No parser available for the given buffer' @@ -96,7 +98,7 @@ function M.new(self, bufnr, lang) -- the primary tree that contains that root. Add a mapping from the node in the primary tree to -- the root in the child tree to the {injections} table. local root = parser:parse()[1]:root() - local injections = {} + local injections = {} ---@type table<integer,table> parser:for_each_child(function(child, lang_) child:for_each_tree(function(tree) local r = tree:root() @@ -112,7 +114,7 @@ function M.new(self, bufnr, lang) local nodes = traverse(root, 0, parser:lang(), injections, {}) - local named = {} + local named = {} ---@type Node[] for _, v in ipairs(nodes) do if v.named then named[#named + 1] = v @@ -134,30 +136,38 @@ function M.new(self, bufnr, lang) return t end +local decor_ns = api.nvim_create_namespace('ts.playground') + --- Write the contents of this Playground into {bufnr}. --- ---@param bufnr number Buffer number to write into. ---@private -function M.draw(self, bufnr) +function TSPlayground:draw(bufnr) vim.bo[bufnr].modifiable = true - local lines = {} + local lines = {} ---@type string[] for _, item in self:iter() do - lines[#lines + 1] = table.concat({ - string.rep(' ', item.depth), - item.text, - item.lnum == item.end_lnum - and string.format(' [%d:%d-%d]', item.lnum + 1, item.col + 1, item.end_col) - or string.format( - ' [%d:%d-%d:%d]', - item.lnum + 1, - item.col + 1, - item.end_lnum + 1, - item.end_col - ), - self.opts.lang and string.format(' %s', item.lang) or '', - }) + lines[#lines + 1] = string.rep(' ', item.depth) .. item.text end api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) + + api.nvim_buf_clear_namespace(bufnr, decor_ns, 0, -1) + + for i, item in self:iter() do + local range_str + if item.lnum == item.end_lnum then + range_str = string.format('[%d:%d-%d]', item.lnum + 1, item.col + 1, item.end_col) + else + range_str = + string.format('[%d:%d-%d:%d]', item.lnum + 1, item.col + 1, item.end_lnum + 1, item.end_col) + end + + local lang_str = self.opts.lang and string.format(' %s', item.lang) or '' + + api.nvim_buf_set_extmark(bufnr, decor_ns, i - 1, 0, { + virt_text = { { range_str, 'Comment' }, { lang_str, 'Title' } }, + }) + end + vim.bo[bufnr].modifiable = false end @@ -168,19 +178,19 @@ end ---@param i number Node number to get ---@return Node ---@private -function M.get(self, i) +function TSPlayground:get(i) local t = self.opts.anon and self.nodes or self.named return t[i] end --- Iterate over all of the nodes in this Playground object. --- ----@return function Iterator over all nodes in this Playground +---@return (fun(): integer, Node) Iterator over all nodes in this Playground ---@return table ---@return number ---@private -function M.iter(self) +function TSPlayground:iter() return ipairs(self.opts.anon and self.nodes or self.named) end -return M +return TSPlayground diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index dbf134573d..a0522d7cda 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -1,21 +1,25 @@ local a = vim.api local language = require('vim.treesitter.language') --- query: pattern matching on trees --- predicate matching is implemented in lua --- ---@class Query ---@field captures string[] List of captures used in query ----@field info table Contains used queries, predicates, directives +---@field info TSQueryInfo Contains used queries, predicates, directives ---@field query userdata Parsed query local Query = {} Query.__index = Query +---@class TSQueryInfo +---@field captures table +---@field patterns table<string,any[][]> + local M = {} ---@private +---@param files string[] +---@return string[] local function dedupe_files(files) local result = {} + ---@type table<string,boolean> local seen = {} for _, path in ipairs(files) do @@ -51,6 +55,38 @@ local function add_included_lang(base_langs, lang, ilang) return false end +---@private +---@param buf (number) +---@param range (table) +---@param concat (boolean) +---@returns (string[]|string|nil) +local function buf_range_get_text(buf, range, concat) + local lines + local start_row, start_col, end_row, end_col = unpack(range) + local eof_row = a.nvim_buf_line_count(buf) + if start_row >= eof_row then + return nil + end + + if end_col == 0 then + lines = a.nvim_buf_get_lines(buf, start_row, end_row, true) + end_col = -1 + else + lines = a.nvim_buf_get_lines(buf, start_row, end_row + 1, true) + end + + if #lines > 0 then + if #lines == 1 then + lines[1] = string.sub(lines[1], start_col + 1, end_col) + else + lines[1] = string.sub(lines[1], start_col + 1) + lines[#lines] = string.sub(lines[#lines], 1, end_col) + end + end + + return concat and table.concat(lines, '\n') or lines +end + --- Gets the list of files used to make up a query --- ---@param lang string Language to get query for @@ -65,10 +101,10 @@ function M.get_query_files(lang, query_name, is_included) return {} end - local base_query = nil + local base_query = nil ---@type string? local extensions = {} - local base_langs = {} + local base_langs = {} ---@type string[] -- Now get the base languages by looking at the first line of every file -- The syntax is the following : @@ -87,6 +123,7 @@ function M.get_query_files(lang, query_name, is_included) local extension = false for modeline in + ---@return string function() return file:read('*l') end @@ -97,6 +134,7 @@ function M.get_query_files(lang, query_name, is_included) local langlist = modeline:match(MODELINE_FORMAT) if langlist then + ---@diagnostic disable-next-line:param-type-mismatch for _, incllang in ipairs(vim.split(langlist, ',', true)) do local is_optional = incllang:match('%(.*%)') @@ -137,6 +175,8 @@ function M.get_query_files(lang, query_name, is_included) end ---@private +---@param filenames string[] +---@return string local function read_query_files(filenames) local contents = {} @@ -147,7 +187,8 @@ local function read_query_files(filenames) return table.concat(contents, '') end ---- The explicitly set queries from |vim.treesitter.query.set_query()| +-- The explicitly set queries from |vim.treesitter.query.set_query()| +---@type table<string,table<string,Query>> local explicit_queries = setmetatable({}, { __index = function(t, k) local lang_queries = {} @@ -174,7 +215,7 @@ end ---@param lang string Language to use for the query ---@param query_name string Name of the query (e.g. "highlights") --- ----@return Query Parsed query +---@return Query|nil Parsed query function M.get_query(lang, query_name) if explicit_queries[lang][query_name] then return explicit_queries[lang][query_name] @@ -188,6 +229,7 @@ function M.get_query(lang, query_name) end end +---@type {[string]: {[string]: Query}} local query_cache = vim.defaulttable(function() return setmetatable({}, { __mode = 'v' }) end) @@ -226,49 +268,36 @@ end --- Gets the text corresponding to a given node --- ----@param node userdata |tsnode| +---@param node TSNode ---@param source (number|string) Buffer or string from which the {node} is extracted ---@param opts (table|nil) Optional parameters. --- - concat: (boolean) Concatenate result in a string (default true) ----@return (string[]|string) +--- - metadata (table) Metadata of a specific capture. This would be +--- set to `metadata[capture_id]` when using +--- |vim.treesitter.query.add_directive()|. +---@return (string[]|string|nil) function M.get_node_text(node, source, opts) opts = opts or {} local concat = vim.F.if_nil(opts.concat, true) + local metadata = opts.metadata or {} - local start_row, start_col, start_byte = node:start() - local end_row, end_col, end_byte = node:end_() - - if type(source) == 'number' then - local lines - local eof_row = a.nvim_buf_line_count(source) - if start_row >= eof_row then - return nil - end - - if end_col == 0 then - lines = a.nvim_buf_get_lines(source, start_row, end_row, true) - end_col = -1 - else - lines = a.nvim_buf_get_lines(source, start_row, end_row + 1, true) - end - - if #lines > 0 then - if #lines == 1 then - lines[1] = string.sub(lines[1], start_col + 1, end_col) - else - lines[1] = string.sub(lines[1], start_col + 1) - lines[#lines] = string.sub(lines[#lines], 1, end_col) - end - end - - return concat and table.concat(lines, '\n') or lines + if metadata.text then + return metadata.text + elseif type(source) == 'number' then + return metadata.range and buf_range_get_text(source, metadata.range, concat) + or buf_range_get_text(source, { node:range() }, concat) elseif type(source) == 'string' then - return source:sub(start_byte + 1, end_byte) + return source:sub(select(3, node:start()) + 1, select(3, node:end_())) end end +---@alias TSMatch table<integer,TSNode> + +---@alias TSPredicate fun(match: TSMatch, _, _, predicate: any[]): boolean + -- Predicate handler receive the following arguments -- (match, pattern, bufnr, predicate) +---@type table<string,TSPredicate> local predicate_handlers = { ['eq?'] = function(match, _, source, predicate) local node = match[predicate[2]] @@ -277,13 +306,13 @@ local predicate_handlers = { end local node_text = M.get_node_text(node, source) - local str + local str ---@type string if type(predicate[3]) == 'string' then -- (#eq? @aa "foo") str = predicate[3] else -- (#eq? @aa @bb) - str = M.get_node_text(match[predicate[3]], source) + str = M.get_node_text(match[predicate[3]], source) --[[@as string]] end if node_text ~= str or str == nil then @@ -299,7 +328,7 @@ local predicate_handlers = { return true end local regex = predicate[3] - return string.find(M.get_node_text(node, source), regex) + return string.find(M.get_node_text(node, source) --[[@as string]], regex) ~= nil end, ['match?'] = (function() @@ -321,10 +350,12 @@ local predicate_handlers = { }) return function(match, _, source, pred) + ---@cast match TSMatch local node = match[pred[2]] if not node then return true end + ---@diagnostic disable-next-line no-unknown local regex = compiled_vim_regexes[pred[3]] return regex:match_str(M.get_node_text(node, source)) end @@ -335,7 +366,7 @@ local predicate_handlers = { if not node then return true end - local node_text = M.get_node_text(node, source) + local node_text = M.get_node_text(node, source) --[[@as string]] for i = 3, #predicate do if string.find(node_text, predicate[i], 1, true) then @@ -359,6 +390,7 @@ local predicate_handlers = { if not string_set then string_set = {} for i = 3, #predicate do + ---@diagnostic disable-next-line:no-unknown string_set[predicate[i]] = true end predicate['string_set'] = string_set @@ -371,21 +403,39 @@ local predicate_handlers = { -- As we provide lua-match? also expose vim-match? predicate_handlers['vim-match?'] = predicate_handlers['match?'] +---@class TSMetadata +---@field [integer] TSMetadata +---@field [string] integer|string +---@field range Range + +---@alias TSDirective fun(match: TSMatch, _, _, predicate: any[], metadata: TSMetadata) + +-- Predicate handler receive the following arguments +-- (match, pattern, bufnr, predicate) + -- Directives store metadata or perform side effects against a match. -- Directives should always end with a `!`. -- Directive handler receive the following arguments -- (match, pattern, bufnr, predicate, metadata) +---@type table<string,TSDirective> local directive_handlers = { ['set!'] = function(_, _, _, pred, metadata) if #pred == 4 then -- (#set! @capture "key" "value") + ---@diagnostic disable-next-line:no-unknown local _, capture_id, key, value = unpack(pred) + ---@cast value integer|string + ---@cast capture_id integer + ---@cast key string if not metadata[capture_id] then metadata[capture_id] = {} end metadata[capture_id][key] = value else + ---@diagnostic disable-next-line:no-unknown local _, key, value = unpack(pred) + ---@cast value integer|string + ---@cast key string -- (#set! "key" "value") metadata[key] = value end @@ -393,9 +443,13 @@ local directive_handlers = { -- Shifts the range of a node. -- Example: (#offset! @_node 0 1 0 -1) ['offset!'] = function(match, _, _, pred, metadata) + ---@cast pred integer[] local capture_id = pred[2] - local offset_node = match[capture_id] - local range = { offset_node:range() } + if not metadata[capture_id] then + metadata[capture_id] = {} + end + + local range = metadata[capture_id].range or { match[capture_id]:range() } local start_row_offset = pred[3] or 0 local start_col_offset = pred[4] or 0 local end_row_offset = pred[5] or 0 @@ -408,19 +462,32 @@ local directive_handlers = { -- If this produces an invalid range, we just skip it. if range[1] < range[3] or (range[1] == range[3] and range[2] <= range[4]) then - if not metadata[capture_id] then - metadata[capture_id] = {} - end metadata[capture_id].range = range end end, + + -- Transform the content of the node + -- Example: (#gsub! @_node ".*%.(.*)" "%1") + ['gsub!'] = function(match, _, bufnr, pred, metadata) + assert(#pred == 4) + + local id = pred[2] + local node = match[id] + local text = M.get_node_text(node, bufnr, { metadata = metadata[id] }) or '' + + if not metadata[id] then + metadata[id] = {} + end + metadata[id].text = text:gsub(pred[3], pred[4]) + end, } --- Adds a new predicate to be used in queries --- ---@param name string Name of the predicate, without leading # ----@param handler function(match:table, pattern:string, bufnr:number, predicate:string[]) +---@param handler function(match:table<string,TSNode>, pattern:string, bufnr:number, predicate:string[]) --- - see |vim.treesitter.query.add_directive()| for argument meanings +---@param force boolean function M.add_predicate(name, handler, force) if predicate_handlers[name] and not force then error(string.format('Overriding %s', name)) @@ -437,12 +504,13 @@ end --- metadata table `metadata[capture_id].key = value` --- ---@param name string Name of the directive, without leading # ----@param handler function(match:table, pattern:string, bufnr:number, predicate:string[], metadata:table) +---@param handler function(match:table<string,TSNode>, pattern:string, bufnr:number, predicate:string[], metadata:table) --- - match: see |treesitter-query| --- - node-level data are accessible via `match[capture_id]` --- - pattern: see |treesitter-query| --- - predicate: list of strings containing the full directive being called, e.g. --- `(node (#set! conceal "-"))` would get the predicate `{ "#set!", "conceal", "-" }` +---@param force boolean function M.add_directive(name, handler, force) if directive_handlers[name] and not force then error(string.format('Overriding %s', name)) @@ -474,6 +542,9 @@ local function is_directive(name) end ---@private +---@param match TSMatch +---@param pattern string +---@param source integer|string function Query:match_preds(match, pattern, source) local preds = self.info.patterns[pattern] @@ -482,8 +553,9 @@ function Query:match_preds(match, pattern, source) -- continue on the other case. This way unknown predicates will not be considered, -- which allows some testing and easier user extensibility (#12173). -- Also, tree-sitter strips the leading # from predicates for us. - local pred_name - local is_not + local pred_name ---@type string + + local is_not ---@type boolean -- Skip over directives... they will get processed after all the predicates. if not is_directive(pred[1]) then @@ -513,6 +585,8 @@ function Query:match_preds(match, pattern, source) end ---@private +---@param match TSMatch +---@param metadata TSMetadata function Query:apply_directives(match, pattern, source, metadata) local preds = self.info.patterns[pattern] @@ -534,6 +608,10 @@ end -- When the node's range is used, the stop is incremented by 1 -- to make the search inclusive. ---@private +---@param start integer +---@param stop integer +---@param node TSNode +---@return integer, integer local function value_or_node_range(start, stop, node) if start == nil and stop == nil then local node_start, _, node_stop, _ = node:range() @@ -565,14 +643,12 @@ end --- end --- </pre> --- ----@param node userdata |tsnode| under which the search will occur ----@param source (number|string) Source buffer or string to extract text from +---@param node TSNode under which the search will occur +---@param source (integer|string) Source buffer or string to extract text from ---@param start number Starting line for the search ---@param stop number Stopping line for the search (end-exclusive) --- ----@return number capture Matching capture id ----@return table capture_node Capture for {node} ----@return table metadata for the {capture} +---@return (fun(): integer, TSNode, TSMetadata): capture id, capture node, metadata function Query:iter_captures(node, source, start, stop) if type(source) == 'number' and source == 0 then source = vim.api.nvim_get_current_buf() @@ -622,14 +698,12 @@ end --- end --- </pre> --- ----@param node userdata |tsnode| under which the search will occur ----@param source (number|string) Source buffer or string to search ----@param start number Starting line for the search ----@param stop number Stopping line for the search (end-exclusive) +---@param node TSNode under which the search will occur +---@param source (integer|string) Source buffer or string to search +---@param start integer Starting line for the search +---@param stop integer Stopping line for the search (end-exclusive) --- ----@return number pattern id ----@return table match ----@return table metadata +---@return (fun(): integer, table<integer,TSNode>, table): pattern id, match, metadata function Query:iter_matches(node, source, start, stop) if type(source) == 'number' and source == 0 then source = vim.api.nvim_get_current_buf() @@ -638,6 +712,7 @@ function Query:iter_matches(node, source, start, stop) start, stop = value_or_node_range(start, stop, node) local raw_iter = node:_rawquery(self.query, false, start, stop) + ---@cast raw_iter fun(): string, any local function iter() local pattern, match = raw_iter() local metadata = {} diff --git a/scripts/lintcommit.lua b/scripts/lintcommit.lua index 87a8e62503..977f7e7e46 100644 --- a/scripts/lintcommit.lua +++ b/scripts/lintcommit.lua @@ -78,10 +78,12 @@ local function validate_commit(commit_message) -- Check if type is correct local type = vim.split(before_colon, "%(")[1] - local allowed_types = {'build', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'test', 'dist', 'vim-patch'} + local allowed_types = {'build', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'test', 'vim-patch'} if not vim.tbl_contains(allowed_types, type) then return string.format( - 'Invalid commit type "%s". Allowed types are:\n %s', + [[Invalid commit type "%s". Allowed types are: + %s. + If none of these seem appropriate then use "fix"]], type, vim.inspect(allowed_types)) end @@ -126,10 +128,10 @@ local function validate_commit(commit_message) return [[There should only be one whitespace after the colon.]] end - -- Check that first character after space isn't uppercase. - if string.match(after_colon:sub(2,2), '%u') then - return [[First character should not be uppercase.]] - end + -- Allow lowercase or ALL_UPPER but not Titlecase. + if after_colon:match(' *%u%l') then + return [[Description should not be Capitalized.]] + end -- Check that description isn't just whitespaces if vim.trim(after_colon) == "" then @@ -164,13 +166,16 @@ function M.main(opt) local invalid_msg = validate_commit(msg) if invalid_msg then failed = failed + 1 + + -- Some breathing room + if failed == 1 then + p('\n') + end + p(string.format([[ Invalid commit message: "%s" Commit: %s %s - See also: - https://github.com/neovim/neovim/blob/master/CONTRIBUTING.md#commit-messages - https://www.conventionalcommits.org/en/v1.0.0/ ]], msg, commit_id, @@ -180,6 +185,10 @@ Invalid commit message: "%s" end if failed > 0 then + p([[ +See also: + https://github.com/neovim/neovim/blob/master/CONTRIBUTING.md#commit-messages +]]) die() -- Exit with error. else p('') @@ -198,7 +207,6 @@ function M._test() ['refactor: normal message'] = true, ['revert: normal message'] = true, ['test: normal message'] = true, - ['dist: normal message'] = true, ['ci(window): message with scope'] = true, ['ci!: message with breaking change'] = true, ['ci(tui)!: message with scope and breaking change'] = true, @@ -223,7 +231,8 @@ function M._test() ['refactor(): empty scope'] = false, ['ci( ): whitespace as scope'] = false, ['ci: period at end of sentence.'] = false, - ['ci: Starting sentence capitalized'] = false, + ['ci: Capitalized first word'] = false, + ['ci: UPPER_CASE first word'] = true, ['unknown: using unknown type'] = false, ['ci: you\'re saying this commit message just goes on and on and on and on and on and on for way too long?'] = false, } diff --git a/scripts/lua2dox.lua b/scripts/lua2dox.lua index 19f8f8141d..fc0e915307 100644 --- a/scripts/lua2dox.lua +++ b/scripts/lua2dox.lua @@ -286,7 +286,12 @@ local function checkComment4fn(Fn_magic, MagicLines) return fn_magic end -local types = { 'number', 'string', 'table', 'list', 'boolean', 'function' } +local types = { 'integer', 'number', 'string', 'table', 'list', 'boolean', 'function' } + +local tagged_types = { 'TSNode', 'LanguageTree' } + +-- Document these as 'table' +local alias_types = { 'Range' } --! \brief run the filter function TLua2DoX_filter.readfile(this, AppStamp, Filename) @@ -320,7 +325,12 @@ function TLua2DoX_filter.readfile(this, AppStamp, Filename) offset = 1 end - if string.sub(line, 3, 3) == '@' or string.sub(line, 1, 4) == '---@' then -- it's a magic comment + if vim.startswith(line, '---@cast') + or vim.startswith(line, '---@diagnostic') + or vim.startswith(line, '---@type') then + -- Ignore LSP directives + outStream:writeln('// gg:"' .. line .. '"') + elseif string.sub(line, 3, 3) == '@' or string.sub(line, 1, 4) == '---@' then -- it's a magic comment state = 'in_magic_comment' local magic = string.sub(line, 4 + offset) @@ -366,6 +376,17 @@ function TLua2DoX_filter.readfile(this, AppStamp, Filename) magic_split[type_index] = magic_split[type_index]:gsub(k, v) end end + + for _, type in ipairs(tagged_types) do + magic_split[type_index] = + magic_split[type_index]:gsub(type, '|%1|') + end + + for _, type in ipairs(alias_types) do + magic_split[type_index] = + magic_split[type_index]:gsub('^'..type..'$', 'table') + end + -- surround some types by () for _, type in ipairs(types) do magic_split[type_index] = @@ -373,6 +394,8 @@ function TLua2DoX_filter.readfile(this, AppStamp, Filename) magic_split[type_index] = magic_split[type_index]:gsub('^(' .. type .. '):?$', '(%1)') end + + end magic = table.concat(magic_split, ' ') diff --git a/src/mpack/lmpack.c b/src/mpack/lmpack.c index 53d7092a0c..957bac37cc 100644 --- a/src/mpack/lmpack.c +++ b/src/mpack/lmpack.c @@ -644,7 +644,13 @@ static void lmpack_unparse_enter(mpack_parser_t *parser, mpack_node_t *node) mpack_node_t *n; int has_meta = lua_getmetatable(L, -1); - if (packer->ext != LUA_NOREF && has_meta) { + int has_mtdict = false; + if (has_meta && packer->mtdict != LUA_NOREF) { + lmpack_geti(L, packer->reg, packer->mtdict); // [table, metatable, mtdict] + has_mtdict = lua_rawequal(L, -1, -2); + lua_pop(L, 1); // [table, metatable]; + } + if (packer->ext != LUA_NOREF && has_meta && !has_mtdict) { /* check if there's a handler for this metatable */ lmpack_geti(L, packer->reg, packer->ext); lua_pushvalue(L, -2); @@ -701,14 +707,7 @@ static void lmpack_unparse_enter(mpack_parser_t *parser, mpack_node_t *node) } } - int is_array = 1; if (has_meta) { - // stack: [table, metatable] - if (packer->mtdict != LUA_NOREF) { - lmpack_geti(L, packer->reg, packer->mtdict); // [table, metatable, mtdict] - is_array = !lua_rawequal(L, -1, -2); - lua_pop(L, 1); // [table, metatable]; - } lua_pop(L, 1); // [table] } @@ -726,6 +725,7 @@ static void lmpack_unparse_enter(mpack_parser_t *parser, mpack_node_t *node) lua_pop(L, 1); } + int is_array = !has_mtdict; len = lmpack_objlen(L, &is_array); if (is_array) { node->tok = mpack_pack_array(len); diff --git a/src/mpack/object.c b/src/mpack/object.c index e2d893bc88..60f49f73aa 100644 --- a/src/mpack/object.c +++ b/src/mpack/object.c @@ -128,8 +128,11 @@ MPACK_API int mpack_unparse(mpack_parser_t *parser, char **buf, size_t *buflen, return status; } -MPACK_API void mpack_parser_copy(mpack_parser_t *dst, mpack_parser_t *src) +MPACK_API void mpack_parser_copy(mpack_parser_t *d, mpack_parser_t *s) { + // workaround UBSAN being NOT happy with a flexible array member with arr[N>1] initial size + mpack_one_parser_t *dst = (mpack_one_parser_t *)d; + mpack_one_parser_t *src = (mpack_one_parser_t *)s; mpack_uint32_t i; mpack_uint32_t dst_capacity = dst->capacity; assert(src->capacity <= dst_capacity); @@ -148,8 +151,9 @@ static int mpack_parser_full(mpack_parser_t *parser) return parser->size == parser->capacity; } -static mpack_node_t *mpack_parser_push(mpack_parser_t *parser) +static mpack_node_t *mpack_parser_push(mpack_parser_t *p) { + mpack_one_parser_t *parser = (mpack_one_parser_t *)p; mpack_node_t *top; assert(parser->size < parser->capacity); top = parser->items + parser->size + 1; @@ -162,8 +166,9 @@ static mpack_node_t *mpack_parser_push(mpack_parser_t *parser) return top; } -static mpack_node_t *mpack_parser_pop(mpack_parser_t *parser) +static mpack_node_t *mpack_parser_pop(mpack_parser_t *p) { + mpack_one_parser_t *parser = (mpack_one_parser_t *)p; mpack_node_t *top, *parent; assert(parser->size); top = parser->items + parser->size; diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index fd34a30619..22cbec0d06 100755 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -78,8 +78,7 @@ if(ENABLE_IWYU) endif() if(MSVC) - # TODO(dundargoc): bump warning level - target_compile_options(main_lib INTERFACE -W2) + target_compile_options(main_lib INTERFACE -W3) # Disable warnings that give too many false positives. target_compile_options(main_lib INTERFACE -wd4311 -wd4146) @@ -106,37 +105,12 @@ if(HAVE_WIMPLICIT_FALLTHROUGH_FLAG) target_compile_options(main_lib INTERFACE -Wimplicit-fallthrough) endif() -option(ENABLE_COMPILER_SUGGESTIONS "Enable -Wsuggest compiler warnings" OFF) -if(ENABLE_COMPILER_SUGGESTIONS) - # Clang doesn't have -Wsuggest-attribute so check for each one. - check_c_compiler_flag(-Wsuggest-attribute=pure HAVE_WSUGGEST_ATTRIBUTE_PURE) - if(HAVE_WSUGGEST_ATTRIBUTE_PURE) - target_compile_options(main_lib INTERFACE -Wsuggest-attribute=pure) - endif() - - check_c_compiler_flag(-Wsuggest-attribute=const HAVE_WSUGGEST_ATTRIBUTE_CONST) - if(HAVE_WSUGGEST_ATTRIBUTE_CONST) - target_compile_options(main_lib INTERFACE -Wsuggest-attribute=const) - endif() - - check_c_compiler_flag(-Wsuggest-attribute=malloc HAVE_WSUGGEST_ATTRIBUTE_MALLOC) - if(HAVE_WSUGGEST_ATTRIBUTE_MALLOC) - target_compile_options(main_lib INTERFACE -Wsuggest-attribute=malloc) - endif() - - check_c_compiler_flag(-Wsuggest-attribute=cold HAVE_WSUGGEST_ATTRIBUTE_COLD) - if(HAVE_WSUGGEST_ATTRIBUTE_COLD) - target_compile_options(main_lib INTERFACE -Wsuggest-attribute=cold) - endif() -endif() - if(MINGW) # Use POSIX compatible stdio in Mingw target_compile_definitions(main_lib INTERFACE __USE_MINGW_ANSI_STDIO) endif() if(WIN32) - # Windows Vista is the minimum supported version - target_compile_definitions(main_lib INTERFACE _WIN32_WINNT=0x0600 MSWIN) + target_compile_definitions(main_lib INTERFACE _WIN32_WINNT=0x0602 MSWIN) endif() # OpenBSD's GCC (4.2.1) doesn't have -Wvla @@ -166,13 +140,14 @@ if(CI_BUILD) target_compile_options(main_lib INTERFACE -WX) else() target_compile_options(main_lib INTERFACE -Werror) - if(DEFINED ENV{BUILD_UCHAR}) - # Get some test coverage for unsigned char - target_compile_options(main_lib INTERFACE -funsigned-char) - endif() endif() endif() +option(UNSIGNED_CHAR "Set char to be unsigned" OFF) +if(UNSIGNED_CHAR) + target_compile_options(main_lib INTERFACE -funsigned-char) +endif() + list(APPEND CMAKE_REQUIRED_INCLUDES "${MSGPACK_INCLUDE_DIRS}") check_c_source_compiles(" #include <msgpack.h> @@ -252,11 +227,11 @@ if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang") target_compile_definitions(main_lib INTERFACE _GNU_SOURCE) endif() -option(USE_GCOV "Enable gcov support" OFF) -if(USE_GCOV) +option(ENABLE_GCOV "Enable gcov support" OFF) +if(ENABLE_GCOV) if(CLANG_TSAN) # GCOV and TSAN results in false data race reports - message(FATAL_ERROR "USE_GCOV cannot be used with CLANG_TSAN") + message(FATAL_ERROR "ENABLE_GCOV cannot be used with CLANG_TSAN") endif() message(STATUS "Enabling gcov support") target_compile_options(main_lib INTERFACE --coverage) @@ -406,13 +381,16 @@ list(REMOVE_ITEM NVIM_SOURCES ${to_remove}) # xdiff, mpack, lua-cjson: inlined external project, we don't maintain it. #9306 if(MSVC) set_source_files_properties( - ${EXTERNAL_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} /wd4090 /wd4244") + ${EXTERNAL_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -wd4090 -wd4244 -wd4267") else() set_source_files_properties( ${EXTERNAL_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion -Wno-missing-noreturn -Wno-missing-format-attribute -Wno-double-promotion -Wno-strict-prototypes") endif() # Log level (MIN_LOG_LEVEL in log.h) +if($ENV{CI} MATCHES "true") + set(MIN_LOG_LEVEL 3) +endif() if("${MIN_LOG_LEVEL}" MATCHES "^$") # Minimize logging for release-type builds. target_compile_definitions(main_lib INTERFACE MIN_LOG_LEVEL=$<IF:$<CONFIG:Debug>,1,3>) @@ -448,12 +426,12 @@ set(gen_cflags ${gen_cflags} -O2) set(NVIM_VERSION_GIT_H ${PROJECT_BINARY_DIR}/cmake.config/auto/versiondef_git.h) add_custom_target(update_version_stamp COMMAND ${CMAKE_COMMAND} - -DNVIM_VERSION_MAJOR=${NVIM_VERSION_MAJOR} - -DNVIM_VERSION_MINOR=${NVIM_VERSION_MINOR} - -DNVIM_VERSION_PATCH=${NVIM_VERSION_PATCH} - -DNVIM_VERSION_PRERELEASE=${NVIM_VERSION_PRERELEASE} - -DOUTPUT=${NVIM_VERSION_GIT_H} - -DNVIM_SOURCE_DIR=${CMAKE_SOURCE_DIR} + -D NVIM_VERSION_MAJOR=${NVIM_VERSION_MAJOR} + -D NVIM_VERSION_MINOR=${NVIM_VERSION_MINOR} + -D NVIM_VERSION_PATCH=${NVIM_VERSION_PATCH} + -D NVIM_VERSION_PRERELEASE=${NVIM_VERSION_PRERELEASE} + -D OUTPUT=${NVIM_VERSION_GIT_H} + -D NVIM_SOURCE_DIR=${CMAKE_SOURCE_DIR} -P ${PROJECT_SOURCE_DIR}/cmake/GenerateVersion.cmake BYPRODUCTS ${NVIM_VERSION_GIT_H}) @@ -664,9 +642,14 @@ else() target_compile_definitions(nvim PRIVATE $<$<CONFIG:Debug>:UNIT_TESTING>) endif() -target_sources(nvim PRIVATE ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS} - ${NVIM_GENERATED_SOURCES} ${NVIM_SOURCES} ${NVIM_HEADERS} - ${EXTERNAL_SOURCES} ${EXTERNAL_HEADERS}) +target_sources(main_lib INTERFACE + ${NVIM_GENERATED_FOR_SOURCES} + ${NVIM_GENERATED_FOR_HEADERS} + ${NVIM_GENERATED_SOURCES} + ${NVIM_SOURCES} + ${NVIM_HEADERS} + ${EXTERNAL_SOURCES} + ${EXTERNAL_HEADERS}) set_target_properties(nvim PROPERTIES @@ -705,12 +688,65 @@ if(WIN32) add_custom_target(nvim_dll_deps DEPENDS nvim COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/windows_runtime_deps COMMAND ${CMAKE_COMMAND} - "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" - -DBINARY="${PROJECT_BINARY_DIR}/bin/nvim${CMAKE_EXECUTABLE_SUFFIX}" - -DDST=${PROJECT_BINARY_DIR}/windows_runtime_deps + -D CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} + -D BINARY="${PROJECT_BINARY_DIR}/bin/nvim${CMAKE_EXECUTABLE_SUFFIX}" + -D DST=${PROJECT_BINARY_DIR}/windows_runtime_deps -P ${PROJECT_SOURCE_DIR}/cmake/WindowsDllCopy.cmake) add_dependencies(nvim_runtime_deps nvim_dll_deps) + if(USE_BUNDLED_NVIMQT) + set(NVIMQT_DEPS + # Dependencies for neovim-qt + bearer/qgenericbearer.dll + iconengines/qsvgicon.dll + imageformats/qgif.dll + imageformats/qicns.dll + imageformats/qico.dll + imageformats/qjpeg.dll + imageformats/qsvg.dll + imageformats/qtga.dll + imageformats/qtiff.dll + imageformats/qwbmp.dll + imageformats/qwebp.dll + platforms/qwindows.dll + styles/qwindowsvistastyle.dll + translations/qt_ar.qm + translations/qt_bg.qm + translations/qt_ca.qm + translations/qt_cs.qm + translations/qt_da.qm + translations/qt_de.qm + translations/qt_en.qm + translations/qt_es.qm + translations/qt_fi.qm + translations/qt_fr.qm + translations/qt_gd.qm + translations/qt_he.qm + translations/qt_hu.qm + translations/qt_it.qm + translations/qt_ja.qm + translations/qt_ko.qm + translations/qt_lv.qm + translations/qt_pl.qm + translations/qt_ru.qm + translations/qt_sk.qm + translations/qt_uk.qm + D3Dcompiler_47.dll + libEGL.dll + libgcc_s_seh-1.dll + libGLESv2.dll + libstdc++-6.dll + libwinpthread-1.dll + nvim-qt.exe + opengl32sw.dll + Qt5Core.dll + Qt5Gui.dll + Qt5Network.dll + Qt5Svg.dll + Qt5Widgets.dll + ) + endif() + # A CMake script is used for copying the files to avoid the # "command line is too long" error that occurs when Ninja tries running # a command that exceeds the length limit (8191 characters) on Windows. @@ -718,67 +754,19 @@ if(WIN32) set(EXTERNAL_BLOBS_SCRIPT "file(MAKE_DIRECTORY \"${PROJECT_BINARY_DIR}/windows_runtime_deps/platforms\")") foreach(DEP_FILE IN ITEMS - curl-ca-bundle.crt - curl.exe - diff.exe - tee.exe - win32yank.exe - xxd.exe - - # Dependencies for neovim-qt - bearer/qgenericbearer.dll - iconengines/qsvgicon.dll - imageformats/qgif.dll - imageformats/qicns.dll - imageformats/qico.dll - imageformats/qjpeg.dll - imageformats/qsvg.dll - imageformats/qtga.dll - imageformats/qtiff.dll - imageformats/qwbmp.dll - imageformats/qwebp.dll - platforms/qwindows.dll - styles/qwindowsvistastyle.dll - translations/qt_ar.qm - translations/qt_bg.qm - translations/qt_ca.qm - translations/qt_cs.qm - translations/qt_da.qm - translations/qt_de.qm - translations/qt_en.qm - translations/qt_es.qm - translations/qt_fi.qm - translations/qt_fr.qm - translations/qt_gd.qm - translations/qt_he.qm - translations/qt_hu.qm - translations/qt_it.qm - translations/qt_ja.qm - translations/qt_ko.qm - translations/qt_lv.qm - translations/qt_pl.qm - translations/qt_ru.qm - translations/qt_sk.qm - translations/qt_uk.qm - D3Dcompiler_47.dll - libEGL.dll - libgcc_s_seh-1.dll - libGLESv2.dll - libstdc++-6.dll - libwinpthread-1.dll - nvim-qt.exe - opengl32sw.dll - Qt5Core.dll - Qt5Gui.dll - Qt5Network.dll - Qt5Svg.dll - Qt5Widgets.dll - - ) - get_filename_component(DEP_FILE_DIR ${DEP_FILE} DIRECTORY) - set(EXTERNAL_BLOBS_SCRIPT "${EXTERNAL_BLOBS_SCRIPT}\n" - "file(COPY \"${DEPS_PREFIX}/bin/${DEP_FILE}\" - DESTINATION \"${PROJECT_BINARY_DIR}/windows_runtime_deps/${DEP_FILE_DIR}\")") + curl-ca-bundle.crt + curl.exe + diff.exe + tee.exe + win32yank.exe + xxd.exe + + ${NVIMQT_DEPS} + ) + get_filename_component(DEP_FILE_DIR ${DEP_FILE} DIRECTORY) + set(EXTERNAL_BLOBS_SCRIPT "${EXTERNAL_BLOBS_SCRIPT}\n" + "file(COPY \"${DEPS_PREFIX}/bin/${DEP_FILE}\" + DESTINATION \"${PROJECT_BINARY_DIR}/windows_runtime_deps/${DEP_FILE_DIR}\")") endforeach() file(WRITE ${PROJECT_BINARY_DIR}/external_blobs.cmake ${EXTERNAL_BLOBS_SCRIPT}) add_custom_target(external_blobs @@ -804,14 +792,7 @@ install(DIRECTORY ${BINARY_LIB_DIR} DESTINATION ${CMAKE_INSTALL_LIBDIR}/nvim/ USE_SOURCE_PERMISSIONS) -add_library( - libnvim - STATIC - EXCLUDE_FROM_ALL - ${NVIM_SOURCES} ${NVIM_GENERATED_SOURCES} - ${NVIM_HEADERS} ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS} - ${EXTERNAL_SOURCES} ${EXTERNAL_HEADERS} -) +add_library(libnvim STATIC EXCLUDE_FROM_ALL) if(MSVC) set(LIBNVIM_NAME libnvim) else() @@ -854,63 +835,35 @@ elseif(CLANG_TSAN) target_link_libraries(nvim PRIVATE -fsanitize=thread) endif() -function(get_test_target prefix sfile relative_path_var target_var) - get_filename_component(full_d "${sfile}" DIRECTORY) - file(RELATIVE_PATH d "${PROJECT_SOURCE_DIR}/src/nvim" "${full_d}") - if(d MATCHES "^[.][.]") - file(RELATIVE_PATH d "${GENERATED_DIR}" "${full_d}") - endif() - get_filename_component(r "${sfile}" NAME) - if(NOT d MATCHES "^[.]?$") - set(r "${d}/${r}") - endif() - string(REGEX REPLACE "[/.]" "-" suffix "${r}") - set(${relative_path_var} ${r} PARENT_SCOPE) - if(prefix STREQUAL "") - set(${target_var} "${suffix}" PARENT_SCOPE) - else() - set(${target_var} "${prefix}-${suffix}" PARENT_SCOPE) - endif() -endfunction() - +find_program(CLANG_TIDY_PRG clang-tidy) +set(EXCLUDE_CLANG_TIDY typval_encode.c.h ui_events.in.h) if(WIN32) - set(NO_SINGLE_CHECK_HEADERS + list(APPEND EXCLUDE_CLANG_TIDY os/pty_process_unix.h os/unix_defs.h) else() - set(NO_SINGLE_CHECK_HEADERS + list(APPEND EXCLUDE_CLANG_TIDY os/win_defs.h os/pty_process_win.h os/pty_conpty_win.h os/os_win_console.h) endif() -foreach(hfile ${NVIM_HEADERS}) - get_test_target(test-includes "${hfile}" relative_path texe) - - if(NOT ${hfile} MATCHES "[.](c|in)[.]h$") - set(tsource "${GENERATED_DIR}/${relative_path}.test-include.c") - write_file("${tsource}" "#include \"${hfile}\"\nint main(int argc, char **argv) { return 0; }") - add_executable( - ${texe} - EXCLUDE_FROM_ALL - ${tsource} ${NVIM_HEADERS} ${NVIM_GENERATED_FOR_HEADERS}) - target_link_libraries(${texe} PRIVATE main_lib) - set_target_properties(${texe} PROPERTIES FOLDER test) - - list(FIND NO_SINGLE_CHECK_HEADERS "${relative_path}" hfile_exclude_idx) - if(${hfile_exclude_idx} EQUAL -1) - list(APPEND HEADER_CHECK_TARGETS ${texe}) - endif() - endif() -endforeach() -add_custom_target(check-single-includes DEPENDS ${HEADER_CHECK_TARGETS}) +add_glob_target( + TARGET clang-tidy + COMMAND ${CLANG_TIDY_PRG} + FILES ${NVIM_SOURCES} ${NVIM_HEADERS} + FLAGS --quiet + EXCLUDE ${EXCLUDE_CLANG_TIDY}) +add_custom_target(copy_compile_commands + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/compile_commands.json ${PROJECT_SOURCE_DIR}/compile_commands.json) +add_dependencies(copy_compile_commands nvim) +add_dependencies(clang-tidy copy_compile_commands) if(CI_BUILD) set(LINT_OUTPUT_FORMAT gh_action) else() set(LINT_OUTPUT_FORMAT vs7) endif() - add_glob_target( TARGET lintc-clint COMMAND ${PROJECT_SOURCE_DIR}/src/clint.py diff --git a/src/nvim/README.md b/src/nvim/README.md index 6876227e48..712fda87ba 100644 --- a/src/nvim/README.md +++ b/src/nvim/README.md @@ -70,8 +70,8 @@ Create a directory to store logs: Configure the sanitizer(s) via these environment variables: - # Change to detect_leaks=1 to detect memory leaks (slower). - export ASAN_OPTIONS="detect_leaks=0:log_path=$HOME/logs/asan" + # Change to detect_leaks=1 to detect memory leaks (slower, noisier). + export ASAN_OPTIONS="detect_leaks=0:log_path=$HOME/logs/asan,handle_abort=1,handle_sigill=1" # Show backtraces in the logs. export UBSAN_OPTIONS=print_stacktrace=1 export MSAN_OPTIONS="log_path=${HOME}/logs/msan" diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index a2cb297b15..36d3e04f54 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -12,6 +12,7 @@ #include "nvim/api/autocmd.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" @@ -107,25 +108,24 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) break; case kObjectTypeString: group = augroup_find(opts->group.data.string.data); - if (group < 0) { - api_set_error(err, kErrorTypeValidation, "invalid augroup passed."); + VALIDATE_S((group >= 0), "group", "", { goto cleanup; - } + }); break; case kObjectTypeInteger: group = (int)opts->group.data.integer; char *name = augroup_name(group); - if (!augroup_exists(name)) { - api_set_error(err, kErrorTypeValidation, "invalid augroup passed."); + VALIDATE_S(augroup_exists(name), "group", "", { goto cleanup; - } + }); break; default: - api_set_error(err, kErrorTypeValidation, "group must be a string or an integer."); - goto cleanup; + VALIDATE_S(false, "group (must be string or integer)", "", { + goto cleanup; + }); } - if (opts->event.type != kObjectTypeNil) { + if (HAS_KEY(opts->event)) { check_event = true; Object v = opts->event; @@ -134,57 +134,50 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) event_set[event_nr] = true; } else if (v.type == kObjectTypeArray) { FOREACH_ITEM(v.data.array, event_v, { - if (event_v.type != kObjectTypeString) { - api_set_error(err, - kErrorTypeValidation, - "Every event must be a string in 'event'"); + VALIDATE_T("event item", kObjectTypeString, event_v.type, { goto cleanup; - } + }); GET_ONE_EVENT(event_nr, event_v, cleanup); event_set[event_nr] = true; }) } else { - api_set_error(err, - kErrorTypeValidation, - "Not a valid 'event' value. Must be a string or an array"); - goto cleanup; + VALIDATE_S(false, "event (must be String or Array)", "", { + goto cleanup; + }); } } - if (opts->pattern.type != kObjectTypeNil && opts->buffer.type != kObjectTypeNil) { - api_set_error(err, kErrorTypeValidation, - "Cannot use both 'pattern' and 'buffer'"); + VALIDATE((!HAS_KEY(opts->pattern) || !HAS_KEY(opts->buffer)), + "%s", "Cannot use both 'pattern' and 'buffer'", { goto cleanup; - } + }); int pattern_filter_count = 0; - if (opts->pattern.type != kObjectTypeNil) { + if (HAS_KEY(opts->pattern)) { Object v = opts->pattern; if (v.type == kObjectTypeString) { pattern_filters[pattern_filter_count] = v.data.string.data; pattern_filter_count += 1; } else if (v.type == kObjectTypeArray) { if (v.data.array.size > AUCMD_MAX_PATTERNS) { - api_set_error(err, kErrorTypeValidation, - "Too many patterns. Please limit yourself to %d or fewer", + api_set_error(err, kErrorTypeValidation, "Too many patterns (maximum of %d)", AUCMD_MAX_PATTERNS); goto cleanup; } FOREACH_ITEM(v.data.array, item, { - if (item.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'pattern': must be a string"); + VALIDATE_T("pattern", kObjectTypeString, item.type, { goto cleanup; - } + }); pattern_filters[pattern_filter_count] = item.data.string.data; pattern_filter_count += 1; }); } else { - api_set_error(err, kErrorTypeValidation, - "Not a valid 'pattern' value. Must be a string or an array"); - goto cleanup; + VALIDATE_EXP(false, "pattern", "String or Array", api_typename(v.type), { + goto cleanup; + }); } } @@ -194,34 +187,33 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) goto cleanup; } - snprintf((char *)pattern_buflocal, BUFLOCAL_PAT_LEN, "<buffer=%d>", (int)buf->handle); - ADD(buffers, CSTR_TO_OBJ((char *)pattern_buflocal)); + snprintf(pattern_buflocal, BUFLOCAL_PAT_LEN, "<buffer=%d>", (int)buf->handle); + ADD(buffers, CSTR_TO_OBJ(pattern_buflocal)); } else if (opts->buffer.type == kObjectTypeArray) { if (opts->buffer.data.array.size > AUCMD_MAX_PATTERNS) { - api_set_error(err, - kErrorTypeValidation, - "Too many buffers. Please limit yourself to %d or fewer", AUCMD_MAX_PATTERNS); + api_set_error(err, kErrorTypeValidation, "Too many buffers (maximum of %d)", + AUCMD_MAX_PATTERNS); goto cleanup; } FOREACH_ITEM(opts->buffer.data.array, bufnr, { - if (bufnr.type != kObjectTypeInteger && bufnr.type != kObjectTypeBuffer) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'buffer': must be an integer"); + VALIDATE_EXP((bufnr.type == kObjectTypeInteger || bufnr.type == kObjectTypeBuffer), + "buffer", "Integer", api_typename(bufnr.type), { goto cleanup; - } + }); buf_T *buf = find_buffer_by_handle((Buffer)bufnr.data.integer, err); if (ERROR_SET(err)) { goto cleanup; } - snprintf((char *)pattern_buflocal, BUFLOCAL_PAT_LEN, "<buffer=%d>", (int)buf->handle); - ADD(buffers, CSTR_TO_OBJ((char *)pattern_buflocal)); + snprintf(pattern_buflocal, BUFLOCAL_PAT_LEN, "<buffer=%d>", (int)buf->handle); + ADD(buffers, CSTR_TO_OBJ(pattern_buflocal)); + }); + } else if (HAS_KEY(opts->buffer)) { + VALIDATE_EXP(false, "buffer", "Integer or Array", api_typename(opts->buffer.type), { + goto cleanup; }); - } else if (opts->buffer.type != kObjectTypeNil) { - api_set_error(err, kErrorTypeValidation, - "Invalid value for 'buffer': must be an integer or array of integers"); - goto cleanup; } FOREACH_ITEM(buffers, bufnr, { @@ -319,7 +311,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err) PUT(autocmd_info, "pattern", - STRING_OBJ(cstr_to_string((char *)ap->pat))); + STRING_OBJ(cstr_to_string(ap->pat))); PUT(autocmd_info, "event", @@ -421,10 +413,8 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc { int64_t autocmd_id = -1; char *desc = NULL; - Array patterns = ARRAY_DICT_INIT; Array event_array = ARRAY_DICT_INIT; - AucmdExecutable aucmd = AUCMD_EXECUTABLE_INIT; Callback cb = CALLBACK_NONE; @@ -432,30 +422,23 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc goto cleanup; } - if (opts->callback.type != kObjectTypeNil && opts->command.type != kObjectTypeNil) { - api_set_error(err, kErrorTypeValidation, "specify either 'callback' or 'command', not both"); + VALIDATE((!HAS_KEY(opts->callback) || !HAS_KEY(opts->command)), + "%s", "Cannot use both 'callback' and 'command'", { goto cleanup; - } else if (opts->callback.type != kObjectTypeNil) { - // TODO(tjdevries): It's possible we could accept callable tables, - // but we don't do that many other places, so for the moment let's - // not do that. + }); + + if (HAS_KEY(opts->callback)) { + // NOTE: We could accept callable tables, but that isn't common in the API. Object *callback = &opts->callback; switch (callback->type) { case kObjectTypeLuaRef: - if (callback->data.luaref == LUA_NOREF) { - api_set_error(err, - kErrorTypeValidation, - "must pass an actual value"); + VALIDATE_S((callback->data.luaref != LUA_NOREF), "callback", "<no value>", { goto cleanup; - } - - if (!nlua_ref_is_function(callback->data.luaref)) { - api_set_error(err, - kErrorTypeValidation, - "must pass a function for callback"); + }); + VALIDATE_S(nlua_ref_is_function(callback->data.luaref), "callback", "<not a function>", { goto cleanup; - } + }); cb.type = kCallbackLua; cb.data.luaref = api_new_luaref(callback->data.luaref); @@ -465,28 +448,25 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc cb.data.funcref = string_to_cstr(callback->data.string); break; default: - api_set_error(err, - kErrorTypeException, - "'callback' must be a lua function or name of vim function"); - goto cleanup; + VALIDATE_EXP(false, "callback", "Lua function or Vim function name", + api_typename(callback->type), { + goto cleanup; + }); } aucmd.type = CALLABLE_CB; aucmd.callable.cb = cb; - } else if (opts->command.type != kObjectTypeNil) { + } else if (HAS_KEY(opts->command)) { Object *command = &opts->command; - if (command->type == kObjectTypeString) { - aucmd.type = CALLABLE_EX; - aucmd.callable.cmd = string_to_cstr(command->data.string); - } else { - api_set_error(err, - kErrorTypeValidation, - "'command' must be a string"); + VALIDATE_T("command", kObjectTypeString, command->type, { goto cleanup; - } + }); + aucmd.type = CALLABLE_EX; + aucmd.callable.cmd = string_to_cstr(command->data.string); } else { - api_set_error(err, kErrorTypeValidation, "must pass one of: 'command', 'callback'"); - goto cleanup; + VALIDATE(false, "%s", "Required: 'command' or 'callback'", { + goto cleanup; + }); } bool is_once = api_object_to_bool(opts->once, "once", false, err); @@ -501,25 +481,20 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc goto cleanup; } - if (opts->desc.type != kObjectTypeNil) { - if (opts->desc.type == kObjectTypeString) { - desc = opts->desc.data.string.data; - } else { - api_set_error(err, - kErrorTypeValidation, - "'desc' must be a string"); + if (HAS_KEY(opts->desc)) { + VALIDATE_T("desc", kObjectTypeString, opts->desc.type, { goto cleanup; - } + }); + desc = opts->desc.data.string.data; } if (patterns.size == 0) { ADD(patterns, STRING_OBJ(STATIC_CSTR_TO_STRING("*"))); } - if (event_array.size == 0) { - api_set_error(err, kErrorTypeValidation, "'event' is a required key"); + VALIDATE_R((event_array.size > 0), "event", { goto cleanup; - } + }); autocmd_id = next_autocmd_id++; FOREACH_ITEM(event_array, event_str, { @@ -564,10 +539,9 @@ cleanup: void nvim_del_autocmd(Integer id, Error *err) FUNC_API_SINCE(9) { - if (id <= 0) { - api_set_error(err, kErrorTypeException, "Invalid autocmd id"); + VALIDATE_INT((id > 0), "autocmd id", id, { return; - } + }); if (!autocmd_delete_id(id)) { api_set_error(err, kErrorTypeException, "Failed to delete autocmd"); } @@ -610,11 +584,10 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err) goto cleanup; } - if (opts->pattern.type != kObjectTypeNil && opts->buffer.type != kObjectTypeNil) { - api_set_error(err, kErrorTypeValidation, - "Cannot use both 'pattern' and 'buffer'"); + VALIDATE((!HAS_KEY(opts->pattern) || !HAS_KEY(opts->buffer)), + "%s", "Cannot use both 'pattern' and 'buffer'", { goto cleanup; - } + }); int au_group = get_augroup_from_object(opts->group, err); if (au_group == AUGROUP_ERROR) { @@ -772,32 +745,29 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err) break; case kObjectTypeString: au_group = augroup_find(opts->group.data.string.data); - if (au_group == AUGROUP_ERROR) { - api_set_error(err, - kErrorTypeValidation, - "invalid augroup: %s", opts->group.data.string.data); + VALIDATE_S((au_group != AUGROUP_ERROR), "group", opts->group.data.string.data, { goto cleanup; - } + }); break; case kObjectTypeInteger: au_group = (int)opts->group.data.integer; char *name = augroup_name(au_group); - if (!augroup_exists(name)) { - api_set_error(err, kErrorTypeValidation, "invalid augroup: %d", au_group); + VALIDATE_INT(augroup_exists(name), "group", (int64_t)au_group, { goto cleanup; - } + }); break; default: - api_set_error(err, kErrorTypeValidation, "'group' must be a string or an integer."); - goto cleanup; + VALIDATE_EXP(false, "group", "String or Integer", api_typename(opts->group.type), { + goto cleanup; + }); } - if (opts->buffer.type != kObjectTypeNil) { + if (HAS_KEY(opts->buffer)) { Object buf_obj = opts->buffer; - if (buf_obj.type != kObjectTypeInteger && buf_obj.type != kObjectTypeBuffer) { - api_set_error(err, kErrorTypeException, "invalid buffer: %d", buf_obj.type); + VALIDATE_EXP((buf_obj.type == kObjectTypeInteger || buf_obj.type == kObjectTypeBuffer), + "buffer", "Integer", api_typename(buf_obj.type), { goto cleanup; - } + }); buf = find_buffer_by_handle((Buffer)buf_obj.data.integer, err); @@ -814,7 +784,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err) ADD(patterns, STRING_OBJ(STATIC_CSTR_TO_STRING(""))); } - if (opts->data.type != kObjectTypeNil) { + if (HAS_KEY(opts->data)) { data = &opts->data; } @@ -825,7 +795,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err) GET_ONE_EVENT(event_nr, event_str, cleanup) FOREACH_ITEM(patterns, pat, { - char *fname = opts->buffer.type == kObjectTypeNil ? pat.data.string.data : NULL; + char *fname = !HAS_KEY(opts->buffer) ? pat.data.string.data : NULL; did_aucmd |= apply_autocmds_group(event_nr, fname, NULL, true, au_group, buf, NULL, data); }) @@ -840,45 +810,19 @@ cleanup: api_free_array(patterns); } -static bool check_autocmd_string_array(Array arr, char *k, Error *err) -{ - FOREACH_ITEM(arr, entry, { - if (entry.type != kObjectTypeString) { - api_set_error(err, - kErrorTypeValidation, - "All entries in '%s' must be strings", - k); - return false; - } - - // Disallow newlines in the middle of the line. - const String l = entry.data.string; - if (memchr(l.data, NL, l.size)) { - api_set_error(err, kErrorTypeValidation, - "String cannot contain newlines"); - return false; - } - }) - return true; -} - static bool unpack_string_or_array(Array *array, Object *v, char *k, bool required, Error *err) { if (v->type == kObjectTypeString) { ADD(*array, copy_object(*v, NULL)); } else if (v->type == kObjectTypeArray) { - if (!check_autocmd_string_array(v->data.array, k, err)) { + if (!check_string_array(v->data.array, k, true, err)) { return false; } *array = copy_array(v->data.array, NULL); } else { - if (required) { - api_set_error(err, - kErrorTypeValidation, - "'%s' must be an array or a string.", - k); + VALIDATE_EXP(!required, k, "Array or String", api_typename(v->type), { return false; - } + }); } return true; @@ -894,27 +838,22 @@ static int get_augroup_from_object(Object group, Error *err) return AUGROUP_DEFAULT; case kObjectTypeString: au_group = augroup_find(group.data.string.data); - if (au_group == AUGROUP_ERROR) { - api_set_error(err, - kErrorTypeValidation, - "invalid augroup: %s", group.data.string.data); - + VALIDATE_S((au_group != AUGROUP_ERROR), "group", group.data.string.data, { return AUGROUP_ERROR; - } + }); return au_group; case kObjectTypeInteger: au_group = (int)group.data.integer; char *name = augroup_name(au_group); - if (!augroup_exists(name)) { - api_set_error(err, kErrorTypeValidation, "invalid augroup: %d", au_group); + VALIDATE_INT(augroup_exists(name), "group", (int64_t)au_group, { return AUGROUP_ERROR; - } - + }); return au_group; default: - api_set_error(err, kErrorTypeValidation, "'group' must be a string or an integer."); - return AUGROUP_ERROR; + VALIDATE_EXP(false, "group", "String or Integer", api_typename(group.type), { + return AUGROUP_ERROR; + }); } } @@ -923,24 +862,25 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob { const char pattern_buflocal[BUFLOCAL_PAT_LEN]; - if (pattern.type != kObjectTypeNil && buffer.type != kObjectTypeNil) { - api_set_error(err, kErrorTypeValidation, - "cannot pass both: 'pattern' and 'buffer' for the same autocmd"); + VALIDATE((!HAS_KEY(pattern) || !HAS_KEY(buffer)), + "%s", "Cannot use both 'pattern' and 'buffer' for the same autocmd", { return false; - } else if (pattern.type != kObjectTypeNil) { + }); + + if (HAS_KEY(pattern)) { Object *v = &pattern; if (v->type == kObjectTypeString) { char *pat = v->data.string.data; size_t patlen = aucmd_pattern_length(pat); while (patlen) { - ADD(*patterns, STRING_OBJ(cbuf_to_string((char *)pat, patlen))); + ADD(*patterns, STRING_OBJ(cbuf_to_string(pat, patlen))); pat = aucmd_next_pattern(pat, patlen); patlen = aucmd_pattern_length(pat); } } else if (v->type == kObjectTypeArray) { - if (!check_autocmd_string_array(v->data.array, "pattern", err)) { + if (!check_string_array(v->data.array, "pattern", true, err)) { return false; } @@ -949,25 +889,22 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob char *pat = entry.data.string.data; size_t patlen = aucmd_pattern_length(pat); while (patlen) { - ADD(*patterns, STRING_OBJ(cbuf_to_string((char *)pat, patlen))); + ADD(*patterns, STRING_OBJ(cbuf_to_string(pat, patlen))); pat = aucmd_next_pattern(pat, patlen); patlen = aucmd_pattern_length(pat); } }) } else { - api_set_error(err, - kErrorTypeValidation, - "'pattern' must be a string or table"); - return false; + VALIDATE_EXP(false, "pattern", "String or Table", api_typename(v->type), { + return false; + }); } - } else if (buffer.type != kObjectTypeNil) { - if (buffer.type != kObjectTypeInteger && buffer.type != kObjectTypeBuffer) { - api_set_error(err, - kErrorTypeValidation, - "'buffer' must be an integer"); + } else if (HAS_KEY(buffer)) { + VALIDATE_EXP((buffer.type == kObjectTypeInteger || buffer.type == kObjectTypeBuffer), + "buffer", "Integer", api_typename(buffer.type), { return false; - } + }); buf_T *buf = find_buffer_by_handle((Buffer)buffer.data.integer, err); if (ERROR_SET(err)) { @@ -975,7 +912,7 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob } snprintf((char *)pattern_buflocal, BUFLOCAL_PAT_LEN, "<buffer=%d>", (int)buf->handle); - ADD(*patterns, STRING_OBJ(cstr_to_string((char *)pattern_buflocal))); + ADD(*patterns, STRING_OBJ(cstr_to_string(pattern_buflocal))); } return true; diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index fe9e6077d6..9c2d14d30f 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -16,6 +16,7 @@ #include "nvim/api/buffer.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" @@ -179,11 +180,9 @@ Boolean nvim_buf_attach(uint64_t channel_id, Buffer buffer, Boolean send_buffer, if (is_lua) { for (size_t j = 0; cbs[j].name; j++) { if (strequal(cbs[j].name, k.data)) { - if (v->type != kObjectTypeLuaRef) { - api_set_error(err, kErrorTypeValidation, - "%s is not a function", cbs[j].name); + VALIDATE_T(cbs[j].name, kObjectTypeLuaRef, v->type, { goto error; - } + }); *(cbs[j].dest) = v->data.luaref; v->data.luaref = LUA_NOREF; key_used = true; @@ -194,26 +193,23 @@ Boolean nvim_buf_attach(uint64_t channel_id, Buffer buffer, Boolean send_buffer, if (key_used) { continue; } else if (strequal("utf_sizes", k.data)) { - if (v->type != kObjectTypeBoolean) { - api_set_error(err, kErrorTypeValidation, "utf_sizes must be boolean"); + VALIDATE_T("utf_sizes", kObjectTypeBoolean, v->type, { goto error; - } + }); cb.utf_sizes = v->data.boolean; key_used = true; } else if (strequal("preview", k.data)) { - if (v->type != kObjectTypeBoolean) { - api_set_error(err, kErrorTypeValidation, "preview must be boolean"); + VALIDATE_T("preview", kObjectTypeBoolean, v->type, { goto error; - } + }); cb.preview = v->data.boolean; key_used = true; } } - if (!key_used) { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); + VALIDATE_S(key_used, "key", k.data, { goto error; - } + }); } return buf_updates_register(buf, channel_id, cb, send_buffer); @@ -297,10 +293,9 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id, start = normalize_index(buf, start, true, &oob); end = normalize_index(buf, end, true, &oob); - if (strict_indexing && oob) { - api_set_error(err, kErrorTypeValidation, "Index out of bounds"); + VALIDATE((!strict_indexing || !oob), "%s", "Index out of bounds", { return rv; - } + }); if (start >= end) { // Return 0-length array @@ -325,28 +320,6 @@ end: return rv; } -static bool check_string_array(Array arr, bool disallow_nl, Error *err) -{ - for (size_t i = 0; i < arr.size; i++) { - if (arr.items[i].type != kObjectTypeString) { - api_set_error(err, - kErrorTypeValidation, - "All items in the replacement array must be strings"); - return false; - } - // Disallow newlines in the middle of the line. - if (disallow_nl) { - const String l = arr.items[i].data.string; - if (memchr(l.data, NL, l.size)) { - api_set_error(err, kErrorTypeValidation, - "String cannot contain newlines"); - return false; - } - } - } - return true; -} - /// Sets (replaces) a line-range in the buffer. /// /// Indexing is zero-based, end-exclusive. Negative indices are interpreted @@ -383,20 +356,15 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ start = normalize_index(buf, start, true, &oob); end = normalize_index(buf, end, true, &oob); - if (strict_indexing && oob) { - api_set_error(err, kErrorTypeValidation, "Index out of bounds"); + VALIDATE((!strict_indexing || !oob), "%s", "Index out of bounds", { return; - } - - if (start > end) { - api_set_error(err, - kErrorTypeValidation, - "Argument \"start\" is higher than \"end\""); + }); + VALIDATE((start <= end), "%s", "'start' is higher than 'end'", { return; - } + }); bool disallow_nl = (channel_id != VIML_INTERNAL_CALL); - if (!check_string_array(replacement, disallow_nl, err)) { + if (!check_string_array(replacement, "replacement string", disallow_nl, err)) { return; } @@ -453,10 +421,9 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ for (size_t i = 0; i < to_replace; i++) { int64_t lnum = start + (int64_t)i; - if (lnum >= MAXLNUM) { - api_set_error(err, kErrorTypeValidation, "Index value is too high"); + VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", { goto end; - } + }); if (ml_replace((linenr_T)lnum, lines[i], false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to replace line"); @@ -473,10 +440,9 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ for (size_t i = to_replace; i < new_len; i++) { int64_t lnum = start + (int64_t)i - 1; - if (lnum >= MAXLNUM) { - api_set_error(err, kErrorTypeValidation, "Index value is too high"); + VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", { goto end; - } + }); if (ml_append((linenr_T)lnum, lines[i], 0, false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to insert line"); @@ -563,16 +529,14 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // check range is ordered and everything! // start_row, end_row within buffer len (except add text past the end?) start_row = normalize_index(buf, start_row, false, &oob); - if (oob) { - api_set_error(err, kErrorTypeValidation, "start_row out of bounds"); + VALIDATE_RANGE((!oob), "start_row", { return; - } + }); end_row = normalize_index(buf, end_row, false, &oob); - if (oob) { - api_set_error(err, kErrorTypeValidation, "end_row out of bounds"); + VALIDATE_RANGE((!oob), "end_row", { return; - } + }); char *str_at_start = NULL; char *str_at_end = NULL; @@ -580,26 +544,24 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // Another call to ml_get_buf() may free the line, so make a copy. str_at_start = xstrdup(ml_get_buf(buf, (linenr_T)start_row, false)); size_t len_at_start = strlen(str_at_start); - if (start_col < 0 || (size_t)start_col > len_at_start) { - api_set_error(err, kErrorTypeValidation, "start_col out of bounds"); + VALIDATE_RANGE((start_col >= 0 && (size_t)start_col <= len_at_start), "start_col", { goto early_end; - } + }); // Another call to ml_get_buf() may free the line, so make a copy. str_at_end = xstrdup(ml_get_buf(buf, (linenr_T)end_row, false)); size_t len_at_end = strlen(str_at_end); - if (end_col < 0 || (size_t)end_col > len_at_end) { - api_set_error(err, kErrorTypeValidation, "end_col out of bounds"); + VALIDATE_RANGE((end_col >= 0 && (size_t)end_col <= len_at_end), "end_col", { goto early_end; - } + }); - if (start_row > end_row || (end_row == start_row && start_col > end_col)) { - api_set_error(err, kErrorTypeValidation, "start is higher than end"); + VALIDATE((start_row <= end_row && !(end_row == start_row && start_col > end_col)), + "%s", "'start' is higher than 'end'", { goto early_end; - } + }); bool disallow_nl = (channel_id != VIML_INTERNAL_CALL); - if (!check_string_array(replacement, disallow_nl, err)) { + if (!check_string_array(replacement, "replacement string", disallow_nl, err)) { goto early_end; } @@ -702,10 +664,9 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In for (size_t i = 0; i < to_replace; i++) { int64_t lnum = start_row + (int64_t)i; - if (lnum >= MAXLNUM) { - api_set_error(err, kErrorTypeValidation, "Index value is too high"); + VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", { goto end; - } + }); if (ml_replace((linenr_T)lnum, lines[i], false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to replace line"); @@ -720,10 +681,9 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In for (size_t i = to_replace; i < new_len; i++) { int64_t lnum = start_row + (int64_t)i - 1; - if (lnum >= MAXLNUM) { - api_set_error(err, kErrorTypeValidation, "Index value is too high"); + VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", { goto end; - } + }); if (ml_append((linenr_T)lnum, lines[i], 0, false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to insert line"); @@ -800,10 +760,9 @@ ArrayOf(String) nvim_buf_get_text(uint64_t channel_id, Buffer buffer, { Array rv = ARRAY_DICT_INIT; - if (opts.size > 0) { - api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); + VALIDATE((opts.size == 0), "%s", "opts dict isn't empty", { return rv; - } + }); buf_T *buf = find_buffer_by_handle(buffer, err); @@ -820,18 +779,16 @@ ArrayOf(String) nvim_buf_get_text(uint64_t channel_id, Buffer buffer, start_row = normalize_index(buf, start_row, false, &oob); end_row = normalize_index(buf, end_row, false, &oob); - if (oob) { - api_set_error(err, kErrorTypeValidation, "Index out of bounds"); + VALIDATE((!oob), "%s", "Index out of bounds", { return rv; - } + }); // nvim_buf_get_lines doesn't care if the start row is greater than the end // row (it will just return an empty array), but nvim_buf_get_text does in // order to maintain symmetry with nvim_buf_set_text. - if (start_row > end_row) { - api_set_error(err, kErrorTypeValidation, "start is higher than end"); + VALIDATE((start_row <= end_row), "%s", "'start' is higher than 'end'", { return rv; - } + }); bool replace_nl = (channel_id != VIML_INTERNAL_CALL); @@ -907,10 +864,9 @@ Integer nvim_buf_get_offset(Buffer buffer, Integer index, Error *err) return -1; } - if (index < 0 || index > buf->b_ml.ml_line_count) { - api_set_error(err, kErrorTypeValidation, "Index out of bounds"); + VALIDATE((index >= 0 && index <= buf->b_ml.ml_line_count), "%s", "Index out of bounds", { return 0; - } + }); return ml_find_line_or_offset(buf, (int)index + 1, NULL, true); } @@ -1118,8 +1074,9 @@ void nvim_buf_delete(Buffer buffer, Dictionary opts, Error *err) } else if (strequal("unload", k.data)) { unload = api_object_to_bool(v, "unload", false, err); } else { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); - return; + VALIDATE_S(false, "key", k.data, { + return; + }); } } @@ -1174,20 +1131,16 @@ Boolean nvim_buf_del_mark(Buffer buffer, String name, Error *err) return res; } - if (name.size != 1) { - api_set_error(err, kErrorTypeValidation, - "Mark name must be a single character"); + VALIDATE_S((name.size == 1), "mark name (must be a single char)", name.data, { return res; - } + }); fmark_T *fm = mark_get(buf, curwin, NULL, kMarkAllNoResolve, *name.data); // fm is NULL when there's no mark with the given name - if (fm == NULL) { - api_set_error(err, kErrorTypeValidation, "Invalid mark name: '%c'", - *name.data); + VALIDATE_S((fm != NULL), "mark name", name.data, { return res; - } + }); // mark.lnum is 0 when the mark is not valid in the buffer, or is not set. if (fm->mark.lnum != 0 && fm->fnum == buf->handle) { @@ -1224,11 +1177,9 @@ Boolean nvim_buf_set_mark(Buffer buffer, String name, Integer line, Integer col, return res; } - if (name.size != 1) { - api_set_error(err, kErrorTypeValidation, - "Mark name must be a single character"); + VALIDATE_S((name.size == 1), "mark name (must be a single char)", name.data, { return res; - } + }); res = set_mark(buf, name, line, col, err); @@ -1257,21 +1208,18 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err) return rv; } - if (name.size != 1) { - api_set_error(err, kErrorTypeValidation, - "Mark name must be a single character"); + VALIDATE_S((name.size == 1), "mark name (must be a single char)", name.data, { return rv; - } + }); fmark_T *fm; pos_T pos; char mark = *name.data; fm = mark_get(buf, curwin, NULL, kMarkAllNoResolve, mark); - if (fm == NULL) { - api_set_error(err, kErrorTypeValidation, "Invalid mark name"); + VALIDATE_S((fm != NULL), "mark name", name.data, { return rv; - } + }); // (0, 0) uppercase/file mark set in another buffer. if (fm->fnum != buf->handle) { pos.lnum = 0; diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index abd265f2cf..cae3927dfd 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -11,6 +11,7 @@ #include "nvim/api/command.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" @@ -99,10 +100,9 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) { Dictionary result = ARRAY_DICT_INIT; - if (opts.size > 0) { - api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); + VALIDATE((opts.size == 0), "%s", "opts dict isn't empty", { return result; - } + }); // Parse command line exarg_T ea; @@ -127,7 +127,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) // otherwise split arguments by whitespace. if (ea.argt & EX_NOSPC) { if (*ea.arg != NUL) { - ADD(args, STRING_OBJ(cstrn_to_string((char *)ea.arg, length))); + ADD(args, STRING_OBJ(cstrn_to_string(ea.arg, length))); } } else { size_t end = 0; @@ -153,9 +153,9 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) } if (cmd != NULL) { - PUT(result, "cmd", CSTR_TO_OBJ((char *)cmd->uc_name)); + PUT(result, "cmd", CSTR_TO_OBJ(cmd->uc_name)); } else { - PUT(result, "cmd", CSTR_TO_OBJ((char *)get_command_name(NULL, ea.cmdidx))); + PUT(result, "cmd", CSTR_TO_OBJ(get_command_name(NULL, ea.cmdidx))); } if (ea.argt & EX_RANGE) { @@ -237,7 +237,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) break; } PUT(result, "addr", CSTR_TO_OBJ(addr)); - PUT(result, "nextcmd", CSTR_TO_OBJ((char *)ea.nextcmd)); + PUT(result, "nextcmd", CSTR_TO_OBJ(ea.nextcmd)); Dictionary mods = ARRAY_DICT_INIT; @@ -512,7 +512,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } else if (cmd->count.type != kObjectTypeInteger || cmd->count.data.integer < 0) { VALIDATION_ERROR("'count' must be a non-negative Integer"); } - set_cmd_count(&ea, cmd->count.data.integer, true); + set_cmd_count(&ea, (linenr_T)cmd->count.data.integer, true); } if (HAS_KEY(cmd->reg)) { @@ -998,14 +998,14 @@ void nvim_buf_del_user_command(Buffer buffer, String name, Error *err) } } - api_set_error(err, kErrorTypeException, "No such user-defined command: %s", name.data); + api_set_error(err, kErrorTypeException, "Invalid command (not found): %s", name.data); } void create_user_command(String name, Object command, Dict(user_command) *opts, int flags, Error *err) { uint32_t argt = 0; - long def = -1; + int64_t def = -1; cmd_addr_T addr_type_arg = ADDR_NONE; int compl = EXPAND_NOTHING; char *compl_arg = NULL; @@ -1014,20 +1014,17 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, LuaRef compl_luaref = LUA_NOREF; LuaRef preview_luaref = LUA_NOREF; - if (!uc_validate_name(name.data)) { - api_set_error(err, kErrorTypeValidation, "Invalid command name"); + VALIDATE_S(uc_validate_name(name.data), "command name", name.data, { goto err; - } - - if (mb_islower(name.data[0])) { - api_set_error(err, kErrorTypeValidation, "'name' must begin with an uppercase letter"); + }); + VALIDATE_S(!mb_islower(name.data[0]), "command name (must begin with an uppercase letter)", + name.data, { goto err; - } - - if (HAS_KEY(opts->range) && HAS_KEY(opts->count)) { - api_set_error(err, kErrorTypeValidation, "'range' and 'count' are mutually exclusive"); + }); + VALIDATE((!HAS_KEY(opts->range) || !HAS_KEY(opts->count)), "%s", + "Cannot use both 'range' and 'count'", { goto err; - } + }); if (opts->nargs.type == kObjectTypeInteger) { switch (opts->nargs.data.integer) { @@ -1038,14 +1035,14 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, argt |= EX_EXTRA | EX_NOSPC | EX_NEEDARG; break; default: - api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'"); - goto err; + VALIDATE_INT(false, "nargs", (int64_t)opts->nargs.data.integer, { + goto err; + }); } } else if (opts->nargs.type == kObjectTypeString) { - if (opts->nargs.data.string.size > 1) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'"); + VALIDATE_S((opts->nargs.data.string.size <= 1), "nargs", opts->nargs.data.string.data, { goto err; - } + }); switch (opts->nargs.data.string.data[0]) { case '*': @@ -1058,18 +1055,19 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, argt |= EX_EXTRA | EX_NEEDARG; break; default: - api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'"); - goto err; + VALIDATE_S(false, "nargs", opts->nargs.data.string.data, { + goto err; + }); } } else if (HAS_KEY(opts->nargs)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'"); - goto err; + VALIDATE_S(false, "nargs", "", { + goto err; + }); } - if (HAS_KEY(opts->complete) && !argt) { - api_set_error(err, kErrorTypeValidation, "'complete' used without 'nargs'"); + VALIDATE((!HAS_KEY(opts->complete) || argt), "%s", "'complete' used without 'nargs'", { goto err; - } + }); if (opts->range.type == kObjectTypeBoolean) { if (opts->range.data.boolean) { @@ -1077,20 +1075,20 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, addr_type_arg = ADDR_LINES; } } else if (opts->range.type == kObjectTypeString) { - if (opts->range.data.string.data[0] == '%' && opts->range.data.string.size == 1) { - argt |= EX_RANGE | EX_DFLALL; - addr_type_arg = ADDR_LINES; - } else { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'range'"); + VALIDATE_S((opts->range.data.string.data[0] == '%' && opts->range.data.string.size == 1), + "range", "", { goto err; - } + }); + argt |= EX_RANGE | EX_DFLALL; + addr_type_arg = ADDR_LINES; } else if (opts->range.type == kObjectTypeInteger) { argt |= EX_RANGE | EX_ZEROR; def = opts->range.data.integer; addr_type_arg = ADDR_LINES; } else if (HAS_KEY(opts->range)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'range'"); - goto err; + VALIDATE_S(false, "range", "", { + goto err; + }); } if (opts->count.type == kObjectTypeBoolean) { @@ -1104,23 +1102,25 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, addr_type_arg = ADDR_OTHER; def = opts->count.data.integer; } else if (HAS_KEY(opts->count)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'count'"); - goto err; + VALIDATE_S(false, "count", "", { + goto err; + }); } - if (opts->addr.type == kObjectTypeString) { - if (parse_addr_type_arg(opts->addr.data.string.data, (int)opts->addr.data.string.size, - &addr_type_arg) != OK) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'addr'"); + if (HAS_KEY(opts->addr)) { + VALIDATE_T("addr", kObjectTypeString, opts->addr.type, { goto err; - } + }); + + VALIDATE_S(OK == parse_addr_type_arg(opts->addr.data.string.data, + (int)opts->addr.data.string.size, &addr_type_arg), "addr", + opts->addr.data.string.data, { + goto err; + }); if (addr_type_arg != ADDR_LINES) { argt |= EX_ZEROR; } - } else if (HAS_KEY(opts->addr)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'addr'"); - goto err; } if (api_object_to_bool(opts->bang, "bang", false, err)) { @@ -1156,23 +1156,25 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, compl = EXPAND_USER_LUA; compl_luaref = api_new_luaref(opts->complete.data.luaref); } else if (opts->complete.type == kObjectTypeString) { - if (parse_compl_arg(opts->complete.data.string.data, - (int)opts->complete.data.string.size, &compl, &argt, - &compl_arg) != OK) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'complete'"); + VALIDATE_S(OK == parse_compl_arg(opts->complete.data.string.data, + (int)opts->complete.data.string.size, &compl, &argt, + &compl_arg), + "complete", opts->complete.data.string.data, { goto err; - } + }); } else if (HAS_KEY(opts->complete)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'complete'"); - goto err; + VALIDATE(false, "%s", "Invalid complete: expected Function or String", { + goto err; + }); } - if (opts->preview.type == kObjectTypeLuaRef) { + if (HAS_KEY(opts->preview)) { + VALIDATE_T("preview", kObjectTypeLuaRef, opts->preview.type, { + goto err; + }); + argt |= EX_PREVIEW; preview_luaref = api_new_luaref(opts->preview.data.luaref); - } else if (HAS_KEY(opts->preview)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'preview'"); - goto err; } switch (command.type) { @@ -1188,8 +1190,9 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, rep = command.data.string.data; break; default: - api_set_error(err, kErrorTypeValidation, "'command' must be a string or Lua function"); - goto err; + VALIDATE(false, "%s", "Invalid command: expected Function or String", { + goto err; + }); } if (uc_add_command(name.data, name.size, rep, argt, def, flags, compl, compl_arg, compl_luaref, diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index ab3b3485e4..15f759eddf 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -11,6 +11,7 @@ #include "nvim/api/extmark.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/decoration.h" @@ -218,10 +219,9 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, return rv; } - if (!ns_initialized((uint32_t)ns_id)) { - api_set_error(err, kErrorTypeValidation, "Invalid ns_id"); + VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, { return rv; - } + }); bool details = false; for (size_t i = 0; i < opts.size; i++) { @@ -233,12 +233,14 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, } else if (v->type == kObjectTypeInteger) { details = v->data.integer; } else { - api_set_error(err, kErrorTypeValidation, "details is not an boolean"); - return rv; + VALIDATE_EXP(false, "details", "Boolean or Integer", api_typename(v->type), { + return rv; + }); } } else { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); - return rv; + VALIDATE_S(false, "key", k.data, { + return rv; + }); } } @@ -301,10 +303,9 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e return rv; } - if (!ns_initialized((uint32_t)ns_id)) { - api_set_error(err, kErrorTypeValidation, "Invalid ns_id"); + VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, { return rv; - } + }); Integer limit = -1; bool details = false; @@ -313,10 +314,9 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e String k = opts.items[i].key; Object *v = &opts.items[i].value; if (strequal("limit", k.data)) { - if (v->type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, "limit is not an integer"); + VALIDATE_T("limit", kObjectTypeInteger, v->type, { return rv; - } + }); limit = v->data.integer; } else if (strequal("details", k.data)) { if (v->type == kObjectTypeBoolean) { @@ -324,12 +324,14 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e } else if (v->type == kObjectTypeInteger) { details = v->data.integer; } else { - api_set_error(err, kErrorTypeValidation, "details is not an boolean"); - return rv; + VALIDATE_EXP(false, "details", "Boolean or Integer", api_typename(v->type), { + return rv; + }); } } else { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); - return rv; + VALIDATE_S(false, "key", k.data, { + return rv; + }); } } @@ -501,27 +503,26 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer goto error; } - if (!ns_initialized((uint32_t)ns_id)) { - api_set_error(err, kErrorTypeValidation, "Invalid ns_id"); + VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, { goto error; - } + }); uint32_t id = 0; if (opts->id.type == kObjectTypeInteger && opts->id.data.integer > 0) { id = (uint32_t)opts->id.data.integer; } else if (HAS_KEY(opts->id)) { - api_set_error(err, kErrorTypeValidation, "id is not a positive integer"); - goto error; + VALIDATE_S(false, "id (must be positive integer)", "", { + goto error; + }); } int line2 = -1; // For backward compatibility we support "end_line" as an alias for "end_row" if (HAS_KEY(opts->end_line)) { - if (HAS_KEY(opts->end_row)) { - api_set_error(err, kErrorTypeValidation, "cannot use both end_row and end_line"); + VALIDATE(!HAS_KEY(opts->end_row), "%s", "cannot use both 'end_row' and 'end_line'", { goto error; - } + }); opts->end_row = opts->end_line; } @@ -534,31 +535,29 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer bool strict = true; OPTION_TO_BOOL(strict, strict, true); - if (opts->end_row.type == kObjectTypeInteger) { + if (HAS_KEY(opts->end_row)) { + VALIDATE_T("end_row", kObjectTypeInteger, opts->end_row.type, { + goto error; + }); + Integer val = opts->end_row.data.integer; - if (val < 0 || (val > buf->b_ml.ml_line_count && strict)) { - api_set_error(err, kErrorTypeValidation, "end_row value outside range"); + VALIDATE_RANGE((val >= 0 && !(val > buf->b_ml.ml_line_count && strict)), "end_row", { goto error; - } else { - line2 = (int)val; - } - } else if (HAS_KEY(opts->end_row)) { - api_set_error(err, kErrorTypeValidation, "end_row is not an integer"); - goto error; + }); + line2 = (int)val; } colnr_T col2 = -1; - if (opts->end_col.type == kObjectTypeInteger) { + if (HAS_KEY(opts->end_col)) { + VALIDATE_T("end_col", kObjectTypeInteger, opts->end_col.type, { + goto error; + }); + Integer val = opts->end_col.data.integer; - if (val < 0 || val > MAXCOL) { - api_set_error(err, kErrorTypeValidation, "end_col value outside range"); + VALIDATE_RANGE((val >= 0 && val <= MAXCOL), "end_col", { goto error; - } else { - col2 = (int)val; - } - } else if (HAS_KEY(opts->end_col)) { - api_set_error(err, kErrorTypeValidation, "end_col is not an integer"); - goto error; + }); + col2 = (int)val; } // uncrustify:off @@ -588,31 +587,37 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } } - if (opts->conceal.type == kObjectTypeString) { + if (HAS_KEY(opts->conceal)) { + VALIDATE_T("conceal", kObjectTypeString, opts->conceal.type, { + goto error; + }); + String c = opts->conceal.data.string; decor.conceal = true; if (c.size) { decor.conceal_char = utf_ptr2char(c.data); } has_decor = true; - } else if (HAS_KEY(opts->conceal)) { - api_set_error(err, kErrorTypeValidation, "conceal is not a String"); - goto error; } - if (opts->virt_text.type == kObjectTypeArray) { + if (HAS_KEY(opts->virt_text)) { + VALIDATE_T("virt_text", kObjectTypeArray, opts->virt_text.type, { + goto error; + }); + decor.virt_text = parse_virt_text(opts->virt_text.data.array, err, &decor.virt_text_width); has_decor = true; if (ERROR_SET(err)) { goto error; } - } else if (HAS_KEY(opts->virt_text)) { - api_set_error(err, kErrorTypeValidation, "virt_text is not an Array"); - goto error; } - if (opts->virt_text_pos.type == kObjectTypeString) { + if (HAS_KEY(opts->virt_text_pos)) { + VALIDATE_T("virt_text_pos", kObjectTypeString, opts->virt_text_pos.type, { + goto error; + }); + String str = opts->virt_text_pos.data.string; if (strequal("eol", str.data)) { decor.virt_text_pos = kVTEndOfLine; @@ -621,21 +626,19 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } else if (strequal("right_align", str.data)) { decor.virt_text_pos = kVTRightAlign; } else { - api_set_error(err, kErrorTypeValidation, "virt_text_pos: invalid value"); - goto error; + VALIDATE_S(false, "virt_text_pos", "", { + goto error; + }); } - } else if (HAS_KEY(opts->virt_text_pos)) { - api_set_error(err, kErrorTypeValidation, "virt_text_pos is not a String"); - goto error; } - if (opts->virt_text_win_col.type == kObjectTypeInteger) { + if (HAS_KEY(opts->virt_text_win_col)) { + VALIDATE_T("virt_text_win_col", kObjectTypeInteger, opts->virt_text_win_col.type, { + goto error; + }); + decor.col = (int)opts->virt_text_win_col.data.integer; decor.virt_text_pos = kVTWinCol; - } else if (HAS_KEY(opts->virt_text_win_col)) { - api_set_error(err, kErrorTypeValidation, - "virt_text_win_col is not a Number of the correct size"); - goto error; } OPTION_TO_BOOL(decor.virt_text_hide, virt_text_hide, false); @@ -650,25 +653,29 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } else if (strequal("blend", str.data)) { decor.hl_mode = kHlModeBlend; } else { - api_set_error(err, kErrorTypeValidation, - "virt_text_pos: invalid value"); - goto error; + VALIDATE_S(false, "virt_text_pos", "", { + goto error; + }); } } else if (HAS_KEY(opts->hl_mode)) { - api_set_error(err, kErrorTypeValidation, "hl_mode is not a String"); - goto error; + VALIDATE_T("hl_mode", kObjectTypeString, opts->hl_mode.type, { + goto error; + }); } bool virt_lines_leftcol = false; OPTION_TO_BOOL(virt_lines_leftcol, virt_lines_leftcol, false); - if (opts->virt_lines.type == kObjectTypeArray) { + if (HAS_KEY(opts->virt_lines)) { + VALIDATE_T("virt_lines", kObjectTypeArray, opts->virt_lines.type, { + goto error; + }); + Array a = opts->virt_lines.data.array; for (size_t j = 0; j < a.size; j++) { - if (a.items[j].type != kObjectTypeArray) { - api_set_error(err, kErrorTypeValidation, "virt_text_line item is not an Array"); + VALIDATE_T("virt_text_line", kObjectTypeArray, a.items[j].type, { goto error; - } + }); int dummig; VirtText jtem = parse_virt_text(a.items[j].data.array, err, &dummig); kv_push(decor.virt_lines, ((struct virt_line){ jtem, virt_lines_leftcol })); @@ -677,36 +684,33 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } has_decor = true; } - } else if (HAS_KEY(opts->virt_lines)) { - api_set_error(err, kErrorTypeValidation, "virt_lines is not an Array"); - goto error; } OPTION_TO_BOOL(decor.virt_lines_above, virt_lines_above, false); - if (opts->priority.type == kObjectTypeInteger) { + if (HAS_KEY(opts->priority)) { + VALIDATE_T("priority", kObjectTypeInteger, opts->priority.type, { + goto error; + }); + Integer val = opts->priority.data.integer; - if (val < 0 || val > UINT16_MAX) { - api_set_error(err, kErrorTypeValidation, "priority is not a valid value"); + VALIDATE_RANGE((val >= 0 && val <= UINT16_MAX), "priority", { goto error; - } + }); decor.priority = (DecorPriority)val; - } else if (HAS_KEY(opts->priority)) { - api_set_error(err, kErrorTypeValidation, "priority is not a Number of the correct size"); - goto error; } - if (opts->sign_text.type == kObjectTypeString) { - if (!init_sign_text(&decor.sign_text, - opts->sign_text.data.string.data)) { - api_set_error(err, kErrorTypeValidation, "sign_text is not a valid value"); + if (HAS_KEY(opts->sign_text)) { + VALIDATE_T("sign_text", kObjectTypeString, opts->sign_text.type, { goto error; - } + }); + + VALIDATE_S(init_sign_text(&decor.sign_text, opts->sign_text.data.string.data), + "sign_text", "", { + goto error; + }); has_decor = true; - } else if (HAS_KEY(opts->sign_text)) { - api_set_error(err, kErrorTypeValidation, "sign_text is not a String"); - goto error; } bool right_gravity = true; @@ -714,11 +718,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer // Only error out if they try to set end_right_gravity without // setting end_col or end_row - if (line2 == -1 && col2 == -1 && HAS_KEY(opts->end_right_gravity)) { - api_set_error(err, kErrorTypeValidation, - "cannot set end_right_gravity without setting end_row or end_col"); + VALIDATE(!(line2 == -1 && col2 == -1 && HAS_KEY(opts->end_right_gravity)), + "%s", "cannot set end_right_gravity without end_row or end_col", { goto error; - } + }); bool end_right_gravity = false; OPTION_TO_BOOL(end_right_gravity, end_right_gravity, false); @@ -728,7 +731,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer bool ephemeral = false; OPTION_TO_BOOL(ephemeral, ephemeral, false); - if (opts->spell.type == kObjectTypeNil) { + if (!HAS_KEY(opts->spell)) { decor.spell = kNone; } else { bool spell = false; @@ -742,16 +745,15 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer has_decor = true; } - if (line < 0) { - api_set_error(err, kErrorTypeValidation, "line value outside range"); + VALIDATE_RANGE((line >= 0), "line", { goto error; - } else if (line > buf->b_ml.ml_line_count) { - if (strict) { - api_set_error(err, kErrorTypeValidation, "line value outside range"); + }); + + if (line > buf->b_ml.ml_line_count) { + VALIDATE_RANGE(!strict, "line", { goto error; - } else { - line = buf->b_ml.ml_line_count; - } + }); + line = buf->b_ml.ml_line_count; } else if (line < buf->b_ml.ml_line_count) { len = ephemeral ? MAXCOL : strlen(ml_get_buf(buf, (linenr_T)line + 1, false)); } @@ -759,15 +761,14 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer if (col == -1) { col = (Integer)len; } else if (col > (Integer)len) { - if (strict) { - api_set_error(err, kErrorTypeValidation, "col value outside range"); + VALIDATE_RANGE(!strict, "col", { goto error; - } else { - col = (Integer)len; - } + }); + col = (Integer)len; } else if (col < -1) { - api_set_error(err, kErrorTypeValidation, "col value outside range"); - goto error; + VALIDATE_RANGE(false, "col", { + goto error; + }); } if (col2 >= 0) { @@ -781,12 +782,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer line2 = (int)line; } if (col2 > (Integer)len) { - if (strict) { - api_set_error(err, kErrorTypeValidation, "end_col value outside range"); + VALIDATE_RANGE(!strict, "end_col", { goto error; - } else { - col2 = (int)len; - } + }); + col2 = (int)len; } } else if (line2 >= 0) { col2 = 0; @@ -829,10 +828,9 @@ Boolean nvim_buf_del_extmark(Buffer buffer, Integer ns_id, Integer id, Error *er if (!buf) { return false; } - if (!ns_initialized((uint32_t)ns_id)) { - api_set_error(err, kErrorTypeValidation, "Invalid ns_id"); + VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, { return false; - } + }); return extmark_del(buf, (uint32_t)ns_id, (uint32_t)id); } @@ -887,14 +885,13 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In return 0; } - if (line < 0 || line >= MAXLNUM) { - api_set_error(err, kErrorTypeValidation, "Line number outside range"); + VALIDATE_RANGE((line >= 0 && line < MAXLNUM), "line number", { return 0; - } - if (col_start < 0 || col_start > MAXCOL) { - api_set_error(err, kErrorTypeValidation, "Column value outside range"); + }); + VALIDATE_RANGE((col_start >= 0 && col_start <= MAXCOL), "column", { return 0; - } + }); + if (col_end < 0 || col_end > MAXCOL) { col_end = MAXCOL; } @@ -950,10 +947,10 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, return; } - if (line_start < 0 || line_start >= MAXLNUM) { - api_set_error(err, kErrorTypeValidation, "Line number outside range"); + VALIDATE_RANGE((line_start >= 0 && line_start < MAXLNUM), "line number", { return; - } + }); + if (line_end < 0 || line_end > MAXLNUM) { line_end = MAXLNUM; } @@ -1034,11 +1031,10 @@ void nvim_set_decoration_provider(Integer ns_id, Dict(set_decoration_provider) * continue; } - if (v->type != kObjectTypeLuaRef) { - api_set_error(err, kErrorTypeValidation, - "%s is not a function", cbs[i].name); + VALIDATE_T(cbs[i].name, kObjectTypeLuaRef, v->type, { goto error; - } + }); + *(cbs[i].dest) = v->data.luaref; v->data.luaref = LUA_NOREF; } @@ -1075,39 +1071,39 @@ static bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, in *col = MAXCOL; return true; } else if (id < 0) { - api_set_error(err, kErrorTypeValidation, "Mark id must be positive"); - return false; + VALIDATE_INT(false, "mark id", id, { + return false; + }); } ExtmarkInfo extmark = extmark_from_id(buf, (uint32_t)ns_id, (uint32_t)id); - if (extmark.row >= 0) { - *row = extmark.row; - *col = extmark.col; - return true; - } else { - api_set_error(err, kErrorTypeValidation, "No mark with requested id"); + + VALIDATE_INT((extmark.row >= 0), "mark id (not found)", id, { return false; - } + }); + *row = extmark.row; + *col = extmark.col; + return true; // Check if it is a position } else if (obj.type == kObjectTypeArray) { Array pos = obj.data.array; - if (pos.size != 2 - || pos.items[0].type != kObjectTypeInteger - || pos.items[1].type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, - "Position must have 2 integer elements"); + VALIDATE((pos.size == 2 + && pos.items[0].type == kObjectTypeInteger + && pos.items[1].type == kObjectTypeInteger), + "%s", "Invalid position: expected 2 Integer items", { return false; - } + }); + Integer pos_row = pos.items[0].data.integer; Integer pos_col = pos.items[1].data.integer; *row = (int)(pos_row >= 0 ? pos_row : MAXLNUM); *col = (colnr_T)(pos_col >= 0 ? pos_col : MAXCOL); return true; } else { - api_set_error(err, kErrorTypeValidation, - "Position must be a mark id Integer or position Array"); - return false; + VALIDATE(false, "%s", "Invalid position: expected mark id Integer or 2-item Array", { + return false; + }); } } // adapted from sign.c:sign_define_init_text. @@ -1151,17 +1147,14 @@ VirtText parse_virt_text(Array chunks, Error *err, int *width) VirtText virt_text = KV_INITIAL_VALUE; int w = 0; for (size_t i = 0; i < chunks.size; i++) { - if (chunks.items[i].type != kObjectTypeArray) { - api_set_error(err, kErrorTypeValidation, "Chunk is not an array"); + VALIDATE_T("chunk", kObjectTypeArray, chunks.items[i].type, { goto free_exit; - } + }); Array chunk = chunks.items[i].data.array; - if (chunk.size == 0 || chunk.size > 2 - || chunk.items[0].type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "Chunk is not an array with one or two strings"); + VALIDATE((chunk.size > 0 && chunk.size <= 2 && chunk.items[0].type == kObjectTypeString), + "%s", "Invalid chunk: expected Array with 1 or 2 Strings", { goto free_exit; - } + }); String str = chunk.items[0].data.string; diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index bfcb99754f..40720c31c7 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -9,6 +9,7 @@ #include "nvim/api/options.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/eval/window.h" @@ -25,54 +26,56 @@ static int validate_option_value_args(Dict(option) *opts, int *scope, int *opt_type, void **from, Error *err) { - if (opts->scope.type == kObjectTypeString) { + if (HAS_KEY(opts->scope)) { + VALIDATE_T("scope", kObjectTypeString, opts->scope.type, { + return FAIL; + }); + if (!strcmp(opts->scope.data.string.data, "local")) { *scope = OPT_LOCAL; } else if (!strcmp(opts->scope.data.string.data, "global")) { *scope = OPT_GLOBAL; } else { - api_set_error(err, kErrorTypeValidation, "invalid scope: must be 'local' or 'global'"); - return FAIL; + VALIDATE(false, "%s", "Invalid scope: expected 'local' or 'global'", { + return FAIL; + }); } - } else if (HAS_KEY(opts->scope)) { - api_set_error(err, kErrorTypeValidation, "invalid value for key: scope"); - return FAIL; } *opt_type = SREQ_GLOBAL; - if (opts->win.type == kObjectTypeInteger) { + if (HAS_KEY(opts->win)) { + VALIDATE_T("win", kObjectTypeInteger, opts->win.type, { + return FAIL; + }); + *opt_type = SREQ_WIN; *from = find_window_by_handle((int)opts->win.data.integer, err); if (ERROR_SET(err)) { return FAIL; } - } else if (HAS_KEY(opts->win)) { - api_set_error(err, kErrorTypeValidation, "invalid value for key: win"); - return FAIL; } - if (opts->buf.type == kObjectTypeInteger) { + if (HAS_KEY(opts->buf)) { + VALIDATE_T("buf", kObjectTypeInteger, opts->buf.type, { + return FAIL; + }); + *scope = OPT_LOCAL; *opt_type = SREQ_BUF; *from = find_buffer_by_handle((int)opts->buf.data.integer, err); if (ERROR_SET(err)) { return FAIL; } - } else if (HAS_KEY(opts->buf)) { - api_set_error(err, kErrorTypeValidation, "invalid value for key: buf"); - return FAIL; } - if (HAS_KEY(opts->scope) && HAS_KEY(opts->buf)) { - api_set_error(err, kErrorTypeValidation, "scope and buf cannot be used together"); + VALIDATE((!HAS_KEY(opts->scope) || !HAS_KEY(opts->buf)), "%s", + "cannot use both 'scope' and 'buf'", { return FAIL; - } - - if (HAS_KEY(opts->win) && HAS_KEY(opts->buf)) { - api_set_error(err, kErrorTypeValidation, "buf and win cannot be used together"); + }); + VALIDATE((!HAS_KEY(opts->win) || !HAS_KEY(opts->buf)), "%s", "cannot use both 'buf' and 'win'", { return FAIL; - } + }); return OK; } @@ -132,8 +135,9 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) } break; default: - api_set_error(err, kErrorTypeValidation, "unknown option '%s'", name.data); - return rv; + VALIDATE_S(false, "option", name.data, { + return rv; + }); } return rv; @@ -181,7 +185,7 @@ void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error switch (value.type) { case kObjectTypeInteger: - numval = value.data.integer; + numval = (long)value.data.integer; break; case kObjectTypeBoolean: numval = value.data.boolean ? 1 : 0; @@ -193,8 +197,9 @@ void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error scope |= OPT_CLEAR; break; default: - api_set_error(err, kErrorTypeValidation, "invalid value for option"); - return; + VALIDATE_EXP(false, "option type", "Integer, Boolean, or String", api_typename(value.type), { + return; + }); } access_option_value_for(name.data, &numval, &stringval, scope, opt_type, to, false, err); @@ -351,21 +356,18 @@ static Object get_option_from(void *from, int type, String name, Error *err) { Object rv = OBJECT_INIT; - if (name.size == 0) { - api_set_error(err, kErrorTypeValidation, "Empty option name"); + VALIDATE_S(name.size > 0, "option name", "<empty>", { return rv; - } + }); // Return values int64_t numval; char *stringval = NULL; - int flags = get_option_value_strict(name.data, &numval, &stringval, type, from); - if (!flags) { - api_set_error(err, kErrorTypeValidation, "Invalid option name: '%s'", - name.data); + int flags = get_option_value_strict(name.data, &numval, &stringval, type, from); + VALIDATE_S(flags != 0, "option name", name.data, { return rv; - } + }); if (flags & SOPT_BOOL) { rv.type = kObjectTypeBoolean; @@ -374,20 +376,15 @@ static Object get_option_from(void *from, int type, String name, Error *err) rv.type = kObjectTypeInteger; rv.data.integer = numval; } else if (flags & SOPT_STRING) { - if (stringval) { - rv.type = kObjectTypeString; - rv.data.string.data = stringval; - rv.data.string.size = strlen(stringval); - } else { - api_set_error(err, kErrorTypeException, - "Failed to get value for option '%s'", - name.data); + if (!stringval) { + api_set_error(err, kErrorTypeException, "Failed to get option '%s'", name.data); + return rv; } + rv.type = kObjectTypeString; + rv.data.string.data = stringval; + rv.data.string.size = strlen(stringval); } else { - api_set_error(err, - kErrorTypeException, - "Unknown type for option '%s'", - name.data); + api_set_error(err, kErrorTypeException, "Unknown type for option '%s'", name.data); } return rv; @@ -402,29 +399,22 @@ static Object get_option_from(void *from, int type, String name, Error *err) /// @param[out] err Details of an error that may have occurred void set_option_to(uint64_t channel_id, void *to, int type, String name, Object value, Error *err) { - if (name.size == 0) { - api_set_error(err, kErrorTypeValidation, "Empty option name"); + VALIDATE_S(name.size > 0, "option name", "<empty>", { return; - } + }); int flags = get_option_value_strict(name.data, NULL, NULL, type, to); - - if (flags == 0) { - api_set_error(err, kErrorTypeValidation, "Invalid option name '%s'", - name.data); + VALIDATE_S(flags != 0, "option name", name.data, { return; - } + }); if (value.type == kObjectTypeNil) { if (type == SREQ_GLOBAL) { - api_set_error(err, kErrorTypeException, "Cannot unset option '%s'", - name.data); + api_set_error(err, kErrorTypeException, "Cannot unset option '%s'", name.data); return; } else if (!(flags & SOPT_GLOBAL)) { - api_set_error(err, - kErrorTypeException, - "Cannot unset option '%s' " - "because it doesn't have a global value", + api_set_error(err, kErrorTypeException, + "Cannot unset option '%s' because it doesn't have a global value", name.data); return; } else { @@ -437,39 +427,23 @@ void set_option_to(uint64_t channel_id, void *to, int type, String name, Object char *stringval = NULL; if (flags & SOPT_BOOL) { - if (value.type != kObjectTypeBoolean) { - api_set_error(err, - kErrorTypeValidation, - "Option '%s' requires a Boolean value", - name.data); + VALIDATE(value.type == kObjectTypeBoolean, "Option '%s' value must be Boolean", name.data, { return; - } - + }); numval = value.data.boolean; } else if (flags & SOPT_NUM) { - if (value.type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, - "Option '%s' requires an integer value", - name.data); + VALIDATE(value.type == kObjectTypeInteger, "Option '%s' value must be Integer", name.data, { return; - } - - if (value.data.integer > INT_MAX || value.data.integer < INT_MIN) { - api_set_error(err, kErrorTypeValidation, - "Value for option '%s' is out of range", - name.data); + }); + VALIDATE((value.data.integer <= INT_MAX && value.data.integer >= INT_MIN), + "Option '%s' value is out of range", name.data, { return; - } - + }); numval = (int)value.data.integer; } else { - if (value.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "Option '%s' requires a string value", - name.data); + VALIDATE(value.type == kObjectTypeString, "Option '%s' value must be String", name.data, { return; - } - + }); stringval = value.data.string.data; } diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 519f2cc5bf..c996e19eb9 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -821,12 +821,41 @@ int object_to_hl_id(Object obj, const char *what, Error *err) } else if (obj.type == kObjectTypeInteger) { return MAX((int)obj.data.integer, 0); } else { - api_set_error(err, kErrorTypeValidation, - "%s is not a valid highlight", what); + api_set_error(err, kErrorTypeValidation, "Invalid highlight: %s", what); return 0; } } +char *api_typename(ObjectType t) +{ + switch (t) { + case kObjectTypeNil: + return "nil"; + case kObjectTypeBoolean: + return "Boolean"; + case kObjectTypeInteger: + return "Integer"; + case kObjectTypeFloat: + return "Float"; + case kObjectTypeString: + return "String"; + case kObjectTypeArray: + return "Array"; + case kObjectTypeDictionary: + return "Dict"; + case kObjectTypeLuaRef: + return "Function"; + case kObjectTypeBuffer: + return "Buffer"; + case kObjectTypeWindow: + return "Window"; + case kObjectTypeTabpage: + return "Tabpage"; + default: + abort(); + } +} + HlMessage parse_hl_msg(Array chunks, Error *err) { HlMessage hl_msg = KV_INITIAL_VALUE; diff --git a/src/nvim/api/private/validate.c b/src/nvim/api/private/validate.c new file mode 100644 index 0000000000..41c9472a39 --- /dev/null +++ b/src/nvim/api/private/validate.c @@ -0,0 +1,28 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + +#include "nvim/api/private/defs.h" +#include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "api/private/validate.c.generated.h" +#endif + +bool check_string_array(Array arr, char *name, bool disallow_nl, Error *err) +{ + snprintf(IObuff, sizeof(IObuff), "'%s' item", name); + for (size_t i = 0; i < arr.size; i++) { + VALIDATE_T(IObuff, kObjectTypeString, arr.items[i].type, { + return false; + }); + // Disallow newlines in the middle of the line. + if (disallow_nl) { + const String l = arr.items[i].data.string; + VALIDATE(!memchr(l.data, NL, l.size), "'%s' item contains newlines", name, { + return false; + }); + } + } + return true; +} diff --git a/src/nvim/api/private/validate.h b/src/nvim/api/private/validate.h new file mode 100644 index 0000000000..4a1b99408e --- /dev/null +++ b/src/nvim/api/private/validate.h @@ -0,0 +1,68 @@ +#ifndef NVIM_API_PRIVATE_VALIDATE_H +#define NVIM_API_PRIVATE_VALIDATE_H + +#include "nvim/api/private/defs.h" +#include "nvim/api/private/helpers.h" + +#define VALIDATE_INT(cond, name, val_, code) \ + do { \ + if (!(cond)) { \ + api_set_error(err, kErrorTypeValidation, "Invalid " name ": %" PRId64, val_); \ + code; \ + } \ + } while (0) + +#define VALIDATE_S(cond, name, val_, code) \ + do { \ + if (!(cond)) { \ + if (strequal(val_, "")) { \ + api_set_error(err, kErrorTypeValidation, "Invalid " name); \ + } else { \ + api_set_error(err, kErrorTypeValidation, "Invalid " name ": '%s'", val_); \ + } \ + code; \ + } \ + } while (0) + +#define VALIDATE_EXP(cond, name, expected, actual, code) \ + do { \ + if (!(cond)) { \ + api_set_error(err, kErrorTypeValidation, "Invalid %s: expected %s, got %s", \ + name, expected, actual); \ + code; \ + } \ + } while (0) + +#define VALIDATE_T(name, expected_t, actual_t, code) \ + do { \ + if (expected_t != actual_t) { \ + api_set_error(err, kErrorTypeValidation, "Invalid %s: expected %s, got %s", \ + name, api_typename(expected_t), api_typename(actual_t)); \ + code; \ + } \ + } while (0) + +#define VALIDATE(cond, fmt_, fmt_arg1, code) \ + do { \ + if (!(cond)) { \ + api_set_error(err, kErrorTypeValidation, fmt_, fmt_arg1); \ + code; \ + } \ + } while (0) + +#define VALIDATE_RANGE(cond, name, code) \ + do { \ + if (!(cond)) { \ + api_set_error(err, kErrorTypeValidation, "Invalid '%s': out of range", name); \ + code; \ + } \ + } while (0) + +#define VALIDATE_R(cond, name, code) \ + VALIDATE(cond, "Required: '%s'", name, code); + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "api/private/validate.h.generated.h" +#endif + +#endif // NVIM_API_PRIVATE_VALIDATE_H diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index e67607a7e4..61f2c881b3 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -12,6 +12,7 @@ #include "klib/kvec.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/api/ui.h" #include "nvim/autocmd.h" #include "nvim/channel.h" @@ -202,6 +203,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona data->flushed_events = false; data->ncalls_pos = NULL; data->ncalls = 0; + data->ncells_pending = 0; data->buf_wptr = data->buf; data->temp_buf = NULL; data->wildmenu_active = false; @@ -290,22 +292,20 @@ void nvim_ui_set_option(uint64_t channel_id, String name, Object value, Error *e ui_set_option(ui, false, name, value, error); } -static void ui_set_option(UI *ui, bool init, String name, Object value, Error *error) +static void ui_set_option(UI *ui, bool init, String name, Object value, Error *err) { if (strequal(name.data, "override")) { - if (value.type != kObjectTypeBoolean) { - api_set_error(error, kErrorTypeValidation, "override must be a Boolean"); + VALIDATE_T("override", kObjectTypeBoolean, value.type, { return; - } + }); ui->override = value.data.boolean; return; } if (strequal(name.data, "rgb")) { - if (value.type != kObjectTypeBoolean) { - api_set_error(error, kErrorTypeValidation, "rgb must be a Boolean"); + VALIDATE_T("rgb", kObjectTypeBoolean, value.type, { return; - } + }); ui->rgb = value.data.boolean; // A little drastic, but only takes effect for legacy uis. For linegrid UI // only changes metadata for nvim_list_uis(), no refresh needed. @@ -316,62 +316,56 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e } if (strequal(name.data, "term_name")) { - if (value.type != kObjectTypeString) { - api_set_error(error, kErrorTypeValidation, "term_name must be a String"); + VALIDATE_T("term_name", kObjectTypeString, value.type, { return; - } + }); set_tty_option("term", string_to_cstr(value.data.string)); return; } if (strequal(name.data, "term_colors")) { - if (value.type != kObjectTypeInteger) { - api_set_error(error, kErrorTypeValidation, "term_colors must be a Integer"); + VALIDATE_T("term_colors", kObjectTypeInteger, value.type, { return; - } + }); t_colors = (int)value.data.integer; return; } if (strequal(name.data, "term_background")) { - if (value.type != kObjectTypeString) { - api_set_error(error, kErrorTypeValidation, "term_background must be a String"); + VALIDATE_T("term_background", kObjectTypeString, value.type, { return; - } + }); set_tty_background(value.data.string.data); return; } if (strequal(name.data, "stdin_fd")) { - if (value.type != kObjectTypeInteger || value.data.integer < 0) { - api_set_error(error, kErrorTypeValidation, "stdin_fd must be a non-negative Integer"); + VALIDATE_T("stdin_fd", kObjectTypeInteger, value.type, { return; - } - - if (starting != NO_SCREEN) { - api_set_error(error, kErrorTypeValidation, - "stdin_fd can only be used with first attached ui"); + }); + VALIDATE_INT((value.data.integer >= 0), "stdin_fd", value.data.integer, { return; - } + }); + VALIDATE((starting == NO_SCREEN), "%s", "stdin_fd can only be used with first attached UI", { + return; + }); stdin_fd = (int)value.data.integer; return; } if (strequal(name.data, "stdin_tty")) { - if (value.type != kObjectTypeBoolean) { - api_set_error(error, kErrorTypeValidation, "stdin_tty must be a Boolean"); + VALIDATE_T("stdin_tty", kObjectTypeBoolean, value.type, { return; - } + }); stdin_isatty = value.data.boolean; return; } if (strequal(name.data, "stdout_tty")) { - if (value.type != kObjectTypeBoolean) { - api_set_error(error, kErrorTypeValidation, "stdout_tty must be a Boolean"); + VALIDATE_T("stdout_tty", kObjectTypeBoolean, value.type, { return; - } + }); stdout_isatty = value.data.boolean; return; } @@ -382,17 +376,15 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e for (UIExtension i = 0; i < kUIExtCount; i++) { if (strequal(name.data, ui_ext_names[i]) || (i == kUIPopupmenu && is_popupmenu)) { - if (value.type != kObjectTypeBoolean) { - api_set_error(error, kErrorTypeValidation, "%s must be a Boolean", - name.data); + VALIDATE_EXP((value.type == kObjectTypeBoolean), name.data, "Boolean", + api_typename(value.type), { return; - } + }); bool boolval = value.data.boolean; if (!init && i == kUILinegrid && boolval != ui->ui_ext[i]) { // There shouldn't be a reason for an UI to do this ever // so explicitly don't support this. - api_set_error(error, kErrorTypeValidation, - "ext_linegrid option cannot be changed"); + api_set_error(err, kErrorTypeValidation, "ext_linegrid option cannot be changed"); } ui->ui_ext[i] = boolval; if (!init) { @@ -402,8 +394,7 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e } } - api_set_error(error, kErrorTypeValidation, "No such UI option: %s", - name.data); + api_set_error(err, kErrorTypeValidation, "No such UI option: %s", name.data); } /// Tell Nvim to resize a grid. Triggers a grid_resize event with the requested @@ -644,6 +635,8 @@ void remote_ui_grid_resize(UI *ui, Integer grid, Integer width, Integer height) Array args = data->call_buf; if (ui->ui_ext[kUILinegrid]) { ADD_C(args, INTEGER_OBJ(grid)); + } else { + data->client_col = -1; // force cursor update } ADD_C(args, INTEGER_OBJ(width)); ADD_C(args, INTEGER_OBJ(height)); @@ -854,18 +847,25 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int mpack_uint(buf, repeat); } } + data->ncells_pending += MIN(repeat, 2); last_hl = attrs[i]; repeat = 0; } } if (endcol < clearcol) { nelem++; + data->ncells_pending += 1; mpack_array(buf, 3); mpack_str(buf, " "); mpack_uint(buf, (uint32_t)clearattr); mpack_uint(buf, (uint32_t)(clearcol - endcol)); } mpack_w2(&lenpos, nelem); + + if (data->ncells_pending > 500) { + // pass of cells to UI to let it start processing them + remote_ui_flush_buf(ui); + } } else { for (int i = 0; i < endcol - startcol; i++) { remote_ui_cursor_goto(ui, row, startcol + i); @@ -917,6 +917,8 @@ void remote_ui_flush_buf(UI *ui) // we have sent events to the client, but possibly not yet the final "flush" // event. data->flushed_events = true; + + data->ncells_pending = 0; } /// An intentional flush (vsync) when Nvim is finished redrawing the screen diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index a53b30dd8a..50683ac403 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -18,6 +18,7 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/api/vim.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" @@ -86,10 +87,9 @@ Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *er Dictionary result = ARRAY_DICT_INIT; int id = syn_name2id(name.data); - if (id == 0) { - api_set_error(err, kErrorTypeException, "Invalid highlight name: %s", name.data); + VALIDATE_S((id != 0), "highlight name", name.data, { return result; - } + }); return nvim_get_hl_by_id(id, rgb, arena, err); } @@ -103,10 +103,9 @@ Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *er FUNC_API_SINCE(3) { Dictionary dic = ARRAY_DICT_INIT; - if (syn_get_final_id((int)hl_id) == 0) { - api_set_error(err, kErrorTypeException, "Invalid highlight id: %" PRId64, hl_id); + VALIDATE_INT((syn_get_final_id((int)hl_id) != 0), "highlight id", hl_id, { return dic; - } + }); int attrcode = syn_id2attr((int)hl_id); return hl_get_attr_by_id(attrcode, rgb, arena, err); } @@ -173,10 +172,9 @@ void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err) FUNC_API_SINCE(7) { int hl_id = syn_check_group(name.data, name.size); - if (hl_id == 0) { - api_set_error(err, kErrorTypeException, "Invalid highlight name: %s", name.data); + VALIDATE_S((hl_id != 0), "highlight name", name.data, { return; - } + }); int link_id = -1; HlAttrs attrs = dict2hlattrs(val, true, &link_id, err); @@ -193,10 +191,9 @@ void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err) void nvim_set_hl_ns(Integer ns_id, Error *err) FUNC_API_SINCE(10) { - if (ns_id < 0) { - api_set_error(err, kErrorTypeValidation, "no such namespace"); + VALIDATE_INT((ns_id >= 0), "namespace", ns_id, { return; - } + }); ns_hl_global = (NS)ns_id; hl_check_ns(); @@ -403,11 +400,9 @@ void nvim_input_mouse(String button, String action, String modifier, Integer gri continue; } int mod = name_to_mod_mask(byte); - if (mod == 0) { - api_set_error(err, kErrorTypeValidation, - "invalid modifier %c", byte); + VALIDATE((mod != 0), "Invalid modifier: %c", byte, { return; - } + }); modmask |= mod; } @@ -500,10 +495,9 @@ Object nvim_notify(String msg, Integer log_level, Dictionary opts, Error *err) Integer nvim_strwidth(String text, Error *err) FUNC_API_SINCE(1) { - if (text.size > INT_MAX) { - api_set_error(err, kErrorTypeValidation, "String is too long"); + VALIDATE_S((text.size <= INT_MAX), "text length", "(too long)", { return 0; - } + }); return (Integer)mb_string2cells(text.data); } @@ -554,7 +548,7 @@ static void find_runtime_cb(char *fname, void *cookie) { Array *rv = (Array *)cookie; if (fname != NULL) { - ADD(*rv, STRING_OBJ(cstr_to_string((char *)fname))); + ADD(*rv, STRING_OBJ(cstr_to_string(fname))); } } @@ -575,10 +569,7 @@ ArrayOf(String) nvim__get_runtime(Array pat, Boolean all, Dict(runtime) *opts, E { bool is_lua = api_object_to_bool(opts->is_lua, "is_lua", false, err); bool source = api_object_to_bool(opts->do_source, "do_source", false, err); - if (source && !nlua_is_deferred_safe()) { - api_set_error(err, kErrorTypeValidation, "'do_source' cannot be used in fast callback"); - } - + VALIDATE((!source || nlua_is_deferred_safe()), "%s", "'do_source' used in fast callback", {}); if (ERROR_SET(err)) { return (Array)ARRAY_DICT_INIT; } @@ -602,10 +593,9 @@ ArrayOf(String) nvim__get_runtime(Array pat, Boolean all, Dict(runtime) *opts, E void nvim_set_current_dir(String dir, Error *err) FUNC_API_SINCE(1) { - if (dir.size >= MAXPATHL) { - api_set_error(err, kErrorTypeValidation, "Directory name is too long"); + VALIDATE_S((dir.size < MAXPATHL), "directory name", "(too long)", { return; - } + }); char string[MAXPATHL]; memcpy(string, dir.data, dir.size); @@ -664,16 +654,14 @@ Object nvim_get_var(String name, Error *err) { dictitem_T *di = tv_dict_find(&globvardict, name.data, (ptrdiff_t)name.size); if (di == NULL) { // try to autoload script - if (!script_autoload(name.data, name.size, false) || aborting()) { - api_set_error(err, kErrorTypeValidation, "Key not found: %s", name.data); + VALIDATE_S((script_autoload(name.data, name.size, false) && !aborting()), "key", name.data, { return (Object)OBJECT_INIT; - } + }); di = tv_dict_find(&globvardict, name.data, (ptrdiff_t)name.size); } - if (di == NULL) { - api_set_error(err, kErrorTypeValidation, "Key not found: %s", name.data); + VALIDATE_S((di != NULL), "key (not found)", name.data, { return (Object)OBJECT_INIT; - } + }); return vim_to_object(&di->di_tv); } @@ -991,16 +979,14 @@ Integer nvim_open_term(Buffer buffer, DictionaryOf(LuaRef) opts, Error *err) String k = opts.items[i].key; Object *v = &opts.items[i].value; if (strequal("on_input", k.data)) { - if (v->type != kObjectTypeLuaRef) { - api_set_error(err, kErrorTypeValidation, - "%s is not a function", "on_input"); + VALIDATE_T("on_input", kObjectTypeLuaRef, v->type, { return 0; - } + }); cb = v->data.luaref; v->data.luaref = LUA_NOREF; break; } else { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); + VALIDATE_S(false, "key", k.data, {}); } } @@ -1075,9 +1061,7 @@ void nvim_chan_send(Integer chan, String data, Error *err) channel_send((uint64_t)chan, data.data, data.size, false, &error); - if (error) { - api_set_error(err, kErrorTypeValidation, "%s", error); - } + VALIDATE(!error, "%s", error, {}); } /// Gets the current list of tabpage handles. @@ -1164,10 +1148,9 @@ Boolean nvim_paste(String data, Boolean crlf, Integer phase, Error *err) static bool draining = false; bool cancel = false; - if (phase < -1 || phase > 3) { - api_set_error(err, kErrorTypeValidation, "Invalid phase: %" PRId64, phase); + VALIDATE_INT((phase >= -1 && phase <= 3), "phase", phase, { return false; - } + }); Array args = ARRAY_DICT_INIT; Object rv = OBJECT_INIT; if (phase == -1 || phase == 1) { // Start of paste-stream. @@ -1234,20 +1217,17 @@ void nvim_put(ArrayOf(String) lines, String type, Boolean after, Boolean follow, FUNC_API_CHECK_TEXTLOCK { yankreg_T *reg = xcalloc(1, sizeof(yankreg_T)); - if (!prepare_yankreg_from_object(reg, type, lines.size)) { - api_set_error(err, kErrorTypeValidation, "Invalid type: '%s'", type.data); + VALIDATE_S((prepare_yankreg_from_object(reg, type, lines.size)), "type", type.data, { goto cleanup; - } + }); if (lines.size == 0) { goto cleanup; // Nothing to do. } for (size_t i = 0; i < lines.size; i++) { - if (lines.items[i].type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "Invalid lines (expected array of strings)"); + VALIDATE_T("line", kObjectTypeString, lines.items[i].type, { goto cleanup; - } + }); String line = lines.items[i].data.string; reg->y_array[i] = xmemdupz(line.data, line.size); memchrsub(reg->y_array[i], NUL, NL, line.size); @@ -1348,11 +1328,11 @@ Dictionary nvim_get_context(Dict(context) *opts, Error *err) FUNC_API_SINCE(6) { Array types = ARRAY_DICT_INIT; - if (opts->types.type == kObjectTypeArray) { + if (HAS_KEY(opts->types)) { + VALIDATE_T("types", kObjectTypeArray, opts->types.type, { + return (Dictionary)ARRAY_DICT_INIT; + }); types = opts->types.data.array; - } else if (opts->types.type != kObjectTypeNil) { - api_set_error(err, kErrorTypeValidation, "invalid value for key: types"); - return (Dictionary)ARRAY_DICT_INIT; } int int_types = types.size > 0 ? 0 : kCtxAll; @@ -1373,8 +1353,9 @@ Dictionary nvim_get_context(Dict(context) *opts, Error *err) } else if (strequal(s, "funcs")) { int_types |= kCtxFuncs; } else { - api_set_error(err, kErrorTypeValidation, "unexpected type: %s", s); - return (Dictionary)ARRAY_DICT_INIT; + VALIDATE_S(false, "type", s, { + return (Dictionary)ARRAY_DICT_INIT; + }); } } } @@ -1651,34 +1632,20 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Arena *arena, Error *er size_t i; // also used for freeing the variables for (i = 0; i < calls.size; i++) { - if (calls.items[i].type != kObjectTypeArray) { - api_set_error(err, - kErrorTypeValidation, - "Items in calls array must be arrays"); + VALIDATE_T("calls item", kObjectTypeArray, calls.items[i].type, { goto theend; - } + }); Array call = calls.items[i].data.array; - if (call.size != 2) { - api_set_error(err, - kErrorTypeValidation, - "Items in calls array must be arrays of size 2"); + VALIDATE((call.size == 2), "%s", "calls item must be a 2-item Array", { goto theend; - } - - if (call.items[0].type != kObjectTypeString) { - api_set_error(err, - kErrorTypeValidation, - "Name must be String"); + }); + VALIDATE_T("name", kObjectTypeString, call.items[0].type, { goto theend; - } + }); String name = call.items[0].data.string; - - if (call.items[1].type != kObjectTypeArray) { - api_set_error(err, - kErrorTypeValidation, - "Args must be Array"); + VALIDATE_T("args", kObjectTypeArray, call.items[1].type, { goto theend; - } + }); Array args = call.items[1].data.array; MsgpackRpcRequestHandler handler = @@ -1850,10 +1817,9 @@ Array nvim_get_proc_children(Integer pid, Error *err) Array rvobj = ARRAY_DICT_INIT; int *proc_list = NULL; - if (pid <= 0 || pid > INT_MAX) { - api_set_error(err, kErrorTypeException, "Invalid pid: %" PRId64, pid); + VALIDATE_INT((pid > 0 && pid <= INT_MAX), "pid", pid, { goto end; - } + }); size_t proc_count; int rv = os_proc_children((int)pid, &proc_list, &proc_count); @@ -1892,10 +1858,10 @@ Object nvim_get_proc(Integer pid, Error *err) rvobj.data.dictionary = (Dictionary)ARRAY_DICT_INIT; rvobj.type = kObjectTypeDictionary; - if (pid <= 0 || pid > INT_MAX) { - api_set_error(err, kErrorTypeException, "Invalid pid: %" PRId64, pid); + VALIDATE_INT((pid > 0 && pid <= INT_MAX), "pid", pid, { return NIL; - } + }); + #ifdef MSWIN rvobj.data.dictionary = os_proc_info((int)pid); if (rvobj.data.dictionary.size == 0) { // Process not found. @@ -1937,10 +1903,9 @@ void nvim_select_popupmenu_item(Integer item, Boolean insert, Boolean finish, Di Error *err) FUNC_API_SINCE(6) { - if (opts.size > 0) { - api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); + VALIDATE((opts.size == 0), "%s", "opts dict isn't empty", { return; - } + }); if (finish) { insert = true; @@ -1961,13 +1926,10 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Arena *arena, E g = &pum_grid; } else if (grid > 1) { win_T *wp = get_win_by_grid_handle((handle_T)grid); - if (wp != NULL && wp->w_grid_alloc.chars != NULL) { - g = &wp->w_grid_alloc; - } else { - api_set_error(err, kErrorTypeValidation, - "No grid with the given handle"); + VALIDATE_INT((wp != NULL && wp->w_grid_alloc.chars != NULL), "grid handle", grid, { return ret; - } + }); + g = &wp->w_grid_alloc; } if (row < 0 || row >= g->rows @@ -2009,20 +1971,16 @@ Boolean nvim_del_mark(String name, Error *err) FUNC_API_SINCE(8) { bool res = false; - if (name.size != 1) { - api_set_error(err, kErrorTypeValidation, - "Mark name must be a single character"); + VALIDATE_S((name.size == 1), "mark name (must be a single char)", name.data, { return res; - } + }); // Only allow file/uppercase marks // TODO(muniter): Refactor this ASCII_ISUPPER macro to a proper function - if (ASCII_ISUPPER(*name.data) || ascii_isdigit(*name.data)) { - res = set_mark(NULL, name, 0, 0, err); - } else { - api_set_error(err, kErrorTypeValidation, - "Only file/uppercase marks allowed, invalid mark name: '%c'", - *name.data); - } + VALIDATE_S((ASCII_ISUPPER(*name.data) || ascii_isdigit(*name.data)), + "mark name (must be file/uppercase)", name.data, { + return res; + }); + res = set_mark(NULL, name, 0, 0, err); return res; } @@ -2043,16 +2001,13 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err) { Array rv = ARRAY_DICT_INIT; - if (name.size != 1) { - api_set_error(err, kErrorTypeValidation, - "Mark name must be a single character"); + VALIDATE_S((name.size == 1), "mark name (must be a single char)", name.data, { return rv; - } else if (!(ASCII_ISUPPER(*name.data) || ascii_isdigit(*name.data))) { - api_set_error(err, kErrorTypeValidation, - "Only file/uppercase marks allowed, invalid mark name: '%c'", - *name.data); + }); + VALIDATE_S((ASCII_ISUPPER(*name.data) || ascii_isdigit(*name.data)), + "mark name (must be file/uppercase)", name.data, { return rv; - } + }); xfmark_T *mark = mark_get_global(false, *name.data); // false avoids loading the mark buffer pos_T pos = mark->fmark.mark; @@ -2137,27 +2092,28 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * if (str.size < 2 || memcmp(str.data, "%!", 2) != 0) { const char *const errmsg = check_stl_option(str.data); - if (errmsg) { - api_set_error(err, kErrorTypeValidation, "%s", errmsg); + VALIDATE(!errmsg, "%s", errmsg, { return result; - } + }); } if (HAS_KEY(opts->winid)) { - if (opts->winid.type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, "winid must be an integer"); + VALIDATE_T("winid", kObjectTypeInteger, opts->winid.type, { return result; - } + }); window = (Window)opts->winid.data.integer; } if (HAS_KEY(opts->fillchar)) { - if (opts->fillchar.type != kObjectTypeString || opts->fillchar.data.string.size == 0 - || ((size_t)utf_ptr2len(opts->fillchar.data.string.data) - != opts->fillchar.data.string.size)) { - api_set_error(err, kErrorTypeValidation, "fillchar must be a single character"); + VALIDATE_T("fillchar", kObjectTypeString, opts->fillchar.type, { return result; - } + }); + VALIDATE((opts->fillchar.data.string.size != 0 + && ((size_t)utf_ptr2len(opts->fillchar.data.string.data) + == opts->fillchar.data.string.size)), + "%s", "Invalid fillchar: expected single character", { + return result; + }); fillchar = utf_ptr2char(opts->fillchar.data.string.data); } if (HAS_KEY(opts->highlights)) { @@ -2181,10 +2137,9 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * return result; } } - if (use_winbar && use_tabline) { - api_set_error(err, kErrorTypeValidation, "use_winbar and use_tabline are mutually exclusive"); + VALIDATE(!(use_winbar && use_tabline), "%s", "Cannot use both 'use_winbar' and 'use_tabline'", { return result; - } + }); win_T *wp, *ewp; @@ -2211,10 +2166,9 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * } if (HAS_KEY(opts->maxwidth)) { - if (opts->maxwidth.type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, "maxwidth must be an integer"); + VALIDATE_T("maxwidth", kObjectTypeInteger, opts->maxwidth.type, { return result; - } + }); maxwidth = (int)opts->maxwidth.data.integer; } else { @@ -2266,7 +2220,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * for (stl_hlrec_t *sp = hltab; sp->start != NULL; sp++) { Dictionary hl_info = ARRAY_DICT_INIT; - PUT(hl_info, "start", INTEGER_OBJ((char *)sp->start - buf)); + PUT(hl_info, "start", INTEGER_OBJ(sp->start - buf)); if (sp->userhl == 0) { grpname = get_default_stl_hl(wp, use_winbar); @@ -2281,7 +2235,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * } PUT(result, "highlights", ARRAY_OBJ(hl_values)); } - PUT(result, "str", CSTR_TO_OBJ((char *)buf)); + PUT(result, "str", CSTR_TO_OBJ(buf)); return result; } diff --git a/src/nvim/arglist.c b/src/nvim/arglist.c index c6a4be7e13..3882b98c2c 100644 --- a/src/nvim/arglist.c +++ b/src/nvim/arglist.c @@ -619,8 +619,6 @@ void ex_argument(exarg_T *eap) /// Edit file "argn" of the argument lists. void do_argfile(exarg_T *eap, int argn) { - int other; - char *p; int old_arg_idx = curwin->w_arg_idx; if (argn < 0 || argn >= ARGCOUNT) { @@ -646,9 +644,9 @@ void do_argfile(exarg_T *eap, int argn) } else { // if 'hidden' set, only check for changed file when re-editing // the same buffer - other = true; + int other = true; if (buf_hide(curbuf)) { - p = fix_fname(alist_name(&ARGLIST[argn])); + char *p = fix_fname(alist_name(&ARGLIST[argn])); other = otherfile(p); xfree(p); } @@ -683,8 +681,6 @@ void do_argfile(exarg_T *eap, int argn) /// ":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 (buf_hide(curbuf) @@ -692,6 +688,7 @@ void ex_next(exarg_T *eap) || !check_changed(curbuf, CCGD_AW | (eap->forceit ? CCGD_FORCEIT : 0) | CCGD_EXCMD)) { + int i; if (*eap->arg != NUL) { // redefine file list if (do_arglist(eap->arg, AL_SET, 0, true) == FAIL) { return; diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 01ebdfdafe..239a07da1f 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -221,7 +221,7 @@ static void aupat_show(AutoPat *ap, event_T event, int previous_group) char *exec_to_string = aucmd_exec_to_string(ac, ac->exec); if (ac->desc != NULL) { size_t msglen = 100; - char *msg = (char *)xmallocz(msglen); + char *msg = xmallocz(msglen); if (ac->exec.type == CALLABLE_CB) { msg_puts_attr(exec_to_string, HL_ATTR(HLF_8)); snprintf(msg, msglen, " [%s]", ac->desc); @@ -286,7 +286,7 @@ static void au_show_for_event(int group, event_T event, char *pat) if (aupat_is_buflocal(pat, patlen)) { // normalize pat into standard "<buffer>#N" form aupat_normalize_buflocal_pat(buflocal_pat, pat, patlen, aupat_get_buflocal_nr(pat, patlen)); - pat = (char *)buflocal_pat; + pat = buflocal_pat; patlen = (int)strlen(buflocal_pat); } @@ -1535,6 +1535,7 @@ win_found: globaldir = aco->globaldir; // the buffer contents may have changed + VIsual_active = aco->save_VIsual_active; check_cursor(); if (curwin->w_topline > curbuf->b_ml.ml_line_count) { curwin->w_topline = curbuf->b_ml.ml_line_count; @@ -1563,14 +1564,16 @@ win_found: curwin = save_curwin; curbuf = curwin->w_buffer; prevwin = win_find_by_handle(aco->save_prevwin_handle); + // In case the autocommand moves the cursor to a position that does not // exist in curbuf + VIsual_active = aco->save_VIsual_active; check_cursor(); } } - check_cursor(); // just in case lines got deleted VIsual_active = aco->save_VIsual_active; + check_cursor(); // just in case lines got deleted if (VIsual_active) { check_pos(curbuf, &VIsual); } @@ -2116,8 +2119,8 @@ static bool call_autocmd_callback(const AutoCmd *ac, const AutoPatCmd *apc) Dictionary data = ARRAY_DICT_INIT; PUT(data, "id", INTEGER_OBJ(ac->id)); PUT(data, "event", CSTR_TO_OBJ(event_nr2name(apc->event))); - PUT(data, "match", CSTR_TO_OBJ((char *)autocmd_match)); - PUT(data, "file", CSTR_TO_OBJ((char *)autocmd_fname)); + PUT(data, "match", CSTR_TO_OBJ(autocmd_match)); + PUT(data, "file", CSTR_TO_OBJ(autocmd_fname)); PUT(data, "buf", INTEGER_OBJ(autocmd_bufnr)); if (apc->data) { @@ -2737,14 +2740,12 @@ void do_autocmd_focusgained(bool gained) { static bool recursive = false; static Timestamp last_time = (time_t)0; - bool need_redraw = false; if (recursive) { return; // disallow recursion } recursive = true; - need_redraw |= apply_autocmds((gained ? EVENT_FOCUSGAINED : EVENT_FOCUSLOST), - NULL, NULL, false, curbuf); + apply_autocmds((gained ? EVENT_FOCUSGAINED : EVENT_FOCUSLOST), NULL, NULL, false, curbuf); // When activated: Check if any file was modified outside of Vim. // Only do this when not done within the last two seconds as: @@ -2752,32 +2753,10 @@ void do_autocmd_focusgained(bool gained) // has a granularity of 2 seconds. // 2. We could get multiple notifications in a row. if (gained && last_time + (Timestamp)2000 < os_now()) { - need_redraw = check_timestamps(true); + check_timestamps(true); last_time = os_now(); } - if (need_redraw) { - // Something was executed, make sure the cursor is put back where it - // belongs. - need_wait_return = false; - - if (State & MODE_CMDLINE) { - redrawcmdline(); - } else if ((State & MODE_NORMAL) || (State & MODE_INSERT)) { - if (must_redraw != 0) { - update_screen(); - } - - setcursor(); - } - - ui_flush(); - } - - if (need_maketitle) { - maketitle(); - } - recursive = false; } diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 4c99191170..05901893b9 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -337,36 +337,6 @@ struct mapblock { bool m_replace_keycodes; // replace keycodes in result of expression }; -/// Used for highlighting in the status line. -typedef struct stl_hlrec stl_hlrec_t; -struct stl_hlrec { - char *start; - int userhl; // 0: no HL, 1-9: User HL, < 0 for syn ID -}; - -/// Used for building the status line. -typedef struct stl_item stl_item_t; -struct stl_item { - // Where the item starts in the status line output buffer - char *start; - // Function to run for ClickFunc items. - char *cmd; - // The minimum width of the item - int minwid; - // The maximum width of the item - int maxwid; - enum { - Normal, - Empty, - Group, - Separate, - Highlight, - TabPage, - ClickFunc, - Trunc, - } type; -}; - // values for b_syn_spell: what to do with toplevel text #define SYNSPL_DEFAULT 0 // spell check if @Spell not defined #define SYNSPL_TOP 1 // spell check toplevel text @@ -838,6 +808,7 @@ struct file_buffer { Map(uint32_t, uint32_t) b_extmark_ns[1]; // extmark namespaces size_t b_virt_line_blocks; // number of virt_line blocks size_t b_signs; // number of sign extmarks + size_t b_signs_with_text; // number of sign extmarks with text // array of channel_id:s which have asked to receive updates for this // buffer. @@ -1111,20 +1082,23 @@ struct window_S { win_T *w_prev; ///< link to previous window win_T *w_next; ///< link to next window bool w_closing; ///< window is being closed, don't let - /// autocommands close it too. + ///< autocommands close it too. frame_T *w_frame; ///< frame containing this window pos_T w_cursor; ///< cursor position in buffer colnr_T w_curswant; ///< Column we want to be at. This is - /// used to try to stay in the same column - /// for up/down cursor motions. + ///< used to try to stay in the same column + ///< for up/down cursor motions. int w_set_curswant; // If set, then update w_curswant the next // time through cursupdate() to the // current virtual column + linenr_T w_cursorline; ///< Where 'cursorline' should be drawn, + ///< can be different from w_cursor.lnum + ///< for closed folds. linenr_T w_last_cursorline; ///< where last 'cursorline' was drawn pos_T w_last_cursormoved; ///< for CursorMoved event @@ -1416,26 +1390,6 @@ struct window_S { size_t w_statuscol_click_defs_size; }; -/// Struct to hold info for 'statuscolumn' -typedef struct statuscol statuscol_T; - -struct statuscol { - int width; ///< width of the status column - int cur_attr; ///< current attributes in text - int num_attr; ///< attributes used for line number - int fold_attr; ///< attributes used for fold column - int sign_attr[SIGN_SHOW_MAX + 1]; ///< attributes used for signs - int truncate; ///< truncated width - bool draw; ///< draw statuscolumn or not - char fold_text[9 * 4 + 1]; ///< text in fold column (%C) - char *sign_text[SIGN_SHOW_MAX + 1]; ///< text in sign column (%s) - char text[MAXPATHL]; ///< text in status column - char *textp; ///< current position in text - char *text_end; ///< end of text (the NUL byte) - stl_hlrec_t *hlrec; ///< highlight groups - stl_hlrec_t *hlrecp; ///< current highlight group -}; - /// Macros defined in Vim, but not in Neovim // uncrustify:off #define CHANGEDTICK(buf) \ diff --git a/src/nvim/change.c b/src/nvim/change.c index 06696610b0..1bd7ea3a5a 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -296,7 +296,9 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T for (int i = 0; i < wp->w_lines_valid; i++) { if (wp->w_lines[i].wl_valid) { if (wp->w_lines[i].wl_lnum >= lnum) { - if (wp->w_lines[i].wl_lnum < lnume) { + // Do not change wl_lnum at index zero, it is used to + // compare with w_topline. Invalidate it instead. + if (wp->w_lines[i].wl_lnum < lnume || i == 0) { // line included in change wp->w_lines[i].wl_valid = false; } else if (xtra != 0) { diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 65bb87bc2c..7f8e1c9fd1 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -32,12 +32,14 @@ #include "nvim/msgpack_rpc/server.h" #include "nvim/os/os_defs.h" #include "nvim/os/shell.h" +#include "nvim/path.h" #include "nvim/rbuffer.h" + #ifdef MSWIN +# include "nvim/os/fs.h" # include "nvim/os/os_win_console.h" # include "nvim/os/pty_conpty_win.h" #endif -#include "nvim/path.h" static bool did_stdio = false; diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 5e4b49db24..97feab2978 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -222,10 +222,8 @@ static void ExpandEscape(expand_T *xp, char *str, int numfiles, char **files, in int nextwild(expand_T *xp, int type, int options, bool escape) { CmdlineInfo *const ccline = get_cmdline_info(); - int i, j; - char *p1; + int i; char *p2; - int difflen; if (xp->xp_numfiles == -1) { set_expand_context(xp); @@ -258,6 +256,7 @@ int nextwild(expand_T *xp, int type, int options, bool escape) // Get next/previous match for a previous expanded pattern. p2 = ExpandOne(xp, NULL, NULL, 0, type); } else { + char *p1; if (cmdline_fuzzy_completion_supported(xp)) { // If fuzzy matching, don't modify the search string p1 = xstrdup(xp->xp_pattern); @@ -282,6 +281,7 @@ int nextwild(expand_T *xp, int type, int options, bool escape) // Longest match: make sure it is not shorter, happens with :help. if (p2 != NULL && type == WILD_LONGEST) { + int j; for (j = 0; (size_t)j < xp->xp_pattern_len; j++) { if (ccline->cmdbuff[i + j] == '*' || ccline->cmdbuff[i + j] == '?') { @@ -295,7 +295,7 @@ int nextwild(expand_T *xp, int type, int options, bool escape) } if (p2 != NULL && !got_int) { - difflen = (int)strlen(p2) - (int)(xp->xp_pattern_len); + int difflen = (int)strlen(p2) - (int)(xp->xp_pattern_len); if (ccline->cmdlen + difflen + 4 > ccline->cmdbufflen) { realloc_cmdbuff(ccline->cmdlen + difflen + 4); xp->xp_pattern = ccline->cmdbuff + i; @@ -454,8 +454,6 @@ static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int m char *selend = NULL; static int first_match = 0; bool add_left = false; - char *s; - int emenu; int l; if (matches == NULL) { // interrupted completion? @@ -528,10 +526,9 @@ static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int m selstart_col = clen; } - s = SHOW_MATCH(i); + char *s = SHOW_MATCH(i); // Check for menu separators - replace with '|' - emenu = (xp->xp_context == EXPAND_MENUS - || xp->xp_context == EXPAND_MENUNAMES); + int emenu = (xp->xp_context == EXPAND_MENUS || xp->xp_context == EXPAND_MENUNAMES); if (emenu && menu_is_separator(s)) { STRCPY(buf + len, transchar('|')); l = (int)strlen(buf + len); @@ -847,7 +844,6 @@ char *ExpandOne(expand_T *xp, char *str, char *orig, int options, int mode) static int findex; static char *orig_save = NULL; // kept value of orig int orig_saved = false; - int i; // first handle the case of using an old match if (mode == WILD_NEXT || mode == WILD_PREV @@ -900,12 +896,12 @@ char *ExpandOne(expand_T *xp, char *str, char *orig, int options, int mode) // TODO(philix): use xstpcpy instead of strcat in a loop (ExpandOne) if (mode == WILD_ALL && xp->xp_numfiles > 0 && !got_int) { size_t len = 0; - for (i = 0; i < xp->xp_numfiles; i++) { + for (int i = 0; i < xp->xp_numfiles; i++) { len += strlen(xp->xp_files[i]) + 1; } ss = xmalloc(len); *ss = NUL; - for (i = 0; i < xp->xp_numfiles; i++) { + for (int i = 0; i < xp->xp_numfiles; i++) { STRCAT(ss, xp->xp_files[i]); if (i != xp->xp_numfiles - 1) { STRCAT(ss, (options & WILD_USE_NL) ? "\n" : " "); @@ -1375,7 +1371,6 @@ void set_expand_context(expand_T *xp) static const char *set_cmd_index(const char *cmd, exarg_T *eap, expand_T *xp, int *complp) { const char *p = NULL; - size_t len = 0; const bool fuzzy = cmdline_fuzzy_complete(cmd); // Isolate the command and search for it in the command table. @@ -1410,7 +1405,7 @@ static const char *set_cmd_index(const char *cmd, exarg_T *eap, expand_T *xp, in if (p == cmd && vim_strchr("@*!=><&~#", (uint8_t)(*p)) != NULL) { p++; } - len = (size_t)(p - cmd); + size_t len = (size_t)(p - cmd); if (len == 0) { xp->xp_context = EXPAND_UNSUCCESSFUL; @@ -2000,8 +1995,8 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa case CMD_snoremap: case CMD_xmap: case CMD_xnoremap: - return (const char *)set_context_in_map_cmd(xp, (char *)cmd, (char *)arg, forceit, false, - false, cmdidx); + return set_context_in_map_cmd(xp, (char *)cmd, (char *)arg, forceit, false, + false, cmdidx); case CMD_unmap: case CMD_nunmap: case CMD_vunmap: @@ -2011,8 +2006,8 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa case CMD_lunmap: case CMD_sunmap: case CMD_xunmap: - return (const char *)set_context_in_map_cmd(xp, (char *)cmd, (char *)arg, forceit, false, - true, cmdidx); + return set_context_in_map_cmd(xp, (char *)cmd, (char *)arg, forceit, false, + true, cmdidx); case CMD_mapclear: case CMD_nmapclear: case CMD_vmapclear: @@ -2032,13 +2027,13 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa case CMD_cnoreabbrev: case CMD_iabbrev: case CMD_inoreabbrev: - return (const char *)set_context_in_map_cmd(xp, (char *)cmd, (char *)arg, forceit, true, - false, cmdidx); + return set_context_in_map_cmd(xp, (char *)cmd, (char *)arg, forceit, true, + false, cmdidx); case CMD_unabbreviate: case CMD_cunabbrev: case CMD_iunabbrev: - return (const char *)set_context_in_map_cmd(xp, (char *)cmd, (char *)arg, forceit, true, - true, cmdidx); + return set_context_in_map_cmd(xp, (char *)cmd, (char *)arg, forceit, true, + true, cmdidx); case CMD_menu: case CMD_noremenu: case CMD_unmenu: @@ -2955,7 +2950,6 @@ static void expand_shellcmd(char *filepat, char ***matches, int *numMatches, int char *path = NULL; garray_T ga; char *buf = xmalloc(MAXPATHL); - size_t l; char *s, *e; int flags = flagsarg; bool did_curdir = false; @@ -3013,7 +3007,7 @@ static void expand_shellcmd(char *filepat, char ***matches, int *numMatches, int flags &= ~EW_DIR; } - l = (size_t)(e - s); + size_t l = (size_t)(e - s); if (l > MAXPATHL - 5) { break; } @@ -3238,7 +3232,7 @@ void globpath(char *path, char *file, garray_T *ga, int expand_options, bool dir ga_grow(ga, num_p); // take over the pointers and put them in "ga" for (int i = 0; i < num_p; i++) { - ((char_u **)ga->ga_data)[ga->ga_len] = (char_u *)p[i]; + ((char **)ga->ga_data)[ga->ga_len] = p[i]; ga->ga_len++; } xfree(p); diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c index 2df82d9355..c2928eb9c4 100644 --- a/src/nvim/cmdhist.c +++ b/src/nvim/cmdhist.c @@ -368,7 +368,6 @@ static int get_history_idx(int histype) static int calc_hist_idx(int histype, int num) { int i; - int wrapped = false; if (hislen == 0 || histype < 0 || histype >= HIST_COUNT || (i = hisidx[histype]) < 0 || num == 0) { @@ -377,6 +376,7 @@ static int calc_hist_idx(int histype, int num) histentry_T *hist = history[histype]; if (num > 0) { + int wrapped = false; while (hist[i].hisnum > num) { if (--i < 0) { if (wrapped) { @@ -568,14 +568,12 @@ void f_histdel(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "histget()" function void f_histget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - HistoryType type; - int idx; - const char *const str = tv_get_string_chk(&argvars[0]); // NULL on type error if (str == NULL) { rettv->vval.v_string = NULL; } else { - type = get_histtype(str, strlen(str), false); + int idx; + HistoryType type = get_histtype(str, strlen(str), false); if (argvars[1].v_type == VAR_UNKNOWN) { idx = get_history_idx(type); } else { @@ -603,13 +601,11 @@ void f_histnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// :history command - print a history void ex_history(exarg_T *eap) { - histentry_T *hist; int histype1 = HIST_CMD; int histype2 = HIST_CMD; int hisidx1 = 1; int hisidx2 = -1; - int idx; - int i, j, k; + int i; char *end; char *arg = eap->arg; @@ -649,10 +645,10 @@ void ex_history(exarg_T *eap) assert(history_names[histype1] != NULL); STRCAT(STRCAT(IObuff, history_names[histype1]), " history"); msg_puts_title(IObuff); - idx = hisidx[histype1]; - hist = history[histype1]; - j = hisidx1; - k = hisidx2; + int idx = hisidx[histype1]; + histentry_T *hist = history[histype1]; + int j = hisidx1; + int k = hisidx2; if (j < 0) { j = (-j > hislen) ? 0 : hist[(hislen + j + idx + 1) % hislen].hisnum; } diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index b1dbc68ea3..ceeaa65206 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -494,10 +494,10 @@ int gchar_cursor(void) /// Write a character at the current cursor position. /// It is directly written into the block. -void pchar_cursor(char_u c) +void pchar_cursor(char c) { *(ml_get_buf(curbuf, curwin->w_cursor.lnum, true) - + curwin->w_cursor.col) = (char)c; + + curwin->w_cursor.col) = c; } /// @return pointer to cursor line. diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index f7e70a78ce..3c9a63f5a3 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -75,7 +75,6 @@ void do_debug(char *cmd) tasave_T typeaheadbuf; bool typeahead_saved = false; int save_ignore_script = 0; - int n; char *cmdline = NULL; char *p; char *tail = NULL; @@ -146,7 +145,7 @@ void do_debug(char *cmd) } // don't debug any function call, e.g. from an expression mapping - n = debug_break_level; + int n = debug_break_level; debug_break_level = -1; xfree(cmdline); @@ -727,7 +726,7 @@ void ex_breaklist(exarg_T *eap) for (int i = 0; i < dbg_breakp.ga_len; i++) { struct debuggy *bp = &BREAKP(i); if (bp->dbg_type == DBG_FILE) { - home_replace(NULL, bp->dbg_name, (char *)NameBuff, MAXPATHL, true); + home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, true); } if (bp->dbg_type != DBG_EXPR) { smsg(_("%3d %s %s line %" PRId64), diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 63c55ec602..c98ffbeefb 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -100,9 +100,13 @@ void decor_remove(buf_T *buf, int row, int row2, Decoration *decor) if (decor_has_sign(decor)) { assert(buf->b_signs > 0); buf->b_signs--; - } - if (row2 >= row && decor->sign_text) { - buf_signcols_del_check(buf, row + 1, row2 + 1); + if (decor->sign_text) { + assert(buf->b_signs_with_text > 0); + buf->b_signs_with_text--; + if (row2 >= row) { + buf_signcols_del_check(buf, row + 1, row2 + 1); + } + } } } decor_free(decor); @@ -445,11 +449,11 @@ int decor_signcols(buf_T *buf, DecorState *state, int row, int end_row, int max) int signcols = 0; // highest value of count int currow = -1; // current row - if (max <= 1 && buf->b_signs >= (size_t)max) { + if (max <= 1 && buf->b_signs_with_text >= (size_t)max) { return max; } - if (buf->b_signs == 0) { + if (buf->b_signs_with_text == 0) { return 0; } diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 032de561b3..c5b28822d0 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -2652,8 +2652,7 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) bool added = true; linenr_T off = lnum - dp->df_lnum[idx]; - int i; - for (i = 0; i < DB_COUNT; i++) { + for (int i = 0; i < DB_COUNT; i++) { if ((curtab->tp_diffbuf[i] != NULL) && (i != idx)) { // Skip lines that are not in the other change (filler lines). if (off >= dp->df_count[i]) { @@ -3409,7 +3408,7 @@ static int parse_diff_ed(char *line, diffhunk_T *hunk) linenr_T f1 = getdigits_int32(&p, true, 0); if (*p == ',') { p++; - l1 = getdigits(&p, true, 0); + l1 = getdigits_long(&p, true, 0); } else { l1 = f1; } @@ -3417,10 +3416,10 @@ static int parse_diff_ed(char *line, diffhunk_T *hunk) return FAIL; // invalid diff format } int difftype = (uint8_t)(*p++); - long f2 = getdigits(&p, true, 0); + long f2 = getdigits_long(&p, true, 0); if (*p == ',') { p++; - l2 = getdigits(&p, true, 0); + l2 = getdigits_long(&p, true, 0); } else { l2 = f2; } @@ -3458,18 +3457,18 @@ static int parse_diff_unified(char *line, diffhunk_T *hunk) long oldcount; long newline; long newcount; - long oldline = getdigits(&p, true, 0); + long oldline = getdigits_long(&p, true, 0); if (*p == ',') { p++; - oldcount = getdigits(&p, true, 0); + oldcount = getdigits_long(&p, true, 0); } else { oldcount = 1; } if (*p++ == ' ' && *p++ == '+') { - newline = getdigits(&p, true, 0); + newline = getdigits_long(&p, true, 0); if (*p == ',') { p++; - newcount = getdigits(&p, true, 0); + newcount = getdigits_long(&p, true, 0); } else { newcount = 1; } diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 7a64f8ac9d..3cedb04bcb 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -303,7 +303,7 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, static bool use_cursor_line_sign(win_T *wp, linenr_T lnum) { return wp->w_p_cul - && lnum == wp->w_cursor.lnum + && lnum == wp->w_cursorline && (wp->w_p_culopt_flags & CULOPT_NBR); } @@ -404,37 +404,10 @@ static int get_sign_attrs(buf_T *buf, linenr_T lnum, SignTextAttrs *sattrs, int /// the start of the buffer line "lnum" and once for the wrapped lines. /// /// @param[out] stcp Status column attributes -static void get_statuscol_str(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines, - int cul_attr, int sign_num_attr, int sign_cul_attr, statuscol_T *stcp, - foldinfo_T foldinfo, SignTextAttrs *sattrs) +static void get_statuscol_str(win_T *wp, linenr_T lnum, int virtnum, statuscol_T *stcp) { - long relnum = -1; - bool use_cul = use_cursor_line_sign(wp, lnum); - int virtnum = row - startrow - filler_lines; - - // When called the first time for line "lnum" set num_attr - if (stcp->num_attr == 0) { - stcp->num_attr = sign_num_attr ? sign_num_attr - : get_line_number_attr(wp, lnum, row, startrow, filler_lines); - } - // When called for the first non-filler row of line "lnum" set num v:vars and fold column - if (virtnum == 0) { - relnum = labs(get_cursor_rel_lnum(wp, lnum)); - if (compute_foldcolumn(wp, 0)) { - size_t n = fill_foldcolumn(stcp->fold_text, wp, foldinfo, lnum); - stcp->fold_text[n] = NUL; - stcp->fold_attr = win_hl_attr(wp, use_cul ? HLF_CLF : HLF_FC); - } - } - // Make sure to clear->set->clear sign column for filler->first->wrapped lines - int i = 0; - for (; i < wp->w_scwidth; i++) { - SignTextAttrs *sattr = virtnum ? NULL : sign_get_attr(i, sattrs, wp->w_scwidth); - stcp->sign_text[i] = sattr && sattr->text ? sattr->text : " "; - stcp->sign_attr[i] = sattr ? (use_cul && sign_cul_attr ? sign_cul_attr : sattr->hl_attr_id) - : win_hl_attr(wp, use_cul ? HLF_CLS : HLF_SC); - } - stcp->sign_text[i] = NULL; + // When called for the first non-filler row of line "lnum" set num v:vars + long relnum = virtnum == 0 ? labs(get_cursor_rel_lnum(wp, lnum)) : -1; // When a buffer's line count has changed, make a best estimate for the full // width of the status column by building with "w_nrwidth_line_count". Add @@ -494,8 +467,7 @@ static void get_statuscol_display_info(statuscol_T *stcp, LineDrawState *draw_st if (stcp->textp + *n_extrap < stcp->text_end) { int hl = stcp->hlrecp->userhl; stcp->textp = stcp->hlrecp->start; - stcp->cur_attr = hl < 0 ? syn_id2attr(-stcp->hlrecp->userhl) - : hl > 0 ? hl : stcp->num_attr; + stcp->cur_attr = hl < 0 ? syn_id2attr(-hl) : hl > 0 ? hl : stcp->num_attr; stcp->hlrecp++; *draw_state = WL_STC - 1; } @@ -515,7 +487,7 @@ static void get_statuscol_display_info(statuscol_T *stcp, LineDrawState *draw_st static bool use_cursor_line_nr(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines) { return wp->w_p_cul - && lnum == wp->w_cursor.lnum + && lnum == wp->w_cursorline && (wp->w_p_culopt_flags & CULOPT_NBR) && (row == startrow + filler_lines || (row > startrow + filler_lines @@ -545,6 +517,12 @@ static inline void get_line_number_str(win_T *wp, linenr_T lnum, char *buf, size static int get_line_number_attr(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines) { + if (use_cursor_line_nr(wp, lnum, row, startrow, filler_lines)) { + // TODO(vim): Can we use CursorLine instead of CursorLineNr + // when CursorLineNr isn't set? + return win_hl_attr(wp, HLF_CLN); + } + if (wp->w_p_rnu) { if (lnum < wp->w_cursor.lnum) { // Use LineNrAbove @@ -556,12 +534,6 @@ static int get_line_number_attr(win_T *wp, linenr_T lnum, int row, int startrow, } } - if (use_cursor_line_nr(wp, lnum, row, startrow, filler_lines)) { - // TODO(vim): Can we use CursorLine instead of CursorLineNr - // when CursorLineNr isn't set? - return win_hl_attr(wp, HLF_CLN); - } - return win_hl_attr(wp, HLF_N); } @@ -613,7 +585,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, foldinfo_T foldinfo, DecorProviders *providers, char **provider_err) { int c = 0; // init for GCC - long vcol = 0; // virtual column (for tabs) + colnr_T vcol = 0; // virtual column (for tabs) long vcol_sbr = -1; // virtual column after showbreak long vcol_prev = -1; // "vcol" of previous character char *line; // current line @@ -655,7 +627,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, bool noinvcur = false; // don't invert the cursor bool lnum_in_visual_area = false; pos_T pos; - long v; + ptrdiff_t v; int char_attr = 0; // attributes for next character bool attr_pri = false; // char_attr has priority @@ -796,7 +768,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Check for columns to display for 'colorcolumn'. color_cols = wp->w_buffer->terminal ? NULL : wp->w_p_cc_cols; if (color_cols != NULL) { - draw_color_col = advance_color_col((int)VCOL_HLC, &color_cols); + draw_color_col = advance_color_col(VCOL_HLC, &color_cols); } if (wp->w_p_spell @@ -958,20 +930,17 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, filler_todo = filler_lines; // Cursor line highlighting for 'cursorline' in the current window. - if (lnum == wp->w_cursor.lnum) { - // Do not show the cursor line in the text when Visual mode is active, - // because it's not clear what is selected then. - if (wp->w_p_cul && !(wp == curwin && VIsual_active) - && wp->w_p_culopt_flags != CULOPT_NBR) { - cul_screenline = (wp->w_p_wrap - && (wp->w_p_culopt_flags & CULOPT_SCRLINE)); - if (!cul_screenline) { - apply_cursorline_highlight(wp, lnum, &line_attr, &cul_attr, &line_attr_lowprio); - } else { - margin_columns_win(wp, &left_curline_col, &right_curline_col); - } - area_highlighting = true; + if (wp->w_p_cul && wp->w_p_culopt_flags != CULOPT_NBR && lnum == wp->w_cursorline + // Do not show the cursor line in the text when Visual mode is active, + // because it's not clear what is selected then. + && !(wp == curwin && VIsual_active)) { + cul_screenline = (wp->w_p_wrap && (wp->w_p_culopt_flags & CULOPT_SCRLINE)); + if (!cul_screenline) { + apply_cursorline_highlight(wp, lnum, &line_attr, &cul_attr, &line_attr_lowprio); + } else { + margin_columns_win(wp, &left_curline_col, &right_curline_col); } + area_highlighting = true; } SignTextAttrs sattrs[SIGN_SHOW_MAX]; // sign attributes for the sign column @@ -1073,7 +1042,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, chartabsize_T cts; int charsize; - init_chartabsize_arg(&cts, wp, lnum, (colnr_T)vcol, line, ptr); + init_chartabsize_arg(&cts, wp, lnum, vcol, line, ptr); while (cts.cts_vcol < v && *cts.cts_ptr != NUL) { charsize = win_lbr_chartabsize(&cts, NULL); cts.cts_vcol += charsize; @@ -1094,7 +1063,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, || draw_color_col || virtual_active() || (VIsual_active && wp->w_buffer == curwin->w_buffer))) { - vcol = v; + vcol = (colnr_T)v; } // Handle a character that's not completely on the screen: Put ptr at @@ -1114,7 +1083,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (tocol <= vcol) { fromcol = 0; } else if (fromcol >= 0 && fromcol < vcol) { - fromcol = (int)vcol; + fromcol = vcol; } // When w_skipcol is non-zero, first line needs 'showbreak' @@ -1209,7 +1178,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (*wp->w_p_stc != NUL) { // Draw the 'statuscolumn' if option is set. statuscol.draw = true; + statuscol.sattrs = sattrs; + statuscol.foldinfo = foldinfo; statuscol.width = win_col_off(wp); + statuscol.use_cul = use_cursor_line_sign(wp, lnum); + statuscol.sign_cul_attr = statuscol.use_cul ? sign_cul_attr : 0; + statuscol.num_attr = sign_num_attr ? sign_num_attr + : get_line_number_attr(wp, lnum, row, startrow, filler_lines); } int sign_idx = 0; @@ -1355,8 +1330,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Draw the 'statuscolumn' if option is set. if (statuscol.draw) { if (statuscol.textp == NULL) { - get_statuscol_str(wp, lnum, row, startrow, filler_lines, cul_attr, - sign_num_attr, sign_cul_attr, &statuscol, foldinfo, sattrs); + get_statuscol_str(wp, lnum, row - startrow - filler_lines, &statuscol); if (wp->w_redr_statuscol) { break; } @@ -1471,7 +1445,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (has_decor && row == startrow + filler_lines) { // hide virt_text on text hidden by 'nowrap' - decor_redraw_col(wp->w_buffer, (int)vcol, off, true, &decor_state); + decor_redraw_col(wp->w_buffer, vcol, off, true, &decor_state); } if (saved_n_extra) { @@ -1568,7 +1542,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } } else if (area_attr != 0 && (vcol == tocol || (noinvcur - && (colnr_T)vcol == wp->w_virtcol))) { + && vcol == wp->w_virtcol))) { area_attr = 0; // stop highlighting area_active = false; } @@ -1723,9 +1697,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // At start of the line we can have a composing char. // Draw it as a space with a composing char. if (utf_iscomposing(mb_c)) { - int i; - - for (i = MAX_MCO - 1; i > 0; i--) { + for (int i = MAX_MCO - 1; i > 0; i--) { u8cc[i] = u8cc[i - 1]; } u8cc[0] = mb_c; @@ -1873,7 +1845,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (has_decor && v > 0) { bool selected = (area_active || (area_highlighting && noinvcur - && (colnr_T)vcol == wp->w_virtcol)); + && vcol == wp->w_virtcol)); int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v - 1, off, selected, &decor_state); if (extmark_attr != 0) { @@ -1982,7 +1954,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, char *p = ptr - (mb_off + 1); chartabsize_T cts; - init_chartabsize_arg(&cts, wp, lnum, (colnr_T)vcol, line, p); + init_chartabsize_arg(&cts, wp, lnum, vcol, line, p); n_extra = win_lbr_chartabsize(&cts, NULL) - 1; // We have just drawn the showbreak value, no need to add @@ -2001,7 +1973,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } if (c == TAB && n_extra + col > grid->cols) { - n_extra = tabstop_padding((colnr_T)vcol, wp->w_buffer->b_p_ts, + n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts, wp->w_buffer->b_p_vts_array) - 1; } c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' '; @@ -2100,7 +2072,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, n_extra = tab_len; } else { char *p; - int i; int saved_nextra = n_extra; if (vcol_off > 0) { @@ -2129,7 +2100,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, p[len] = NUL; xfree(p_extra_free); p_extra_free = p; - for (i = 0; i < tab_len; i++) { + for (int i = 0; i < tab_len; i++) { if (*p == NUL) { tab_len = i; break; @@ -2201,7 +2172,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && (wp->w_p_rl ? (col >= 0) : (col < grid->cols)) && !(noinvcur && lnum == wp->w_cursor.lnum - && (colnr_T)vcol == wp->w_virtcol))) + && vcol == wp->w_virtcol))) && lcs_eol_one > 0) { // Display a '$' after the line or highlight an extra // character if the line break is included. @@ -2454,7 +2425,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // check if line ends before left margin if (vcol < v + col - win_col_off(wp)) { - vcol = v + col - win_col_off(wp); + vcol = (colnr_T)v + col - win_col_off(wp); } // Get rid of the boguscols now, we want to draw until the right // edge for 'cursorcolumn'. @@ -2462,7 +2433,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // boguscols = 0; // Disabled because value never read after this if (draw_color_col) { - draw_color_col = advance_color_col((int)VCOL_HLC, &color_cols); + draw_color_col = advance_color_col(VCOL_HLC, &color_cols); } bool has_virttext = false; @@ -2484,7 +2455,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, || draw_color_col || line_attr_lowprio || line_attr || diff_hlf != (hlf_T)0 || has_virttext)) { int rightmost_vcol = 0; - int i; if (wp->w_p_cuc) { rightmost_vcol = wp->w_virtcol; @@ -2492,7 +2462,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (draw_color_col) { // determine rightmost colorcolumn to possibly draw - for (i = 0; color_cols[i] >= 0; i++) { + for (int i = 0; color_cols[i] >= 0; i++) { if (rightmost_vcol < color_cols[i]) { rightmost_vcol = color_cols[i]; } @@ -2521,7 +2491,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, schar_from_ascii(linebuf_char[off], ' '); col += col_stride; if (draw_color_col) { - draw_color_col = advance_color_col((int)VCOL_HLC, &color_cols); + draw_color_col = advance_color_col(VCOL_HLC, &color_cols); } int col_attr = base_attr; @@ -2595,7 +2565,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // advance to the next 'colorcolumn' if (draw_color_col) { - draw_color_col = advance_color_col((int)VCOL_HLC, &color_cols); + draw_color_col = advance_color_col(VCOL_HLC, &color_cols); } // Highlight the cursor column if 'cursorcolumn' is set. But don't diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 04c342e068..2c0b6ea3b0 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -318,6 +318,10 @@ void screen_resize(int width, int height) resizing_autocmd = false; redraw_all_later(UPD_CLEAR); + if (State != MODE_ASKMORE && State != MODE_EXTERNCMD && State != MODE_CONFIRM) { + screenclear(); + } + if (starting != NO_SCREEN) { maketitle(); @@ -1548,7 +1552,15 @@ static void win_update(win_T *wp, DecorProviders *providers) wp->w_old_visual_col = 0; } - bool cursorline_standout = win_cursorline_standout(wp); + foldinfo_T cursorline_fi; + wp->w_cursorline = win_cursorline_standout(wp) ? wp->w_cursor.lnum : 0; + if (wp->w_p_cul) { + // Make sure that the cursorline on a closed fold is redrawn + cursorline_fi = fold_info(wp, wp->w_cursor.lnum); + if (cursorline_fi.fi_level > 0 && cursorline_fi.fi_lines > 0) { + wp->w_cursorline = cursorline_fi.fi_lnum; + } + } win_check_ns_hl(wp); @@ -1604,7 +1616,7 @@ static void win_update(win_T *wp, DecorProviders *providers) // if lines were inserted or deleted || (wp->w_match_head != NULL && buf->b_mod_xlines != 0))))) - || (cursorline_standout && lnum == wp->w_cursor.lnum) + || lnum == wp->w_cursorline || lnum == wp->w_last_cursorline) { if (lnum == mod_top) { top_to_mod = false; @@ -1620,8 +1632,6 @@ static void win_update(win_T *wp, DecorProviders *providers) && !(dollar_vcol >= 0 && mod_bot == mod_top + 1) && row >= top_end) { int old_rows = 0; - int new_rows = 0; - int xtra_rows; linenr_T l; int i; @@ -1656,6 +1666,7 @@ static void win_update(win_T *wp, DecorProviders *providers) bot_start = 0; bot_scroll_start = 0; } else { + int new_rows = 0; // Able to count old number of rows: Count new window // rows, and may insert/delete lines long j = idx; @@ -1674,7 +1685,7 @@ static void win_update(win_T *wp, DecorProviders *providers) break; } } - xtra_rows = new_rows - old_rows; + int xtra_rows = new_rows - old_rows; if (xtra_rows < 0) { // May scroll text up. If there is not enough // remaining text or scrolling fails, must redraw the @@ -1756,7 +1767,8 @@ static void win_update(win_T *wp, DecorProviders *providers) // When lines are folded, display one line for all of them. // Otherwise, display normally (can be several display lines when // 'wrap' is on). - foldinfo_T foldinfo = fold_info(wp, lnum); + foldinfo_T foldinfo = wp->w_p_cul && lnum == wp->w_cursor.lnum ? + cursorline_fi : fold_info(wp, lnum); if (foldinfo.fi_lines == 0 && idx < wp->w_lines_valid @@ -1815,7 +1827,8 @@ static void win_update(win_T *wp, DecorProviders *providers) if (wp->w_p_rnu && wp->w_last_cursor_lnum_rnu != wp->w_cursor.lnum) { // 'relativenumber' set and cursor moved vertically: The // text doesn't need to be drawn, but the number column does. - foldinfo_T info = fold_info(wp, lnum); + foldinfo_T info = wp->w_p_cul && lnum == wp->w_cursor.lnum ? + cursorline_fi : fold_info(wp, lnum); (void)win_line(wp, lnum, srow, wp->w_grid.rows, true, true, info, &line_providers, &provider_err); } @@ -1850,7 +1863,7 @@ static void win_update(win_T *wp, DecorProviders *providers) // Now that the window has been redrawn with the old and new cursor line, // update w_last_cursorline. - wp->w_last_cursorline = cursorline_standout ? wp->w_cursor.lnum : 0; + wp->w_last_cursorline = wp->w_cursorline; wp->w_last_cursor_lnum_rnu = wp->w_p_rnu ? wp->w_cursor.lnum : 0; diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 96df6a3044..ff7899d0eb 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -558,10 +558,9 @@ static int insert_execute(VimState *state, int key) if (ins_compl_accept_char(s->c)) { // Trigger InsertCharPre. char *str = do_insert_char_pre(s->c); - char *p; if (str != NULL) { - for (p = str; *p != NUL; MB_PTR_ADV(p)) { + for (char *p = str; *p != NUL; MB_PTR_ADV(p)) { ins_compl_addleader(utf_ptr2char(p)); } xfree(str); @@ -1122,12 +1121,11 @@ normalchar: if (!p_paste) { // Trigger InsertCharPre. char *str = do_insert_char_pre(s->c); - char *p; if (str != NULL) { if (*str != NUL && stop_arrow() != FAIL) { // Insert the new value of v:char literally. - for (p = str; *p != NUL; MB_PTR_ADV(p)) { + for (char *p = str; *p != NUL; MB_PTR_ADV(p)) { s->c = utf_ptr2char(p); if (s->c == CAR || s->c == K_KENTER || s->c == NL) { ins_eol(s->c); @@ -1403,16 +1401,15 @@ static int pc_status; #define PC_STATUS_RIGHT 1 // right half of double-wide char #define PC_STATUS_LEFT 2 // left half of double-wide char #define PC_STATUS_SET 3 // pc_bytes was filled -static char_u pc_bytes[MB_MAXBYTES + 1]; // saved bytes +static char pc_bytes[MB_MAXBYTES + 1]; // saved bytes static int pc_attr; static int pc_row; static int pc_col; void edit_putchar(int c, bool highlight) { - int attr; - if (curwin->w_grid_alloc.chars != NULL || default_grid.chars != NULL) { + int attr; update_topline(curwin); // just in case w_topline isn't valid validate_cursor(); if (highlight) { @@ -1441,7 +1438,7 @@ void edit_putchar(int c, bool highlight) // save the character to be able to put it back if (pc_status == PC_STATUS_UNSET) { - grid_getbytes(&curwin->w_grid, pc_row, pc_col, (char *)pc_bytes, &pc_attr); + grid_getbytes(&curwin->w_grid, pc_row, pc_col, pc_bytes, &pc_attr); pc_status = PC_STATUS_SET; } grid_putchar(&curwin->w_grid, c, pc_row, pc_col, attr); @@ -1524,7 +1521,7 @@ void edit_unputchar(void) if (pc_status == PC_STATUS_RIGHT || pc_status == PC_STATUS_LEFT) { redrawWinline(curwin, curwin->w_cursor.lnum); } else { - grid_puts(&curwin->w_grid, (char *)pc_bytes, pc_row - msg_scrolled, pc_col, pc_attr); + grid_puts(&curwin->w_grid, pc_bytes, pc_row - msg_scrolled, pc_col, pc_attr); } } } @@ -1583,7 +1580,7 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang int start_col; colnr_T vc; colnr_T orig_col = 0; // init for GCC - char *new_line, *orig_line = NULL; // init for GCC + char *orig_line = NULL; // init for GCC // MODE_VREPLACE state needs to know what the line was like before changing if (State & VREPLACE_FLAG) { @@ -1742,7 +1739,7 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang // then put it back again the way we wanted it. if (State & VREPLACE_FLAG) { // Save new line - new_line = xstrdup(get_cursor_line_ptr()); + char *new_line = xstrdup(get_cursor_line_ptr()); // We only put back the new line up to the cursor new_line[curwin->w_cursor.col] = NUL; @@ -1949,9 +1946,6 @@ int get_literal(bool no_simplify) /// @param ctrlv `c` was typed after CTRL-V static void insert_special(int c, int allow_modmask, int ctrlv) { - char *p; - int len; - // Special function key, translate into "<Key>". Up to the last '>' is // inserted with ins_str(), so as not to replace characters in replace // mode. @@ -1961,8 +1955,8 @@ static void insert_special(int c, int allow_modmask, int ctrlv) allow_modmask = true; } if (IS_SPECIAL(c) || (mod_mask && allow_modmask)) { - p = (char *)get_special_key_name(c, mod_mask); - len = (int)strlen(p); + char *p = (char *)get_special_key_name(c, mod_mask); + int len = (int)strlen(p); c = (uint8_t)p[len - 1]; if (len > 2) { if (stop_arrow() == FAIL) { @@ -2057,7 +2051,7 @@ void insertchar(int c, int flags, int second_indent) // Check whether this character should end a comment. if (did_ai && c == end_comment_pending) { - char_u lead_end[COM_MAX_LEN]; // end-comment string + char lead_end[COM_MAX_LEN]; // end-comment string // Need to remove existing (middle) comment leader and insert end // comment leader. First, check what comment leader we can find. @@ -2068,7 +2062,7 @@ void insertchar(int c, int flags, int second_indent) while (*p && p[-1] != ':') { // find end of middle flags p++; } - int middle_len = (int)copy_option_part(&p, (char *)lead_end, COM_MAX_LEN, ","); + int middle_len = (int)copy_option_part(&p, lead_end, COM_MAX_LEN, ","); // Don't count trailing white space for middle_len while (middle_len > 0 && ascii_iswhite(lead_end[middle_len - 1])) { middle_len--; @@ -2078,7 +2072,7 @@ void insertchar(int c, int flags, int second_indent) while (*p && p[-1] != ':') { // find end of end flags p++; } - int end_len = (int)copy_option_part(&p, (char *)lead_end, COM_MAX_LEN, ","); + int end_len = (int)copy_option_part(&p, lead_end, COM_MAX_LEN, ","); // Skip white space before the cursor i = curwin->w_cursor.col; @@ -2089,13 +2083,13 @@ void insertchar(int c, int flags, int second_indent) i -= middle_len; // Check some expected things before we go on - if (i >= 0 && lead_end[end_len - 1] == end_comment_pending) { + if (i >= 0 && (uint8_t)lead_end[end_len - 1] == end_comment_pending) { // Backspace over all the stuff we want to replace backspace_until_column(i); // Insert the end-comment string, except for the last // character, which will get inserted as normal later. - ins_bytes_len((char *)lead_end, (size_t)(end_len - 1)); + ins_bytes_len(lead_end, (size_t)(end_len - 1)); } } } @@ -2294,7 +2288,6 @@ int stop_arrow(void) /// @param nomove <c-\><c-o>, don't move cursor static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) { - int cc; char *ptr; stop_redo_ins(); @@ -2314,6 +2307,7 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) } if (!arrow_used && end_insert_pos != NULL) { + int cc; // Auto-format now. It may seem strange to do this when stopping an // insertion (or moving the cursor), but it's required when appending // a line and having it end in a space. But only do it when something @@ -2422,7 +2416,7 @@ void set_last_insert(int c) if (c < ' ' || c == DEL) { *s++ = Ctrl_V; } - s = (char *)add_char2buf(c, (char_u *)s); + s = add_char2buf(c, s); *s++ = ESC; *s++ = NUL; last_insert_skip = 0; @@ -2449,9 +2443,9 @@ void beginline(int flags) curwin->w_cursor.coladd = 0; if (flags & (BL_WHITE | BL_SOL)) { - char_u *ptr; + char *ptr; - for (ptr = (char_u *)get_cursor_line_ptr(); ascii_iswhite(*ptr) + for (ptr = get_cursor_line_ptr(); ascii_iswhite(*ptr) && !((flags & BL_FIX) && ptr[1] == NUL); ptr++) { curwin->w_cursor.col++; } @@ -2682,7 +2676,7 @@ int stuff_inserted(int c, long count, int no_esc) char *last_ptr; char last = NUL; - ptr = (char *)get_last_insert(); + ptr = get_last_insert(); if (ptr == NULL) { emsg(_(e_noinstext)); return FAIL; @@ -2731,13 +2725,13 @@ int stuff_inserted(int c, long count, int no_esc) return OK; } -char_u *get_last_insert(void) +char *get_last_insert(void) FUNC_ATTR_PURE { if (last_insert == NULL) { return NULL; } - return (char_u *)last_insert + last_insert_skip; + return last_insert + last_insert_skip; } // Get last inserted string, and remove trailing <Esc>. @@ -2883,7 +2877,6 @@ static void mb_replace_pop_ins(int cc) int n; char_u buf[MB_MAXBYTES + 1]; int i; - int c; if ((n = MB_BYTE2LEN(cc)) > 1) { buf[0] = (char_u)cc; @@ -2897,7 +2890,7 @@ static void mb_replace_pop_ins(int cc) // Handle composing chars. for (;;) { - c = replace_pop(); + int c = replace_pop(); if (c == -1) { // stack empty break; } @@ -2943,17 +2936,13 @@ static void replace_flush(void) static void replace_do_bs(int limit_col) { int cc; - int orig_len = 0; - int ins_len; - int orig_vcols = 0; colnr_T start_vcol; - char *p; - int i; - int vcol; const int l_State = State; cc = replace_pop(); if (cc > 0) { + int orig_len = 0; + int orig_vcols = 0; if (l_State & VREPLACE_FLAG) { // Get the number of screen cells used by the character we are // going to delete. @@ -2969,10 +2958,10 @@ static void replace_do_bs(int limit_col) if (l_State & VREPLACE_FLAG) { // Get the number of screen cells used by the inserted characters - p = get_cursor_pos_ptr(); - ins_len = (int)strlen(p) - orig_len; - vcol = start_vcol; - for (i = 0; i < ins_len; i++) { + char *p = get_cursor_pos_ptr(); + int ins_len = (int)strlen(p) - orig_len; + int vcol = start_vcol; + for (int i = 0; i < ins_len; i++) { vcol += win_chartabsize(curwin, p + i, vcol); i += utfc_ptr2len(p) - 1; } @@ -3786,14 +3775,11 @@ static void ins_bs_one(colnr_T *vcolp) static bool ins_bs(int c, int mode, int *inserted_space_p) FUNC_ATTR_NONNULL_ARG(3) { - linenr_T lnum; int cc; int temp = 0; // init for GCC colnr_T save_col; - colnr_T mincol; bool did_backspace = false; int in_indent; - int oldState; int cpc[MAX_MCO]; // composing characters bool call_fix_indent = false; @@ -3844,7 +3830,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) // Delete newline! if (curwin->w_cursor.col == 0) { - lnum = Insstart.lnum; + linenr_T lnum = Insstart.lnum; if (curwin->w_cursor.lnum == lnum || revins_on) { if (u_save((linenr_T)(curwin->w_cursor.lnum - 2), (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL) { @@ -3900,7 +3886,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) // Do the next ins_char() in MODE_NORMAL state, to // prevent ins_char() from replacing characters and // avoiding showmatch(). - oldState = State; + int oldState = State; State = MODE_NORMAL; // restore characters (blanks) deleted after cursor while (cc > 0) { @@ -3920,7 +3906,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) if (revins_on) { // put cursor on last inserted char dec_cursor(); } - mincol = 0; + colnr_T mincol = 0; // keep indent if (mode == BACKSPACE_LINE && (curbuf->b_p_ai || cindent_on()) @@ -3944,7 +3930,6 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) && (*(get_cursor_pos_ptr() - 1) == TAB || (*(get_cursor_pos_ptr() - 1) == ' ' && (!*inserted_space_p || arrow_used)))))) { - int ts; colnr_T vcol; colnr_T want_vcol; colnr_T start_vcol; @@ -3959,7 +3944,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol); inc_cursor(); if (p_sta && in_indent) { - ts = get_sw_value(curbuf); + int ts = get_sw_value(curbuf); want_vcol = (want_vcol / ts) * ts; } else { want_vcol = tabstop_start(want_vcol, @@ -3999,7 +3984,6 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) } } else { // Delete up to starting point, start of line or previous word. - int prev_cclass = 0; int cclass = mb_get_class(get_cursor_pos_ptr()); do { @@ -4008,7 +3992,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) } cc = gchar_cursor(); // look multi-byte character class - prev_cclass = cclass; + int prev_cclass = cclass; cclass = mb_get_class(get_cursor_pos_ptr()); if (mode == BACKSPACE_WORD && !ascii_isspace(cc)) { // start of word? mode = BACKSPACE_WORD_NOT_SPACE; @@ -4425,7 +4409,6 @@ static void ins_pagedown(void) static bool ins_tab(void) FUNC_ATTR_WARN_UNUSED_RESULT { - int i; int temp; if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum) { @@ -4501,6 +4484,7 @@ static bool ins_tab(void) if (!curbuf->b_p_et && (tabstop_count(curbuf->b_p_vsts_array) > 0 || get_sts_value() > 0 || (p_sta && ind))) { + int i; char *ptr; char *saved_line = NULL; // init for GCC pos_T pos; @@ -4597,7 +4581,7 @@ static bool ins_tab(void) // Delete following spaces. i = cursor->col - fpos.col; if (i > 0) { - STRMOVE(ptr, (char *)ptr + i); + STRMOVE(ptr, ptr + i); // correct replace stack. if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) { @@ -4690,7 +4674,6 @@ bool ins_eol(int c) static int ins_digraph(void) { int c; - int cc; bool did_putchar = false; pc_status = PC_STATUS_UNSET; @@ -4736,7 +4719,7 @@ static int ins_digraph(void) } no_mapping++; allow_keys++; - cc = plain_vgetc(); + int cc = plain_vgetc(); no_mapping--; allow_keys--; if (did_putchar) { @@ -4835,13 +4818,14 @@ static int ins_ctrl_ey(int tc) // Used when inserting a "normal" character. static void ins_try_si(int c) { - pos_T *pos, old_pos; - char *ptr; - int i; - bool temp; + pos_T *pos; // do some very smart indenting when entering '{' or '}' if (((did_si || can_si_back) && c == '{') || (can_si && c == '}' && inindent(0))) { + pos_T old_pos; + char *ptr; + int i; + bool temp; // for '}' set indent equal to indent of line containing matching '{' if (c == '}' && (pos = findmatch(NULL, '{')) != NULL) { old_pos = curwin->w_cursor; diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 4392ea306f..3ab704e250 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1949,7 +1949,6 @@ void set_context_for_expression(expand_T *xp, char *arg, cmdidx_T cmdidx) FUNC_ATTR_NONNULL_ALL { bool got_eq = false; - int c; char *p; if (cmdidx == CMD_let || cmdidx == CMD_const) { @@ -1970,7 +1969,7 @@ void set_context_for_expression(expand_T *xp, char *arg, cmdidx_T cmdidx) : EXPAND_EXPRESSION; } while ((xp->xp_pattern = strpbrk(arg, "\"'+-*/%.=!?~|&$([<>,#")) != NULL) { - c = (uint8_t)(*xp->xp_pattern); + int c = (uint8_t)(*xp->xp_pattern); if (c == '&') { c = (uint8_t)xp->xp_pattern[1]; if (c == '&') { @@ -2310,7 +2309,6 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, int evaluate) /// @return OK or FAIL. int eval1(char **arg, typval_T *rettv, int evaluate) { - bool result; typval_T var2; // Get the first variable. @@ -2319,7 +2317,7 @@ int eval1(char **arg, typval_T *rettv, int evaluate) } if ((*arg)[0] == '?') { - result = false; + bool result = false; if (evaluate) { bool error = false; @@ -2499,7 +2497,6 @@ static int eval4(char **arg, typval_T *rettv, int evaluate) char *p; exprtype_T type = EXPR_UNKNOWN; int len = 2; - bool ic; // Get the first variable. if (eval5(arg, rettv, evaluate) == FAIL) { @@ -2552,6 +2549,7 @@ static int eval4(char **arg, typval_T *rettv, int evaluate) // If there is a comparative operator, use it. if (type != EXPR_UNKNOWN) { + bool ic; // extra question mark appended: ignore case if (p[len] == '?') { ic = true; @@ -2594,7 +2592,6 @@ static int eval5(char **arg, typval_T *rettv, int evaluate) { typval_T var2; typval_T var3; - int op; varnumber_T n1, n2; float_T f1 = 0, f2 = 0; char *p; @@ -2606,7 +2603,7 @@ static int eval5(char **arg, typval_T *rettv, int evaluate) // Repeat computing, until no '+', '-' or '.' is following. for (;;) { - op = (char_u)(**arg); + int op = (char_u)(**arg); if (op != '+' && op != '-' && op != '.') { break; } @@ -3276,7 +3273,6 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) { bool empty1 = false; bool empty2 = false; - long n1, n2 = 0; ptrdiff_t len = -1; int range = false; char *key = NULL; @@ -3373,16 +3369,17 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) } if (evaluate) { - n1 = 0; + int n2 = 0; + int n1 = 0; if (!empty1 && rettv->v_type != VAR_DICT && !tv_is_luafunc(rettv)) { - n1 = tv_get_number(&var1); + n1 = (int)tv_get_number(&var1); tv_clear(&var1); } if (range) { if (empty2) { n2 = -1; } else { - n2 = tv_get_number(&var2); + n2 = (int)tv_get_number(&var2); tv_clear(&var2); } } @@ -3397,20 +3394,20 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) // The resulting variable is a substring. If the indexes // are out of range the result is empty. if (n1 < 0) { - n1 = len + n1; + n1 = (int)len + n1; if (n1 < 0) { n1 = 0; } } if (n2 < 0) { - n2 = len + n2; + n2 = (int)len + n2; } else if (n2 >= len) { - n2 = len; + n2 = (int)len; } if (n1 >= len || n2 < 0 || n1 > n2) { v = NULL; } else { - v = xmemdupz(s + n1, (size_t)(n2 - n1 + 1)); + v = xmemdupz(s + n1, (size_t)n2 - (size_t)n1 + 1); } } else { // The resulting variable is a string of a single @@ -3433,15 +3430,15 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) // The resulting variable is a sub-blob. If the indexes // are out of range the result is empty. if (n1 < 0) { - n1 = len + n1; + n1 = (int)len + n1; if (n1 < 0) { n1 = 0; } } if (n2 < 0) { - n2 = len + n2; + n2 = (int)len + n2; } else if (n2 >= len) { - n2 = len - 1; + n2 = (int)len - 1; } if (n1 >= len || n2 < 0 || n1 > n2) { tv_clear(rettv); @@ -3449,8 +3446,8 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) rettv->vval.v_blob = NULL; } else { blob_T *const blob = tv_blob_alloc(); - ga_grow(&blob->bv_ga, (int)(n2 - n1 + 1)); - blob->bv_ga.ga_len = (int)(n2 - n1 + 1); + ga_grow(&blob->bv_ga, n2 - n1 + 1); + blob->bv_ga.ga_len = n2 - n1 + 1; for (long i = n1; i <= n2; i++) { tv_blob_set(blob, (int)(i - n1), tv_blob_get(rettv->vval.v_blob, (int)i)); } @@ -3461,10 +3458,10 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) // The resulting variable is a byte value. // If the index is too big or negative that is an error. if (n1 < 0) { - n1 = len + n1; + n1 = (int)len + n1; } if (n1 < len && n1 >= 0) { - const int v = (int)tv_blob_get(rettv->vval.v_blob, (int)n1); + const int v = (int)tv_blob_get(rettv->vval.v_blob, n1); tv_clear(rettv); rettv->v_type = VAR_NUMBER; rettv->vval.v_number = v; @@ -3476,7 +3473,7 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) case VAR_LIST: len = tv_list_len(rettv->vval.v_list); if (n1 < 0) { - n1 = len + n1; + n1 = (int)len + n1; } if (!empty1 && (n1 < 0 || n1 >= len)) { // For a range we allow invalid values and return an empty @@ -3487,22 +3484,22 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) } return FAIL; } - n1 = len; + n1 = (int)len; } if (range) { list_T *l; listitem_T *item; if (n2 < 0) { - n2 = len + n2; + n2 = (int)len + n2; } else if (n2 >= len) { - n2 = len - 1; + n2 = (int)len - 1; } if (!empty2 && (n2 < 0 || n2 + 1 < n1)) { n2 = -1; } l = tv_list_alloc(n2 - n1 + 1); - item = tv_list_find(rettv->vval.v_list, (int)n1); + item = tv_list_find(rettv->vval.v_list, n1); while (n1++ <= n2) { tv_list_append_tv(l, TV_LIST_ITEM_TV(item)); item = TV_LIST_ITEM_NEXT(rettv->vval.v_list, item); @@ -3915,7 +3912,7 @@ char *partial_name(partial_T *pt) if (pt->pt_name != NULL) { return pt->pt_name; } - return (char *)pt->pt_func->uf_name; + return pt->pt_func->uf_name; } static void partial_free(partial_T *pt) @@ -4784,8 +4781,6 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map) const char *const arg_errmsg = (map ? N_("map() argument") : N_("filter() argument")); - int save_did_emsg; - int idx = 0; // Always return the first argument, also on failure. tv_copy(&argvars[0], rettv); @@ -4815,12 +4810,13 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map) // message. Avoid a misleading error message for an empty string that // was not passed as argument. if (expr->v_type != VAR_UNKNOWN) { + int idx = 0; typval_T save_val; prepare_vimvar(VV_VAL, &save_val); // We reset "did_emsg" to be able to detect whether an error // occurred during evaluation of the expression. - save_did_emsg = did_emsg; + int save_did_emsg = did_emsg; did_emsg = false; typval_T save_key; @@ -5052,7 +5048,7 @@ void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref) if (tv_list_len(list) == 0) { arg_idx = 0; } else if (tv_list_len(list) > MAX_FUNC_ARGS) { - emsg_funcname((char *)e_toomanyarg, s); + emsg_funcname(e_toomanyarg, s); xfree(name); goto theend; } @@ -6220,25 +6216,25 @@ int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp, bool c } int i = 0; - long n; + int n; if (fnump != NULL) { - n = tv_list_find_nr(l, i++, NULL); // fnum + n = (int)tv_list_find_nr(l, i++, NULL); // fnum if (n < 0) { return FAIL; } if (n == 0) { n = curbuf->b_fnum; // Current buffer. } - *fnump = (int)n; + *fnump = n; } - n = tv_list_find_nr(l, i++, NULL); // lnum + n = (int)tv_list_find_nr(l, i++, NULL); // lnum if (n < 0) { return FAIL; } - posp->lnum = (linenr_T)n; + posp->lnum = n; - n = tv_list_find_nr(l, i++, NULL); // col + n = (int)tv_list_find_nr(l, i++, NULL); // col if (n < 0) { return FAIL; } @@ -6252,15 +6248,15 @@ int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp, bool c } n = buf_charidx_to_byteidx(buf, posp->lnum == 0 ? curwin->w_cursor.lnum : posp->lnum, - (int)n) + 1; + n) + 1; } - posp->col = (colnr_T)n; + posp->col = n; - n = tv_list_find_nr(l, i, NULL); // off + n = (int)tv_list_find_nr(l, i, NULL); // off if (n < 0) { posp->coladd = 0; } else { - posp->coladd = (colnr_T)n; + posp->coladd = n; } if (curswantp != NULL) { @@ -7469,7 +7465,6 @@ void ex_execute(exarg_T *eap) if (eap->cmdidx == CMD_echomsg) { msg_ext_set_kind("echomsg"); msg_attr(ga.ga_data, echo_attr); - ui_flush(); } else if (eap->cmdidx == CMD_echoerr) { // We don't want to abort following commands, restore did_emsg. int save_did_emsg = did_emsg; @@ -8065,7 +8060,6 @@ repeat: /// @return an allocated string, NULL for error. char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char *flags) { - int sublen; regmatch_T regmatch; garray_T ga; char *zero_width = NULL; @@ -8081,6 +8075,7 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, const char regmatch.rm_ic = p_ic; regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); if (regmatch.regprog != NULL) { + int sublen; char *tail = str; char *end = str + strlen(str); while (vim_regexec_nl(®match, str, (colnr_T)(tail - str))) { diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 48f3cd4293..6f983d3208 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -492,7 +492,7 @@ buf_T *get_buf_arg(typval_T *arg) /// "byte2line(byte)" function static void f_byte2line(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - long boff = tv_get_number(&argvars[0]) - 1; + long boff = (long)tv_get_number(&argvars[0]) - 1; if (boff < 0) { rettv->vval.v_number = -1; } else { @@ -978,11 +978,11 @@ static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) listitem_T *li = tv_list_first(l); if (argvars[2].v_type != VAR_UNKNOWN) { if (argvars[3].v_type != VAR_UNKNOWN) { - long idx = tv_get_number_chk(&argvars[3], &error); + int64_t idx = tv_get_number_chk(&argvars[3], &error); if (!error) { li = tv_list_find(l, (int)idx); if (li == NULL) { - semsg(_(e_listidx), (int64_t)idx); + semsg(_(e_listidx), idx); } } } @@ -3589,7 +3589,7 @@ static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) semsg(_(e_listblobarg), "insert()"); } else if (!value_check_lock(tv_list_locked((l = argvars[0].vval.v_list)), N_("insert() argument"), TV_TRANSLATE)) { - long before = 0; + int64_t before = 0; if (argvars[2].v_type != VAR_UNKNOWN) { before = tv_get_number_chk(&argvars[2], &error); } @@ -3602,7 +3602,7 @@ static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (before != tv_list_len(l)) { item = tv_list_find(l, (int)before); if (item == NULL) { - semsg(_(e_listidx), (int64_t)before); + semsg(_(e_listidx), before); l = NULL; } } @@ -4371,11 +4371,11 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, const SomeMatchType type) { char *str = NULL; - long len = 0; + int64_t len = 0; char *expr = NULL; regmatch_T regmatch; - long start = 0; - long nth = 1; + int64_t start = 0; + int64_t nth = 1; colnr_T startcol = 0; bool match = false; list_T *l = NULL; @@ -5387,7 +5387,7 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl char *prev = NULL; // previously read bytes, if any ptrdiff_t prevlen = 0; // length of data in prev ptrdiff_t prevsize = 0; // size of prev buffer - long maxline = MAXLNUM; + int64_t maxline = MAXLNUM; if (argvars[1].v_type != VAR_UNKNOWN) { if (strcmp(tv_get_string(&argvars[1]), "b") == 0) { @@ -6161,8 +6161,8 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) { bool save_p_ws = p_ws; int retval = 0; // default: FAIL - long lnum_stop = 0; - long time_limit = 0; + linenr_T lnum_stop = 0; + int64_t time_limit = 0; int options = SEARCH_KEEP; bool use_skip = false; @@ -6184,7 +6184,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) // Optional arguments: line number to stop searching, timeout and skip. if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) { - lnum_stop = tv_get_number_chk(&argvars[2], NULL); + lnum_stop = (linenr_T)tv_get_number_chk(&argvars[2], NULL); if (lnum_stop < 0) { goto theend; } @@ -6214,7 +6214,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) pos_T pos = save_cursor = curwin->w_cursor; pos_T firstpos = { 0 }; searchit_arg_T sia = { - .sa_stop_lnum = (linenr_T)lnum_stop, + .sa_stop_lnum = lnum_stop, .sa_tm = &tm, }; @@ -6652,8 +6652,8 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) bool save_p_ws = p_ws; int flags = 0; int retval = 0; // default: FAIL - long lnum_stop = 0; - long time_limit = 0; + linenr_T lnum_stop = 0; + int64_t time_limit = 0; // Get the three pattern arguments: start, middle, end. Will result in an // error if not a valid argument. @@ -6695,7 +6695,7 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) skip = &argvars[4]; if (argvars[5].v_type != VAR_UNKNOWN) { - lnum_stop = tv_get_number_chk(&argvars[5], NULL); + lnum_stop = (linenr_T)tv_get_number_chk(&argvars[5], NULL); if (lnum_stop < 0) { semsg(_(e_invarg2), tv_get_string(&argvars[5])); goto theend; @@ -6711,7 +6711,7 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) } retval = (int)do_searchpair(spat, mpat, epat, dir, skip, - flags, match_pos, (linenr_T)lnum_stop, time_limit); + flags, match_pos, lnum_stop, time_limit); theend: p_ws = save_p_ws; @@ -6758,7 +6758,7 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv, EvalFuncData fpt /// @returns 0 or -1 for no match, long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir, const typval_T *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, - long time_limit) + int64_t time_limit) FUNC_ATTR_NONNULL_ARG(1, 2, 3) { long retval = 0; @@ -8695,7 +8695,8 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (!callback_from_typval(&callback, &argvars[1])) { return; } - rettv->vval.v_number = (varnumber_T)timer_start(tv_get_number(&argvars[0]), repeat, &callback); + rettv->vval.v_number = (varnumber_T)timer_start((const long)tv_get_number(&argvars[0]), repeat, + &callback); } /// "timer_stop(timerid)" function @@ -8768,7 +8769,7 @@ static void f_tr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) tolen = utfc_ptr2len(p); if (idx-- == 0) { cplen = tolen; - cpstr = (char *)p; + cpstr = p; break; } } diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index c298064d86..9a3a1c3c0f 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -751,8 +751,8 @@ int tv_list_concat(list_T *const l1, list_T *const l2, typval_T *const tv) } typedef struct { - char_u *s; - char_u *tofree; + char *s; + char *tofree; } Join; /// Join list into a string, helper function @@ -785,7 +785,7 @@ static int list_join_inner(garray_T *const gap, list_T *const l, const char *con sumlen += len; Join *const p = GA_APPEND_VIA_PTR(Join, join_gap); - p->tofree = p->s = (char_u *)s; + p->tofree = p->s = s; line_breakcheck(); }); @@ -806,7 +806,7 @@ static int list_join_inner(garray_T *const gap, list_T *const l, const char *con const Join *const p = ((const Join *)join_gap->ga_data) + i; if (p->s != NULL) { - ga_concat(gap, (char *)p->s); + ga_concat(gap, p->s); } line_breakcheck(); } @@ -905,14 +905,14 @@ void tv_list_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) return; } - long idx = tv_get_number_chk(&argvars[1], &error); + int64_t idx = tv_get_number_chk(&argvars[1], &error); listitem_T *item; if (error) { // Type error: do nothing, errmsg already given. } else if ((item = tv_list_find(l, (int)idx)) == NULL) { - semsg(_(e_listidx), (int64_t)idx); + semsg(_(e_listidx), idx); } else { if (argvars[2].v_type == VAR_UNKNOWN) { // Remove one item, return its value. @@ -922,11 +922,11 @@ void tv_list_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) } else { listitem_T *item2; // Remove range of items, return list with values. - long end = tv_get_number_chk(&argvars[2], &error); + int64_t end = tv_get_number_chk(&argvars[2], &error); if (error) { // Type error: do nothing. } else if ((item2 = tv_list_find(l, (int)end)) == NULL) { - semsg(_(e_listidx), (int64_t)end); + semsg(_(e_listidx), end); } else { int cnt = 0; @@ -1140,7 +1140,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) { ListSortItem *ptrs; long len; - long i; + int i; // Pointer to current info struct used in compare function. Save and restore // the current one for nested calls. @@ -1184,7 +1184,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) } else { bool error = false; - i = tv_get_number_chk(&argvars[1], &error); + i = (int)tv_get_number_chk(&argvars[1], &error); if (error) { goto theend; // type error; errmsg already given } @@ -1673,7 +1673,7 @@ char *callback_to_string(Callback *cb) } const size_t msglen = 100; - char *msg = (char *)xmallocz(msglen); + char *msg = xmallocz(msglen); switch (cb->type) { case kCallbackFuncref: @@ -2715,7 +2715,7 @@ void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) } bool error = false; - long idx = tv_get_number_chk(&argvars[1], &error); + int64_t idx = tv_get_number_chk(&argvars[1], &error); if (!error) { const int len = tv_blob_len(b); @@ -2725,7 +2725,7 @@ void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) idx = len + idx; } if (idx < 0 || idx >= len) { - semsg(_(e_blobidx), (int64_t)idx); + semsg(_(e_blobidx), idx); return; } if (argvars[2].v_type == VAR_UNKNOWN) { @@ -2736,7 +2736,7 @@ void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) b->bv_ga.ga_len--; } else { // Remove range of items, return blob with values. - long end = tv_get_number_chk(&argvars[2], &error); + int64_t end = tv_get_number_chk(&argvars[2], &error); if (error) { return; } @@ -2745,7 +2745,7 @@ void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) end = len + end; } if (end >= len || idx > end) { - semsg(_(e_blobidx), (int64_t)end); + semsg(_(e_blobidx), end); return; } blob_T *const blob = tv_blob_alloc(); diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 6c6dc3fa43..3c4cc34464 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -729,7 +729,6 @@ static void cleanup_function_call(funccall_T *fc) /// @param[in] force When true, we are exiting. static void funccal_unref(funccall_T *fc, ufunc_T *fp, bool force) { - funccall_T **pfc; int i; if (fc == NULL) { @@ -738,7 +737,7 @@ static void funccal_unref(funccall_T *fc, ufunc_T *fp, bool force) fc->fc_refcount--; if (force ? fc->fc_refcount <= 0 : !fc_referenced(fc)) { - for (pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller) { + for (funccall_T **pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller) { if (fc == *pfc) { *pfc = fc->caller; free_funccal_contents(fc); @@ -880,7 +879,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett fc->rettv = rettv; fc->level = ex_nesting_level; // Check if this function has a breakpoint. - fc->breakpoint = dbg_find_breakpoint(false, (char *)fp->uf_name, (linenr_T)0); + fc->breakpoint = dbg_find_breakpoint(false, fp->uf_name, (linenr_T)0); fc->dbg_tick = debug_tick; // Set up fields for closure. @@ -1075,7 +1074,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett bool func_not_yet_profiling_but_should = do_profiling_yes - && !fp->uf_profiling && has_profiling(false, (char *)fp->uf_name, NULL); + && !fp->uf_profiling && has_profiling(false, fp->uf_name, NULL); if (func_not_yet_profiling_but_should) { started_profiling = true; @@ -1669,7 +1668,7 @@ static void list_func_head(ufunc_T *fp, int indent, bool force) if (fp->uf_name_exp != NULL) { msg_puts((const char *)fp->uf_name_exp); } else { - msg_puts((const char *)fp->uf_name); + msg_puts(fp->uf_name); } msg_putchar('('); int j; @@ -1999,10 +1998,10 @@ static void list_functions(regmatch_T *regmatch) todo--; if ((fp->uf_flags & FC_DEAD) == 0 && (regmatch == NULL - ? (!message_filtered((char *)fp->uf_name) + ? (!message_filtered(fp->uf_name) && !func_name_refcount(fp->uf_name)) : (!isdigit((uint8_t)(*fp->uf_name)) - && vim_regexec(regmatch, (char *)fp->uf_name, 0)))) { + && vim_regexec(regmatch, fp->uf_name, 0)))) { list_func_head(fp, false, false); if (changed != func_hashtab.ht_changed) { emsg(_("E454: function list was modified")); @@ -2150,8 +2149,7 @@ void ex_function(exarg_T *eap) } } msg_prt_line(FUNCLINE(fp, j), false); - ui_flush(); // show a line at a time - os_breakcheck(); + line_breakcheck(); // show multiple lines at a time! } if (!got_int) { msg_putchar('\n'); @@ -2195,7 +2193,7 @@ void ex_function(exarg_T *eap) j++; } if (arg[j] != NUL) { - emsg_funcname((char *)e_invarg2, arg); + emsg_funcname(e_invarg2, arg); } } // Disallow using the g: dict. @@ -2749,7 +2747,7 @@ char *get_user_func_name(expand_T *xp, int idx) } if (strlen(fp->uf_name) + 4 >= IOSIZE) { - return (char *)fp->uf_name; // Prevent overflow. + return fp->uf_name; // Prevent overflow. } cat_func_name(IObuff, fp); @@ -3229,7 +3227,7 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat) // If breakpoints have been added/deleted need to check for it. if (fcp->dbg_tick != debug_tick) { - fcp->breakpoint = dbg_find_breakpoint(false, (char *)fp->uf_name, SOURCING_LNUM); + fcp->breakpoint = dbg_find_breakpoint(false, fp->uf_name, SOURCING_LNUM); fcp->dbg_tick = debug_tick; } if (do_profiling == PROF_YES) { @@ -3259,9 +3257,9 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat) // Did we encounter a breakpoint? if (fcp->breakpoint != 0 && fcp->breakpoint <= SOURCING_LNUM) { - dbg_breakpoint((char *)fp->uf_name, SOURCING_LNUM); + dbg_breakpoint(fp->uf_name, SOURCING_LNUM); // Find next breakpoint. - fcp->breakpoint = dbg_find_breakpoint(false, (char *)fp->uf_name, SOURCING_LNUM); + fcp->breakpoint = dbg_find_breakpoint(false, fp->uf_name, SOURCING_LNUM); fcp->dbg_tick = debug_tick; } @@ -3290,7 +3288,6 @@ int func_has_abort(void *cookie) /// Changes "rettv" in-place. void make_partial(dict_T *const selfdict, typval_T *const rettv) { - char *fname; char *tofree = NULL; ufunc_T *fp; char fname_buf[FLEN_FIXED + 1]; @@ -3299,7 +3296,7 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv) if (rettv->v_type == VAR_PARTIAL && rettv->vval.v_partial->pt_func != NULL) { fp = rettv->vval.v_partial->pt_func; } else { - fname = rettv->v_type == VAR_FUNC || rettv->v_type == VAR_STRING + char *fname = rettv->v_type == VAR_FUNC || rettv->v_type == VAR_STRING ? rettv->vval.v_string : rettv->vval.v_partial->pt_name; // Translate "s:func" to the stored function name. @@ -3320,7 +3317,6 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv) pt->pt_name = rettv->vval.v_string; } else { partial_T *ret_pt = rettv->vval.v_partial; - int i; // Partial: copy the function name, use selfdict and copy // args. Can't take over name or args, the partial might @@ -3336,7 +3332,7 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv) size_t arg_size = sizeof(typval_T) * (size_t)ret_pt->pt_argc; pt->pt_argv = (typval_T *)xmalloc(arg_size); pt->pt_argc = ret_pt->pt_argc; - for (i = 0; i < pt->pt_argc; i++) { + for (int i = 0; i < pt->pt_argc; i++) { tv_copy(&ret_pt->pt_argv[i], &pt->pt_argv[i]); } } @@ -3642,14 +3638,13 @@ bool set_ref_in_func(char *name, ufunc_T *fp_in, int copyID) int error = FCERR_NONE; char fname_buf[FLEN_FIXED + 1]; char *tofree = NULL; - char *fname; bool abort = false; if (name == NULL && fp_in == NULL) { return false; } if (fp_in == NULL) { - fname = fname_trans_sid(name, fname_buf, &tofree, &error); + char *fname = fname_trans_sid(name, fname_buf, &tofree, &error); fp = find_func(fname); } if (fp != NULL) { diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 9ed245d6c4..d80bdc70f6 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -369,12 +369,10 @@ int ex_let_vars(char *arg_start, typval_T *tv, int copy, int semicolon, int var_ /// @return NULL for an error. const char *skip_var_list(const char *arg, int *var_count, int *semicolon) { - const char *p; - const char *s; - if (*arg == '[') { + const char *s; // "[var, var]": find the matching ']'. - p = arg; + const char *p = arg; for (;;) { p = skipwhite(p + 1); // skip whites after '[', ';' or ',' s = skip_var_one((char *)p); @@ -575,7 +573,6 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_WARN_UNUSED_RESULT { char *arg_end = NULL; - int len; // ":let $VAR = expr": Set environment variable. if (*arg == '$') { @@ -586,7 +583,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo // Find the end of the name. arg++; char *name = arg; - len = get_env_len((const char **)&arg); + int len = get_env_len((const char **)&arg); if (len == 0) { semsg(_(e_invarg2), name - 1); } else { @@ -696,7 +693,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo if (!failed) { if (opt_type != gov_string || s != NULL) { - char *err = set_option_value(arg, n, s, scope); + char *err = set_option_value(arg, (long)n, s, scope); arg_end = p; if (err != NULL) { emsg(_(err)); @@ -722,12 +719,10 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo && vim_strchr(endchars, (uint8_t)(*skipwhite(arg + 1))) == NULL) { emsg(_(e_letunexp)); } else { - char *s; - char *ptofree = NULL; const char *p = tv_get_string_chk(tv); if (p != NULL && op != NULL && *op == '.') { - s = get_reg_contents(*arg == '@' ? '"' : *arg, kGRegExprSrc); + char *s = get_reg_contents(*arg == '@' ? '"' : *arg, kGRegExprSrc); if (s != NULL) { ptofree = concat_str(s, p); p = (const char *)ptofree; @@ -861,10 +856,9 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_ { int forceit = eap->forceit; int ret = OK; - int cc; if (lp->ll_tv == NULL) { - cc = (uint8_t)(*name_end); + int cc = (uint8_t)(*name_end); *name_end = NUL; // Environment variable, normal name or expanded name. diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index f58a0c488a..c1d2e5b38f 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -192,9 +192,9 @@ win_T *find_tabwin(typval_T *wvp, typval_T *tvp) if (wvp->v_type != VAR_UNKNOWN) { if (tvp->v_type != VAR_UNKNOWN) { - long n = tv_get_number(tvp); + int n = (int)tv_get_number(tvp); if (n >= 0) { - tp = find_tabpage((int)n); + tp = find_tabpage(n); } } else { tp = curtab; diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 1a524a56ca..1219566e9b 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -422,7 +422,12 @@ static void exit_event(void **argv) } if (!exiting) { - os_exit(status); + if (ui_client_channel_id) { + os_exit(status); + } else { + assert(status == 0); // Called from rpc_close(), which passes 0 as status. + preserve_exit(NULL); + } } } diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c index a88d62fd6b..a145452afd 100644 --- a/src/nvim/event/rstream.c +++ b/src/nvim/event/rstream.c @@ -155,7 +155,7 @@ static void fread_idle_cb(uv_idle_t *handle) uintmax_t fpos_intmax = stream->fpos; if (fpos_intmax > INT64_MAX) { ELOG("stream offset overflow"); - preserve_exit(); + preserve_exit("stream offset overflow"); } // Synchronous read diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 437a05f61d..67d1a1e2f7 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -724,7 +724,6 @@ sortend: /// @return FAIL for failure, OK otherwise int do_move(linenr_T line1, linenr_T line2, linenr_T dest) { - char *str; linenr_T l; linenr_T extra; // Num lines added before line1 linenr_T num_lines; // Num lines moved @@ -761,7 +760,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) return FAIL; } for (extra = 0, l = line1; l <= line2; l++) { - str = xstrdup(ml_get(l + extra)); + char *str = xstrdup(ml_get(l + extra)); ml_append(dest + l - line1, str, (colnr_T)0, false); xfree(str); if (dest < line1) { @@ -875,10 +874,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) /// ":copy" void ex_copy(linenr_T line1, linenr_T line2, linenr_T n) { - linenr_T count; - char *p; - - count = line2 - line1 + 1; + linenr_T count = line2 - line1 + 1; if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { curbuf->b_op_start.lnum = n + 1; curbuf->b_op_end.lnum = n + count; @@ -902,7 +898,7 @@ void ex_copy(linenr_T line1, linenr_T line2, linenr_T n) while (line1 <= line2) { // need to use xstrdup() because the line will be unlocked within // ml_append() - p = xstrdup(ml_get(line1)); + char *p = xstrdup(ml_get(line1)); ml_append(curwin->w_cursor.lnum, p, (colnr_T)0, false); xfree(p); @@ -952,7 +948,6 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out char *t; char *p; char *trailarg; - size_t len; int scroll_save = msg_scroll; // @@ -975,7 +970,7 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out // Skip leading white space to avoid a strange error with some shells. trailarg = skipwhite(arg); do { - len = strlen(trailarg) + 1; + size_t len = strlen(trailarg) + 1; if (newcmd != NULL) { len += strlen(newcmd); } @@ -1507,7 +1502,6 @@ void print_line(linenr_T lnum, int use_number, int list) print_line_no_prefix(lnum, use_number, list); if (save_silent) { msg_putchar('\n'); - ui_flush(); silent_mode = save_silent; } info_message = false; @@ -1824,7 +1818,7 @@ int check_overwrite(exarg_T *eap, buf_T *buf, char *fname, char *ffname, int oth if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) { char buff[DIALOG_MSG_SIZE]; - dialog_msg((char *)buff, _("Overwrite existing file \"%s\"?"), fname); + dialog_msg(buff, _("Overwrite existing file \"%s\"?"), fname); if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) != VIM_YES) { return FAIL; } @@ -1860,7 +1854,7 @@ int check_overwrite(exarg_T *eap, buf_T *buf, char *fname, char *ffname, int oth if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) { char buff[DIALOG_MSG_SIZE]; - dialog_msg((char *)buff, + dialog_msg(buff, _("Swap file \"%s\" exists, overwrite anyway?"), swapname); if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) @@ -1980,11 +1974,11 @@ static int check_readonly(int *forceit, buf_T *buf) char buff[DIALOG_MSG_SIZE]; if (buf->b_p_ro) { - dialog_msg((char *)buff, + dialog_msg(buff, _("'readonly' option is set for \"%s\".\nDo you wish to write anyway?"), buf->b_fname); } else { - dialog_msg((char *)buff, + dialog_msg(buff, _("File permissions of \"%s\" are read-only.\nIt may still be possible to " "write it.\nDo you wish to try?"), buf->b_fname); @@ -2737,7 +2731,6 @@ void ex_append(exarg_T *eap) linenr_T lnum = eap->line2; int indent = 0; char *p; - int vcol; int empty = (curbuf->b_ml.ml_flags & ML_EMPTY); // the ! flag toggles autoindent @@ -2804,7 +2797,7 @@ void ex_append(exarg_T *eap) } // Look for the "." after automatic indent. - vcol = 0; + int vcol = 0; for (p = theline; indent > vcol; p++) { if (*p == ' ') { vcol++; @@ -2946,7 +2939,7 @@ void ex_z(exarg_T *eap) bigness = 2 * curbuf->b_ml.ml_line_count; } - p_window = bigness; + p_window = (int)bigness; if (*kind == '=') { bigness += 2; } @@ -4340,7 +4333,6 @@ static void global_exe_one(char *const cmd, const linenr_T lnum) void ex_global(exarg_T *eap) { linenr_T lnum; // line number according to old situation - int ndone = 0; int type; // first char of cmd: 'v' or 'g' char *cmd; // command argument @@ -4412,6 +4404,7 @@ void ex_global(exarg_T *eap) global_exe_one(cmd, lnum); } } else { + int ndone = 0; // pass 1: set marks for each (not) matching line for (lnum = eap->line1; lnum <= eap->line2 && !got_int; lnum++) { // a match on this line? @@ -4688,8 +4681,6 @@ int ex_substitute_preview(exarg_T *eap, long cmdpreview_ns, handle_T cmdpreview_ /// @return a pointer to the char just past the pattern plus flags. char *skip_vimgrep_pat(char *p, char **s, int *flags) { - int c; - if (vim_isIDc((uint8_t)(*p))) { // ":vimgrep pattern fname" if (s != NULL) { @@ -4704,7 +4695,7 @@ char *skip_vimgrep_pat(char *p, char **s, int *flags) if (s != NULL) { *s = p + 1; } - c = (uint8_t)(*p); + int c = (uint8_t)(*p); p = skip_regexp(p + 1, c, true); if (*p != c) { return NULL; diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index d08823bc30..c777efb445 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -446,12 +446,9 @@ int buf_write_all(buf_T *buf, int forceit) /// ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo" void ex_listdo(exarg_T *eap) { - int i; win_T *wp; tabpage_T *tp; - int next_fnum = 0; char *save_ei = NULL; - char *p_shm_save; if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo) { // Don't do syntax HL autocommands. Skipping the syntax file is a @@ -469,7 +466,9 @@ void ex_listdo(exarg_T *eap) || !check_changed(curbuf, CCGD_AW | (eap->forceit ? CCGD_FORCEIT : 0) | CCGD_EXCMD)) { - i = 0; + int next_fnum = 0; + char *p_shm_save; + int i = 0; // start at the eap->line1 argument/window/buffer wp = firstwin; tp = first_tabpage; @@ -762,14 +761,13 @@ void ex_compiler(exarg_T *eap) /// ":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 { - buf = buflist_findnr((int)eap->line2); + buf_T *buf = buflist_findnr((int)eap->line2); if (buf != NULL) { // cannot happen? (void)buf_check_timestamp(buf); } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index a24e8458a6..f460b4b93f 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1311,16 +1311,16 @@ static void parse_register(exarg_T *eap) } // Change line1 and line2 of Ex command to use count -void set_cmd_count(exarg_T *eap, long count, bool validate) +void set_cmd_count(exarg_T *eap, linenr_T count, bool validate) { if (eap->addr_type != ADDR_LINES) { // e.g. :buffer 2, :sleep 3 - eap->line2 = (linenr_T)count; + eap->line2 = count; if (eap->addr_count == 0) { eap->addr_count = 1; } } else { eap->line1 = eap->line2; - eap->line2 += (linenr_T)count - 1; + eap->line2 += count - 1; eap->addr_count++; // Be vi compatible: no error message for out of range. if (validate && eap->line2 > curbuf->b_ml.ml_line_count) { @@ -1338,7 +1338,7 @@ static int parse_count(exarg_T *eap, char **errormsg, bool validate) if ((eap->argt & EX_COUNT) && ascii_isdigit(*eap->arg) && (!(eap->argt & EX_BUFNAME) || *(p = skipdigits(eap->arg + 1)) == NUL || ascii_iswhite(*p))) { - long n = getdigits_long(&eap->arg, false, -1); + linenr_T n = getdigits_int32(&eap->arg, false, -1); eap->arg = skipwhite(eap->arg); if (eap->args != NULL) { @@ -3200,7 +3200,7 @@ char *skip_range(const char *cmd, int *ctx) } // Skip ":" and white space. - cmd = skip_colon_white((char *)cmd, false); + cmd = skip_colon_white(cmd, false); return (char *)cmd; } @@ -4011,7 +4011,7 @@ static char *getargcmd(char **argp) if (*arg == '+') { // +[command] arg++; if (ascii_isspace(*arg) || *arg == '\0') { - command = (char *)dollar_command; + command = dollar_command; } else { command = arg; arg = skip_cmd_arg(command, true); @@ -4401,7 +4401,7 @@ static int check_more(int message, bool forceit) if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && curbuf->b_fname != NULL) { char buff[DIALOG_MSG_SIZE]; - vim_snprintf((char *)buff, DIALOG_MSG_SIZE, + vim_snprintf(buff, DIALOG_MSG_SIZE, NGETTEXT("%d more file to edit. Quit anyway?", "%d more files to edit. Quit anyway?", n), n); if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1) == VIM_YES) { @@ -4769,7 +4769,7 @@ void tabpage_close_other(tabpage_T *tp, int forceit) // Limit to 1000 windows, autocommands may add a window while we close // one. OK, so I'm paranoid... while (++done < 1000) { - snprintf((char *)prev_idx, sizeof(prev_idx), "%i", tabpage_index(tp)); + snprintf(prev_idx, sizeof(prev_idx), "%i", tabpage_index(tp)); win_T *wp = tp->tp_lastwin; ex_win_close(forceit, wp, tp); @@ -4838,13 +4838,9 @@ static void ex_stop(exarg_T *eap) } apply_autocmds(EVENT_VIMSUSPEND, NULL, NULL, false, NULL); - // TODO(bfredl): the TUI should do this on suspend - ui_cursor_goto(Rows - 1, 0); - ui_call_grid_scroll(1, 0, Rows, 0, Columns, 1, 0); + ui_call_suspend(); ui_flush(); - ui_call_suspend(); // call machine specific function - ui_flush(); maketitle(); resettitle(); // force updating the title ui_refresh(); // may have resized window @@ -6752,7 +6748,7 @@ char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnum // Note: In "\\%" the % is also not recognized! if (src > srcstart && src[-1] == '\\') { *usedlen = 0; - STRMOVE(src - 1, (char *)src); // remove backslash + STRMOVE(src - 1, src); // remove backslash return NULL; } @@ -6929,7 +6925,7 @@ char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnum *errormsg = _("E961: no line number to use for \"<sflnum>\""); return NULL; } - snprintf((char *)strbuf, sizeof(strbuf), "%" PRIdLINENR, + snprintf(strbuf, sizeof(strbuf), "%" PRIdLINENR, current_sctx.sc_lnum + SOURCING_LNUM); result = strbuf; break; diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index f76e60f6c5..1cef99297a 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -278,9 +278,8 @@ bool cause_errthrow(const char *mesg, bool severe, bool *ignore) /// Free a "msg_list" and the messages it contains. static void free_msglist(msglist_T *l) { - msglist_T *messages, *next; - - messages = l; + msglist_T *next; + msglist_T *messages = l; while (messages != NULL) { next = messages->next; xfree(messages->msg); @@ -379,9 +378,10 @@ int do_intthrow(cstack_T *cstack) char *get_exception_string(void *value, except_type_T type, char *cmdname, int *should_free) { char *ret, *mesg; - char *p, *val; if (type == ET_ERROR) { + char *p; + char *val; *should_free = true; mesg = ((msglist_T *)value)->throw_msg; if (cmdname != NULL && *cmdname != NUL) { @@ -441,9 +441,6 @@ char *get_exception_string(void *value, except_type_T type, char *cmdname, int * /// exception. static int throw_exception(void *value, except_type_T type, char *cmdname) { - except_T *excp; - int should_free; - // Disallow faking Interrupt or error exceptions as user exceptions. They // would be treated differently from real interrupt or error exceptions // when no active try block is found, see do_cmdline(). @@ -456,7 +453,7 @@ static int throw_exception(void *value, except_type_T type, char *cmdname) } } - excp = xmalloc(sizeof(except_T)); + except_T *excp = xmalloc(sizeof(except_T)); if (type == ET_ERROR) { // Store the original message and prefix the exception value with @@ -464,6 +461,7 @@ static int throw_exception(void *value, except_type_T type, char *cmdname) excp->messages = (msglist_T *)value; } + int should_free; excp->value = get_exception_string(value, type, cmdname, &should_free); if (excp->value == NULL && should_free) { goto nomem; @@ -525,8 +523,6 @@ fail: /// caught and the catch clause has been ended normally. static void discard_exception(except_T *excp, bool was_finished) { - char *saved_IObuff; - if (current_exception == excp) { current_exception = NULL; } @@ -538,7 +534,7 @@ static void discard_exception(except_T *excp, bool was_finished) if (p_verbose >= 13 || debug_break_level > 0) { int save_msg_silent = msg_silent; - saved_IObuff = xstrdup(IObuff); + char *saved_IObuff = xstrdup(IObuff); if (debug_break_level > 0) { msg_silent = false; // display messages } else { @@ -677,7 +673,6 @@ static void report_pending(int action, int pending, void *value) { char *mesg; char *s; - int save_msg_silent; assert(value || !(pending & CSTP_THROW)); @@ -727,7 +722,7 @@ static void report_pending(int action, int pending, void *value) } } - save_msg_silent = msg_silent; + int save_msg_silent = msg_silent; if (debug_break_level > 0) { msg_silent = false; // display messages } @@ -806,8 +801,6 @@ void ex_eval(exarg_T *eap) /// Handle ":if". void ex_if(exarg_T *eap) { - int skip; - int result; cstack_T *const cstack = eap->cstack; if (cstack->cs_idx == CSTACK_LEN - 1) { @@ -816,10 +809,10 @@ void ex_if(exarg_T *eap) cstack->cs_idx++; cstack->cs_flags[cstack->cs_idx] = 0; - skip = CHECK_SKIP; + int skip = CHECK_SKIP; bool error; - result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); + int result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); if (!skip && !error) { if (result) { @@ -860,7 +853,6 @@ void ex_endif(exarg_T *eap) /// Handle ":else" and ":elseif". void ex_else(exarg_T *eap) { - bool result = false; cstack_T *const cstack = eap->cstack; bool skip = CHECK_SKIP; @@ -907,6 +899,7 @@ void ex_else(exarg_T *eap) } if (eap->cmdidx == CMD_elseif) { + bool result = false; bool error; // When skipping we ignore most errors, but a missing expression is // wrong, perhaps it should have been "else". @@ -941,13 +934,12 @@ void ex_else(exarg_T *eap) void ex_while(exarg_T *eap) { bool error; - int skip; - int result; cstack_T *const cstack = eap->cstack; if (cstack->cs_idx == CSTACK_LEN - 1) { eap->errmsg = _("E585: :while/:for nesting too deep"); } else { + int result; // The loop flag is set when we have jumped back from the matching // ":endwhile" or ":endfor". When not set, need to initialise this // cstack entry. @@ -959,7 +951,7 @@ void ex_while(exarg_T *eap) cstack->cs_flags[cstack->cs_idx] = eap->cmdidx == CMD_while ? CSF_WHILE : CSF_FOR; - skip = CHECK_SKIP; + int skip = CHECK_SKIP; if (eap->cmdidx == CMD_while) { // ":while bool-expr" result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); @@ -1013,7 +1005,6 @@ void ex_while(exarg_T *eap) /// Handle ":continue" void ex_continue(exarg_T *eap) { - int idx; cstack_T *const cstack = eap->cstack; if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0) { @@ -1023,7 +1014,7 @@ void ex_continue(exarg_T *eap) // conditional not in its finally clause (which is then to be executed // next). Therefore, deactivate all conditionals except the ":while" // itself (if reached). - idx = cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, false); + int idx = cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, false); assert(idx >= 0); if (cstack->cs_flags[idx] & (CSF_WHILE | CSF_FOR)) { rewind_conditionals(cstack, idx, CSF_TRY, &cstack->cs_trylevel); @@ -1043,7 +1034,6 @@ void ex_continue(exarg_T *eap) /// Handle ":break" void ex_break(exarg_T *eap) { - int idx; cstack_T *const cstack = eap->cstack; if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0) { @@ -1053,7 +1043,7 @@ void ex_break(exarg_T *eap) // conditional not in its finally clause (which is then to be // executed next) is found. In the latter case, make the ":break" // pending for execution at the ":endtry". - idx = cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, true); + int idx = cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, true); if (idx >= 0 && !(cstack->cs_flags[idx] & (CSF_WHILE | CSF_FOR))) { cstack->cs_pending[idx] = CSTP_BREAK; report_make_pending(CSTP_BREAK, NULL); @@ -1065,10 +1055,8 @@ void ex_break(exarg_T *eap) void ex_endwhile(exarg_T *eap) { cstack_T *const cstack = eap->cstack; - int idx; char *err; int csf; - int fl; if (eap->cmdidx == CMD_endwhile) { err = e_while; @@ -1081,7 +1069,7 @@ void ex_endwhile(exarg_T *eap) if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0) { eap->errmsg = _(err); } else { - fl = cstack->cs_flags[cstack->cs_idx]; + int fl = cstack->cs_flags[cstack->cs_idx]; if (!(fl & csf)) { // If we are in a ":while" or ":for" but used the wrong endloop // command, do not rewind to the next enclosing ":for"/":while". @@ -1098,6 +1086,7 @@ void ex_endwhile(exarg_T *eap) eap->errmsg = _(e_endtry); } // Try to find the matching ":while" and report what's missing. + int idx; for (idx = cstack->cs_idx; idx > 0; idx--) { fl = cstack->cs_flags[idx]; if ((fl & CSF_TRY) && !(fl & CSF_FINALLY)) { @@ -1163,10 +1152,8 @@ void ex_throw(exarg_T *eap) /// used for rethrowing an uncaught exception. void do_throw(cstack_T *cstack) { - int idx; int inactivate_try = false; - // // Cleanup and deactivate up to the next surrounding try conditional that // is not in its finally clause. Normally, do not deactivate the try // conditional itself, so that its ACTIVE flag can be tested below. But @@ -1174,7 +1161,7 @@ void do_throw(cstack_T *cstack) // deactivate the try conditional, too, as if the conversion had been done, // and reset the did_emsg or got_int flag, so this won't happen again at // the next surrounding try conditional. - // + #ifndef THROW_ON_ERROR_TRUE if (did_emsg && !THROW_ON_ERROR) { inactivate_try = true; @@ -1187,7 +1174,7 @@ void do_throw(cstack_T *cstack) got_int = false; } #endif - idx = cleanup_conditionals(cstack, 0, inactivate_try); + int idx = cleanup_conditionals(cstack, 0, inactivate_try); if (idx >= 0) { // If this try conditional is active and we are before its first // ":catch", set THROWN so that the ":catch" commands will check @@ -1220,7 +1207,6 @@ void do_throw(cstack_T *cstack) /// Handle ":try" void ex_try(exarg_T *eap) { - int skip; cstack_T *const cstack = eap->cstack; if (cstack->cs_idx == CSTACK_LEN - 1) { @@ -1231,7 +1217,7 @@ void ex_try(exarg_T *eap) cstack->cs_flags[cstack->cs_idx] = CSF_TRY; cstack->cs_pending[cstack->cs_idx] = CSTP_NONE; - skip = CHECK_SKIP; + int skip = CHECK_SKIP; if (!skip) { // Set ACTIVE and TRUE. TRUE means that the corresponding ":catch" @@ -1271,12 +1257,9 @@ void ex_catch(exarg_T *eap) int idx = 0; bool give_up = false; bool skip = false; - bool caught = false; char *end; - char save_char = 0; char *save_cpo; regmatch_T regmatch; - int prev_got_int; cstack_T *const cstack = eap->cstack; char *pat; @@ -1319,6 +1302,7 @@ void ex_catch(exarg_T *eap) } if (!give_up) { + bool caught = false; // Don't do something when no exception has been thrown or when the // corresponding try block never got active (because of an inactive // surrounding conditional or after an error or interrupt or throw). @@ -1344,6 +1328,7 @@ void ex_catch(exarg_T *eap) // the original exception, replace it by an interrupt exception, // and don't catch it in this try block. if (!dbg_check_skipped(eap) || !do_intthrow(cstack)) { + char save_char = 0; // Terminate the pattern and avoid the 'l' flag in 'cpoptions' // while compiling it. if (end != NULL) { @@ -1365,12 +1350,11 @@ void ex_catch(exarg_T *eap) if (regmatch.regprog == NULL) { semsg(_(e_invarg2), pat); } else { - // // 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; + + int prev_got_int = got_int; got_int = false; caught = vim_regexec_nl(®match, current_exception->value, (colnr_T)0); got_int |= prev_got_int; @@ -1415,7 +1399,6 @@ void ex_catch(exarg_T *eap) void ex_finally(exarg_T *eap) { int idx; - int skip = false; int pending = CSTP_NONE; cstack_T *const cstack = eap->cstack; @@ -1451,7 +1434,7 @@ void ex_finally(exarg_T *eap) // ":finally". After every other error (did_emsg or the conditional // errors detected above) or after an interrupt (got_int) or an // exception (did_throw), the finally clause must be executed. - skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE); + int skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE); if (!skip) { // When debugging or a breakpoint was encountered, display the @@ -1985,14 +1968,12 @@ void ex_endfunction(exarg_T *eap) /// @return true if the string "p" looks like a ":while" or ":for" command. int has_loop_cmd(char *p) { - int len; - // skip modifiers, white space and ':' for (;;) { while (*p == ' ' || *p == '\t' || *p == ':') { p++; } - len = modifier_len(p); + int len = modifier_len(p); if (len == 0) { break; } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 76c3680742..af26fe8a1c 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1598,8 +1598,10 @@ static int command_line_insert_reg(CommandLineState *s) } } + bool literally = false; if (s->c != ESC) { // use ESC to cancel inserting register - cmdline_paste(s->c, i == Ctrl_R, false); + literally = i == Ctrl_R; + cmdline_paste(s->c, literally, false); // When there was a serious error abort getting the // command line. @@ -1624,8 +1626,9 @@ static int command_line_insert_reg(CommandLineState *s) ccline.special_char = NUL; redrawcmd(); - // The text has been stuffed, the command line didn't change yet. - return CMDLINE_NOT_CHANGED; + // With "literally": the command line has already changed. + // Else: the text has been stuffed, but the command line didn't change yet. + return literally ? CMDLINE_CHANGED : CMDLINE_NOT_CHANGED; } /// Handle the Left and Right mouse clicks in the command-line mode. @@ -1729,7 +1732,6 @@ static int command_line_browse_history(CommandLineState *s) if (s->hiscnt != s->save_hiscnt) { // jumped to other entry char *p; - int len = 0; int old_firstc; XFREE_CLEAR(ccline.cmdbuff); @@ -1743,6 +1745,7 @@ static int command_line_browse_history(CommandLineState *s) if (s->histype == HIST_SEARCH && p != s->lookfor && (old_firstc = (uint8_t)p[strlen(p) + 1]) != s->firstc) { + int len = 0; // Correct for the separator character used when // adding the history entry vs the one used now. // First loop: count length. @@ -1857,12 +1860,12 @@ static int command_line_handle_key(CommandLineState *s) case Ctrl_R: // insert register switch (command_line_insert_reg(s)) { - case CMDLINE_NOT_CHANGED: - return command_line_not_changed(s); case GOTO_NORMAL_MODE: return 0; // back to cmd mode - default: + case CMDLINE_CHANGED: return command_line_changed(s); + default: + return command_line_not_changed(s); } case Ctrl_D: @@ -2015,7 +2018,7 @@ static int command_line_handle_key(CommandLineState *s) if (nextwild(&s->xpc, wild_type, 0, s->firstc != '@') == FAIL) { break; } - return command_line_not_changed(s); + return command_line_changed(s); } FALLTHROUGH; @@ -2037,7 +2040,7 @@ static int command_line_handle_key(CommandLineState *s) if (nextwild(&s->xpc, wild_type, 0, s->firstc != '@') == FAIL) { break; } - return command_line_not_changed(s); + return command_line_changed(s); } else { switch (command_line_browse_history(s)) { case CMDLINE_CHANGED: @@ -3380,14 +3383,14 @@ static void ui_ext_cmdline_show(CmdlineInfo *line) ADD_C(item, INTEGER_OBJ(chunk.attr)); assert(chunk.end >= chunk.start); - ADD_C(item, STRING_OBJ(cbuf_as_string((char *)line->cmdbuff + chunk.start, + ADD_C(item, STRING_OBJ(cbuf_as_string(line->cmdbuff + chunk.start, (size_t)(chunk.end - chunk.start)))); ADD_C(content, ARRAY_OBJ(item)); } } else { Array item = arena_array(&arena, 2); ADD_C(item, INTEGER_OBJ(0)); - ADD_C(item, STRING_OBJ(cstr_as_string((char *)(line->cmdbuff)))); + ADD_C(item, STRING_OBJ(cstr_as_string(line->cmdbuff))); content = arena_array(&arena, 1); ADD_C(content, ARRAY_OBJ(item)); } @@ -3676,7 +3679,6 @@ static void restore_cmdline(CmdlineInfo *ccp) static bool cmdline_paste(int regname, bool literally, bool remcr) { char *arg; - char *p; bool allocated; // check for valid regname; also accept special characters for CTRL-R in @@ -3708,7 +3710,7 @@ static bool cmdline_paste(int regname, bool literally, bool remcr) // When 'incsearch' is set and CTRL-R CTRL-W used: skip the duplicate // part of the word. - p = arg; + char *p = arg; if (p_is && regname == Ctrl_W) { char *w; int len; @@ -3743,17 +3745,15 @@ static bool cmdline_paste(int regname, bool literally, bool remcr) // line. void cmdline_paste_str(char *s, int literally) { - int c, cv; - if (literally) { put_on_cmdline(s, -1, true); } else { while (*s != NUL) { - cv = (uint8_t)(*s); + int cv = (uint8_t)(*s); if (cv == Ctrl_V && s[1]) { s++; } - c = mb_cptr2char_adv((const char **)&s); + int c = mb_cptr2char_adv((const char **)&s); if (cv == Ctrl_V || c == ESC || c == Ctrl_C || c == CAR || c == NL || c == Ctrl_L || (c == Ctrl_BSL && *s == Ctrl_N)) { @@ -3781,8 +3781,6 @@ void redrawcmdline(void) static void redrawcmdprompt(void) { - int i; - if (cmd_silent) { return; } @@ -3801,7 +3799,7 @@ static void redrawcmdprompt(void) ccline.cmdindent--; } } else { - for (i = ccline.cmdindent; i > 0; i--) { + for (int i = ccline.cmdindent; i > 0; i--) { msg_putchar(' '); } } @@ -4284,12 +4282,10 @@ void cmdline_init(void) /// Returns NULL if value is OK, error message otherwise. char *check_cedit(void) { - int n; - if (*p_cedit == NUL) { cedit_key = -1; } else { - n = string_to_key(p_cedit); + int n = string_to_key(p_cedit); if (vim_isprintc(n)) { return e_invarg; } @@ -4309,9 +4305,7 @@ static int open_cmdwin(void) bufref_T old_curbuf; bufref_T bufref; win_T *old_curwin = curwin; - win_T *wp; int i; - linenr_T lnum; garray_T winsizes; char typestr[2]; int save_restart_edit = restart_edit; @@ -4392,7 +4386,7 @@ static int open_cmdwin(void) if (get_hislen() > 0 && histtype != HIST_INVALID) { i = *get_hisidx(histtype); if (i >= 0) { - lnum = 0; + linenr_T lnum = 0; do { if (++i == get_hislen()) { i = 0; @@ -4463,6 +4457,7 @@ static int open_cmdwin(void) cmdwin_result = Ctrl_C; emsg(_("E199: Active window or buffer deleted")); } else { + win_T *wp; // autocmds may abort script processing if (aborting() && cmdwin_result != K_IGNORE) { cmdwin_result = Ctrl_C; diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index 3de5e1db52..8e3e68d9b7 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -65,10 +65,10 @@ static int put_view_curpos(FILE *fd, const win_T *wp, char *spaces) static int ses_winsizes(FILE *fd, int restore_size, win_T *tab_firstwin) { - int n = 0; win_T *wp; if (restore_size && (ssop_flags & SSOP_WINSIZE)) { + int n = 0; for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) { if (!ses_do_win(wp)) { continue; @@ -218,14 +218,13 @@ static int ses_do_win(win_T *wp) static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname, unsigned *flagp) { char *buf = NULL; - char *s; if (fprintf(fd, "%s\n%s\n", cmd, "%argdel") < 0) { return FAIL; } for (int i = 0; i < gap->ga_len; i++) { // NULL file names are skipped (only happens when out of memory). - s = alist_name(&((aentry_T *)gap->ga_data)[i]); + char *s = alist_name(&((aentry_T *)gap->ga_data)[i]); if (s != NULL) { if (fullname) { buf = xmalloc(MAXPATHL); @@ -551,7 +550,6 @@ static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int curr static int makeopens(FILE *fd, char *dirnow) { int only_save_windows = true; - int nr; int restore_size = true; win_T *wp; char *sname; @@ -753,11 +751,9 @@ static int makeopens(FILE *fd, char *dirnow) PUTLINE_FAIL("let &splitright = s:save_splitright"); } - // // Check if window sizes can be restored (no windows omitted). // Remember the window number of the current window after restoring. - // - nr = 0; + int nr = 0; for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) { if (ses_do_win(wp)) { nr++; @@ -927,11 +923,9 @@ void ex_loadview(exarg_T *eap) void ex_mkrc(exarg_T *eap) { FILE *fd; - int failed = false; int view_session = false; // :mkview, :mksession int using_vdir = false; // using 'viewdir'? char *viewFile = NULL; - unsigned *flagp; if (eap->cmdidx == CMD_mksession || eap->cmdidx == CMD_mkview) { view_session = true; @@ -970,6 +964,8 @@ void ex_mkrc(exarg_T *eap) fd = open_exfile(fname, eap->forceit, WRITEBIN); if (fd != NULL) { + int failed = false; + unsigned *flagp; if (eap->cmdidx == CMD_mkview) { flagp = &vop_flags; } else { diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index 3e059bcc6c..1132a5e752 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -152,6 +152,7 @@ revised: buf->b_signs++; } if (decor->sign_text) { + buf->b_signs_with_text++; // TODO(lewis6991): smarter invalidation buf_signcols_add_check(buf, NULL); } diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index 42ba0bee97..e27c7c4349 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -1026,8 +1026,6 @@ static ff_visited_list_hdr_T *ff_get_visited_list(char *filename, static bool ff_wc_equal(char *s1, char *s2) { int i, j; - int c1 = NUL; - int c2 = NUL; int prev1 = NUL; int prev2 = NUL; @@ -1040,8 +1038,8 @@ static bool ff_wc_equal(char *s1, char *s2) } for (i = 0, j = 0; s1[i] != NUL && s2[j] != NUL;) { - c1 = utf_ptr2char(s1 + i); - c2 = utf_ptr2char(s2 + j); + int c1 = utf_ptr2char(s1 + i); + int c2 = utf_ptr2char(s2 + j); if ((p_fic ? mb_tolower(c1) != mb_tolower(c2) : c1 != c2) && (prev1 != '*' || prev2 != '*')) { diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index fbb5c4f1fa..8c904f0c0a 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -64,6 +64,10 @@ #include "nvim/undo.h" #include "nvim/vim.h" +#ifdef BACKSLASH_IN_FILENAME +# include "nvim/charset.h" +#endif + #if defined(HAVE_FLOCK) && defined(HAVE_DIRFD) # include <dirent.h> # include <sys/file.h> @@ -207,7 +211,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, char *line_start = NULL; // init to shut up gcc int wasempty; // buffer was empty before reading colnr_T len; - long size = 0; + ptrdiff_t size = 0; uint8_t *p = NULL; off_T filesize = 0; bool skip_read = false; @@ -217,7 +221,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, linenr_T linecnt; bool error = false; // errors encountered int ff_error = EOL_UNKNOWN; // file format with errors - long linerest = 0; // remaining chars in line + ptrdiff_t linerest = 0; // remaining chars in line int perm = 0; #ifdef UNIX int swap_mode = -1; // protection bits for swap file @@ -1079,7 +1083,7 @@ retry: if (size < 2 || curbuf->b_p_bin) { ccname = NULL; } else { - ccname = check_for_bom(ptr, size, &blen, + ccname = check_for_bom(ptr, (int)size, &blen, fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc)); } if (ccname != NULL) { @@ -4038,7 +4042,7 @@ static int get_fio_flags(const char *name) /// /// @return the name of the encoding and set "*lenp" to the length or, /// NULL when no BOM found. -static char *check_for_bom(const char *p_in, long size, int *lenp, int flags) +static char *check_for_bom(const char *p_in, int size, int *lenp, int flags) { const uint8_t *p = (const uint8_t *)p_in; char *name = NULL; @@ -5630,7 +5634,7 @@ long read_eintr(int fd, void *buf, size_t bufsize) long ret; for (;;) { - ret = read(fd, buf, bufsize); + ret = read(fd, buf, (unsigned int)bufsize); if (ret >= 0 || errno != EINTR) { break; } @@ -5647,7 +5651,7 @@ long write_eintr(int fd, void *buf, size_t bufsize) // Repeat the write() so long it didn't fail, other than being interrupted // by a signal. while (ret < (long)bufsize) { - long wlen = write(fd, (char *)buf + ret, bufsize - (size_t)ret); + long wlen = write(fd, (char *)buf + ret, (unsigned int)(bufsize - (size_t)ret)); if (wlen < 0) { if (errno != EINTR) { break; diff --git a/src/nvim/fileio.h b/src/nvim/fileio.h index dabcda5bf2..3e51e361ac 100644 --- a/src/nvim/fileio.h +++ b/src/nvim/fileio.h @@ -18,8 +18,6 @@ #define READ_NOWINENTER 0x80 // do not trigger BufWinEnter #define READ_NOFILE 0x100 // do not read a file, do trigger BufReadCmd -#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) - typedef varnumber_T (*CheckItem)(void *expr, const char *name); #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/fold.h b/src/nvim/fold.h index ac1e8c9419..cf44cf14c3 100644 --- a/src/nvim/fold.h +++ b/src/nvim/fold.h @@ -9,17 +9,6 @@ #include "nvim/pos.h" #include "nvim/types.h" -// Info used to pass info about a fold from the fold-detection code to the -// code that displays the foldcolumn. -typedef struct foldinfo { - linenr_T fi_lnum; // line number where fold starts - int fi_level; // level of the fold; when this is zero the - // other fields are invalid - int fi_low_level; // lowest fold level that starts in the same - // line - linenr_T fi_lines; -} foldinfo_T; - EXTERN int disable_fold_update INIT(= 0); #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/fold_defs.h b/src/nvim/fold_defs.h new file mode 100644 index 0000000000..c528d25348 --- /dev/null +++ b/src/nvim/fold_defs.h @@ -0,0 +1,17 @@ +#ifndef NVIM_FOLD_DEFS_H +#define NVIM_FOLD_DEFS_H + +#include "nvim/pos.h" + +// Info used to pass info about a fold from the fold-detection code to the +// code that displays the foldcolumn. +typedef struct foldinfo { + linenr_T fi_lnum; // line number where fold starts + int fi_level; // level of the fold; when this is zero the + // other fields are invalid + int fi_low_level; // lowest fold level that starts in the same + // line + linenr_T fi_lines; +} foldinfo_T; + +#endif // NVIM_FOLD_DEFS_H diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 8ed9381bca..37840f8875 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -155,7 +155,6 @@ static char *get_buffcont(buffheader_T *buffer, int dozero) { size_t count = 0; char *p = NULL; - char *p2; // compute the total length of the string for (const buffblock_T *bp = buffer->bh_first.b_next; @@ -165,7 +164,7 @@ static char *get_buffcont(buffheader_T *buffer, int dozero) if (count || dozero) { p = xmalloc(count + 1); - p2 = p; + char *p2 = p; for (const buffblock_T *bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next) { for (const char *str = bp->b_str; *str;) { @@ -180,7 +179,7 @@ static char *get_buffcont(buffheader_T *buffer, int dozero) /// Return the contents of the record buffer as a single string /// and clear the record buffer. /// K_SPECIAL in the returned string is escaped. -char_u *get_recorded(void) +char *get_recorded(void) { char *p; size_t len; @@ -202,7 +201,7 @@ char_u *get_recorded(void) p[len - 1] = NUL; } - return (char_u *)p; + return p; } /// Return the contents of the redo buffer as a single string. @@ -583,7 +582,7 @@ void stuffRedoReadbuff(const char *s) add_buff(&readbuf2, s, -1L); } -void stuffReadbuffLen(const char *s, long len) +void stuffReadbuffLen(const char *s, ptrdiff_t len) { add_buff(&readbuf1, s, len); } @@ -635,7 +634,7 @@ void stuffescaped(const char *arg, bool literally) arg++; } if (arg > start) { - stuffReadbuffLen(start, (arg - start)); + stuffReadbuffLen(start, arg - start); } // stuff a single special character @@ -662,7 +661,6 @@ static int read_redo(bool init, bool old_redo) int c; int n; char_u buf[MB_MAXBYTES + 1]; - int i; if (init) { bp = old_redo ? old_redobuff.bh_first.b_next : redobuff.bh_first.b_next; @@ -683,7 +681,7 @@ static int read_redo(bool init, bool old_redo) } else { n = 1; } - for (i = 0;; i++) { + for (int i = 0;; i++) { if (c == K_SPECIAL) { // special key or escaped K_SPECIAL c = TO_SPECIAL(p[1], p[2]); p += 2; @@ -858,7 +856,6 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent) { char_u *s1, *s2; int addlen; - int i; int val; int nrm; @@ -948,7 +945,7 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent) } else { nrm = noremap; } - for (i = 0; i < addlen; i++) { + for (int i = 0; i < addlen; i++) { typebuf.tb_noremap[typebuf.tb_off + i + offset] = (uint8_t)((--nrm >= 0) ? val : RM_YES); } @@ -979,7 +976,7 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent) int ins_char_typebuf(int c, int modifiers) { char_u buf[MB_MAXBYTES * 3 + 4]; - unsigned int len = special_to_buf(c, modifiers, true, buf); + unsigned int len = special_to_buf(c, modifiers, true, (char *)buf); assert(len < sizeof(buf)); buf[len] = NUL; (void)ins_typebuf((char *)buf, KeyNoremap, 0, !KeyTyped, cmd_silent); @@ -1020,8 +1017,6 @@ int typebuf_maplen(void) // remove "len" characters from typebuf.tb_buf[typebuf.tb_off + offset] void del_typebuf(int len, int offset) { - int i; - if (len == 0) { return; // nothing to do } @@ -1034,7 +1029,7 @@ void del_typebuf(int len, int offset) typebuf.tb_off += len; } else { // Have to move the characters in typebuf.tb_buf[] and typebuf.tb_noremap[] - i = typebuf.tb_off + offset; + int i = typebuf.tb_off + offset; // Leave some extra room at the end to avoid reallocation. if (typebuf.tb_off > MAXMAPLEN) { memmove(typebuf.tb_buf + MAXMAPLEN, @@ -1408,10 +1403,8 @@ int merge_modifiers(int c_arg, int *modifiers) /// Returns the modifiers in the global "mod_mask". int vgetc(void) { - int c, c2; - int n; + int c; char_u buf[MB_MAXBYTES + 1]; - int i; // Do garbage collection when garbagecollect() was called previously and // we are now at the toplevel. @@ -1429,6 +1422,8 @@ int vgetc(void) mouse_row = old_mouse_row; mouse_col = old_mouse_col; } else { + int c2; + int n; // number of characters recorded from the last vgetc() call static size_t last_vgetc_recorded_len = 0; @@ -1554,7 +1549,7 @@ int vgetc(void) if ((n = MB_BYTE2LEN_CHECK(c)) > 1) { no_mapping++; buf[0] = (char_u)c; - for (i = 1; i < n; i++) { + for (int i = 1; i < n; i++) { buf[i] = (char_u)vgetorpeek(true); if (buf[i] == K_SPECIAL) { // Must be a K_SPECIAL - KS_SPECIAL - KE_FILLER sequence, @@ -1754,9 +1749,9 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) int grid = mouse_grid; linenr_T lnum; win_T *wp; - int winnr = 1; if (row >= 0 && col >= 0) { + int winnr = 1; // Find the window at the mouse coordinates and compute the // text position. win_T *const win = mouse_find_win(&grid, &row, &col); @@ -1921,9 +1916,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth) int max_mlen = 0; int tb_c1; int mlen; - int nolmaplen; int keylen = *keylenp; - int i; int local_State = get_real_state(); bool is_plug_map = false; @@ -1956,6 +1949,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth) && State != MODE_ASKMORE && State != MODE_CONFIRM && !at_ins_compl_key()) { + int nolmaplen; if (tb_c1 == K_SPECIAL) { nolmaplen = 2; } else { @@ -2168,6 +2162,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth) // complete match if (keylen >= 0 && keylen <= typebuf.tb_len) { + int i; char *map_str = NULL; // Write chars to script file(s). @@ -2199,7 +2194,7 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth) // mode temporarily. Append K_SELECT to switch back to Select mode. if (VIsual_active && VIsual_select && (mp->m_mode & MODE_VISUAL)) { VIsual_select = false; - (void)ins_typebuf((char *)K_SELECT_STRING, REMAP_NONE, 0, true, false); + (void)ins_typebuf(K_SELECT_STRING, REMAP_NONE, 0, true, false); } // Copy the values from *mp that are used, because evaluating the @@ -2218,9 +2213,6 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth) if (mp->m_expr) { const int save_vgetc_busy = vgetc_busy; const bool save_may_garbage_collect = may_garbage_collect; - const int save_cursor_row = ui_current_row(); - const int save_cursor_col = ui_current_col(); - const handle_T save_cursor_grid = ui_cursor_grid(); const int prev_did_emsg = did_emsg; vgetc_busy = 0; @@ -2232,28 +2224,28 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth) } map_str = eval_map_expr(mp, NUL); - // The mapping may do anything, but we expect it to take care of - // redrawing. Do put the cursor back where it was. - ui_grid_cursor_goto(save_cursor_grid, save_cursor_row, save_cursor_col); - ui_flush(); - - // If an error was displayed and the expression returns an empty - // string, generate a <Nop> to allow for a redraw. - if (prev_did_emsg != did_emsg && (map_str == NULL || *map_str == NUL)) { - char buf[4]; - xfree(map_str); - buf[0] = (char)K_SPECIAL; - buf[1] = (char)KS_EXTRA; - buf[2] = KE_IGNORE; - buf[3] = NUL; - map_str = xstrdup(buf); - if (State & MODE_CMDLINE) { - // redraw the command below the error - msg_didout = true; - if (msg_row < cmdline_row) { - msg_row = cmdline_row; + if ((map_str == NULL || *map_str == NUL)) { + // If an error was displayed and the expression returns an empty + // string, generate a <Nop> to allow for a redraw. + if (prev_did_emsg != did_emsg) { + char buf[4]; + xfree(map_str); + buf[0] = (char)K_SPECIAL; + buf[1] = (char)KS_EXTRA; + buf[2] = KE_IGNORE; + buf[3] = NUL; + map_str = xstrdup(buf); + if (State & MODE_CMDLINE) { + // redraw the command below the error + msg_didout = true; + if (msg_row < cmdline_row) { + msg_row = cmdline_row; + } + redrawcmd(); } - redrawcmd(); + } else if (State & (MODE_NORMAL | MODE_INSERT)) { + // otherwise, just put back the cursor + setcursor(); } } @@ -2512,9 +2504,6 @@ static int vgetorpeek(bool advance) && (State & MODE_INSERT) && (p_timeout || (keylen == KEYLEN_PART_KEY && p_ttimeout)) && (c = inchar(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len, 3, 25L)) == 0) { - colnr_T col = 0; - char_u *ptr; - if (mode_displayed) { unshowmode(true); mode_deleted = true; @@ -2525,6 +2514,8 @@ static int vgetorpeek(bool advance) // move cursor left, if possible if (curwin->w_cursor.col != 0) { + colnr_T col = 0; + char_u *ptr; if (curwin->w_wcol > 0) { // After auto-indenting and no text is following, // we are expecting to truncate the trailing @@ -2893,13 +2884,13 @@ int inchar(char_u *buf, int maxlen, long wait_time) typebuf.tb_change_cnt = 1; } - return fix_input_buffer(buf, len); + return fix_input_buffer((char *)buf, len); } // Fix typed characters for use by vgetc() and check_termcode(). // "buf[]" must have room to triple the number of bytes! // Returns the new length. -int fix_input_buffer(char_u *buf, int len) +int fix_input_buffer(char *buf, int len) FUNC_ATTR_NONNULL_ALL { if (!using_script()) { @@ -2910,13 +2901,12 @@ int fix_input_buffer(char_u *buf, int len) } // Reading from script, need to process special bytes - int i; - char_u *p = buf; + char_u *p = (char_u *)buf; // Two characters are special: NUL and K_SPECIAL. // Replace NUL by K_SPECIAL KS_ZERO KE_FILLER // Replace K_SPECIAL by K_SPECIAL KS_SPECIAL KE_FILLER - for (i = len; --i >= 0; p++) { + for (int i = len; --i >= 0; p++) { if (p[0] == NUL || (p[0] == K_SPECIAL && (i < 2 || p[1] != KS_EXTRA))) { diff --git a/src/nvim/grid.c b/src/nvim/grid.c index 46f8a59710..16ebbfbb90 100644 --- a/src/nvim/grid.c +++ b/src/nvim/grid.c @@ -204,15 +204,11 @@ void grid_puts_len(ScreenGrid *grid, char *text, int textlen, int row, int col, int len = textlen; int c; size_t max_off; - int mbyte_blen = 1; - int mbyte_cells = 1; - int u8c = 0; int u8cc[MAX_MCO]; bool clear_next_cell = false; int prev_c = 0; // previous Arabic character int pc, nc, nc1; int pcc[MAX_MCO]; - int need_redraw; bool do_flush = false; grid_adjust(&grid, &row, &col); @@ -249,13 +245,13 @@ void grid_puts_len(ScreenGrid *grid, char *text, int textlen, int row, int col, && *ptr != NUL) { c = (unsigned char)(*ptr); // check if this is the first byte of a multibyte - mbyte_blen = len > 0 + int mbyte_blen = len > 0 ? utfc_ptr2len_len(ptr, (int)((text + len) - ptr)) : utfc_ptr2len(ptr); - u8c = len >= 0 + int u8c = len >= 0 ? utfc_ptr2char_len(ptr, u8cc, (int)((text + len) - ptr)) : utfc_ptr2char(ptr, u8cc); - mbyte_cells = utf_char2cells(u8c); + int mbyte_cells = utf_char2cells(u8c); if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c)) { // Do Arabic shaping. if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len) { @@ -287,11 +283,11 @@ void grid_puts_len(ScreenGrid *grid, char *text, int textlen, int row, int col, schar_T buf; schar_from_cc(buf, u8c, u8cc); - need_redraw = schar_cmp(grid->chars[off], buf) - || (mbyte_cells == 2 && grid->chars[off + 1][0] != 0) - || grid->attrs[off] != attr - || exmode_active - || rdb_flags & RDB_NODELTA; + int need_redraw = schar_cmp(grid->chars[off], buf) + || (mbyte_cells == 2 && grid->chars[off + 1][0] != 0) + || grid->attrs[off] != attr + || exmode_active + || rdb_flags & RDB_NODELTA; if (need_redraw) { // When at the end of the text and overwriting a two-cell @@ -497,7 +493,6 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle size_t max_off_from; size_t max_off_to; int col = 0; - bool redraw_this; // Does character need redraw? bool redraw_next; // redraw_this for next character bool clear_next = false; int char_cells; // 1: normal char @@ -559,7 +554,7 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle if (col + 1 < endcol) { char_cells = line_off2cells(linebuf_char, off_from, max_off_from); } - redraw_this = redraw_next; + bool redraw_this = redraw_next; // Does character need redraw? redraw_next = grid_char_needs_redraw(grid, off_from + (size_t)char_cells, off_to + (size_t)char_cells, endcol - col - char_cells); @@ -810,7 +805,6 @@ void grid_assign_handle(ScreenGrid *grid) /// 'row', 'col' and 'end' are relative to the start of the region. void grid_ins_lines(ScreenGrid *grid, int row, int line_count, int end, int col, int width) { - int i; int j; unsigned temp; @@ -825,7 +819,7 @@ void grid_ins_lines(ScreenGrid *grid, int row, int line_count, int end, int col, // Shift line_offset[] line_count down to reflect the inserted lines. // Clear the inserted lines. - for (i = 0; i < line_count; i++) { + for (int i = 0; i < line_count; i++) { if (width != grid->cols) { // need to copy part of a line j = end - 1 - i; @@ -860,7 +854,6 @@ void grid_ins_lines(ScreenGrid *grid, int row, int line_count, int end, int col, void grid_del_lines(ScreenGrid *grid, int row, int line_count, int end, int col, int width) { int j; - int i; unsigned temp; int row_off = 0; @@ -874,7 +867,7 @@ void grid_del_lines(ScreenGrid *grid, int row, int line_count, int end, int col, // Now shift line_offset[] line_count up to reflect the deleted lines. // Clear the inserted lines. - for (i = 0; i < line_count; i++) { + for (int i = 0; i < line_count; i++) { if (width != grid->cols) { // need to copy part of a line j = row + i; diff --git a/src/nvim/hashtab.c b/src/nvim/hashtab.c index 851e70caca..8f4c7b1d80 100644 --- a/src/nvim/hashtab.c +++ b/src/nvim/hashtab.c @@ -457,8 +457,8 @@ hash_T hash_hash_len(const char *key, const size_t len) /// /// Used for testing because luajit ffi does not allow getting addresses of /// globals. -const char_u *_hash_key_removed(void) +const char *_hash_key_removed(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - return (char_u *)HI_KEY_REMOVED; + return HI_KEY_REMOVED; } diff --git a/src/nvim/help.c b/src/nvim/help.c index bbc552fa4c..5fa48e0cee 100644 --- a/src/nvim/help.c +++ b/src/nvim/help.c @@ -47,19 +47,14 @@ void ex_help(exarg_T *eap) { char *arg; - char *tag; FILE *helpfd; // file descriptor of help file - int n; - int i; win_T *wp; int num_matches; char **matches; - char *p; int empty_fnum = 0; int alt_fnum = 0; buf_T *buf; int len; - char *lang; const bool old_KeyTyped = KeyTyped; if (eap != NULL) { @@ -88,13 +83,13 @@ void ex_help(exarg_T *eap) } // remove trailing blanks - p = arg + strlen(arg) - 1; + char *p = arg + strlen(arg) - 1; while (p > arg && ascii_iswhite(*p) && p[-1] != '\\') { *p-- = NUL; } // Check for a specified language - lang = check_help_lang(arg); + char *lang = check_help_lang(arg); // When no argument given go to the index. if (*arg == NUL) { @@ -102,9 +97,9 @@ void ex_help(exarg_T *eap) } // Check if there is a match for the argument. - n = find_help_tags(arg, &num_matches, &matches, eap != NULL && eap->forceit); + int n = find_help_tags(arg, &num_matches, &matches, eap != NULL && eap->forceit); - i = 0; + int i = 0; if (n != FAIL && lang != NULL) { // Find first item with the requested language. for (i = 0; i < num_matches; i++) { @@ -128,7 +123,7 @@ void ex_help(exarg_T *eap) } // The first match (in the requested language) is the best match. - tag = xstrdup(matches[i]); + char *tag = xstrdup(matches[i]); FreeWild(num_matches, matches); // Re-use an existing help window or open a new one. @@ -259,11 +254,8 @@ char *check_help_lang(char *arg) int help_heuristic(char *matched_string, int offset, int wrong_case) FUNC_ATTR_PURE { - int num_letters; - char *p; - - num_letters = 0; - for (p = matched_string; *p; p++) { + int num_letters = 0; + for (char *p = matched_string; *p; p++) { if (ASCII_ISALNUM(*p)) { num_letters++; } @@ -298,11 +290,8 @@ int help_heuristic(char *matched_string, int offset, int wrong_case) /// that has been put after the tagname by find_tags(). static int help_compare(const void *s1, const void *s2) { - char *p1; - char *p2; - - p1 = *(char **)s1 + strlen(*(char **)s1) + 1; - p2 = *(char **)s2 + strlen(*(char **)s2) + 1; + char *p1 = *(char **)s1 + strlen(*(char **)s1) + 1; + char *p2 = *(char **)s2 + strlen(*(char **)s2) + 1; // Compare by help heuristic number first. int cmp = strcmp(p1, p2); @@ -320,8 +309,6 @@ static int help_compare(const void *s1, const void *s2) /// When "keep_lang" is true try keeping the language of the current buffer. int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep_lang) { - int i; - // Specific tags that either have a specific replacement or won't go // through the generic rules. static char *(except_tbl[][2]) = { @@ -379,7 +366,7 @@ int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep // When the string starting with "expr-" and containing '?' and matches // the table, it is taken literally (but ~ is escaped). Otherwise '?' // is recognized as a wildcard. - for (i = (int)ARRAY_SIZE(expr_table); --i >= 0;) { + for (int i = (int)ARRAY_SIZE(expr_table); --i >= 0;) { if (strcmp(arg + 5, expr_table[i]) == 0) { for (int si = 0, di = 0;; si++) { if (arg[si] == '~') { @@ -396,7 +383,7 @@ int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep } else { // Recognize a few exceptions to the rule. Some strings that contain // '*'are changed to "star", otherwise '*' is recognized as a wildcard. - for (i = 0; except_tbl[i][0] != NULL; i++) { + for (int i = 0; except_tbl[i][0] != NULL; i++) { if (strcmp(arg, except_tbl[i][0]) == 0) { STRCPY(d, except_tbl[i][1]); break; @@ -660,7 +647,6 @@ void fix_help_buffer(void) { linenr_T lnum; char *line; - bool in_example = false; // Set filetype to "help". if (strcmp(curbuf->b_p_ft, "help") != 0) { @@ -670,6 +656,7 @@ void fix_help_buffer(void) } if (!syntax_present(curwin)) { + bool in_example = false; for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; lnum++) { line = ml_get_buf(curbuf, lnum, false); const size_t len = strlen(line); @@ -722,9 +709,7 @@ void fix_help_buffer(void) && path_full_compare(rt, NameBuff, false, true) != kEqualFiles) { int fcount; char **fnames; - char *s; vimconv_T vc; - char *cp; // Find all "doc/ *.txt" files in this directory. if (!add_pathsep(NameBuff) @@ -740,6 +725,8 @@ void fix_help_buffer(void) if (gen_expand_wildcards(1, buff_list, &fcount, &fnames, EW_FILE|EW_SILENT) == OK && fcount > 0) { + char *s; + char *cp; // If foo.abx is found use it instead of foo.txt in // the same directory. for (int i1 = 0; i1 < fcount; i1++) { @@ -1080,7 +1067,6 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool static void do_helptags(char *dirname, bool add_help_tags, bool ignore_writeerr) FUNC_ATTR_NONNULL_ALL { - int len; garray_T ga; char lang[2]; char ext[5]; @@ -1090,7 +1076,7 @@ static void do_helptags(char *dirname, bool add_help_tags, bool ignore_writeerr) // Get a list of all files in the help directory and in subdirectories. xstrlcpy(NameBuff, dirname, sizeof(NameBuff)); - if (!add_pathsep((char *)NameBuff) + if (!add_pathsep(NameBuff) || xstrlcat(NameBuff, "**", sizeof(NameBuff)) >= MAXPATHL) { emsg(_(e_fnametoolong)); return; @@ -1111,7 +1097,7 @@ static void do_helptags(char *dirname, bool add_help_tags, bool ignore_writeerr) int j; ga_init(&ga, 1, 10); for (int i = 0; i < filecount; i++) { - len = (int)strlen(files[i]); + int len = (int)strlen(files[i]); if (len <= 4) { continue; } @@ -1177,7 +1163,6 @@ static void helptags_cb(char *fname, void *cookie) void ex_helptags(exarg_T *eap) { expand_T xpc; - char *dirname; bool add_help_tags = false; // Check for ":helptags ++t {dir}". @@ -1191,7 +1176,8 @@ void ex_helptags(exarg_T *eap) } else { ExpandInit(&xpc); xpc.xp_context = EXPAND_DIRECTORIES; - dirname = ExpandOne(&xpc, eap->arg, NULL, WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE); + char *dirname = + ExpandOne(&xpc, eap->arg, NULL, WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE); if (dirname == NULL || !os_isdir(dirname)) { semsg(_("E150: Not a directory: %s"), eap->arg); } else { diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index c20eac3c28..5e53bf273f 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -12,6 +12,7 @@ #include "lauxlib.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/api/ui.h" #include "nvim/decoration_provider.h" #include "nvim/drawscreen.h" @@ -205,7 +206,7 @@ int ns_get_hl(NS *ns_hl, int hl_id, bool link, bool nodefault) if (!valid_item && p->hl_def != LUA_NOREF && !recursive) { MAXSIZE_TEMP_ARRAY(args, 3); ADD_C(args, INTEGER_OBJ((Integer)ns_id)); - ADD_C(args, STRING_OBJ(cstr_to_string((char *)syn_id2name(hl_id)))); + ADD_C(args, STRING_OBJ(cstr_to_string(syn_id2name(hl_id)))); ADD_C(args, BOOLEAN_OBJ(link)); // TODO(bfredl): preload the "global" attr dict? @@ -971,35 +972,33 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e return hlattrs; } - if (dict->blend.type == kObjectTypeInteger) { + if (HAS_KEY(dict->blend)) { + VALIDATE_T("blend", kObjectTypeInteger, dict->blend.type, { + return hlattrs; + }); + Integer blend0 = dict->blend.data.integer; - if (blend0 < 0 || blend0 > 100) { - api_set_error(err, kErrorTypeValidation, "'blend' is not between 0 to 100"); - } else { - blend = (int)blend0; - } - } else if (HAS_KEY(dict->blend)) { - api_set_error(err, kErrorTypeValidation, "'blend' must be an integer"); - } - if (ERROR_SET(err)) { - return hlattrs; + VALIDATE_RANGE((blend0 >= 0 && blend0 <= 100), "blend", { + return hlattrs; + }); + blend = (int)blend0; } if (HAS_KEY(dict->link) || HAS_KEY(dict->global_link)) { - if (link_id) { - if (HAS_KEY(dict->global_link)) { - *link_id = object_to_hl_id(dict->global_link, "link", err); - mask |= HL_GLOBAL; - } else { - *link_id = object_to_hl_id(dict->link, "link", err); - } - - if (ERROR_SET(err)) { - return hlattrs; - } - } else { + if (!link_id) { api_set_error(err, kErrorTypeValidation, "Invalid Key: '%s'", HAS_KEY(dict->global_link) ? "global_link" : "link"); + return hlattrs; + } + if (HAS_KEY(dict->global_link)) { + *link_id = object_to_hl_id(dict->global_link, "link", err); + mask |= HL_GLOBAL; + } else { + *link_id = object_to_hl_id(dict->link, "link", err); + } + + if (ERROR_SET(err)) { + return hlattrs; } } @@ -1026,7 +1025,9 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e // TODO(clason): handle via gen_api_dispatch cterm_mask_provided = true; } else if (HAS_KEY(dict->cterm)) { - api_set_error(err, kErrorTypeValidation, "'cterm' must be a Dictionary."); + VALIDATE_T("cterm", kObjectTypeDictionary, dict->cterm.type, { + return hlattrs; + }); } #undef CHECK_FLAG @@ -1083,13 +1084,14 @@ int object_to_color(Object val, char *key, bool rgb, Error *err) } else { color = name_to_ctermcolor(str.data); } - if (color < 0) { - api_set_error(err, kErrorTypeValidation, "'%s' is not a valid color", str.data); - } + VALIDATE_S((color >= 0), "highlight color", str.data, { + return color; + }); return color; } else { - api_set_error(err, kErrorTypeValidation, "'%s' must be string or integer", key); - return 0; + VALIDATE(false, "Invalid %s: expected String or Integer", key, { + return 0; + }); } } @@ -1115,7 +1117,7 @@ static void hl_inspect_impl(Array *arr, int attr) case kHlSyntax: PUT(item, "kind", STRING_OBJ(cstr_to_string("syntax"))); PUT(item, "hi_name", - STRING_OBJ(cstr_to_string((char *)syn_id2name(e.id1)))); + STRING_OBJ(cstr_to_string(syn_id2name(e.id1)))); break; case kHlUI: @@ -1123,7 +1125,7 @@ static void hl_inspect_impl(Array *arr, int attr) const char *ui_name = (e.id1 == -1) ? "Normal" : hlf_names[e.id1]; PUT(item, "ui_name", STRING_OBJ(cstr_to_string(ui_name))); PUT(item, "hi_name", - STRING_OBJ(cstr_to_string((char *)syn_id2name(e.id2)))); + STRING_OBJ(cstr_to_string(syn_id2name(e.id2)))); break; case kHlTerminal: diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 3d91335f55..e34c13abc1 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -1522,7 +1522,7 @@ Dictionary get_global_hl_defs(Arena *arena) char *link = hl_table[h->sg_link - 1].sg_name; PUT_C(attrs, "link", STRING_OBJ(cstr_as_string(link))); } - PUT_C(rv, (char *)h->sg_name, DICTIONARY_OBJ(attrs)); + PUT_C(rv, h->sg_name, DICTIONARY_OBJ(attrs)); } return rv; @@ -1547,7 +1547,7 @@ static bool highlight_list_arg(const int id, bool didh, const int type, int iarg char buf[100]; const char *ts = buf; if (type == LIST_INT) { - snprintf((char *)buf, sizeof(buf), "%d", iarg - 1); + snprintf(buf, sizeof(buf), "%d", iarg - 1); } else if (type == LIST_STRING) { ts = sarg; } else { // type == LIST_ATTR diff --git a/src/nvim/indent.c b/src/nvim/indent.c index ec6c72da6d..ee9bc48460 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -460,7 +460,6 @@ int set_indent(int size, int flags) int line_len; int doit = false; int ind_done = 0; // Measured in spaces. - int ind_col = 0; int tab_pad; int retval = false; @@ -479,6 +478,7 @@ int set_indent(int size, int flags) // 'preserveindent' are set count the number of characters at the // beginning of the line to be copied. if (!curbuf->b_p_et || (!(flags & SIN_INSERT) && curbuf->b_p_pi)) { + int ind_col = 0; // If 'preserveindent' is set then reuse as much as possible of // the existing indent structure for the new indent. if (!(flags & SIN_INSERT) && curbuf->b_p_pi) { @@ -936,14 +936,10 @@ void ex_retab(exarg_T *eap) long num_spaces = 0; long num_tabs; long len; - long col; - long vcol; long start_col = 0; // For start of white-space string long start_vcol = 0; // For start of white-space string long old_len; - char *ptr; char *new_line = (char *)1; // init to non-NULL - bool did_undo; // called u_save for current line long *new_vts_array = NULL; char *new_ts_str; // string value of tab argument @@ -972,10 +968,10 @@ void ex_retab(exarg_T *eap) new_ts_str = xstrnsave(new_ts_str, (size_t)(eap->arg - new_ts_str)); } for (lnum = eap->line1; !got_int && lnum <= eap->line2; lnum++) { - ptr = ml_get(lnum); - col = 0; - vcol = 0; - did_undo = false; + char *ptr = ml_get(lnum); + long col = 0; + long vcol = 0; + bool did_undo = false; // called u_save for current line for (;;) { if (ascii_iswhite(ptr[col])) { if (!got_tab && num_spaces == 0) { @@ -1186,10 +1182,6 @@ int get_lisp_indent(void) pos_T *pos, realpos, paren; int amount; char *that; - colnr_T col; - colnr_T firsttry; - int parencount; - int quotecount; int vi_lisp; // Set vi_lisp to use the vi-compatible method. @@ -1213,7 +1205,7 @@ int get_lisp_indent(void) // Extra trick: Take the indent of the first previous non-white // line that is at the same () level. amount = -1; - parencount = 0; + int parencount = 0; while (--curwin->w_cursor.lnum >= pos->lnum) { if (linewhite(curwin->w_cursor.lnum)) { @@ -1268,7 +1260,7 @@ int get_lisp_indent(void) if (amount == -1) { curwin->w_cursor.lnum = pos->lnum; curwin->w_cursor.col = pos->col; - col = pos->col; + colnr_T col = pos->col; that = get_cursor_line_ptr(); @@ -1298,7 +1290,7 @@ int get_lisp_indent(void) that++; amount++; } - firsttry = amount; + colnr_T firsttry = amount; init_chartabsize_arg(&cts, curwin, (colnr_T)(that - line), amount, line, that); @@ -1319,13 +1311,13 @@ int get_lisp_indent(void) } parencount = 0; - quotecount = 0; init_chartabsize_arg(&cts, curwin, (colnr_T)(that - line), amount, line, that); if (vi_lisp || ((*that != '"') && (*that != '\'') && (*that != '#') && (((uint8_t)(*that) < '0') || ((uint8_t)(*that) > '9')))) { + int quotecount = 0; while (*cts.cts_ptr && (!ascii_iswhite(*cts.cts_ptr) || quotecount || parencount) && (!((*cts.cts_ptr == '(' || *cts.cts_ptr == '[') @@ -1373,12 +1365,11 @@ int get_lisp_indent(void) static int lisp_match(char *p) { char buf[LSIZE]; - int len; char *word = *curbuf->b_p_lw != NUL ? curbuf->b_p_lw : p_lispwords; while (*word != NUL) { (void)copy_option_part(&word, buf, LSIZE, ","); - len = (int)strlen(buf); + int len = (int)strlen(buf); if ((strncmp(buf, p, (size_t)len) == 0) && ascii_iswhite_or_nul(p[len])) { return true; diff --git a/src/nvim/input.c b/src/nvim/input.c index 96214d45c2..5b9b866778 100644 --- a/src/nvim/input.c +++ b/src/nvim/input.c @@ -86,9 +86,8 @@ int ask_yesno(const char *const str, const bool direct) /// Translates the interrupt character for unix to ESC. int get_keystroke(MultiQueue *events) { - char_u *buf = NULL; + char *buf = NULL; int buflen = 150; - int maxlen; int len = 0; int n; int save_mapped_ctrl_c = mapped_ctrl_c; @@ -100,7 +99,7 @@ int get_keystroke(MultiQueue *events) // Leave some room for check_termcode() to insert a key code into (max // 5 chars plus NUL). And fix_input_buffer() can triple the number of // bytes. - maxlen = (buflen - 6 - len) / 3; + int maxlen = (buflen - 6 - len) / 3; if (buf == NULL) { buf = xmalloc((size_t)buflen); } else if (maxlen < 10) { @@ -113,7 +112,7 @@ int get_keystroke(MultiQueue *events) // First time: blocking wait. Second time: wait up to 100ms for a // terminal code to complete. - n = os_inchar(buf + len, maxlen, len == 0 ? -1L : 100L, 0, events); + n = os_inchar((uint8_t *)buf + len, maxlen, len == 0 ? -1L : 100L, 0, events); if (n > 0) { // Replace zero and K_SPECIAL by a special key code. n = fix_input_buffer(buf + len, n); @@ -128,14 +127,14 @@ int get_keystroke(MultiQueue *events) } // Handle modifier and/or special key code. - n = buf[0]; + n = (uint8_t)buf[0]; if (n == K_SPECIAL) { - n = TO_SPECIAL(buf[1], buf[2]); - if (buf[1] == KS_MODIFIER + n = TO_SPECIAL((uint8_t)buf[1], (uint8_t)buf[2]); + if ((uint8_t)buf[1] == KS_MODIFIER || n == K_IGNORE || (is_mouse_key(n) && n != K_LEFTMOUSE)) { - if (buf[1] == KS_MODIFIER) { - mod_mask = buf[2]; + if ((uint8_t)buf[1] == KS_MODIFIER) { + mod_mask = (uint8_t)buf[2]; } len -= 3; if (len > 0) { @@ -150,7 +149,7 @@ int get_keystroke(MultiQueue *events) continue; } buf[len >= buflen ? buflen - 1 : len] = NUL; - n = utf_ptr2char((char *)buf); + n = utf_ptr2char(buf); break; } xfree(buf); @@ -166,7 +165,6 @@ int get_keystroke(MultiQueue *events) int get_number(int colon, int *mouse_used) { int n = 0; - int c; int typed = 0; if (mouse_used != NULL) { @@ -183,7 +181,7 @@ int get_number(int colon, int *mouse_used) allow_keys++; // no mapping here, but recognize keys for (;;) { ui_cursor_goto(msg_row, msg_col); - c = safe_vgetc(); + int c = safe_vgetc(); if (ascii_isdigit(c)) { n = n * 10 + c - '0'; msg_putchar(c); diff --git a/src/nvim/keycodes.c b/src/nvim/keycodes.c index e19806e464..8114efc10c 100644 --- a/src/nvim/keycodes.c +++ b/src/nvim/keycodes.c @@ -582,7 +582,7 @@ unsigned int trans_special(const char **const srcp, const size_t src_len, char * return 0; } - return special_to_buf(key, modifiers, escape_ks, (char_u *)dst); + return special_to_buf(key, modifiers, escape_ks, dst); } /// Put the character sequence for "key" with "modifiers" into "dst" and return @@ -590,27 +590,27 @@ unsigned int trans_special(const char **const srcp, const size_t src_len, char * /// When "escape_ks" is true escape K_SPECIAL bytes in the character. /// The sequence is not NUL terminated. /// This is how characters in a string are encoded. -unsigned int special_to_buf(int key, int modifiers, bool escape_ks, char_u *dst) +unsigned int special_to_buf(int key, int modifiers, bool escape_ks, char *dst) { unsigned int dlen = 0; // Put the appropriate modifier in a string. if (modifiers != 0) { - dst[dlen++] = K_SPECIAL; - dst[dlen++] = KS_MODIFIER; - dst[dlen++] = (char_u)modifiers; + dst[dlen++] = (char)(uint8_t)K_SPECIAL; + dst[dlen++] = (char)(uint8_t)KS_MODIFIER; + dst[dlen++] = (char)(uint8_t)modifiers; } if (IS_SPECIAL(key)) { - dst[dlen++] = K_SPECIAL; - dst[dlen++] = (char_u)KEY2TERMCAP0(key); - dst[dlen++] = KEY2TERMCAP1(key); + dst[dlen++] = (char)(uint8_t)K_SPECIAL; + dst[dlen++] = (char)(uint8_t)KEY2TERMCAP0(key); + dst[dlen++] = (char)(uint8_t)KEY2TERMCAP1(key); } else if (escape_ks) { - char_u *after = add_char2buf(key, dst + dlen); + char *after = add_char2buf(key, dst + dlen); assert(after >= dst && (uintmax_t)(after - dst) <= UINT_MAX); dlen = (unsigned int)(after - dst); } else { - dlen += (unsigned int)utf_char2bytes(key, (char *)dst + dlen); + dlen += (unsigned int)utf_char2bytes(key, dst + dlen); } return dlen; @@ -637,7 +637,6 @@ int find_special_key(const char **const srcp, const size_t src_len, int *const m const bool in_string = flags & FSK_IN_STRING; int modifiers; int bit; - int key; uvarnumber_T n; int l; @@ -685,6 +684,7 @@ int find_special_key(const char **const srcp, const size_t src_len, int *const m } if (bp <= end && *bp == '>') { // found matching '>' + int key; end_of_name = bp + 1; // Which modifiers are given? @@ -1033,20 +1033,20 @@ char *replace_termcodes(const char *const from, const size_t from_len, char **co /// @param[out] s Buffer to add to. Must have at least MB_MAXBYTES + 1 bytes. /// /// @return Pointer to after the added bytes. -char_u *add_char2buf(int c, char_u *s) +char *add_char2buf(int c, char *s) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - char_u temp[MB_MAXBYTES + 1]; - const int len = utf_char2bytes(c, (char *)temp); + char temp[MB_MAXBYTES + 1]; + const int len = utf_char2bytes(c, temp); for (int i = 0; i < len; i++) { c = (uint8_t)temp[i]; // Need to escape K_SPECIAL like in the typeahead buffer. if (c == K_SPECIAL) { - *s++ = K_SPECIAL; - *s++ = KS_SPECIAL; + *s++ = (char)(uint8_t)K_SPECIAL; + *s++ = (char)(uint8_t)KS_SPECIAL; *s++ = KE_FILLER; } else { - *s++ = (char_u)c; + *s++ = (char)(uint8_t)c; } } return s; @@ -1060,9 +1060,9 @@ char *vim_strsave_escape_ks(char *p) // illegal utf-8 byte: // 0xc0 -> 0xc3 - 0x80 -> 0xc3 K_SPECIAL KS_SPECIAL KE_FILLER char *res = xmalloc(strlen(p) * 4 + 1); - char_u *d = (char_u *)res; - for (char_u *s = (char_u *)p; *s != NUL;) { - if (s[0] == K_SPECIAL && s[1] != NUL && s[2] != NUL) { + char *d = res; + for (char *s = p; *s != NUL;) { + if ((uint8_t)s[0] == K_SPECIAL && s[1] != NUL && s[2] != NUL) { // Copy special key unmodified. *d++ = *s++; *d++ = *s++; @@ -1070,8 +1070,8 @@ char *vim_strsave_escape_ks(char *p) } else { // Add character, possibly multi-byte to destination, escaping // K_SPECIAL. Be careful, it can be an illegal byte! - d = add_char2buf(utf_ptr2char((char *)s), d); - s += utf_ptr2len((char *)s); + d = add_char2buf(utf_ptr2char(s), d); + s += utf_ptr2len(s); } } *d = NUL; @@ -1081,9 +1081,9 @@ char *vim_strsave_escape_ks(char *p) /// Remove escaping from K_SPECIAL characters. Reverse of /// vim_strsave_escape_ks(). Works in-place. -void vim_unescape_ks(char_u *p) +void vim_unescape_ks(char *p) { - char_u *s = p, *d = p; + char_u *s = (char_u *)p, *d = (char_u *)p; while (*s != NUL) { if (s[0] == K_SPECIAL && s[1] == KS_SPECIAL && s[2] == KE_FILLER) { diff --git a/src/nvim/keycodes.h b/src/nvim/keycodes.h index 7842dee92c..7c143fc99e 100644 --- a/src/nvim/keycodes.h +++ b/src/nvim/keycodes.h @@ -59,7 +59,7 @@ // Used for switching Select mode back on after a mapping or menu. #define KS_SELECT 245 -#define K_SELECT_STRING (char_u *)"\200\365X" +#define K_SELECT_STRING "\200\365X" /// Used a termcap entry that produces a normal character. #define KS_KEY 242 diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 1415ceeaed..c8fc76e20d 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -211,9 +211,7 @@ static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult, int flags if (status) { if (status == LUA_ERRMEM && !(flags & LUVF_CALLBACK_NOEXIT)) { // consider out of memory errors unrecoverable, just like xmalloc() - os_errmsg(e_outofmem); - os_errmsg("\n"); - preserve_exit(); + preserve_exit(e_outofmem); } const char *error = lua_tostring(lstate, -1); @@ -1768,13 +1766,12 @@ bool nlua_exec_file(const char *path) StringBuilder sb = KV_INITIAL_VALUE; kv_resize(sb, 64); - ptrdiff_t read_size = -1; // Read all input from stdin, unless interrupted (ctrl-c). while (true) { if (got_int) { // User canceled. return false; } - read_size = file_read(stdin_dup, IObuff, 64); + ptrdiff_t read_size = file_read(stdin_dup, IObuff, 64); if (read_size < 0) { // Error. return false; } @@ -1995,7 +1992,7 @@ char *nlua_register_table_as_callable(const typval_T *const arg) void nlua_execute_on_key(int c) { char buf[NUMBUFLEN]; - size_t buf_len = special_to_buf(c, mod_mask, false, (char_u *)buf); + size_t buf_len = special_to_buf(c, mod_mask, false, buf); lua_State *const lstate = global_lstate; diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c index d510d25e90..78e023c26d 100644 --- a/src/nvim/lua/spell.c +++ b/src/nvim/lua/spell.c @@ -51,7 +51,6 @@ int nlua_spell_check(lua_State *lstate) } hlf_T attr = HLF_COUNT; - size_t len = 0; size_t pos = 0; int capcol = -1; int no_res = 0; @@ -61,7 +60,7 @@ int nlua_spell_check(lua_State *lstate) while (*str != NUL) { attr = HLF_COUNT; - len = spell_check(curwin, (char *)str, &attr, &capcol, false); + size_t len = spell_check(curwin, (char *)str, &attr, &capcol, false); assert(len <= INT_MAX); if (attr != HLF_COUNT) { diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 6ebca6d97e..5aeff4de98 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -78,20 +78,20 @@ static int regex_match_line(lua_State *lstate) return luaL_error(lstate, "not enough args"); } - long bufnr = luaL_checkinteger(lstate, 2); + handle_T bufnr = (handle_T)luaL_checkinteger(lstate, 2); linenr_T rownr = (linenr_T)luaL_checkinteger(lstate, 3); - long start = 0, end = -1; + int start = 0, end = -1; if (narg >= 4) { - start = luaL_checkinteger(lstate, 4); + start = (int)luaL_checkinteger(lstate, 4); } if (narg >= 5) { - end = luaL_checkinteger(lstate, 5); + end = (int)luaL_checkinteger(lstate, 5); if (end < 0) { return luaL_error(lstate, "invalid end"); } } - buf_T *buf = bufnr ? handle_get_buffer((int)bufnr) : curbuf; + buf_T *buf = bufnr ? handle_get_buffer(bufnr) : curbuf; if (!buf || buf->b_ml.ml_mfp == NULL) { return luaL_error(lstate, "invalid buffer"); } @@ -218,11 +218,11 @@ static int nlua_str_utf_start(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL { size_t s1_len; const char *s1 = luaL_checklstring(lstate, 1, &s1_len); - long offset = luaL_checkinteger(lstate, 2); + ptrdiff_t offset = luaL_checkinteger(lstate, 2); if (offset < 0 || offset > (intptr_t)s1_len) { return luaL_error(lstate, "index out of range"); } - int head_offset = utf_cp_head_off((char_u *)s1, (char_u *)s1 + offset - 1); + int head_offset = utf_cp_head_off(s1, s1 + offset - 1); lua_pushinteger(lstate, head_offset); return 1; } @@ -238,7 +238,7 @@ static int nlua_str_utf_end(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL { size_t s1_len; const char *s1 = luaL_checklstring(lstate, 1, &s1_len); - long offset = luaL_checkinteger(lstate, 2); + ptrdiff_t offset = luaL_checkinteger(lstate, 2); if (offset < 0 || offset > (intptr_t)s1_len) { return luaL_error(lstate, "index out of range"); } diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 56f4daed1a..5248ebed14 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -393,7 +393,7 @@ static int parser_parse(lua_State *L) TSTree *new_tree = NULL; size_t len; const char *str; - long bufnr; + handle_T bufnr; buf_T *buf; TSInput input; @@ -406,13 +406,13 @@ static int parser_parse(lua_State *L) break; case LUA_TNUMBER: - bufnr = lua_tointeger(L, 3); - buf = handle_get_buffer((handle_T)bufnr); + bufnr = (handle_T)lua_tointeger(L, 3); + buf = handle_get_buffer(bufnr); if (!buf) { #define BUFSIZE 256 char ebuf[BUFSIZE] = { 0 }; - vim_snprintf(ebuf, BUFSIZE, "invalid buffer handle: %ld", bufnr); + vim_snprintf(ebuf, BUFSIZE, "invalid buffer handle: %d", bufnr); return luaL_argerror(L, 3, ebuf); #undef BUFSIZE } @@ -898,8 +898,8 @@ static int node_child(lua_State *L) if (!node_check(L, 1, &node)) { return 0; } - long num = lua_tointeger(L, 2); - TSNode child = ts_node_child(node, (uint32_t)num); + uint32_t num = (uint32_t)lua_tointeger(L, 2); + TSNode child = ts_node_child(node, num); push_node(L, child, 1); return 1; @@ -911,8 +911,8 @@ static int node_named_child(lua_State *L) if (!node_check(L, 1, &node)) { return 0; } - long num = lua_tointeger(L, 2); - TSNode child = ts_node_named_child(node, (uint32_t)num); + uint32_t num = (uint32_t)lua_tointeger(L, 2); + TSNode child = ts_node_named_child(node, num); push_node(L, child, 1); return 1; diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c index 857b159af5..9a7ae5c146 100644 --- a/src/nvim/lua/xdiff.c +++ b/src/nvim/lua/xdiff.c @@ -257,13 +257,13 @@ static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg, if (check_xdiff_opt(v->type, kObjectTypeInteger, "ctxlen", err)) { goto exit_1; } - cfg->ctxlen = v->data.integer; + cfg->ctxlen = (long)v->data.integer; } else if (strequal("interhunkctxlen", k.data)) { if (check_xdiff_opt(v->type, kObjectTypeInteger, "interhunkctxlen", err)) { goto exit_1; } - cfg->interhunkctxlen = v->data.integer; + cfg->interhunkctxlen = (long)v->data.integer; } else if (strequal("linematch", k.data)) { *linematch = api_object_to_bool(*v, "linematch", false, err); if (ERROR_SET(err)) { diff --git a/src/nvim/main.c b/src/nvim/main.c index e26922bf8e..c12de07077 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -182,6 +182,9 @@ void early_init(mparm_T *paramp) #ifdef MSWIN OSVERSIONINFO ovi; ovi.dwOSVersionInfoSize = sizeof(ovi); + // Disable warning about GetVersionExA being deprecated. There doesn't seem to be a conventient + // replacement that doesn't add a ton of extra code as of writing this. +# pragma warning(suppress : 4996) GetVersionEx(&ovi); snprintf(windowsVersion, sizeof(windowsVersion), "%d.%d", (int)ovi.dwMajorVersion, (int)ovi.dwMinorVersion); @@ -671,6 +674,7 @@ void os_exit(int r) void getout(int exitval) FUNC_ATTR_NORETURN { + assert(!ui_client_channel_id); exiting = true; // On error during Ex mode, exit with a non-zero code. @@ -790,10 +794,11 @@ void getout(int exitval) os_exit(exitval); } -/// Preserve files, print contents of `IObuff`, and exit 1. +/// Preserve files, print contents of `errmsg`, and exit 1. +/// @param errmsg If NULL, this function will not print anything. /// /// May be called from deadly_signal(). -void preserve_exit(void) +void preserve_exit(const char *errmsg) FUNC_ATTR_NORETURN { // 'true' when we are sure to exit, e.g., after a deadly signal @@ -813,19 +818,24 @@ void preserve_exit(void) signal_reject_deadly(); if (ui_client_channel_id) { + // For TUI: exit alternate screen so that the error messages can be seen. + ui_client_stop(); + } + if (errmsg != NULL) { + os_errmsg(errmsg); + os_errmsg("\n"); + } + if (ui_client_channel_id) { os_exit(1); } - os_errmsg(IObuff); - os_errmsg("\n"); - ui_flush(); - ml_close_notmod(); // close all not-modified buffers FOR_ALL_BUFFERS(buf) { if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) { - os_errmsg("Vim: preserving files...\r\n"); - ui_flush(); + if (errmsg != NULL) { + os_errmsg("Vim: preserving files...\r\n"); + } ml_sync_all(false, false, true); // preserve all swap files break; } @@ -833,7 +843,9 @@ void preserve_exit(void) ml_close_all(false); // close all memfiles, without deleting - os_errmsg("Vim: Finished.\r\n"); + if (errmsg != NULL) { + os_errmsg("Vim: Finished.\r\n"); + } getout(1); } @@ -908,9 +920,8 @@ static void remote_request(mparm_T *params, int remote_args, char *server_addr, } Array args = ARRAY_DICT_INIT; - String arg_s; for (int t_argc = remote_args; t_argc < argc; t_argc++) { - arg_s = cstr_to_string(argv[t_argc]); + String arg_s = cstr_to_string(argv[t_argc]); ADD(args, STRING_OBJ(arg_s)); } @@ -1583,7 +1594,7 @@ static void open_script_files(mparm_T *parmp) scriptin[0] = file_open_new(&error, parmp->scriptin, kFileReadOnly|kFileNonBlocking, 0); if (scriptin[0] == NULL) { - vim_snprintf((char *)IObuff, IOSIZE, + vim_snprintf(IObuff, IOSIZE, _("Cannot open for reading: \"%s\": %s\n"), parmp->scriptin, os_strerror(error)); os_errmsg(IObuff); @@ -1608,9 +1619,6 @@ static void open_script_files(mparm_T *parmp) // Also does recovery if "recoverymode" set. static void create_windows(mparm_T *parmp) { - int dorewind; - int done = 0; - // Create the number of windows that was requested. if (parmp->window_count == -1) { // was not set parmp->window_count = 1; @@ -1646,6 +1654,7 @@ static void create_windows(mparm_T *parmp) } do_modelines(0); // do modelines } else { + int done = 0; // Open a buffer for windows that don't have one yet. // Commands in the vimrc might have loaded a file or split the window. // Watch out for autocommands that delete a window. @@ -1653,7 +1662,7 @@ static void create_windows(mparm_T *parmp) // Don't execute Win/Buf Enter/Leave autocommands here autocmd_no_enter++; autocmd_no_leave++; - dorewind = true; + int dorewind = true; while (done++ < 1000) { if (dorewind) { if (parmp->window_layout == WIN_TABS) { diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 831d1299a8..c740fb41bc 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -1162,7 +1162,7 @@ static bool expand_buffer = false; /// @param cpo_flags Value of various flags present in &cpo /// /// @return NULL when there is a problem. -static char_u *translate_mapping(char_u *str, int cpo_flags) +static char *translate_mapping(char_u *str, int cpo_flags) { garray_T ga; ga_init(&ga, 1, 40); @@ -1203,7 +1203,7 @@ static char_u *translate_mapping(char_u *str, int cpo_flags) } } ga_append(&ga, NUL); - return (char_u *)(ga.ga_data); + return (char *)ga.ga_data; } /// Work out what to complete when doing command line completion of mapping @@ -1212,8 +1212,8 @@ static char_u *translate_mapping(char_u *str, int cpo_flags) /// @param forceit true if '!' given /// @param isabbrev true if abbreviation /// @param isunmap true if unmap/unabbrev command -char_u *set_context_in_map_cmd(expand_T *xp, char *cmd, char *arg, bool forceit, bool isabbrev, - bool isunmap, cmdidx_T cmdidx) +char *set_context_in_map_cmd(expand_T *xp, char *cmd, char *arg, bool forceit, bool isabbrev, + bool isunmap, cmdidx_T cmdidx) { if (forceit && cmdidx != CMD_map && cmdidx != CMD_unmap) { xp->xp_context = EXPAND_NOTHING; @@ -1346,7 +1346,7 @@ int ExpandMappings(char *pat, regmatch_T *regmatch, int *numMatches, char ***mat continue; } - char *p = (char *)translate_mapping((char_u *)mp->m_keys, CPO_TO_CPO_FLAGS); + char *p = translate_mapping((char_u *)mp->m_keys, CPO_TO_CPO_FLAGS); if (p == NULL) { continue; } @@ -1434,15 +1434,11 @@ int ExpandMappings(char *pat, regmatch_T *regmatch, int *numMatches, char ***mat // Return true if there is an abbreviation, false if not. bool check_abbr(int c, char *ptr, int col, int mincol) { - int len; int scol; // starting column of the abbr. - int j; - char *s; char_u tb[MB_MAXBYTES + 4]; mapblock_T *mp; mapblock_T *mp2; int clen = 0; // length in characters - bool is_id = true; if (typebuf.tb_no_abbr_cnt) { // abbrev. are not recursive return false; @@ -1462,6 +1458,7 @@ bool check_abbr(int c, char *ptr, int col, int mincol) } { + bool is_id = true; bool vim_abbr; char *p = mb_prevptr(ptr, ptr + col); if (!vim_iswordp(p)) { @@ -1489,7 +1486,7 @@ bool check_abbr(int c, char *ptr, int col, int mincol) } if (scol < col) { // there is a word in front of the cursor ptr += scol; - len = col - scol; + int len = col - scol; mp = curbuf->b_first_abbr; mp2 = first_abbr; if (mp == NULL) { @@ -1506,7 +1503,7 @@ bool check_abbr(int c, char *ptr, int col, int mincol) if (strchr((const char *)mp->m_keys, K_SPECIAL) != NULL) { // Might have K_SPECIAL escaped mp->m_keys. q = xstrdup(mp->m_keys); - vim_unescape_ks((char_u *)q); + vim_unescape_ks(q); qlen = (int)strlen(q); } // find entries with right mode and keys @@ -1532,7 +1529,7 @@ bool check_abbr(int c, char *ptr, int col, int mincol) // // Character CTRL-] is treated specially - it completes the // abbreviation, but is not inserted into the input stream. - j = 0; + int j = 0; if (c != Ctrl_RSB) { // special key code, split up if (IS_SPECIAL(c) || c == K_SPECIAL) { @@ -1568,6 +1565,7 @@ bool check_abbr(int c, char *ptr, int col, int mincol) const bool silent = mp->m_silent; const bool expr = mp->m_expr; + char *s; if (expr) { s = eval_map_expr(mp, c); } else { @@ -1609,7 +1607,7 @@ char *eval_map_expr(mapblock_T *mp, int c) // typeahead. if (mp->m_luaref == LUA_NOREF) { expr = xstrdup(mp->m_str); - vim_unescape_ks((char_u *)expr); + vim_unescape_ks(expr); } const bool replace_keycodes = mp->m_replace_keycodes; diff --git a/src/nvim/mark.c b/src/nvim/mark.c index f1a1f25e6c..855fcb33ae 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -521,11 +521,10 @@ fmark_T *pos_to_mark(buf_T *buf, fmark_T *fmp, pos_T pos) /// @return whether the buffer was switched or not. static MarkMoveRes switch_to_mark_buf(fmark_T *fm, bool pcmark_on_switch) { - bool res; if (fm->fnum != curbuf->b_fnum) { // Switch to another file. int getfile_flag = pcmark_on_switch ? GETF_SETMARK : 0; - res = buflist_getfile(fm->fnum, (linenr_T)1, getfile_flag, false) == OK; + bool res = buflist_getfile(fm->fnum, (linenr_T)1, getfile_flag, false) == OK; return res == true ? kMarkSwitchedBuf : kMarkMoveFailed; } return 0; @@ -617,11 +616,8 @@ fmarkv_T mark_view_make(linenr_T topline, pos_T pos) /// @return next mark or NULL if no mark is found. fmark_T *getnextmark(pos_T *startpos, int dir, int begin_line) { - int i; fmark_T *result = NULL; - pos_T pos; - - pos = *startpos; + pos_T pos = *startpos; if (dir == BACKWARD && begin_line) { pos.col = 0; @@ -629,7 +625,7 @@ fmark_T *getnextmark(pos_T *startpos, int dir, int begin_line) pos.col = MAXCOL; } - for (i = 0; i < NMARKS; i++) { + for (int i = 0; i < NMARKS; i++) { if (curbuf->b_namedm[i].mark.lnum > 0) { if (dir == FORWARD) { if ((result == NULL || lt(curbuf->b_namedm[i].mark, result->mark)) @@ -686,18 +682,17 @@ static void fname2fnum(xfmark_T *fm) void fmarks_check_names(buf_T *buf) { char *name = buf->b_ffname; - int i; if (buf->b_ffname == NULL) { return; } - for (i = 0; i < NGLOBALMARKS; i++) { + for (int i = 0; i < NGLOBALMARKS; i++) { fmarks_check_one(&namedfm[i], name, buf); } FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - for (i = 0; i < wp->w_jumplistlen; i++) { + for (int i = 0; i < wp->w_jumplistlen; i++) { fmarks_check_one(&wp->w_jumplist[i], name, buf); } } @@ -821,7 +816,6 @@ static char *mark_line(pos_T *mp, int lead_len) void ex_marks(exarg_T *eap) { char *arg = eap->arg; - int i; char *name; pos_T *posp, *startp, *endp; @@ -830,10 +824,10 @@ void ex_marks(exarg_T *eap) } show_one_mark('\'', arg, &curwin->w_pcmark, NULL, true); - for (i = 0; i < NMARKS; i++) { + for (int i = 0; i < NMARKS; i++) { show_one_mark(i + 'a', arg, &curbuf->b_namedm[i].mark, NULL, true); } - for (i = 0; i < NGLOBALMARKS; i++) { + for (int i = 0; i < NGLOBALMARKS; i++) { if (namedfm[i].fmark.fnum != 0) { name = fm_getname(&namedfm[i].fmark, 15); } else { @@ -919,7 +913,6 @@ void ex_delmarks(exarg_T *eap) { char *p; int from, to; - int i; int lower; int digit; int n; @@ -954,7 +947,7 @@ void ex_delmarks(exarg_T *eap) from = to = (uint8_t)(*p); } - for (i = from; i <= to; i++) { + for (int i = from; i <= to; i++) { if (lower) { curbuf->b_namedm[i - 'a'].mark.lnum = 0; } else { @@ -998,13 +991,12 @@ void ex_delmarks(exarg_T *eap) // print the jumplist void ex_jumps(exarg_T *eap) { - int i; char *name; cleanup_jumplist(curwin, true); // Highlight title msg_puts_title(_("\n jump line col file/text")); - for (i = 0; i < curwin->w_jumplistlen && !got_int; i++) { + for (int i = 0; i < curwin->w_jumplistlen && !got_int; i++) { if (curwin->w_jumplist[i].fmark.mark.lnum != 0) { name = fm_getname(&curwin->w_jumplist[i].fmark, 16); @@ -1051,13 +1043,12 @@ void ex_clearjumps(exarg_T *eap) // print the changelist void ex_changes(exarg_T *eap) { - int i; char *name; // Highlight title msg_puts_title(_("\nchange line col text")); - for (i = 0; i < curbuf->b_changelistlen && !got_int; i++) { + for (int i = 0; i < curbuf->b_changelistlen && !got_int; i++) { if (curbuf->b_changelist[i].mark.lnum != 0) { msg_putchar('\n'); if (got_int) { @@ -1138,7 +1129,6 @@ void mark_adjust_nofold(linenr_T line1, linenr_T line2, linenr_T amount, linenr_ static void mark_adjust_internal(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T amount_after, bool adjust_folds, ExtmarkOp op) { - int i; int fnum = curbuf->b_fnum; linenr_T *lp; static pos_T initpos = { 1, 0, 0 }; @@ -1149,13 +1139,13 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2, linenr_T amount if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { // named marks, lower case and upper case - for (i = 0; i < NMARKS; i++) { + for (int i = 0; i < NMARKS; i++) { ONE_ADJUST(&(curbuf->b_namedm[i].mark.lnum)); if (namedfm[i].fmark.fnum == fnum) { ONE_ADJUST_NODEL(&(namedfm[i].fmark.mark.lnum)); } } - for (i = NMARKS; i < NGLOBALMARKS; i++) { + for (int i = NMARKS; i < NGLOBALMARKS; i++) { if (namedfm[i].fmark.fnum == fnum) { ONE_ADJUST_NODEL(&(namedfm[i].fmark.mark.lnum)); } @@ -1173,7 +1163,7 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2, linenr_T amount } // list of change positions - for (i = 0; i < curbuf->b_changelistlen; i++) { + for (int i = 0; i < curbuf->b_changelistlen; i++) { ONE_ADJUST_NODEL(&(curbuf->b_changelist[i].mark.lnum)); } @@ -1217,7 +1207,7 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2, linenr_T amount if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { // Marks in the jumplist. When deleting lines, this may create // duplicate marks in the jumplist, they will be removed later. - for (i = 0; i < win->w_jumplistlen; i++) { + for (int i = 0; i < win->w_jumplistlen; i++) { if (win->w_jumplist[i].fmark.fnum == fnum) { ONE_ADJUST_NODEL(&(win->w_jumplist[i].fmark.mark.lnum)); } @@ -1227,7 +1217,7 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2, linenr_T amount if (win->w_buffer == curbuf) { if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { // marks in the tag stack - for (i = 0; i < win->w_tagstacklen; i++) { + for (int i = 0; i < win->w_tagstacklen; i++) { if (win->w_tagstack[i].fmark.fnum == fnum) { ONE_ADJUST_NODEL(&(win->w_tagstack[i].fmark.mark.lnum)); } @@ -1309,7 +1299,6 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2, linenr_T amount void mark_col_adjust(linenr_T lnum, colnr_T mincol, linenr_T lnum_amount, long col_amount, int spaces_removed) { - int i; int fnum = curbuf->b_fnum; pos_T *posp; @@ -1317,13 +1306,13 @@ void mark_col_adjust(linenr_T lnum, colnr_T mincol, linenr_T lnum_amount, long c return; // nothing to do } // named marks, lower case and upper case - for (i = 0; i < NMARKS; i++) { + for (int i = 0; i < NMARKS; i++) { COL_ADJUST(&(curbuf->b_namedm[i].mark)); if (namedfm[i].fmark.fnum == fnum) { COL_ADJUST(&(namedfm[i].fmark.mark)); } } - for (i = NMARKS; i < NGLOBALMARKS; i++) { + for (int i = NMARKS; i < NGLOBALMARKS; i++) { if (namedfm[i].fmark.fnum == fnum) { COL_ADJUST(&(namedfm[i].fmark.mark)); } @@ -1336,7 +1325,7 @@ void mark_col_adjust(linenr_T lnum, colnr_T mincol, linenr_T lnum_amount, long c COL_ADJUST(&(curbuf->b_last_change.mark)); // list of change positions - for (i = 0; i < curbuf->b_changelistlen; i++) { + for (int i = 0; i < curbuf->b_changelistlen; i++) { COL_ADJUST(&(curbuf->b_changelist[i].mark)); } @@ -1356,7 +1345,7 @@ void mark_col_adjust(linenr_T lnum, colnr_T mincol, linenr_T lnum_amount, long c // Adjust items in all windows related to the current buffer. FOR_ALL_WINDOWS_IN_TAB(win, curtab) { // marks in the jumplist - for (i = 0; i < win->w_jumplistlen; i++) { + for (int i = 0; i < win->w_jumplistlen; i++) { if (win->w_jumplist[i].fmark.fnum == fnum) { COL_ADJUST(&(win->w_jumplist[i].fmark.mark)); } @@ -1364,7 +1353,7 @@ void mark_col_adjust(linenr_T lnum, colnr_T mincol, linenr_T lnum_amount, long c if (win->w_buffer == curbuf) { // marks in the tag stack - for (i = 0; i < win->w_tagstacklen; i++) { + for (int i = 0; i < win->w_tagstacklen; i++) { if (win->w_tagstack[i].fmark.fnum == fnum) { COL_ADJUST(&(win->w_tagstack[i].fmark.mark)); } @@ -1457,9 +1446,7 @@ void cleanup_jumplist(win_T *wp, bool loadfiles) // Copy the jumplist from window "from" to window "to". void copy_jumplist(win_T *from, win_T *to) { - int i; - - for (i = 0; i < from->w_jumplistlen; i++) { + for (int i = 0; i < from->w_jumplistlen; i++) { to->w_jumplist[i] = from->w_jumplist[i]; if (from->w_jumplist[i].fname != NULL) { to->w_jumplist[i].fname = xstrdup(from->w_jumplist[i].fname); @@ -1671,9 +1658,7 @@ bool mark_set_local(const char name, buf_T *const buf, const fmark_T fm, const b // Free items in the jumplist of window "wp". void free_jumplist(win_T *wp) { - int i; - - for (i = 0; i < wp->w_jumplistlen; i++) { + for (int i = 0; i < wp->w_jumplistlen; i++) { free_xfmark(wp->w_jumplist[i]); } wp->w_jumplistlen = 0; diff --git a/src/nvim/match.c b/src/nvim/match.c index 6663dfd7ec..93c8a58051 100644 --- a/src/nvim/match.c +++ b/src/nvim/match.c @@ -419,7 +419,6 @@ static void next_search_hl(win_T *win, match_T *search_hl, match_T *shl, linenr_ colnr_T mincol, matchitem_T *cur) FUNC_ATTR_NONNULL_ARG(2) { - linenr_T l; colnr_T matchcol; long nmatched = 0; const int called_emsg_before = called_emsg; @@ -435,7 +434,7 @@ static void next_search_hl(win_T *win, match_T *search_hl, match_T *shl, linenr_ // 1. If the "lnum" is below a previous match, start a new search. // 2. If the previous match includes "mincol", use it. // 3. Continue after the previous match. - l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum; + linenr_T l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum; if (lnum > l) { shl->lnum = 0; } else if (lnum < l || shl->rm.endpos[0].col > mincol) { diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 8b50ba719a..e27bb003e7 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -449,18 +449,16 @@ int mb_get_class_tab(const char *p, const uint64_t *const chartab) static bool intable(const struct interval *table, size_t n_items, int c) FUNC_ATTR_PURE { - int mid, bot, top; - // first quick check for Latin1 etc. characters if (c < table[0].first) { return false; } // binary search in table - bot = 0; - top = (int)(n_items - 1); + int bot = 0; + int top = (int)(n_items - 1); while (top >= bot) { - mid = (bot + top) / 2; + int mid = (bot + top) / 2; if (table[mid].last < c) { bot = mid + 1; } else if (table[mid].first > c) { @@ -518,11 +516,9 @@ int utf_char2cells(int c) /// This doesn't take care of unprintable characters, use ptr2cells() for that. int utf_ptr2cells(const char *p) { - int c; - // Need to convert to a character number. if ((uint8_t)(*p) >= 0x80) { - c = utf_ptr2char(p); + int c = utf_ptr2char(p); // An illegal byte is displayed as <xx>. if (utf_ptr2len(p) == 1 || c == NUL) { return 4; @@ -540,14 +536,12 @@ int utf_ptr2cells(const char *p) /// For an empty string or truncated character returns 1. int utf_ptr2cells_len(const char *p, int size) { - int c; - // Need to convert to a wide character. if (size > 0 && (uint8_t)(*p) >= 0x80) { if (utf_ptr2len_len(p, size) < utf8len_tab[(uint8_t)(*p)]) { return 1; // truncated } - c = utf_ptr2char((char *)p); + int c = utf_ptr2char((char *)p); // An illegal byte is displayed as <xx>. if (utf_ptr2len((char *)p) == 1 || c == NUL) { return 4; @@ -664,8 +658,6 @@ int utf_ptr2char(const char *const p_in) // "s". static int utf_safe_read_char_adv(const char_u **s, size_t *n) { - int c; - if (*n == 0) { // end of buffer return 0; } @@ -682,7 +674,7 @@ static int utf_safe_read_char_adv(const char_u **s, size_t *n) // We have a multibyte sequence and it isn't truncated by buffer // limits so utf_ptr2char() is safe to use. Or the first byte is // illegal (k=0), and it's also safe to use utf_ptr2char(). - c = utf_ptr2char((char *)(*s)); + int c = utf_ptr2char((char *)(*s)); // On failure, utf_ptr2char() returns the first byte, so here we // check equality with the first byte. The only non-ASCII character @@ -855,7 +847,6 @@ int utf_byte2len(int b) int utf_ptr2len_len(const char *p, int size) { int len; - int i; int m; len = utf8len_tab[(uint8_t)(*p)]; @@ -867,7 +858,7 @@ int utf_ptr2len_len(const char *p, int size) } else { m = len; } - for (i = 1; i < m; i++) { + for (int i = 1; i < m; i++) { if ((p[i] & 0xc0) != 0x80) { return 1; } @@ -1141,7 +1132,6 @@ int utf_class_tab(const int c, const uint64_t *const chartab) }; int bot = 0; int top = ARRAY_SIZE(classes) - 1; - int mid; // First quick check for Latin1 characters, use 'iskeyword'. if (c < 0x100) { @@ -1161,7 +1151,7 @@ int utf_class_tab(const int c, const uint64_t *const chartab) // binary search in table while (top >= bot) { - mid = (bot + top) / 2; + int mid = (bot + top) / 2; if (classes[mid].last < (unsigned int)c) { bot = mid + 1; } else if (classes[mid].first > (unsigned int)c) { @@ -1186,13 +1176,12 @@ bool utf_ambiguous_width(int c) // the given conversion "table". Uses binary search on "table". static int utf_convert(int a, const convertStruct *const table, size_t n_items) { - size_t start, mid, end; // indices into table - - start = 0; - end = n_items; + // indices into table + size_t start = 0; + size_t end = n_items; while (start < end) { // need to search further - mid = (end + start) / 2; + size_t mid = (end + start) / 2; if (table[mid].rangeEnd < a) { start = mid + 1; } else { @@ -1540,7 +1529,6 @@ void show_utf8(void) int rlen = 0; char *line; int clen; - int i; // Get the byte length of the char under the cursor, including composing // characters. @@ -1552,7 +1540,7 @@ void show_utf8(void) } clen = 0; - for (i = 0; i < len; i++) { + for (int i = 0; i < len; i++) { if (clen == 0) { // start of (composing) character, get its length if (i > 0) { @@ -1579,9 +1567,6 @@ void show_utf8(void) /// Returns 0 when already at the first byte of a character. int utf_head_off(const char *base_in, const char *p_in) { - int c; - int len; - if ((uint8_t)(*p_in) < 0x80) { // be quick for ASCII return 0; } @@ -1603,7 +1588,7 @@ int utf_head_off(const char *base_in, const char *p_in) } // Check for illegal sequence. Do allow an illegal byte after where we // started. - len = utf8len_tab[*q]; + int len = utf8len_tab[*q]; if (len != (int)(s - q + 1) && len != (int)(p - q + 1)) { return 0; } @@ -1612,7 +1597,7 @@ int utf_head_off(const char *base_in, const char *p_in) break; } - c = utf_ptr2char((char *)q); + int c = utf_ptr2char((char *)q); if (utf_iscomposing(c)) { continue; } @@ -1795,7 +1780,6 @@ int mb_off_next(const char *base, const char *p_in) { const uint8_t *p = (uint8_t *)p_in; int i; - int j; if (*p < 0x80) { // be quick for ASCII return 0; @@ -1804,6 +1788,7 @@ int mb_off_next(const char *base, const char *p_in) // Find the next character that isn't 10xx.xxxx for (i = 0; (p[i] & 0xc0) == 0x80; i++) {} if (i > 0) { + int j; // Check for illegal sequence. for (j = 0; p - j > (uint8_t *)base; j++) { if ((p[-j] & 0xc0) != 0x80) { @@ -1855,7 +1840,7 @@ int utf_cp_tail_off(const char *base, const char *p_in) /// @param[in] p Pointer to byte for which to return the offset to the previous codepoint // /// @return 0 if invalid sequence, else offset to previous codepoint -int utf_cp_head_off(const char_u *base, const char_u *p) +int utf_cp_head_off(const char *base, const char *p) { int i; int j; @@ -1866,16 +1851,16 @@ int utf_cp_head_off(const char_u *base, const char_u *p) // Find the first character that is not 10xx.xxxx for (i = 0; p - i > base; i--) { - if ((p[i] & 0xc0) != 0x80) { + if (((uint8_t)p[i] & 0xc0) != 0x80) { break; } } // Find the last character that is 10xx.xxxx - for (j = 0; (p[j + 1] & 0xc0) == 0x80; j++) {} + for (j = 0; ((uint8_t)p[j + 1] & 0xc0) == 0x80; j++) {} // Check for illegal sequence. - if (utf8len_tab[p[i]] == 1) { + if (utf8len_tab[(uint8_t)p[i]] == 1) { return 0; } return i; @@ -2184,9 +2169,7 @@ char *enc_canonize(char *enc) /// Returns -1 when not found. static int enc_alias_search(const char *name) { - int i; - - for (i = 0; enc_alias_table[i].name != NULL; i++) { + for (int i = 0; enc_alias_table[i].name != NULL; i++) { if (strcmp(name, enc_alias_table[i].name) == 0) { return enc_alias_table[i].canon; } @@ -2479,7 +2462,6 @@ char *string_convert_ext(const vimconv_T *const vcp, char *ptr, size_t *lenp, si { char_u *retval = NULL; char_u *d; - int l; int c; size_t len; @@ -2547,7 +2529,7 @@ char *string_convert_ext(const vimconv_T *const vcp, char *ptr, size_t *lenp, si retval = xmalloc(len + 1); d = retval; for (size_t i = 0; i < len; i++) { - l = utf_ptr2len_len(ptr + i, (int)(len - i)); + int l = utf_ptr2len_len(ptr + i, (int)(len - i)); if (l == 0) { *d++ = NUL; } else if (l == 1) { @@ -2627,8 +2609,8 @@ char *string_convert_ext(const vimconv_T *const vcp, char *ptr, size_t *lenp, si /// Table set by setcellwidths(). typedef struct { - long first; - long last; + int64_t first; + int64_t last; char width; } cw_interval_T; diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index 46be9ccea5..118b5d5886 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -603,11 +603,9 @@ static int mf_read(memfile_T *mfp, bhdr_T *hp) static int mf_write(memfile_T *mfp, bhdr_T *hp) { off_T offset; // offset in the file - blocknr_T nr; // block nr which is being written bhdr_T *hp2; unsigned page_size; // number of bytes in a page unsigned page_count; // number of pages written - unsigned size; // number of bytes written if (mfp->mf_fd < 0) { // there is no file, can't write return FAIL; @@ -626,7 +624,7 @@ static int mf_write(memfile_T *mfp, bhdr_T *hp) /// If block 'mf_infile_count' is not in the hash list, it has been /// freed. Fill the space in the file with data from the current block. for (;;) { - nr = hp->bh_bnum; + blocknr_T nr = hp->bh_bnum; // block nr which is being written if (nr > mfp->mf_infile_count) { // beyond end of file nr = mfp->mf_infile_count; hp2 = mf_find_hash(mfp, nr); // NULL caught below @@ -645,7 +643,7 @@ static int mf_write(memfile_T *mfp, bhdr_T *hp) } else { page_count = hp2->bh_page_count; } - size = page_size * page_count; + unsigned size = page_size * page_count; // number of bytes written void *data = (hp2 == NULL) ? hp->bh_data : hp2->bh_data; if ((unsigned)write_eintr(mfp->mf_fd, data, size) != size) { /// Avoid repeating the error message, this mostly happens when the diff --git a/src/nvim/memline.c b/src/nvim/memline.c index dfca19aa96..ff0a6d7627 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -185,8 +185,8 @@ struct block0 { char_u b0_mtime[4]; // last modification time of file char_u b0_ino[4]; // inode of b0_fname char_u b0_pid[4]; // process id of creator (or 0) - char_u b0_uname[B0_UNAME_SIZE]; // name of user (uid if no name) - char_u b0_hname[B0_HNAME_SIZE]; // host name (if it has a name) + char b0_uname[B0_UNAME_SIZE]; // name of user (uid if no name) + char b0_hname[B0_HNAME_SIZE]; // host name (if it has a name) char b0_fname[B0_FNAME_SIZE_ORG]; // name of file being edited long b0_magic_long; // check for byte order of long int b0_magic_int; // check for byte order of int @@ -303,11 +303,11 @@ int ml_open(buf_T *buf) b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0; b0p->b0_flags = (char)(get_fileformat(buf) + 1); set_b0_fname(b0p, buf); - (void)os_get_username((char *)b0p->b0_uname, B0_UNAME_SIZE); + (void)os_get_username(b0p->b0_uname, B0_UNAME_SIZE); b0p->b0_uname[B0_UNAME_SIZE - 1] = NUL; - os_get_hostname((char *)b0p->b0_hname, B0_HNAME_SIZE); + os_get_hostname(b0p->b0_hname, B0_HNAME_SIZE); b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL; - long_to_char(os_get_pid(), b0p->b0_pid); + long_to_char((long)os_get_pid(), b0p->b0_pid); } // Always sync block number 0 to disk, so we can check the file name in @@ -632,7 +632,7 @@ static void set_b0_fname(ZERO_BL *b0p, buf_T *buf) // editing the same file on different machines over a network. // First replace home dir path with "~/" with home_replace(). // Then insert the user name to get "~user/". - home_replace(NULL, buf->b_ffname, (char *)b0p->b0_fname, + home_replace(NULL, buf->b_ffname, b0p->b0_fname, B0_FNAME_SIZE_CRYPT, true); if (b0p->b0_fname[0] == '~') { // If there is no user name or it is too long, don't use "~/" @@ -691,7 +691,7 @@ static void add_b0_fenc(ZERO_BL *b0p, buf_T *buf) if ((int)strlen(b0p->b0_fname) + n + 1 > size) { b0p->b0_flags = (char)(b0p->b0_flags & ~B0_HAS_FENC); } else { - memmove((char *)b0p->b0_fname + size - n, + memmove(b0p->b0_fname + size - n, buf->b_p_fenc, (size_t)n); *(b0p->b0_fname + size - n - 1) = NUL; b0p->b0_flags |= B0_HAS_FENC; @@ -848,7 +848,7 @@ void ml_recover(bool checkext) msg_puts_attr(_("The file was created on "), attr | MSG_HIST); // avoid going past the end of a corrupted hostname b0p->b0_fname[0] = NUL; - msg_puts_attr((char *)b0p->b0_hname, attr | MSG_HIST); + msg_puts_attr(b0p->b0_hname, attr | MSG_HIST); msg_puts_attr(_(",\nor the file has been damaged."), attr | MSG_HIST); msg_end(); goto theend; @@ -886,7 +886,7 @@ void ml_recover(bool checkext) // If .swp file name given directly, use name from swap file for buffer. if (directly) { - expand_env((char *)b0p->b0_fname, NameBuff, MAXPATHL); + expand_env(b0p->b0_fname, NameBuff, MAXPATHL); if (setfname(curbuf, NameBuff, NULL, true) == FAIL) { goto theend; } @@ -922,7 +922,7 @@ void ml_recover(bool checkext) if (b0p->b0_flags & B0_HAS_FENC) { int fnsize = B0_FNAME_SIZE_NOCRYPT; - for (p = (char *)b0p->b0_fname + fnsize; p > b0p->b0_fname && p[-1] != NUL; p--) {} + for (p = b0p->b0_fname + fnsize; p > b0p->b0_fname && p[-1] != NUL; p--) {} b0_fenc = xstrnsave(p, (size_t)(b0p->b0_fname + fnsize - p)); } @@ -1411,11 +1411,11 @@ void get_b0_dict(const char *fname, dict_T *d) } else { // We have swap information. tv_dict_add_str_len(d, S_LEN("version"), b0.b0_version, 10); - tv_dict_add_str_len(d, S_LEN("user"), (char *)b0.b0_uname, + tv_dict_add_str_len(d, S_LEN("user"), b0.b0_uname, B0_UNAME_SIZE); - tv_dict_add_str_len(d, S_LEN("host"), (char *)b0.b0_hname, + tv_dict_add_str_len(d, S_LEN("host"), b0.b0_hname, B0_HNAME_SIZE); - tv_dict_add_str_len(d, S_LEN("fname"), (char *)b0.b0_fname, + tv_dict_add_str_len(d, S_LEN("fname"), b0.b0_fname, B0_FNAME_SIZE_ORG); tv_dict_add_nr(d, S_LEN("pid"), char_to_long(b0.b0_pid)); @@ -1480,7 +1480,7 @@ static time_t swapfile_info(char *fname) if (b0.b0_fname[0] == NUL) { msg_puts(_("[No Name]")); } else { - msg_outtrans((char *)b0.b0_fname); + msg_outtrans(b0.b0_fname); } msg_puts(_("\n modified: ")); @@ -1488,7 +1488,7 @@ static time_t swapfile_info(char *fname) if (*(b0.b0_uname) != NUL) { msg_puts(_("\n user name: ")); - msg_outtrans((char *)b0.b0_uname); + msg_outtrans(b0.b0_uname); } if (*(b0.b0_hname) != NUL) { @@ -1497,7 +1497,7 @@ static time_t swapfile_info(char *fname) } else { msg_puts(_("\n host name: ")); } - msg_outtrans((char *)b0.b0_hname); + msg_outtrans(b0.b0_hname); } if (char_to_long(b0.b0_pid) != 0L) { @@ -2022,7 +2022,6 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char *line, colnr_T len, boo int lineadd; blocknr_T bnum_left, bnum_right; linenr_T lnum_left, lnum_right; - int pb_idx; PTR_BL *pp_new; // We are going to allocate a new data block. Depending on the @@ -2156,7 +2155,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char *line, colnr_T len, boo // update pointer blocks for the new data block for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0; stack_idx--) { infoptr_T *ip = &(buf->b_ml.ml_stack[stack_idx]); - pb_idx = ip->ip_index; + int pb_idx = ip->ip_index; if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL) { return FAIL; } @@ -3029,7 +3028,7 @@ char *makeswapname(char *fname, char *ffname, buf_T *buf, char *dir_name) // Expand symlink in the file name, so that we put the swap file with the // actual file instead of with the symlink. - if (resolve_symlink(fname, (char *)fname_buf) == OK) { + if (resolve_symlink(fname, fname_buf) == OK) { fname_res = fname_buf; } #endif @@ -3211,7 +3210,6 @@ static int do_swapexists(buf_T *buf, char *fname) static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_existing_dir) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 2, 4) { - size_t n; char *buf_fname = buf->b_fname; // Isolate a directory name from *dirp and put it in dir_name. @@ -3224,6 +3222,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ char *fname = makeswapname(buf_fname, buf->b_ffname, buf, dir_name); for (;;) { + size_t n; if (fname == NULL) { // must be out of memory break; } @@ -3267,12 +3266,12 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ // have a different mountpoint. if (b0.b0_flags & B0_SAME_DIR) { if (path_fnamecmp(path_tail(buf->b_ffname), - path_tail((char *)b0.b0_fname)) != 0 + path_tail(b0.b0_fname)) != 0 || !same_directory(fname, buf->b_ffname)) { // Symlinks may point to the same file even // when the name differs, need to check the // inode too. - expand_env((char *)b0.b0_fname, NameBuff, MAXPATHL); + expand_env(b0.b0_fname, NameBuff, MAXPATHL); if (fnamecmp_ino(buf->b_ffname, NameBuff, char_to_long(b0.b0_ino))) { differ = true; @@ -3281,7 +3280,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ } else { // The name in the swap file may be // "~user/path/file". Expand it first. - expand_env((char *)b0.b0_fname, NameBuff, MAXPATHL); + expand_env(b0.b0_fname, NameBuff, MAXPATHL); if (fnamecmp_ino(buf->b_ffname, NameBuff, char_to_long(b0.b0_ino))) { differ = true; @@ -3516,8 +3515,8 @@ static bool fnamecmp_ino(char *fname_c, char *fname_s, long ino_block0) // One of the inode numbers is unknown, try a forced vim_FullName() and // compare the file names. - retval_c = vim_FullName(fname_c, (char *)buf_c, MAXPATHL, true); - retval_s = vim_FullName(fname_s, (char *)buf_s, MAXPATHL, true); + retval_c = vim_FullName(fname_c, buf_c, MAXPATHL, true); + retval_s = vim_FullName(fname_s, buf_s, MAXPATHL, true); if (retval_c == OK && retval_s == OK) { return strcmp(buf_c, buf_s) != 0; } @@ -3605,11 +3604,8 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype) linenr_T curline = ml_upd_lastcurline; int curix = ml_upd_lastcurix; - long size; chunksize_T *curchnk; - int rest; bhdr_T *hp; - DATA_BL *dp; if (buf->b_ml.ml_usedchunks == -1 || len == 0) { return; @@ -3655,6 +3651,8 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype) } curchnk->mlcs_totalsize += len; if (updtype == ML_CHNK_ADDLINE) { + int rest; + DATA_BL *dp; curchnk->mlcs_numlines++; // May resize here so we don't have to do it in both cases below @@ -3665,17 +3663,14 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype) } if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MAXL) { - int count; // number of entries in block - int idx; int text_end; - int linecnt; memmove(buf->b_ml.ml_chunksize + curix + 1, buf->b_ml.ml_chunksize + curix, (size_t)(buf->b_ml.ml_usedchunks - curix) * sizeof(chunksize_T)); // Compute length of first half of lines in the split chunk - size = 0; - linecnt = 0; + long size = 0; + int linecnt = 0; while (curline < buf->b_ml.ml_line_count && linecnt < MLCS_MINL) { if ((hp = ml_find_line(buf, curline, ML_FIND)) == NULL) { @@ -3683,8 +3678,9 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype) return; } dp = hp->bh_data; - count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1; - idx = curline - buf->b_ml.ml_locked_low; + int count + = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1; // number of entries in block + int idx = curline - buf->b_ml.ml_locked_low; curline = buf->b_ml.ml_locked_high + 1; if (idx == 0) { // first line in block, text at the end text_end = (int)dp->db_txt_end; @@ -3793,13 +3789,8 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff) int curix; long size; bhdr_T *hp; - DATA_BL *dp; - int count; // number of entries in block - int idx; - int start_idx; int text_end; long offset; - int len; int ffdos = !no_ff && (get_fileformat(buf) == EOL_DOS); int extra = 0; @@ -3859,9 +3850,11 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff) || (hp = ml_find_line(buf, curline, ML_FIND)) == NULL) { return -1; } - dp = hp->bh_data; - count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1; - start_idx = idx = curline - buf->b_ml.ml_locked_low; + DATA_BL *dp = hp->bh_data; + int count + = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1; // number of entries in block + int idx; + int start_idx = idx = curline - buf->b_ml.ml_locked_low; if (idx == 0) { // first line in block, text at the end text_end = (int)dp->db_txt_end; } else { @@ -3889,7 +3882,7 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff) idx++; } } - len = text_end - (int)((dp->db_index[idx]) & DB_INDEX_MASK); + int len = text_end - (int)((dp->db_index[idx]) & DB_INDEX_MASK); size += len; if (offset != 0 && size >= offset) { if (size + ffdos == offset) { diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 5356300382..4e799dfd08 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -121,9 +121,7 @@ void *xmalloc(size_t size) { void *ret = try_malloc(size); if (!ret) { - os_errmsg(e_outofmem); - os_errmsg("\n"); - preserve_exit(); + preserve_exit(e_outofmem); } return ret; } @@ -152,9 +150,7 @@ void *xcalloc(size_t count, size_t size) try_to_free_memory(); ret = calloc(allocated_count, allocated_size); if (!ret) { - os_errmsg(e_outofmem); - os_errmsg("\n"); - preserve_exit(); + preserve_exit(e_outofmem); } } return ret; @@ -174,9 +170,7 @@ void *xrealloc(void *ptr, size_t size) try_to_free_memory(); ret = realloc(ptr, allocated_size); if (!ret) { - os_errmsg(e_outofmem); - os_errmsg("\n"); - preserve_exit(); + preserve_exit(e_outofmem); } } return ret; @@ -194,8 +188,7 @@ void *xmallocz(size_t size) { size_t total_size = size + 1; if (total_size < size) { - os_errmsg(_("Vim: Data too large to fit into virtual memory space\n")); - preserve_exit(); + preserve_exit(_("Vim: Data too large to fit into virtual memory space\n")); } void *ret = xmalloc(total_size); diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 2a18b08d8d..4fad926cb0 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -281,7 +281,6 @@ static int add_menu_path(const char *const menu_path, vimmenu_T *menuarg, const char *next_name; char c; char d; - int i; int pri_idx = 0; int old_modes = 0; int amenu; @@ -411,7 +410,7 @@ static int add_menu_path(const char *const menu_path, vimmenu_T *menuarg, const p = (call_data == NULL) ? NULL : xstrdup(call_data); // loop over all modes, may add more than one - for (i = 0; i < MENU_MODES; i++) { + for (int i = 0; i < MENU_MODES; i++) { if (modes & (1 << i)) { // free any old menu free_menu_string(menu, i); @@ -617,10 +616,7 @@ static int remove_menu(vimmenu_T **menup, char *name, int modes, bool silent) // Free the given menu structure and remove it from the linked list. static void free_menu(vimmenu_T **menup) { - int i; - vimmenu_T *menu; - - menu = *menup; + vimmenu_T *menu = *menup; // Don't change *menup until after calling gui_mch_destroy_menu(). The // MacOS code needs the original structure to properly delete the menu. @@ -630,7 +626,7 @@ static void free_menu(vimmenu_T **menup) xfree(menu->en_name); xfree(menu->en_dname); xfree(menu->actext); - for (i = 0; i < MENU_MODES; i++) { + for (int i = 0; i < MENU_MODES; i++) { free_menu_string(menu, i); } xfree(menu); @@ -640,9 +636,8 @@ static void free_menu(vimmenu_T **menup) static void free_menu_string(vimmenu_T *menu, int idx) { int count = 0; - int i; - for (i = 0; i < MENU_MODES; i++) { + for (int i = 0; i < MENU_MODES; i++) { if (menu->strings[i] == menu->strings[idx]) { count++; } @@ -662,13 +657,11 @@ static void free_menu_string(vimmenu_T *menu, int idx) /// @see menu_get static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes) { - dict_T *dict; - if (!menu || (menu->modes & modes) == 0x0) { return NULL; } - dict = tv_dict_alloc(); + dict_T *dict = tv_dict_alloc(); tv_dict_add_str(dict, S_LEN("name"), menu->dname); tv_dict_add_nr(dict, S_LEN("priority"), (int)menu->priority); tv_dict_add_nr(dict, S_LEN("hidden"), menu_is_hidden(menu->dname)); @@ -815,7 +808,6 @@ static int show_menus(char *const path_name, int modes) static void show_menus_recursive(vimmenu_T *menu, int modes, int depth) { int i; - int bit; if (menu != NULL && (menu->modes & modes) == 0x0) { return; @@ -838,7 +830,7 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth) } if (menu != NULL && menu->children == NULL) { - for (bit = 0; bit < MENU_MODES; bit++) { + for (int bit = 0; bit < MENU_MODES; bit++) { if ((menu->modes & modes & (1 << bit)) != 0) { msg_putchar('\n'); if (got_int) { // "q" hit for "--more--" @@ -902,7 +894,6 @@ char *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char *arg, bool for char *after_dot; char *p; char *path_name = NULL; - char *name; int unmenu; vimmenu_T *menu; int expand_menus; @@ -963,7 +954,7 @@ char *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char *arg, bool for path_name = xmalloc(path_len); xstrlcpy(path_name, arg, path_len); } - name = path_name; + char *name = path_name; while (name != NULL && *name) { p = menu_name_skip(name); while (menu != NULL) { diff --git a/src/nvim/message.c b/src/nvim/message.c index 40453211b4..4904bde095 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -369,14 +369,13 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline) char *msg_strtrunc(char *s, int force) { char *buf = NULL; - int len; - int room; // May truncate message to avoid a hit-return prompt if ((!msg_scroll && !need_wait_return && shortmess(SHM_TRUNCALL) && !exmode_active && msg_silent == 0 && !ui_has(kUIMessages)) || force) { - len = vim_strsize(s); + int room; + int len = vim_strsize(s); if (msg_scrolled != 0) { // Use all the columns. room = (Rows - msg_row) * Columns - 1; @@ -1033,7 +1032,6 @@ void ex_messages(void *const eap_p) { const exarg_T *const eap = (const exarg_T *)eap_p; struct msg_hist *p; - int c = 0; if (strcmp(eap->arg, "clear") == 0) { int keep = eap->addr_count == 0 ? 0 : eap->line2; @@ -1052,6 +1050,7 @@ void ex_messages(void *const eap_p) p = first_msg_hist; if (eap->addr_count != 0) { + int c = 0; // Count total messages for (; p != NULL && !got_int; p = p->next) { c++; @@ -1085,7 +1084,7 @@ void ex_messages(void *const eap_p) } else if (p->msg && p->msg[0]) { Array content_entry = ARRAY_DICT_INIT; ADD(content_entry, INTEGER_OBJ(p->attr)); - ADD(content_entry, STRING_OBJ(cstr_to_string((char *)(p->msg)))); + ADD(content_entry, STRING_OBJ(cstr_to_string(p->msg))); ADD(content, ARRAY_OBJ(content_entry)); } ADD(entry, ARRAY_OBJ(content)); @@ -1470,9 +1469,9 @@ void msg_putchar_attr(int c, int attr) buf[2] = (char)K_THIRD(c); buf[3] = NUL; } else { - buf[utf_char2bytes(c, (char *)buf)] = NUL; + buf[utf_char2bytes(c, buf)] = NUL; } - msg_puts_attr((const char *)buf, attr); + msg_puts_attr(buf, attr); } void msg_outnum(long n) @@ -1542,7 +1541,6 @@ int msg_outtrans_len_attr(const char *msgstr, int len, int attr) const char *str = msgstr; const char *plain_start = msgstr; char *s; - int mb_l; int c; int save_got_int = got_int; @@ -1565,7 +1563,7 @@ int msg_outtrans_len_attr(const char *msgstr, int len, int attr) // Normal characters are printed several at a time. while (--len >= 0 && !got_int) { // Don't include composing chars after the end. - mb_l = utfc_ptr2len_len(str, len + 1); + int mb_l = utfc_ptr2len_len(str, len + 1); if (mb_l > 1) { c = utf_ptr2char(str); if (vim_isprintc(c)) { @@ -2139,7 +2137,7 @@ static void msg_puts_display(const char *str, int maxlen, int attr, int recurse) int t_col = 0; // Screen cells todo, 0 when "t_s" not used. int l; int cw; - const char *sb_str = (char *)str; + const char *sb_str = str; int sb_col = msg_col; int wrap; int did_last_char; @@ -2153,7 +2151,7 @@ static void msg_puts_display(const char *str, int maxlen, int attr, int recurse) } // Concat pieces with the same highlight size_t len = strnlen(str, (size_t)maxlen); // -V781 - ga_concat_len(&msg_ext_last_chunk, (char *)str, len); + ga_concat_len(&msg_ext_last_chunk, str, len); msg_ext_cur_len += len; return; } @@ -2652,12 +2650,11 @@ void msg_sb_eol(void) static msgchunk_T *disp_sb_line(int row, msgchunk_T *smp) { msgchunk_T *mp = smp; - char *p; for (;;) { msg_row = row; msg_col = mp->sb_msg_col; - p = mp->sb_text; + char *p = mp->sb_text; if (*p == '\n') { // don't display the line break p++; } @@ -2767,7 +2764,6 @@ static int do_more_prompt(int typed_char) int oldState = State; int c; int retval = false; - int toscroll; bool to_redraw = false; msgchunk_T *mp_last = NULL; msgchunk_T *mp; @@ -2809,7 +2805,7 @@ static int do_more_prompt(int typed_char) c = get_keystroke(resize_events); } - toscroll = 0; + int toscroll = 0; switch (c) { case BS: // scroll one line back case K_BS: @@ -3507,7 +3503,6 @@ int do_dialog(int type, char *title, char *message, char *buttons, int dfltbutto { int retval = 0; char *hotkeys; - int c; int i; if (silent_mode // No dialogs in silent mode ("ex -s") @@ -3530,7 +3525,7 @@ int do_dialog(int type, char *title, char *message, char *buttons, int dfltbutto for (;;) { // Get a typed character directly from the user. - c = get_keystroke(NULL); + int c = get_keystroke(NULL); switch (c) { case CAR: // User accepts default option case NL: diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 950b025e53..60efd6a72a 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -86,15 +86,11 @@ static int get_mouse_class(char *p) /// Move "pos" back to the start of the word it's in. static void find_start_of_word(pos_T *pos) { - char *line; - int cclass; - int col; - - line = ml_get(pos->lnum); - cclass = get_mouse_class(line + pos->col); + char *line = ml_get(pos->lnum); + int cclass = get_mouse_class(line + pos->col); while (pos->col > 0) { - col = pos->col - 1; + int col = pos->col - 1; col -= utf_head_off(line, line + col); if (get_mouse_class(line + col) != cclass) { break; @@ -109,7 +105,6 @@ static void find_end_of_word(pos_T *pos) { char *line; int cclass; - int col; line = ml_get(pos->lnum); if (*p_sel == 'e' && pos->col > 0) { @@ -118,7 +113,7 @@ static void find_end_of_word(pos_T *pos) } cclass = get_mouse_class(line + pos->col); while (line[pos->col] != NUL) { - col = pos->col + utfc_ptr2len(line + pos->col); + int col = pos->col + utfc_ptr2len(line + pos->col); if (get_mouse_class(line + col) != cclass) { if (*p_sel == 'e') { pos->col = col; @@ -296,18 +291,16 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent) bool in_status_line; // mouse in status line static bool in_tab_line = false; // mouse clicked in tab line bool in_sep_line; // mouse in vertical separator line - int c1, c2; - pos_T save_cursor; + int c1; win_T *old_curwin = curwin; static pos_T orig_cursor; colnr_T leftcol, rightcol; pos_T end_visual; - long diff; int old_active = VIsual_active; int old_mode = VIsual_mode; int regname; - save_cursor = curwin->w_cursor; + pos_T save_cursor = curwin->w_cursor; for (;;) { which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag); @@ -731,6 +724,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent) } if (start_visual.lnum) { // right click in visual mode + long diff; // When ALT is pressed make Visual mode blockwise. if (mod_mask & MOD_MASK_ALT) { VIsual_mode = Ctrl_V; @@ -800,6 +794,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent) // Middle mouse click: Put text before cursor. if (which_button == MOUSE_MIDDLE) { + int c2; if (regname == 0 && eval_has_provider("clipboard")) { regname = '*'; } @@ -888,13 +883,13 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent) // A double click selects a word or a block. if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) { pos_T *pos = NULL; - int gc; if (is_click) { // If the character under the cursor (skipping white space) is // not a word character, try finding a match and select a (), // {}, [], #if/#endif, etc. block. end_visual = curwin->w_cursor; + int gc; while (gc = gchar_pos(&end_visual), ascii_iswhite(gc)) { inc(&end_visual); } @@ -1388,16 +1383,14 @@ bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump) { int col = *colp; int row = *rowp; - linenr_T lnum; bool retval = false; - int off; int count; if (win->w_p_rl) { col = win->w_width_inner - 1 - col; } - lnum = win->w_topline; + linenr_T lnum = win->w_topline; while (row > 0) { // Don't include filler lines in "count" @@ -1429,7 +1422,7 @@ bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump) if (!retval) { // Compute the column without wrapping. - off = win_col_off(win) - win_col_off2(win); + int off = win_col_off(win) - win_col_off2(win); if (col < off) { col = off; } @@ -1467,9 +1460,7 @@ win_T *mouse_find_win(int *gridp, int *rowp, int *colp) return NULL; } - frame_T *fp; - - fp = topframe; + frame_T *fp = topframe; *rowp -= firstwin->w_winrow; for (;;) { if (fp->fr_layout == FR_LEAF) { @@ -1716,10 +1707,8 @@ static int mouse_adjust_click(win_T *wp, int row, int col) ptr_end += utfc_ptr2len(ptr_end); } - int matchid; int prev_matchid; int nudge = 0; - int cwidth = 0; vcol = offset; @@ -1727,7 +1716,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) #define DECR() nudge--; ptr_end -= utfc_ptr2len((char *)ptr_end) while (ptr < ptr_end && *ptr != NUL) { - cwidth = win_chartabsize(curwin, ptr, vcol); + int cwidth = win_chartabsize(curwin, ptr, vcol); vcol += cwidth; if (cwidth > 1 && *ptr == '\t' && nudge > 0) { // A tab will "absorb" any previous adjustments. @@ -1738,7 +1727,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) } } - matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line)); + int matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line)); if (matchid != 0) { if (wp->w_p_cole == 3) { INCR(); @@ -1780,9 +1769,7 @@ int mouse_check_fold(void) int max_col = Columns; int multigrid = ui_has(kUIMultigrid); - win_T *wp; - - wp = mouse_find_win(&click_grid, &click_row, &click_col); + win_T *wp = mouse_find_win(&click_grid, &click_row, &click_col); if (wp && multigrid) { max_row = wp->w_grid_alloc.rows; max_col = wp->w_grid_alloc.cols; diff --git a/src/nvim/move.c b/src/nvim/move.c index 3af26b910e..a946633bf6 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -145,7 +145,6 @@ void update_topline(win_T *wp) { linenr_T old_topline; int old_topfill; - bool check_topline = false; bool check_botline = false; long *so_ptr = wp->w_p_so >= 0 ? &wp->w_p_so : &p_so; long save_so = *so_ptr; @@ -189,6 +188,7 @@ void update_topline(win_T *wp) wp->w_viewport_invalid = true; wp->w_scbind_pos = 1; } else { + bool check_topline = false; // If the cursor is above or near the top of the window, scroll the window // to show the line the cursor is in, with 'scrolloff' context. if (wp->w_topline > 1) { diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index d60e18590f..f8be0d4c8d 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -247,10 +247,13 @@ static void parse_msgpack(Channel *channel) Unpacker *p = channel->rpc.unpacker; while (unpacker_advance(p)) { if (p->type == kMessageTypeRedrawEvent) { - if (p->grid_line_event) { - ui_client_event_raw_line(p->grid_line_event); - } else if (p->ui_handler.fn != NULL && p->result.type == kObjectTypeArray) { - p->ui_handler.fn(p->result.data.array); + // When exiting, ui_client_stop() has already been called, so don't handle UI events. + if (ui_client_channel_id && !exiting) { + if (p->grid_line_event) { + ui_client_event_raw_line(p->grid_line_event); + } else if (p->ui_handler.fn != NULL && p->result.type == kObjectTypeArray) { + p->ui_handler.fn(p->result.data.array); + } } arena_mem_free(arena_finish(&p->arena)); } else if (p->type == kMessageTypeResponse) { @@ -547,6 +550,10 @@ void rpc_close(Channel *channel) if (channel->streamtype == kChannelStreamStdio || (channel->id == ui_client_channel_id && channel->streamtype != kChannelStreamProc)) { + if (channel->streamtype == kChannelStreamStdio) { + // Avoid hanging when there are no other UIs and a prompt is triggered on exit. + remote_ui_disconnect(channel->id); + } exit_from_channel(0); } } diff --git a/src/nvim/normal.c b/src/nvim/normal.c index b88cfb8926..a84d5c73a4 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -401,10 +401,8 @@ void init_normal_cmds(void) /// @return -1 for invalid command. static int find_command(int cmdchar) { - int i; int idx; int top, bot; - int c; // A multi-byte character is never a command. if (cmdchar >= 0x100) { @@ -429,8 +427,8 @@ static int find_command(int cmdchar) top = NV_CMDS_SIZE - 1; idx = -1; while (bot <= top) { - i = (top + bot) / 2; - c = nv_cmds[nv_cmd_idx[i]].cmd_char; + int i = (top + bot) / 2; + int c = nv_cmds[nv_cmd_idx[i]].cmd_char; if (c < 0) { c = -c; } @@ -693,7 +691,6 @@ static void normal_get_additional_char(NormalState *s) int *cp; bool repl = false; // get character for replace mode bool lit = false; // get extra character literally - bool langmap_active = false; // using :lmap mappings int lang; // getting a text character no_mapping++; @@ -729,6 +726,7 @@ static void normal_get_additional_char(NormalState *s) // Get a second or third character. if (cp != NULL) { + bool langmap_active = false; // using :lmap mappings if (repl) { State = MODE_REPLACE; // pretend Replace mode ui_cursor_shape(); // show different cursor shape @@ -1848,7 +1846,6 @@ void clear_showcmd(void) snprintf(showcmd_buf, SHOWCMD_BUFLEN, "%" PRId64, (int64_t)lines); } else { char *s, *e; - int l; int bytes = 0; int chars = 0; @@ -1860,7 +1857,7 @@ void clear_showcmd(void) e = ml_get_pos(&VIsual); } while ((*p_sel != 'e') ? s <= e : s < e) { - l = utfc_ptr2len(s); + int l = utfc_ptr2len(s); if (l == 0) { bytes++; chars++; @@ -2427,7 +2424,6 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist) int linelen = linetabsize(get_cursor_line_ptr()); bool retval = true; bool atend = false; - int n; int col_off1; // margin offset for first screen line int col_off2; // margin offset for wrapped screen line int width1; // text width for first screen line @@ -2446,6 +2442,7 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist) } if (curwin->w_width_inner != 0) { + int n; // Instead of sticking at the last character of the buffer line we // try to stick in the last column of the screen. if (curwin->w_curswant == MAXCOL) { @@ -2793,7 +2790,6 @@ static int nv_zg_zw(cmdarg_T *cap, int nchar) /// Commands that start with "z". static void nv_zet(cmdarg_T *cap) { - int n; colnr_T col; int nchar = cap->nchar; long old_fdl = curwin->w_p_fdl; @@ -2949,7 +2945,7 @@ static void nv_zet(cmdarg_T *cap) } else { getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col); } - n = curwin->w_width_inner - curwin_col_off(); + int n = curwin->w_width_inner - curwin_col_off(); if (col + siso < n) { col = 0; } else { @@ -3438,7 +3434,6 @@ static void nv_ident(cmdarg_T *cap) int cmdchar; bool g_cmd; // "g" command bool tag_cmd = false; - char *aux_ptr; if (cap->cmdchar == 'g') { // "g*", "g#", "g]" and "gCTRL-]" cmdchar = cap->nchar; @@ -3542,6 +3537,7 @@ static void nv_ident(cmdarg_T *cap) STRCAT(buf, p); xfree(p); } else { + char *aux_ptr; if (cmdchar == '*') { aux_ptr = (magic_isset() ? "/.*~[^$\\" : "/^$\\"); } else if (cmdchar == '#') { @@ -3653,10 +3649,8 @@ static void nv_tagpop(cmdarg_T *cap) /// Handle scrolling command 'H', 'L' and 'M'. static void nv_scroll(cmdarg_T *cap) { - int used = 0; long n; linenr_T lnum; - int half; cap->oap->motion_type = kMTLineWise; setpcmark(); @@ -3683,11 +3677,12 @@ static void nv_scroll(cmdarg_T *cap) } } else { if (cap->cmdchar == 'M') { + int used = 0; // Don't count filler lines above the window. used -= win_get_fill(curwin, curwin->w_topline) - curwin->w_topfill; validate_botline(curwin); // make sure w_empty_rows is valid - half = (curwin->w_height_inner - curwin->w_empty_rows + 1) / 2; + int half = (curwin->w_height_inner - curwin->w_empty_rows + 1) / 2; for (n = 0; curwin->w_topline + n < curbuf->b_ml.ml_line_count; n++) { // Count half the number of filler lines to be "below this // line" and half to be "above the next line". @@ -4115,7 +4110,6 @@ static void nv_bracket_block(cmdarg_T *cap, const pos_T *old_pos) pos_T prev_pos; long n; int findc; - int c; if (cap->nchar == '*') { cap->nchar = '/'; @@ -4155,6 +4149,7 @@ static void nv_bracket_block(cmdarg_T *cap, const pos_T *old_pos) // Try finding the '{' or '}' we want to be at. // Also repeat for the given count. if (cap->nchar == 'm' || cap->nchar == 'M') { + int c; // norm is true for "]M" and "[m" int norm = ((findc == '{') == (cap->nchar == 'm')); @@ -4361,7 +4356,6 @@ static void nv_brackets(cmdarg_T *cap) /// Handle Normal mode "%" command. static void nv_percent(cmdarg_T *cap) { - pos_T *pos; linenr_T lnum = curwin->w_cursor.lnum; cap->oap->inclusive = true; @@ -4391,6 +4385,7 @@ static void nv_percent(cmdarg_T *cap) beginline(BL_SOL | BL_FIX); } } else { // "%" : go to matching paren + pos_T *pos; cap->oap->motion_type = kMTCharWise; cap->oap->use_reg_one = true; if ((pos = findmatch(cap->oap, NUL)) == NULL) { @@ -6046,9 +6041,8 @@ static void adjust_for_sel(cmdarg_T *cap) /// @return true when backed up to the previous line. bool unadjust_for_sel(void) { - pos_T *pp; - if (*p_sel == 'e' && !equalpos(VIsual, curwin->w_cursor)) { + pos_T *pp; if (lt(VIsual, curwin->w_cursor)) { pp = &curwin->w_cursor; } else { @@ -6460,7 +6454,6 @@ static void nv_put(cmdarg_T *cap) /// @param fix_indent true for "[p", "[P", "]p" and "]P". static void nv_put_opt(cmdarg_T *cap, bool fix_indent) { - int regname = 0; yankreg_T *savereg = NULL; bool empty = false; bool was_visual = false; @@ -6506,7 +6499,7 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent) // Need to save and restore the registers that the delete // overwrites if the old contents is being put. was_visual = true; - regname = cap->oap->regname; + int regname = cap->oap->regname; bool keep_registers = cap->cmdchar == 'P'; // '+' and '*' could be the same selection bool clipoverwrite = (regname == '+' || regname == '*') && (cb_flags & CB_UNNAMEDMASK); diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 435ca106ab..e89844098b 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -214,7 +214,6 @@ int get_extra_op_char(int optype) void op_shift(oparg_T *oap, int curs_top, int amount) { long i; - int first_char; int block_col = 0; if (u_save((linenr_T)(oap->start.lnum - 1), @@ -227,7 +226,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount) } for (i = oap->line_count - 1; i >= 0; i--) { - first_char = (uint8_t)(*get_cursor_line_ptr()); + int first_char = (uint8_t)(*get_cursor_line_ptr()); if (first_char == NUL) { // empty line curwin->w_cursor.col = 0; } else if (oap->motion_type == kMTBlockWise) { @@ -289,15 +288,13 @@ void op_shift(oparg_T *oap, int curs_top, int amount) /// @param call_changed_bytes call changed_bytes() void shift_line(int left, int round, int amount, int call_changed_bytes) { - int count; - int i, j; const int sw_val = (int)get_sw_value_indent(curbuf); - count = get_indent(); // get current indent + int count = get_indent(); // get current indent if (round) { // round off indent - i = count / sw_val; // number of 'shiftwidth' rounded down - j = count % sw_val; // extra spaces + int i = count / sw_val; // number of 'shiftwidth' rounded down + int j = count % sw_val; // extra spaces if (j && left) { // first remove extra spaces amount--; } @@ -636,8 +633,6 @@ static void block_insert(oparg_T *oap, char *s, int b_insert, struct block_def * void op_reindent(oparg_T *oap, Indenter how) { long i = 0; - char *l; - int amount; linenr_T first_changed = 0; linenr_T last_changed = 0; linenr_T start_lnum = curwin->w_cursor.lnum; @@ -652,6 +647,8 @@ void op_reindent(oparg_T *oap, Indenter how) // for each line separately, especially when undoing. if (u_savecommon(curbuf, start_lnum - 1, start_lnum + (linenr_T)oap->line_count, start_lnum + (linenr_T)oap->line_count, false) == OK) { + char *l; + int amount; for (i = oap->line_count - 1; i >= 0 && !got_int; i--) { // it's a slow thing to do, so give feedback so there's no worry // that the computer's just hung. @@ -902,7 +899,6 @@ bool yank_register_mline(int regname) /// @return FAIL for failure, OK otherwise. int do_record(int c) { - char *p; static int regname; yankreg_T *old_y_previous; int retval; @@ -927,10 +923,10 @@ int do_record(int c) dict_T *dict = get_v_event(&save_v_event); // The recorded text contents. - p = (char *)get_recorded(); + char *p = get_recorded(); if (p != NULL) { // Remove escaping for K_SPECIAL in multi-byte chars. - vim_unescape_ks((char_u *)p); + vim_unescape_ks(p); (void)tv_dict_add_str(dict, S_LEN("regcontents"), (const char *)p); } @@ -1149,7 +1145,6 @@ int do_execreg(int regname, int colon, int addcr, int silent) // Insert lines into typeahead buffer, from last one to first one. put_reedit_in_typebuf(silent); - char *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) { @@ -1168,7 +1163,7 @@ int do_execreg(int regname, int colon, int addcr, int silent) free_str = true; } } - escaped = vim_strsave_escape_ks(str); + char *escaped = vim_strsave_escape_ks(str); if (free_str) { xfree(str); } @@ -1651,10 +1646,9 @@ int op_delete(oparg_T *oap) } } else { if (virtual_op) { - int endcol = 0; - // For virtualedit: break the tabs that are partly included. if (gchar_pos(&oap->start) == '\t') { + int endcol = 0; if (u_save_cursor() == FAIL) { // save first line for undo return FAIL; } @@ -1820,10 +1814,7 @@ static void replace_character(int c) /// Replace a whole area with one character. static int op_replace(oparg_T *oap, int c) { - int n, numc; - int num_chars; - char *newp, *oldp; - colnr_T oldlen; + int n; struct block_def bd; char *after_p = NULL; int had_ctrl_v_cr = false; @@ -1848,6 +1839,11 @@ static int op_replace(oparg_T *oap, int c) // block mode replace if (oap->motion_type == kMTBlockWise) { + int numc; + int num_chars; + char *newp; + char *oldp; + colnr_T oldlen; bd.is_MAX = (curwin->w_curswant == MAXCOL); for (; curwin->w_cursor.lnum <= oap->end.lnum; curwin->w_cursor.lnum++) { curwin->w_cursor.col = 0; // make sure cursor position is valid @@ -2218,12 +2214,11 @@ bool swapchar(int op_type, pos_T *pos) /// Insert and append operators for Visual mode. void op_insert(oparg_T *oap, long count1) { - long ins_len, pre_textlen = 0; - char *firstline, *ins_text; - colnr_T ind_pre_col = 0, ind_post_col; - int ind_pre_vcol = 0, ind_post_vcol = 0; + long pre_textlen = 0; + char *firstline; + colnr_T ind_pre_col = 0; + int ind_pre_vcol = 0; struct block_def bd; - int i; pos_T t1; // edit() changes this - record it for OP_APPEND @@ -2284,7 +2279,7 @@ void op_insert(oparg_T *oap, long count1) if (u_save_cursor() == FAIL) { return; } - for (i = 0; i < bd.endspaces; i++) { + for (int i = 0; i < bd.endspaces; i++) { ins_char(' '); } bd.textlen += bd.endspaces; @@ -2321,12 +2316,13 @@ void op_insert(oparg_T *oap, long count1) } if (oap->motion_type == kMTBlockWise) { + int ind_post_vcol = 0; struct block_def bd2; bool did_indent = false; // if indent kicked in, the firstline might have changed // but only do that, if the indent actually increased - ind_post_col = (colnr_T)getwhitecols_curline(); + colnr_T ind_post_col = (colnr_T)getwhitecols_curline(); if (curbuf->b_op_start.col > ind_pre_col && ind_post_col > ind_pre_col) { bd.textcol += ind_post_col - ind_pre_col; ind_post_vcol = get_indent(); @@ -2414,9 +2410,9 @@ void op_insert(oparg_T *oap, long count1) } else { firstline += add; } - ins_len = (long)strlen(firstline) - pre_textlen - offset; + long ins_len = (long)strlen(firstline) - pre_textlen - offset; if (pre_textlen >= 0 && ins_len > 0) { - ins_text = xstrnsave(firstline, (size_t)ins_len); + char *ins_text = xstrnsave(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); @@ -2434,20 +2430,13 @@ void op_insert(oparg_T *oap, long count1) /// @return true if edit() returns because of a CTRL-O command int op_change(oparg_T *oap) { - colnr_T l; int retval; - long offset; - linenr_T linenr; - long ins_len; long pre_textlen = 0; long pre_indent = 0; - char *newp; char *firstline; - char *ins_text; - char *oldp; struct block_def bd; - l = oap->start.col; + colnr_T l = oap->start.col; if (oap->motion_type == kMTLineWise) { l = 0; can_si = may_do_si(); // Like opening a new line, do smart indent @@ -2499,6 +2488,7 @@ int op_change(oparg_T *oap) // Don't repeat the insert when Insert mode ended with CTRL-C. if (oap->motion_type == kMTBlockWise && oap->start.lnum != oap->end.lnum && !got_int) { + long ins_len; // Auto-indenting may have changed the indent. If the cursor was past // the indent, exclude that indent change from the inserted text. firstline = ml_get(oap->start.lnum); @@ -2511,11 +2501,14 @@ int op_change(oparg_T *oap) ins_len = (long)strlen(firstline) - pre_textlen; if (ins_len > 0) { + long offset; + char *newp; + char *oldp; // Subsequent calls to ml_get() flush the firstline data - take a // copy of the inserted text. - ins_text = xmalloc((size_t)(ins_len + 1)); + char *ins_text = xmalloc((size_t)(ins_len + 1)); xstrlcpy(ins_text, firstline + bd.textcol, (size_t)ins_len + 1); - for (linenr = oap->start.lnum + 1; linenr <= oap->end.lnum; + for (linenr_T linenr = oap->start.lnum + 1; linenr <= oap->end.lnum; linenr++) { block_prep(oap, &bd, linenr, true); if (!bd.is_short || virtual_op) { @@ -2619,7 +2612,6 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) yankreg_T newreg; // new yank register when appending char **new_ptr; linenr_T lnum; // current line number - size_t j; MotionType yank_type = oap->motion_type; size_t yanklines = (size_t)oap->line_count; linenr_T yankendlnum = oap->end.lnum; @@ -2743,6 +2735,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) } if (curr != reg) { // append the new block to the old block + size_t j; new_ptr = xmalloc(sizeof(char *) * (curr->y_size + reg->y_size)); for (j = 0; j < curr->y_size; j++) { new_ptr[j] = curr->y_array[j]; @@ -3773,7 +3766,6 @@ void ex_display(exarg_T *eap) { char *p; yankreg_T *yb; - int name; char *arg = eap->arg; int clen; int type; @@ -3786,7 +3778,7 @@ void ex_display(exarg_T *eap) // Highlight title msg_puts_title(_("\nType Name Content")); for (int i = -1; i < NUM_REGISTERS && !got_int; i++) { - name = get_register_name(i); + int name = get_register_name(i); switch (get_reg_type(name, NULL)) { case kMTLineWise: type = 'l'; break; @@ -3856,7 +3848,7 @@ void ex_display(exarg_T *eap) } // display last inserted text - if ((p = (char *)get_last_insert()) != NULL + if ((p = get_last_insert()) != NULL && (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int && !message_filtered(p)) { msg_puts("\n c \". "); @@ -3912,13 +3904,11 @@ void ex_display(exarg_T *eap) static void dis_msg(const char *p, bool skip_esc) FUNC_ATTR_NONNULL_ALL { - int n; - int l; - - n = Columns - 6; + int n = Columns - 6; while (*p != NUL && !(*p == ESC && skip_esc && *(p + 1) == NUL) && (n -= ptr2cells(p)) >= 0) { + int l; if ((l = utfc_ptr2len(p)) > 1) { msg_outtrans_len(p, l); p += l; @@ -4137,7 +4127,7 @@ int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions linenr_T lnum = curwin->w_cursor.lnum + t; colnr_T mincol = (colnr_T)0; linenr_T lnum_amount = -t; - long col_amount = (cend - newp - spaces_removed); + colnr_T col_amount = (colnr_T)(cend - newp - spaces_removed); mark_col_adjust(lnum, mincol, lnum_amount, col_amount, spaces_removed); @@ -4389,7 +4379,6 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd) changed_lines(pos.lnum, 0, pos.lnum + 1, 0L, true); } } else { - int one_change; int length; pos_T startpos; @@ -4429,7 +4418,7 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd) length = oap->end.col - pos.col + 1; } } - one_change = do_addsub(oap->op_type, &pos, length, amount); + int one_change = do_addsub(oap->op_type, &pos, length, amount); if (one_change) { // Remember the start position of the first change. if (change_cnt == 0) { @@ -5323,7 +5312,6 @@ void cursor_pos_info(dict_T *dict) char *p; char buf1[50]; char buf2[40]; - linenr_T lnum; varnumber_T byte_count = 0; varnumber_T bom_count = 0; varnumber_T byte_count_cursor = 0; @@ -5331,9 +5319,6 @@ void cursor_pos_info(dict_T *dict) varnumber_T char_count_cursor = 0; varnumber_T word_count = 0; varnumber_T word_count_cursor = 0; - int eol_size; - varnumber_T last_check = 100000L; - long line_count_selected = 0; pos_T min_pos, max_pos; oparg_T oparg; struct block_def bd; @@ -5347,6 +5332,10 @@ void cursor_pos_info(dict_T *dict) return; } } else { + linenr_T lnum; + int eol_size; + varnumber_T last_check = 100000L; + long line_count_selected = 0; if (get_fileformat(curbuf) == EOL_DOS) { eol_size = 2; } else { @@ -5501,7 +5490,7 @@ void cursor_pos_info(dict_T *dict) validate_virtcol(); col_print(buf1, sizeof(buf1), (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); - col_print((char *)buf2, sizeof(buf2), (int)strlen(p), linetabsize(p)); + col_print(buf2, sizeof(buf2), (int)strlen(p), linetabsize(p)); if (char_count_cursor == byte_count_cursor && char_count == byte_count) { @@ -5777,22 +5766,20 @@ typedef struct { void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) { oparg_T *oap = cap->oap; - pos_T old_cursor; - bool empty_region_error; - int restart_edit_save; int lbr_saved = curwin->w_p_lbr; // The visual area is remembered for redo static redo_VIsual_T redo_VIsual = { NUL, 0, 0, 0, 0 }; - bool include_line_break = false; - - old_cursor = curwin->w_cursor; + pos_T old_cursor = curwin->w_cursor; // If an operation is pending, handle it... if ((finish_op || VIsual_active) && oap->op_type != OP_NOP) { + bool empty_region_error; + int restart_edit_save; + bool include_line_break = false; // Yank can be redone when 'y' is in 'cpoptions', but not when yanking // for the clipboard. const bool redo_yank = vim_strchr(p_cpo, CPO_YANK) != NULL && !gui_yank; @@ -5914,8 +5901,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) } else if (VIsual_mode == 'v') { // If 'selection' is "exclusive", backup one character for // charwise selections. - include_line_break = - unadjust_for_sel(); + include_line_break = unadjust_for_sel(); } oap->start = VIsual; diff --git a/src/nvim/option.c b/src/nvim/option.c index fd58ebd6fe..069304d9e1 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -30,7 +30,10 @@ #include <string.h> #include "auto/config.h" +#include "nvim/api/extmark.h" #include "nvim/api/private/defs.h" +#include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" @@ -61,6 +64,7 @@ #include "nvim/keycodes.h" #include "nvim/locale.h" #include "nvim/log.h" +#include "nvim/lua/executor.h" #include "nvim/macros.h" #include "nvim/mapping.h" #include "nvim/mbyte.h" @@ -75,6 +79,8 @@ #include "nvim/option.h" #include "nvim/option_defs.h" #include "nvim/optionstr.h" +#include "nvim/os/input.h" +#include "nvim/os/lang.h" #include "nvim/os/os.h" #include "nvim/path.h" #include "nvim/popupmenu.h" @@ -95,14 +101,10 @@ #include "nvim/undo.h" #include "nvim/vim.h" #include "nvim/window.h" -#ifdef MSWIN -# include "nvim/os/pty_conpty_win.h" + +#ifdef BACKSLASH_IN_FILENAME +# include "nvim/arglist.h" #endif -#include "nvim/api/extmark.h" -#include "nvim/api/private/helpers.h" -#include "nvim/lua/executor.h" -#include "nvim/os/input.h" -#include "nvim/os/lang.h" static char e_unknown_option[] = N_("E518: Unknown option"); @@ -165,121 +167,175 @@ void set_init_tablocal(void) p_ch = (long)options[ch_idx].def_val; } -/// Initialize the options, first part. -/// -/// Called only once from main(), just after creating the first buffer. -/// If "clean_arg" is true, Nvim was started with --clean. -/// -/// NOTE: ELOG() etc calls are not allowed here, as log location depends on -/// env var expansion which depends on expression evaluation and other -/// editor state initialized here. Do logging in set_init_2 or later. -void set_init_1(bool clean_arg) +/// Initialize the 'shell' option to a default value. +static void set_init_default_shell(void) { - langmap_init(); - // Find default value for 'shell' option. // Don't use it if it is empty. - { - const char *shell = os_getenv("SHELL"); - if (shell != NULL) { - if (vim_strchr(shell, ' ') != NULL) { - const size_t len = strlen(shell) + 3; // two quotes and a trailing NUL - char *const cmd = xmalloc(len); - snprintf(cmd, len, "\"%s\"", shell); - set_string_default("sh", cmd, true); - } else { - set_string_default("sh", (char *)shell, false); - } + const char *shell = os_getenv("SHELL"); + if (shell != NULL) { + if (vim_strchr(shell, ' ') != NULL) { + const size_t len = strlen(shell) + 3; // two quotes and a trailing NUL + char *const cmd = xmalloc(len); + snprintf(cmd, len, "\"%s\"", shell); + set_string_default("sh", cmd, true); + } else { + set_string_default("sh", (char *)shell, false); } } +} - // Set the default for 'backupskip' to include environment variables for - // temp files. - { +/// Set the default for 'backupskip' to include environment variables for +/// temp files. +static void set_init_default_backupskip(void) +{ #ifdef UNIX - static char *(names[4]) = { "", "TMPDIR", "TEMP", "TMP" }; + static char *(names[4]) = { "", "TMPDIR", "TEMP", "TMP" }; #else - static char *(names[3]) = { "TMPDIR", "TEMP", "TMP" }; + static char *(names[3]) = { "TMPDIR", "TEMP", "TMP" }; #endif - garray_T ga; - int opt_idx = findoption("backupskip"); + garray_T ga; + int opt_idx = findoption("backupskip"); - ga_init(&ga, 1, 100); - for (size_t n = 0; n < ARRAY_SIZE(names); n++) { - bool mustfree = true; - char *p; + ga_init(&ga, 1, 100); + for (size_t n = 0; n < ARRAY_SIZE(names); n++) { + bool mustfree = true; + char *p; #ifdef UNIX - if (*names[n] == NUL) { + if (*names[n] == NUL) { # ifdef __APPLE__ - p = "/private/tmp"; + p = "/private/tmp"; # else - p = "/tmp"; + p = "/tmp"; # endif - mustfree = false; - } else // NOLINT(readability/braces) + mustfree = false; + } else // NOLINT(readability/braces) #endif - { - p = vim_getenv(names[n]); - } - if (p != NULL && *p != NUL) { - // First time count the NUL, otherwise count the ','. - const size_t len = strlen(p) + 3; - char *item = xmalloc(len); - xstrlcpy(item, p, len); - add_pathsep(item); - xstrlcat(item, "*", len); - if (find_dup_item(ga.ga_data, item, options[opt_idx].flags) - == NULL) { - ga_grow(&ga, (int)len); - if (!GA_EMPTY(&ga)) { - STRCAT(ga.ga_data, ","); - } - STRCAT(ga.ga_data, p); - add_pathsep(ga.ga_data); - STRCAT(ga.ga_data, "*"); - ga.ga_len += (int)len; + { + p = vim_getenv(names[n]); + } + if (p != NULL && *p != NUL) { + // First time count the NUL, otherwise count the ','. + const size_t len = strlen(p) + 3; + char *item = xmalloc(len); + xstrlcpy(item, p, len); + add_pathsep(item); + xstrlcat(item, "*", len); + if (find_dup_item(ga.ga_data, item, options[opt_idx].flags) + == NULL) { + ga_grow(&ga, (int)len); + if (!GA_EMPTY(&ga)) { + STRCAT(ga.ga_data, ","); } - xfree(item); - } - if (mustfree) { - xfree(p); + STRCAT(ga.ga_data, p); + add_pathsep(ga.ga_data); + STRCAT(ga.ga_data, "*"); + ga.ga_len += (int)len; } + xfree(item); } - if (ga.ga_data != NULL) { - set_string_default("bsk", ga.ga_data, true); + if (mustfree) { + xfree(p); } } + if (ga.ga_data != NULL) { + set_string_default("bsk", ga.ga_data, true); + } +} - { - // Initialize the 'cdpath' option's default value. - char *cdpath = vim_getenv("CDPATH"); - if (cdpath != NULL) { - char *buf = xmalloc(2 * strlen(cdpath) + 2); - { - buf[0] = ','; // start with ",", current dir first - int j = 1; - for (int i = 0; cdpath[i] != NUL; i++) { - if (vim_ispathlistsep(cdpath[i])) { - buf[j++] = ','; - } else { - if (cdpath[i] == ' ' || cdpath[i] == ',') { - buf[j++] = '\\'; - } - buf[j++] = cdpath[i]; - } - } - buf[j] = NUL; - int opt_idx = findoption("cdpath"); - if (opt_idx >= 0) { - options[opt_idx].def_val = buf; - options[opt_idx].flags |= P_DEF_ALLOCED; - } else { - xfree(buf); // cannot happen - } +/// Initialize the 'cdpath' option to a default value. +static void set_init_default_cdpath(void) +{ + char *cdpath = vim_getenv("CDPATH"); + if (cdpath == NULL) { + return; + } + + char *buf = xmalloc(2 * strlen(cdpath) + 2); + buf[0] = ','; // start with ",", current dir first + int j = 1; + for (int i = 0; cdpath[i] != NUL; i++) { + if (vim_ispathlistsep(cdpath[i])) { + buf[j++] = ','; + } else { + if (cdpath[i] == ' ' || cdpath[i] == ',') { + buf[j++] = '\\'; + } + buf[j++] = cdpath[i]; + } + } + buf[j] = NUL; + int opt_idx = findoption("cdpath"); + if (opt_idx >= 0) { + options[opt_idx].def_val = buf; + options[opt_idx].flags |= P_DEF_ALLOCED; + } else { + xfree(buf); // cannot happen + } + xfree(cdpath); +} + +/// Expand environment variables and things like "~" for the defaults. +/// If option_expand() returns non-NULL the variable is expanded. This can +/// only happen for non-indirect options. +/// Also set the default to the expanded value, so ":set" does not list +/// them. +/// Don't set the P_ALLOCED flag, because we don't want to free the +/// default. +static void set_init_expand_env(void) +{ + for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) { + vimoption_T *opt = &options[opt_idx]; + if (opt->flags & P_NO_DEF_EXP) { + continue; + } + char *p; + if ((opt->flags & P_GETTEXT) && opt->var != NULL) { + p = _(*(char **)opt->var); + } else { + p = option_expand(opt_idx, NULL); + } + if (p != NULL) { + p = xstrdup(p); + *(char **)opt->var = p; + if (opt->flags & P_DEF_ALLOCED) { + xfree(opt->def_val); } - xfree(cdpath); + opt->def_val = p; + opt->flags |= P_DEF_ALLOCED; } } +} + +/// Initialize the encoding used for "default" in 'fileencodings'. +static void set_init_fenc_default(void) +{ + // enc_locale() will try to find the encoding of the current locale. + // This will be used when "default" is used as encoding specifier + // in 'fileencodings'. + char *p = enc_locale(); + if (p == NULL) { + // Use utf-8 as "default" if locale encoding can't be detected. + p = xmemdupz(S_LEN("utf-8")); + } + fenc_default = p; +} + +/// Initialize the options, first part. +/// +/// Called only once from main(), just after creating the first buffer. +/// If "clean_arg" is true, Nvim was started with --clean. +/// +/// NOTE: ELOG() etc calls are not allowed here, as log location depends on +/// env var expansion which depends on expression evaluation and other +/// editor state initialized here. Do logging in set_init_2 or later. +void set_init_1(bool clean_arg) +{ + langmap_init(); + + set_init_default_shell(); + set_init_default_backupskip(); + set_init_default_cdpath(); char *backupdir = stdpaths_user_state_subpath("backup", 2, true); const size_t backupdir_len = strlen(backupdir); @@ -328,33 +384,7 @@ void set_init_1(bool clean_arg) init_spell_chartab(); // Expand environment variables and things like "~" for the defaults. - // If option_expand() returns non-NULL the variable is expanded. This can - // only happen for non-indirect options. - // Also set the default to the expanded value, so ":set" does not list - // them. - // Don't set the P_ALLOCED flag, because we don't want to free the - // default. - for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) { - vimoption_T *opt = &options[opt_idx]; - if (opt->flags & P_NO_DEF_EXP) { - continue; - } - char *p; - if ((opt->flags & P_GETTEXT) && opt->var != NULL) { - p = _(*(char **)opt->var); - } else { - p = option_expand(opt_idx, NULL); - } - if (p != NULL) { - p = xstrdup(p); - *(char **)opt->var = p; - if (opt->flags & P_DEF_ALLOCED) { - xfree(opt->def_val); - } - opt->def_val = p; - opt->flags |= P_DEF_ALLOCED; - } - } + set_init_expand_env(); save_file_ff(curbuf); // Buffer is unchanged @@ -370,16 +400,7 @@ void set_init_1(bool clean_arg) didset_options2(); lang_init(); - - // enc_locale() will try to find the encoding of the current locale. - // This will be used when 'default' is used as encoding specifier - // in 'fileencodings' - char *p = enc_locale(); - if (p == NULL) { - // use utf-8 as 'default' if locale encoding can't be detected. - p = xmemdupz(S_LEN("utf-8")); - } - fenc_default = p; + set_init_fenc_default(); #ifdef HAVE_WORKING_LIBINTL // GNU gettext 0.10.37 supports this feature: set the codeset used for @@ -753,7 +774,7 @@ static void do_set_bool(int opt_idx, int opt_flags, int prefix, int nextchar, co } } - *errmsg = set_bool_option(opt_idx, (char_u *)varp, (int)value, opt_flags); + *errmsg = set_bool_option(opt_idx, (char *)varp, (int)value, opt_flags); } static void do_set_num(int opt_idx, int opt_flags, char **argp, int nextchar, const set_op_T op, @@ -1108,7 +1129,7 @@ static void do_set_string(int opt_idx, int opt_flags, char **argp, int nextchar, } // Set the new value. - *(char_u **)(varp) = (char_u *)newval; + *(char **)(varp) = newval; // origval may be freed by did_set_string_option(), make a copy. char *saved_origval = (origval != NULL) ? xstrdup(origval) : NULL; @@ -1549,7 +1570,6 @@ int do_set(char *arg, int opt_flags) silent_mode = false; info_message = true; // use os_msg(), not os_errmsg() msg_putchar('\n'); - ui_flush(); silent_mode = true; info_message = false; // use os_msg(), not os_errmsg() } @@ -1974,7 +1994,7 @@ static void apply_optionset_autocmd(int opt_idx, long opt_flags, long oldval, lo /// @param[in] opt_flags OPT_LOCAL and/or OPT_GLOBAL. /// /// @return NULL on success, error message on error. -static char *set_bool_option(const int opt_idx, char_u *const varp, const int value, +static char *set_bool_option(const int opt_idx, char *const varp, const int value, const int opt_flags) { int old_value = *(int *)varp; @@ -2010,7 +2030,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va // Ensure that options set to p_force_off cannot be enabled. } else if ((int *)varp == &p_force_off && p_force_off == true) { p_force_off = false; - return (char *)e_unsupportedoption; + return e_unsupportedoption; } else if ((int *)varp == &p_lrm) { // 'langremap' -> !'langnoremap' p_lnr = !p_lrm; @@ -2023,7 +2043,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va // delete the undo file, the option may be set again without making // any changes in between. if (curbuf->b_p_udf || p_udf) { - char_u hash[UNDO_HASH_SIZE]; + uint8_t hash[UNDO_HASH_SIZE]; FOR_ALL_BUFFERS(bp) { // When 'undofile' is set globally: for every buffer, otherwise @@ -2103,7 +2123,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va } } } - } else if (varp == (char_u *)&(curbuf->b_p_lisp)) { + } else if (varp == (char *)&(curbuf->b_p_lisp)) { // When 'lisp' option changes include/exclude '-' in // keyword characters. (void)buf_init_chartab(curbuf, false); // ignore errors @@ -3062,6 +3082,8 @@ char *set_option_value(const char *const name, const long number, const char *co const int opt_flags) FUNC_ATTR_NONNULL_ARG(1) { + static char errbuf[80]; + if (is_tty_option(name)) { return NULL; // Fail silently; many old vimrcs set t_xx options. } @@ -3084,7 +3106,7 @@ char *set_option_value(const char *const name, const long number, const char *co if (s == NULL || opt_flags & OPT_CLEAR) { s = ""; } - return set_string_option(opt_idx, s, opt_flags); + return set_string_option(opt_idx, s, opt_flags, errbuf, sizeof(errbuf)); } char_u *varp = (char_u *)get_varp_scope(&(options[opt_idx]), opt_flags); @@ -3122,9 +3144,9 @@ char *set_option_value(const char *const name, const long number, const char *co } } if (flags & P_NUM) { - return set_num_option(opt_idx, varp, numval, NULL, 0, opt_flags); + return set_num_option(opt_idx, varp, numval, errbuf, sizeof(errbuf), opt_flags); } - return set_bool_option(opt_idx, varp, (int)numval, opt_flags); + return set_bool_option(opt_idx, (char *)varp, (int)numval, opt_flags); } /// Call set_option_value() and when an error is returned report it. @@ -3215,13 +3237,13 @@ static void showoptions(bool all, int opt_flags) continue; } - char_u *varp = NULL; + char *varp = NULL; if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) != 0) { if (p->indir != PV_NONE) { - varp = (char_u *)get_varp_scope(p, opt_flags); + varp = get_varp_scope(p, opt_flags); } } else { - varp = get_varp(p); + varp = (char *)get_varp(p); } if (varp != NULL && (all == 1 || (all == 0 && !optval_default(p, varp)))) { @@ -3275,7 +3297,7 @@ static void showoptions(bool all, int opt_flags) } /// Return true if option "p" has its default value. -static int optval_default(vimoption_T *p, const char_u *varp) +static int optval_default(vimoption_T *p, const char *varp) { if (varp == NULL) { return true; // hidden option is always at default @@ -3400,7 +3422,7 @@ int makeset(FILE *fd, int opt_flags, int local_only) continue; } // Global values are only written when not at the default value. - if ((opt_flags & OPT_GLOBAL) && optval_default(p, (char_u *)varp)) { + if ((opt_flags & OPT_GLOBAL) && optval_default(p, varp)) { continue; } @@ -3421,7 +3443,7 @@ int makeset(FILE *fd, int opt_flags, int local_only) // default, need to write it too. if (!(opt_flags & OPT_GLOBAL) && !local_only) { char_u *varp_fresh = (char_u *)get_varp_scope(p, OPT_GLOBAL); // local value - if (!optval_default(p, varp_fresh)) { + if (!optval_default(p, (char *)varp_fresh)) { round = 1; varp_local = (char_u *)varp; varp = (char *)varp_fresh; @@ -4828,10 +4850,9 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, char *fuzzystr, int *numM // loop == 0: count the number of matching options // loop == 1: copy the matching options into allocated memory for (int loop = 0; loop <= 1; loop++) { - int match; regmatch->rm_ic = ic; if (xp->xp_context != EXPAND_BOOL_SETTINGS) { - for (match = 0; match < (int)ARRAY_SIZE(names); + for (int match = 0; match < (int)ARRAY_SIZE(names); match++) { if (match_str(names[match], regmatch, *matches, count, (loop == 0), fuzzy, fuzzystr, fuzmatch)) { @@ -4963,7 +4984,7 @@ static void option_value2string(vimoption_T *opp, int scope) if (varp == NULL) { // Just in case. NameBuff[0] = NUL; } else if (opp->flags & P_EXPAND) { - home_replace(NULL, varp, (char *)NameBuff, MAXPATHL, false); + home_replace(NULL, varp, NameBuff, MAXPATHL, false); // Translate 'pastetoggle' into special key names. } else if ((char **)opp->var == &p_pt) { str2specialbuf((const char *)p_pt, NameBuff, MAXPATHL); @@ -5184,8 +5205,8 @@ void fill_breakat_flags(void) } if (p_breakat != NULL) { - for (char_u *p = (char_u *)p_breakat; *p; p++) { - breakat_flags[*p] = true; + for (char *p = p_breakat; *p; p++) { + breakat_flags[(uint8_t)(*p)] = true; } } } @@ -5601,10 +5622,9 @@ long get_sidescrolloff_value(win_T *wp) Dictionary get_vimoption(String name, Error *err) { int opt_idx = findoption_len((const char *)name.data, name.size); - if (opt_idx < 0) { - api_set_error(err, kErrorTypeValidation, "no such option: '%s'", name.data); + VALIDATE_S(opt_idx >= 0, "option (not found)", name.data, { return (Dictionary)ARRAY_DICT_INIT; - } + }); return vimoption2dict(&options[opt_idx]); } diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index d190fc5999..0e0cc4c983 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -630,6 +630,8 @@ EXTERN unsigned rdb_flags; #define RDB_NOTHROTTLE 0x002 #define RDB_INVALID 0x004 #define RDB_NODELTA 0x008 +#define RDB_LINE 0x010 +#define RDB_FLUSH 0x020 EXTERN long p_rdt; // 'redrawtime' EXTERN long p_re; // 'regexpengine' diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index ca50c3ab00..f903ad3d09 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -125,7 +125,8 @@ static char *(p_spo_values[]) = { "camel", "noplainbuffer", NULL }; static char *(p_icm_values[]) = { "nosplit", "split", NULL }; static char *(p_jop_values[]) = { "stack", "view", NULL }; static char *(p_tpf_values[]) = { "BS", "HT", "FF", "ESC", "DEL", "C0", "C1", NULL }; -static char *(p_rdb_values[]) = { "compositor", "nothrottle", "invalid", "nodelta", NULL }; +static char *(p_rdb_values[]) = { "compositor", "nothrottle", "invalid", "nodelta", "line", + "flush", NULL }; static char *(p_sloc_values[]) = { "last", "statusline", "tabline", NULL }; /// All possible flags for 'shm'. @@ -329,7 +330,6 @@ void set_string_option_direct(const char *name, int opt_idx, const char *val, in int set_sid) { char *s; - char **varp; int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; int idx = opt_idx; @@ -352,7 +352,7 @@ void set_string_option_direct(const char *name, int opt_idx, const char *val, in s = xstrdup(val); { - varp = (char **)get_varp_scope(opt, both ? OPT_LOCAL : opt_flags); + char **varp = (char **)get_varp_scope(opt, both ? OPT_LOCAL : opt_flags); if ((opt_flags & OPT_FREE) && (opt->flags & P_ALLOCED)) { free_string_option(*varp); } @@ -410,7 +410,8 @@ void set_string_option_direct_in_win(win_T *wp, const char *name, int opt_idx, c /// #OPT_GLOBAL. /// /// @return NULL on success, an untranslated error message on error. -char *set_string_option(const int opt_idx, const char *const value, const int opt_flags) +char *set_string_option(const int opt_idx, const char *const value, const int opt_flags, + char *const errbuf, const size_t errbuflen) FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_WARN_UNUSED_RESULT { vimoption_T *opt = get_option(opt_idx); @@ -442,7 +443,7 @@ char *set_string_option(const int opt_idx, const char *const value, const int op int value_checked = false; char *const errmsg = did_set_string_option(opt_idx, varp, oldval, - NULL, 0, + errbuf, errbuflen, opt_flags, &value_checked); if (errmsg == NULL) { did_set_option(opt_idx, opt_flags, true, value_checked); @@ -1581,7 +1582,7 @@ static void do_spelllang_source(win_T *win) q += 4; } - // Source the spell/LANG.vim in 'runtimepath'. + // Source the spell/LANG.{vim,lua} in 'runtimepath'. // They could set 'spellcapcheck' depending on the language. // Use the first name in 'spelllang' up to '_region' or // '.encoding'. @@ -1592,7 +1593,7 @@ static void do_spelllang_source(win_T *win) } } if (p > q) { - vim_snprintf(fname, sizeof(fname), "spell/%.*s.vim", (int)(p - q), q); + vim_snprintf(fname, sizeof(fname), "spell/%.*s.\\(vim\\|lua\\)", (int)(p - q), q); source_runtime(fname, DIP_ALL); } } diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 0611de14aa..30092b9142 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -34,7 +34,11 @@ #include "nvim/vim.h" #ifdef MSWIN -# include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8 +# include "nvim/mbyte.h" +#endif + +#ifdef BACKSLASH_IN_FILENAME +# include "nvim/fileio.h" #endif #ifdef HAVE__NSGETENVIRON diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index 5af39555c9..846219f720 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -27,6 +27,10 @@ #include "nvim/rbuffer.h" #include "nvim/types.h" +#ifdef MSWIN +# include "nvim/os/os_win_console.h" +#endif + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/fileio.c.generated.h" #endif diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 6157341ec9..85d95960a7 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -12,14 +12,20 @@ #include <stdlib.h> #include <string.h> #include <sys/stat.h> +#include <uv.h> #include "auto/config.h" +#include "nvim/ascii.h" #include "nvim/gettext.h" #include "nvim/globals.h" #include "nvim/log.h" #include "nvim/macros.h" +#include "nvim/memory.h" +#include "nvim/message.h" #include "nvim/option_defs.h" #include "nvim/os/fs_defs.h" +#include "nvim/os/os.h" +#include "nvim/path.h" #include "nvim/types.h" #include "nvim/vim.h" @@ -27,24 +33,17 @@ # include <sys/uio.h> #endif -#include <uv.h> - -#include "nvim/ascii.h" -#include "nvim/memory.h" -#include "nvim/message.h" -#include "nvim/os/os.h" -#include "nvim/path.h" - -struct iovec; - #ifdef MSWIN -# include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8 +# include "nvim/mbyte.h" +# include "nvim/option.h" #endif #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/fs.c.generated.h" #endif +struct iovec; + #define RUN_UV_FS_FUNC(ret, func, ...) \ do { \ bool did_try_to_free = false; \ diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 759b3cf83c..d472836d0a 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -470,11 +470,6 @@ static InbufPollResult inbuf_poll(int ms, MultiQueue *events) return input_eof ? kInputEof : kInputNone; } -void input_done(void) -{ - input_eof = true; -} - bool input_available(void) { return rbuffer_size(input_buffer) != 0; @@ -483,7 +478,7 @@ bool input_available(void) static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, bool at_eof) { if (at_eof) { - input_done(); + input_eof = true; } assert(rbuffer_space(input_buffer) >= rbuffer_size(buf)); @@ -550,8 +545,7 @@ static void read_error_exit(void) if (silent_mode) { // Normal way to exit for "nvim -es". getout(0); } - STRCPY(IObuff, _("Vim: Error reading input, exiting...\n")); - preserve_exit(); + preserve_exit(_("Vim: Error reading input, exiting...\n")); } static bool pending_events(MultiQueue *events) diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c index b8daaabba2..e7b745fb7e 100644 --- a/src/nvim/os/signal.c +++ b/src/nvim/os/signal.c @@ -172,11 +172,10 @@ static void deadly_signal(int signum) ILOG("got signal %d (%s)", signum, signal_name(signum)); - snprintf(IObuff, sizeof(IObuff), "Vim: Caught deadly signal '%s'\r\n", - signal_name(signum)); + snprintf(IObuff, IOSIZE, "Vim: Caught deadly signal '%s'\r\n", signal_name(signum)); // Preserve files and exit. - preserve_exit(); + preserve_exit(IObuff); } static void on_signal(SignalWatcher *handle, int signum, void *data) diff --git a/src/nvim/path.c b/src/nvim/path.c index e4c2253357..9bbf56276e 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -810,7 +810,7 @@ static int find_previous_pathsep(char *path, char **psep) } /// Returns true if "maybe_unique" is unique wrt other_paths in "gap". -/// "maybe_unique" is the end portion of "((char_u **)gap->ga_data)[i]". +/// "maybe_unique" is the end portion of "((char **)gap->ga_data)[i]". static bool is_unique(char *maybe_unique, garray_T *gap, int i) { char **other_paths = gap->ga_data; @@ -879,7 +879,7 @@ static void expand_path_option(char *curdir, garray_T *gap) } STRMOVE(buf + len + 1, buf); STRCPY(buf, curdir); - buf[len] = (char_u)PATHSEP; + buf[len] = PATHSEP; simplify_filename(buf); } @@ -1923,7 +1923,7 @@ void path_fix_case(char *name) xstrlcpy(newname + (tail - name), entry, (size_t)(MAXPATHL - (tail - name) + 1)); FileInfo file_info_new; - if (os_fileinfo_link((char *)newname, &file_info_new) + if (os_fileinfo_link(newname, &file_info_new) && os_fileinfo_id_equal(&file_info, &file_info_new)) { STRCPY(tail, entry); break; @@ -1956,11 +1956,11 @@ bool same_directory(char *f1, char *f2) return false; } - (void)vim_FullName(f1, (char *)ffname, MAXPATHL, false); + (void)vim_FullName(f1, ffname, MAXPATHL, false); t1 = path_tail_with_sep(ffname); t2 = path_tail_with_sep(f2); return t1 - ffname == t2 - f2 - && pathcmp((char *)ffname, f2, (int)(t1 - ffname)) == 0; + && pathcmp(ffname, f2, (int)(t1 - ffname)) == 0; } // Compare path "p[]" to "q[]". diff --git a/src/nvim/plines.c b/src/nvim/plines.c index 5469d94800..a3e5640b18 100644 --- a/src/nvim/plines.c +++ b/src/nvim/plines.c @@ -356,14 +356,9 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp) char *s = cts->cts_ptr; colnr_T vcol = cts->cts_vcol; - colnr_T col2; colnr_T col_adj = 0; // vcol + screen size of tab - colnr_T colmax; - int added; int mb_added = 0; int numberextra; - char *ps; - int n; cts->cts_cur_text_width = 0; @@ -397,12 +392,12 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp) // Count all characters from first non-blank after a blank up to next // non-blank after a blank. numberextra = win_col_off(wp); - col2 = vcol; - colmax = (colnr_T)(wp->w_width_inner - numberextra - col_adj); + colnr_T col2 = vcol; + colnr_T colmax = (colnr_T)(wp->w_width_inner - numberextra - col_adj); if (vcol >= colmax) { colmax += col_adj; - n = colmax + win_col_off2(wp); + int n = colmax + win_col_off2(wp); if (n > 0) { colmax += (((vcol - colmax) / n) + 1) * n - col_adj; @@ -410,7 +405,7 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp) } for (;;) { - ps = s; + char *ps = s; MB_PTR_ADV(s); c = (uint8_t)(*s); @@ -439,7 +434,7 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp) // string at start of line. // Set *headp to the size of what we add. // Do not use 'showbreak' at the NUL after the text. - added = 0; + int added = 0; char *const sbr = c == NUL ? empty_option : get_showbreak_value(wp); if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && vcol != 0) { colnr_T sbrlen = 0; diff --git a/src/nvim/po/CMakeLists.txt b/src/nvim/po/CMakeLists.txt index 1db21880bb..74f043fe03 100644 --- a/src/nvim/po/CMakeLists.txt +++ b/src/nvim/po/CMakeLists.txt @@ -1,9 +1,14 @@ find_package(Gettext REQUIRED) find_program(XGETTEXT_PRG xgettext) find_program(ICONV_PRG iconv) - -option(LANGUAGES "Localizations to build") -if(NOT LANGUAGES) +mark_as_advanced( + GETTEXT_MSGFMT_EXECUTABLE + GETTEXT_MSGMERGE_EXECUTABLE + ICONV_PRG + XGETTEXT_PRG) + +option(ENABLE_LANGUAGES "Localizations to build" ON) +if(ENABLE_LANGUAGES) set(LANGUAGES af ca @@ -100,12 +105,12 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG) add_custom_target(update-po-${lang} COMMAND ${CMAKE_COMMAND} - -DICONV_PRG=${ICONV_PRG} - -DINPUT_FILE=${inputFile} - -DOUTPUT_FILE=${outputFile} - -DINPUT_ENC=${inputEnc} - -DOUTPUT_ENC=${outputEnc} - -DOUTPUT_CHARSET=${outputCharSet} + -D ICONV_PRG=${ICONV_PRG} + -D INPUT_FILE=${inputFile} + -D OUTPUT_FILE=${outputFile} + -D INPUT_ENC=${inputEnc} + -D OUTPUT_ENC=${outputEnc} + -D OUTPUT_CHARSET=${outputCharSet} -P ${PROJECT_SOURCE_DIR}/cmake/ConvertPo.cmake COMMENT "Updating ${outputName}.po" DEPENDS ${inputFile}) diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index 245ce87865..cdf8d5720b 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -113,8 +113,6 @@ static void pum_compute_size(void) void pum_display(pumitem_T *array, int size, int selected, bool array_changed, int cmd_startcol) { int context_lines; - int above_row; - int below_row; int redo_count = 0; int pum_win_row; int cursor_col; @@ -134,8 +132,8 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i pum_is_visible = true; pum_is_drawn = true; validate_cursor_col(); - above_row = 0; - below_row = cmdline_row; + int above_row = 0; + int below_row = cmdline_row; // wildoptions=pum if (State == MODE_CMDLINE) { @@ -409,17 +407,15 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i void pum_redraw(void) { int row = 0; - int grid_col; int attr_norm = win_hl_attr(curwin, HLF_PNI); int attr_select = win_hl_attr(curwin, HLF_PSI); int attr_scroll = win_hl_attr(curwin, HLF_PSB); int attr_thumb = win_hl_attr(curwin, HLF_PST); - int attr; int i; - int idx; char *s; char *p = NULL; - int totwidth, width, w; + int width; + int w; int thumb_pos = 0; int thumb_height = 1; int round; @@ -485,8 +481,8 @@ void pum_redraw(void) } for (i = 0; i < pum_height; i++) { - idx = i + pum_first; - attr = (idx == pum_selected) ? attr_select : attr_norm; + int idx = i + pum_first; + int attr = (idx == pum_selected) ? attr_select : attr_norm; grid_puts_line_start(&pum_grid, row); @@ -501,8 +497,8 @@ void pum_redraw(void) // Display each entry, use two spaces for a Tab. // Do this 3 times: For the main text, kind and extra info - grid_col = col_off; - totwidth = 0; + int grid_col = col_off; + int totwidth = 0; for (round = 1; round <= 3; round++) { width = 0; @@ -725,7 +721,6 @@ static bool pum_set_selected(int n, int repeat) && (vim_strchr(p_cot, 'p') != NULL)) { win_T *curwin_save = curwin; tabpage_T *curtab_save = curtab; - int res = OK; // Open a preview window. 3 lines by default. Prefer // 'previewheight' if set and smaller. @@ -744,6 +739,7 @@ static bool pum_set_selected(int n, int repeat) g_do_tagpreview = 0; if (curwin->w_p_pvw) { + int res = OK; if (!resized && (curbuf->b_nwindows == 1) && (curbuf->b_fname == NULL) @@ -1092,7 +1088,6 @@ void pum_show_popupmenu(vimmenu_T *menu) pum_is_drawn = true; pum_redraw(); setcursor_mayforce(true); - ui_flush(); int c = vgetc(); diff --git a/src/nvim/profile.c b/src/nvim/profile.c index fd024f2d38..173332a428 100644 --- a/src/nvim/profile.c +++ b/src/nvim/profile.c @@ -689,10 +689,8 @@ void profile_init(scriptitem_T *si) /// @param tm place to store wait time void script_prof_save(proftime_T *tm) { - scriptitem_T *si; - if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len) { - si = &SCRIPT_ITEM(current_sctx.sc_sid); + scriptitem_T *si = &SCRIPT_ITEM(current_sctx.sc_sid); if (si->sn_prof_on && si->sn_pr_nest++ == 0) { si->sn_pr_child = profile_start(); } @@ -720,12 +718,11 @@ void script_prof_restore(const proftime_T *tm) /// 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++) { - si = &SCRIPT_ITEM(id); + scriptitem_T *si = &SCRIPT_ITEM(id); if (si->sn_prof_on) { fprintf(fd, "SCRIPT %s\n", si->sn_name); if (si->sn_pr_count == 1) { @@ -808,7 +805,6 @@ void profile_dump(void) void script_line_start(void) { scriptitem_T *si; - sn_prl_T *pp; if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len) { return; @@ -822,7 +818,7 @@ void script_line_start(void) 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. - pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len); + sn_prl_T *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(); @@ -853,7 +849,6 @@ void script_line_exec(void) void script_line_end(void) { scriptitem_T *si; - sn_prl_T *pp; if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len) { return; @@ -862,7 +857,7 @@ void script_line_end(void) 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); + sn_prl_T *pp = &PRL_ITEM(si, si->sn_prl_idx); 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); diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index b071e10cf9..cff0f886ce 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -276,10 +276,8 @@ static void source_callback(char *fname, void *cookie) /// return FAIL when no file could be sourced, OK otherwise. int do_in_path(char *path, char *name, int flags, DoInRuntimepathCB callback, void *cookie) { - char *tail; int num_files; char **files; - int i; bool did_one = false; // Make a copy of 'runtimepath'. Invoking the callback may change the @@ -287,6 +285,7 @@ int do_in_path(char *path, char *name, int flags, DoInRuntimepathCB callback, vo char *rtp_copy = xstrdup(path); char *buf = xmallocz(MAXPATHL); { + char *tail; if (p_verbose > 10 && name != NULL) { verbose_enter(); smsg(_("Searching for \"%s\" in \"%s\""), name, path); @@ -335,7 +334,7 @@ int do_in_path(char *path, char *name, int flags, DoInRuntimepathCB callback, vo // Expand wildcards, invoke the callback for each match. if (gen_expand_wildcards(1, &buf, &num_files, &files, ew_flags) == OK) { - for (i = 0; i < num_files; i++) { + for (int i = 0; i < num_files; i++) { (*callback)(files[i], cookie); did_one = true; if (!(flags & DIP_ALL)) { @@ -416,7 +415,6 @@ int do_in_cached_path(char *name, int flags, DoInRuntimepathCB callback, void *c char *tail; int num_files; char **files; - int i; bool did_one = false; char buf[MAXPATHL]; @@ -469,7 +467,7 @@ int do_in_cached_path(char *name, int flags, DoInRuntimepathCB callback, void *c // Expand wildcards, invoke the callback for each match. char *(pat[]) = { buf }; if (gen_expand_wildcards(1, pat, &num_files, &files, ew_flags) == OK) { - for (i = 0; i < num_files; i++) { + for (int i = 0; i < num_files; i++) { (*callback)(files[i], cookie); did_one = true; if (!(flags & DIP_ALL)) { @@ -2329,7 +2327,6 @@ char *getsourceline(int c, void *cookie, int indent, bool do_concat) { struct source_cookie *sp = (struct source_cookie *)cookie; char *line; - char *p; // If breakpoints have been added/deleted need to check for it. if (sp->dbg_tick < debug_tick) { @@ -2359,6 +2356,7 @@ char *getsourceline(int c, void *cookie, int indent, bool do_concat) // Only concatenate lines starting with a \ when 'cpoptions' doesn't // contain the 'C' flag. if (line != NULL && do_concat && (vim_strchr(p_cpo, CPO_CONCAT) == NULL)) { + char *p; // compensate for the one line read-ahead sp->sourcing_lnum--; diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 05da6e0ef1..da9178bdff 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -248,11 +248,8 @@ size_t fill_foldcolumn(char *p, win_T *wp, foldinfo_T foldinfo, linenr_T lnum) /// Only works for single-byte characters (e.g., numbers). void rl_mirror(char *str) { - char *p1, *p2; - char t; - - for (p1 = str, p2 = str + strlen(str) - 1; p1 < p2; p1++, p2--) { - t = *p1; + for (char *p1 = str, *p2 = str + strlen(str) - 1; p1 < p2; p1++, p2--) { + char t = *p1; *p1 = *p2; *p2 = t; } @@ -264,9 +261,7 @@ void rl_mirror(char *str) /// line of the window right of it. If not, then it's a vertical separator. bool stl_connected(win_T *wp) { - frame_T *fr; - - fr = wp->w_frame; + frame_T *fr = wp->w_frame; while (fr->fr_parent != NULL) { if (fr->fr_parent->fr_layout == FR_COL) { if (fr->fr_next != NULL) { @@ -437,11 +432,7 @@ bool skip_showmode(void) /// @return the length of the message (0 if no message). int showmode(void) { - bool need_clear; int length = 0; - int do_mode; - int attr; - int sub_attr; if (ui_has(kUIMessages) && clear_cmdline) { msg_ext_clear(true); @@ -452,12 +443,13 @@ int showmode(void) msg_grid_validate(); - do_mode = ((p_smd && msg_silent == 0) - && ((State & MODE_TERMINAL) - || (State & MODE_INSERT) - || restart_edit != NUL - || VIsual_active)); + int do_mode = ((p_smd && msg_silent == 0) + && ((State & MODE_TERMINAL) + || (State & MODE_INSERT) + || restart_edit != NUL + || VIsual_active)); if (do_mode || reg_recording != 0) { + int sub_attr; if (skip_showmode()) { return 0; // show mode later } @@ -468,14 +460,14 @@ int showmode(void) check_for_delay(false); // if the cmdline is more than one line high, erase top lines - need_clear = clear_cmdline; + bool need_clear = clear_cmdline; if (clear_cmdline && cmdline_row < Rows - 1) { msg_clr_cmdline(); // will reset clear_cmdline } // Position on the last line in the window, column 0 msg_pos_mode(); - attr = HL_ATTR(HLF_CM); // Highlight mode + int attr = HL_ATTR(HLF_CM); // Highlight mode // When the screen is too narrow to show the entire mode message, // avoid scrolling and truncate instead. diff --git a/src/nvim/search.c b/src/nvim/search.c index eb5cc2e07f..e5a456161f 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -95,7 +95,7 @@ static struct spat spats[2] = { static int last_idx = 0; // index in spats[] for RE_LAST -static char_u lastc[2] = { NUL, NUL }; // last character searched for +static uint8_t lastc[2] = { NUL, NUL }; // last character searched for static Direction lastcdir = FORWARD; // last direction of character search static int last_t_cmd = true; // last search t_cmd static char lastc_bytes[MB_MAXBYTES + 1]; @@ -136,14 +136,12 @@ typedef struct SearchedFile { int search_regcomp(char *pat, char **used_pat, int pat_save, int pat_use, int options, regmmatch_T *regmatch) { - int magic; - int i; - rc_did_emsg = false; - magic = magic_isset(); + int magic = magic_isset(); // If no pattern given, use a previously defined pattern. if (pat == NULL || *pat == NUL) { + int i; if (pat_use == RE_LAST) { i = last_idx; } else { @@ -439,7 +437,7 @@ int last_csearch_until(void) void set_last_csearch(int c, char *s, int len) { - *lastc = (char_u)c; + *lastc = (uint8_t)c; lastc_bytelen = len; if (len) { memcpy(lastc_bytes, s, (size_t)len); @@ -557,8 +555,6 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, lpos_T endpos; lpos_T matchpos; int loop; - pos_T start_pos; - int at_first_line; int extra_col; int start_char_len; bool match_ok; @@ -611,9 +607,9 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, extra_col = (options & SEARCH_START) ? start_char_len : 0; } - start_pos = *pos; // remember start pos for detecting no match + pos_T start_pos = *pos; // remember start pos for detecting no match found = 0; // default: not found - at_first_line = true; // default: start in first line + int at_first_line = true; // default: start in first line if (pos->lnum == 0) { // correct lnum for when starting in line 0 pos->lnum = 1; pos->col = 0; @@ -1028,10 +1024,9 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, long count, i { pos_T pos; // position of the last match char *searchstr; - struct soffset old_off; int retval; // Return value char *p; - long c; + int64_t c; char *dircp; char *strcopy = NULL; char *ps; @@ -1047,13 +1042,13 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, long count, i // Save the values for when (options & SEARCH_KEEP) is used. // (there is no "if ()" around this because gcc wants them initialized) - old_off = spats[0].off; + struct soffset old_off = spats[0].off; pos = curwin->w_cursor; // start searching at the cursor position // Find out the direction of the search. if (dirc == 0) { - dirc = (char_u)spats[0].off.dir; + dirc = (uint8_t)spats[0].off.dir; } else { spats[0].off.dir = (char)dirc; set_vv_searchforward(); @@ -1434,8 +1429,6 @@ end_do_search: int search_for_exact_line(buf_T *buf, pos_T *pos, Direction dir, char *pat) { linenr_T start = 0; - char *ptr; - char *p; if (buf->b_ml.ml_line_count == 0) { return FAIL; @@ -1469,8 +1462,8 @@ int search_for_exact_line(buf_T *buf, pos_T *pos, Direction dir, char *pat) if (start == 0) { start = pos->lnum; } - ptr = ml_get_buf(buf, pos->lnum, false); - p = skipwhite(ptr); + char *ptr = ml_get_buf(buf, pos->lnum, false); + char *p = skipwhite(ptr); pos->col = (colnr_T)(p - ptr); // when adding lines the matching line may be empty but it is not @@ -1503,14 +1496,11 @@ int searchc(cmdarg_T *cap, int t_cmd) int c = cap->nchar; // char to search for int dir = cap->arg; // true for searching forward long count = cap->count1; // repeat count - int col; - char *p; - int len; bool stop = true; if (c != NUL) { // normal search: remember args for repeat if (!KeyStuffed) { // don't remember when redoing - *lastc = (char_u)c; + *lastc = (uint8_t)c; set_csearch_direction(dir); set_csearch_until(t_cmd); lastc_bytelen = utf_char2bytes(c, lastc_bytes); @@ -1550,9 +1540,9 @@ int searchc(cmdarg_T *cap, int t_cmd) cap->oap->inclusive = true; } - p = get_cursor_line_ptr(); - col = curwin->w_cursor.col; - len = (int)strlen(p); + char *p = get_cursor_line_ptr(); + int col = curwin->w_cursor.col; + int len = (int)strlen(p); while (count--) { for (;;) { @@ -2295,15 +2285,10 @@ int check_linecomment(const char *line) /// @param c char to show match for void showmatch(int c) { - pos_T *lpos, save_cursor; - pos_T mpos; + pos_T *lpos; colnr_T vcol; long *so = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so; long *siso = curwin->w_p_siso >= 0 ? &curwin->w_p_siso : &p_siso; - long save_so; - long save_siso; - int save_state; - colnr_T save_dollar_vcol; char *p; // Only show match for chars in the 'matchpairs' option. @@ -2345,10 +2330,10 @@ void showmatch(int c) return; } - mpos = *lpos; // save the pos, update_screen() may change it - save_cursor = curwin->w_cursor; - save_so = *so; - save_siso = *siso; + pos_T mpos = *lpos; // save the pos, update_screen() may change it + pos_T save_cursor = curwin->w_cursor; + long save_so = *so; + long save_siso = *siso; // Handle "$" in 'cpo': If the ')' is typed on top of the "$", // stop displaying the "$". if (dollar_vcol >= 0 && dollar_vcol == curwin->w_virtcol) { @@ -2357,8 +2342,8 @@ void showmatch(int c) curwin->w_virtcol++; // do display ')' just before "$" update_screen(); // show the new char first - save_dollar_vcol = dollar_vcol; - save_state = State; + colnr_T save_dollar_vcol = dollar_vcol; + int save_state = State; State = MODE_SHOWMATCH; ui_cursor_shape(); // may show different cursor shape curwin->w_cursor = mpos; // move to matching char @@ -2531,7 +2516,6 @@ int current_search(long count, bool forward) static int is_zero_width(char *pattern, int move, pos_T *cur, Direction direction) { regmmatch_T regmatch; - int nmatched = 0; int result = -1; pos_T pos; const int called_emsg_before = called_emsg; @@ -2558,6 +2542,7 @@ static int is_zero_width(char *pattern, int move, pos_T *cur, Direction directio } if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1, SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL) { + int nmatched = 0; // Zero-width pattern should match somewhere, then we can check if // start and end are in the same position. do { @@ -2587,9 +2572,7 @@ static int is_zero_width(char *pattern, int move, pos_T *cur, Direction directio /// return true if line 'lnum' is empty or has white chars only. int linewhite(linenr_T lnum) { - char *p; - - p = skipwhite(ml_get(lnum)); + char *p = skipwhite(ml_get(lnum)); return *p == NUL; } @@ -2682,7 +2665,6 @@ static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchst static int chgtick = 0; static char *lastpat = NULL; static buf_T *lbuf = NULL; - proftime_T start; CLEAR_POINTER(stat); @@ -2722,6 +2704,7 @@ static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchst && (dirc == 0 || dirc == '/' ? cur < cnt : cur > 0)) { cur += dirc == 0 ? 0 : dirc == '/' ? 1 : -1; } else { + proftime_T start; bool done_search = false; pos_T endpos = { 0, 0, 0 }; p_ws = false; @@ -2788,7 +2771,6 @@ void f_searchcount(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (argvars[0].v_type != VAR_UNKNOWN) { dict_T *dict; dictitem_T *di; - listitem_T *li; bool error = false; if (argvars[0].v_type != VAR_DICT || argvars[0].vval.v_dict == NULL) { @@ -2834,7 +2816,7 @@ void f_searchcount(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) semsg(_(e_invarg2), "List format should be [lnum, col, off]"); return; } - li = tv_list_find(di->di_tv.vval.v_list, 0L); + listitem_T *li = tv_list_find(di->di_tv.vval.v_list, 0L); if (li != NULL) { pos.lnum = (linenr_T)tv_get_number_chk(TV_LIST_ITEM_TV(li), &error); if (error) { @@ -3125,8 +3107,7 @@ static int fuzzy_match_recursive(const char *fuzpat, const char *str, uint32_t s /// normalized and varies with pattern. /// Recursion is limited internally (default=10) to prevent degenerate cases /// (pat_arg="aaaaaa" str="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"). -/// Uses char_u for match indices. Therefore patterns are limited to -/// MAX_FUZZY_MATCHES characters. +/// Patterns are limited to MAX_FUZZY_MATCHES characters. /// /// @return true if "pat_arg" matches "str". Also returns the match score in /// "outScore" and the matching character positions in "matches". @@ -4157,8 +4138,6 @@ static void show_pat_in_path(char *line, int type, bool did_show, int action, FI linenr_T *lnum, long count) FUNC_ATTR_NONNULL_ARG(1, 6) { - char *p; - if (did_show) { msg_putchar('\n'); // cursor below last one } else if (!msg_silent) { @@ -4168,7 +4147,7 @@ static void show_pat_in_path(char *line, int type, bool did_show, int action, FI return; } for (;;) { - p = line + strlen(line) - 1; + char *p = line + strlen(line) - 1; if (fp != NULL) { // We used fgets(), so get rid of newline at end if (p >= line && *p == '\n') { diff --git a/src/nvim/sha256.c b/src/nvim/sha256.c index db647f3ecb..f0a9aecdcc 100644 --- a/src/nvim/sha256.c +++ b/src/nvim/sha256.c @@ -201,14 +201,14 @@ void sha256_update(context_sha256_T *ctx, const uint8_t *input, size_t length) memcpy(ctx->buffer + left, input, fill); sha256_process(ctx, ctx->buffer); length -= fill; - input += fill; + input += fill; left = 0; } while (length >= SHA256_BUFFER_SIZE) { sha256_process(ctx, input); length -= SHA256_BUFFER_SIZE; - input += SHA256_BUFFER_SIZE; + input += SHA256_BUFFER_SIZE; } if (length) { diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 90a01aaf97..98f10c0082 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -2579,7 +2579,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef { STATIC_CSTR_AS_STRING("pid"), INTEGER_OBJ((Integer)os_get_pid()) }, { STATIC_CSTR_AS_STRING("encoding"), - STRING_OBJ(cstr_as_string((char *)p_enc)) }, + STRING_OBJ(cstr_as_string(p_enc)) }, }), } } diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 00e282b76e..d555b8bf4a 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -153,11 +153,10 @@ static int sign_group_get_next_signid(buf_T *buf, const char *groupname) int id = 1; signgroup_T *group = NULL; sign_entry_T *sign; - hashitem_T *hi; int found = false; if (groupname != NULL) { - hi = hash_find(&sg_table, (char *)groupname); + hashitem_T *hi = hash_find(&sg_table, (char *)groupname); if (HASHITEM_EMPTY(hi)) { return id; } @@ -298,8 +297,8 @@ static dict_T *sign_get_info(sign_entry_T *sign) dict_T *d = tv_dict_alloc(); tv_dict_add_nr(d, S_LEN("id"), sign->se_id); tv_dict_add_str(d, S_LEN("group"), ((sign->se_group == NULL) - ? (char *)"" - : (char *)sign->se_group->sg_name)); + ? "" + : sign->se_group->sg_name)); tv_dict_add_nr(d, S_LEN("lnum"), sign->se_lnum); tv_dict_add_str(d, S_LEN("name"), sign_typenr2name(sign->se_typenr)); tv_dict_add_nr(d, S_LEN("priority"), sign->se_priority); @@ -576,7 +575,7 @@ static linenr_T buf_delsign(buf_T *buf, linenr_T atlnum, int id, char *group) lnum = sign->se_lnum; buf_signcols_del_check(buf, lnum, lnum); if (sign->se_group != NULL) { - sign_group_unref((char *)sign->se_group->sg_name); + sign_group_unref(sign->se_group->sg_name); } xfree(sign); redraw_buf_line_later(buf, lnum, false); @@ -688,7 +687,7 @@ void buf_delete_signs(buf_T *buf, char *group) next->se_prev = sign->se_prev; } if (sign->se_group != NULL) { - sign_group_unref((char *)sign->se_group->sg_name); + sign_group_unref(sign->se_group->sg_name); } xfree(sign); } else { @@ -1198,7 +1197,6 @@ static linenr_T sign_jump(int sign_id, char *sign_group, buf_T *buf) /// ":sign define {name} ..." command static void sign_define_cmd(char *sign_name, char *cmdline) { - char *arg; char *p = cmdline; char *icon = NULL; char *text = NULL; @@ -1210,7 +1208,7 @@ static void sign_define_cmd(char *sign_name, char *cmdline) // set values for a defined sign. for (;;) { - arg = skipwhite(p); + char *arg = skipwhite(p); if (*arg == NUL) { break; } @@ -1585,7 +1583,6 @@ static void sign_getinfo(sign_T *sp, dict_T *retdict) static void sign_getlist(const char *name, list_T *retlist) { sign_T *sp = first_sign; - dict_T *dict; if (name != NULL) { sp = sign_find((char *)name, NULL); @@ -1595,7 +1592,7 @@ static void sign_getlist(const char *name, list_T *retlist) } for (; sp != NULL && !got_int; sp = sp->sn_next) { - dict = tv_dict_alloc(); + dict_T *dict = tv_dict_alloc(); tv_list_append_dict(retlist, dict); sign_getinfo(sp, dict); @@ -1610,11 +1607,10 @@ list_T *get_buffer_signs(buf_T *buf) FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { sign_entry_T *sign; - dict_T *d; list_T *const l = tv_list_alloc(kListLenMayKnow); FOR_ALL_SIGNS_IN_BUF(buf, sign) { - d = sign_get_info(sign); + dict_T *d = sign_get_info(sign); tv_list_append_dict(l, d); } return l; @@ -1778,7 +1774,7 @@ static char *get_nth_sign_group_name(int idx) todo--; if (current_idx++ == idx) { signgroup_T *const group = HI2SG(hi); - return (char *)group->sg_name; + return group->sg_name; } } } @@ -2055,7 +2051,6 @@ void f_sign_getdefined(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) void f_sign_getplaced(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { buf_T *buf = NULL; - dict_T *dict; dictitem_T *di; linenr_T lnum = 0; int sign_id = 0; @@ -2072,6 +2067,7 @@ void f_sign_getplaced(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } if (argvars[1].v_type != VAR_UNKNOWN) { + dict_T *dict; if (argvars[1].v_type != VAR_DICT || ((dict = argvars[1].vval.v_dict) == NULL)) { emsg(_(e_dictreq)); @@ -2327,8 +2323,6 @@ static void sign_undefine_multiple(list_T *l, list_T *retlist) /// "sign_undefine()" function void f_sign_undefine(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - const char *name; - if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_UNKNOWN) { // Undefine multiple signs tv_list_alloc_ret(rettv, kListLenMayKnow); @@ -2345,7 +2339,7 @@ void f_sign_undefine(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->vval.v_number = 0; } else { // Free only the specified sign - name = tv_get_string_chk(&argvars[0]); + const char *name = tv_get_string_chk(&argvars[0]); if (name == NULL) { return; } diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 2204cda169..117a770e50 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -380,7 +380,7 @@ size_t spell_check(win_T *wp, char *ptr, hlf_T *attrp, int *capcol, bool docount MB_PTR_ADV(mi.mi_end); } else if (mi.mi_result == SP_BAD && LANGP_ENTRY(wp->w_s->b_langp, 0)->lp_slang->sl_nobreak) { - char *p, *fp; + char *p; int save_result = mi.mi_result; // First language in 'spelllang' is NOBREAK. Find first position @@ -388,7 +388,7 @@ size_t spell_check(win_T *wp, char *ptr, hlf_T *attrp, int *capcol, bool docount mi.mi_lp = LANGP_ENTRY(wp->w_s->b_langp, 0); if (mi.mi_lp->lp_slang->sl_fidxs != NULL) { p = mi.mi_word; - fp = mi.mi_fword; + char *fp = mi.mi_fword; for (;;) { MB_PTR_ADV(p); MB_PTR_ADV(fp); @@ -437,14 +437,14 @@ static void find_word(matchinf_T *mip, int mode) int flen; char *ptr; slang_T *slang = mip->mi_lp->lp_slang; - char_u *byts; + uint8_t *byts; idx_T *idxs; if (mode == FIND_KEEPWORD || mode == FIND_KEEPCOMPOUND) { // Check for word with matching case in keep-case tree. ptr = mip->mi_word; flen = 9999; // no case folding, always enough bytes - byts = (char_u *)slang->sl_kbyts; + byts = (uint8_t *)slang->sl_kbyts; idxs = slang->sl_kidxs; if (mode == FIND_KEEPCOMPOUND) { @@ -455,7 +455,7 @@ static void find_word(matchinf_T *mip, int mode) // Check for case-folded in case-folded tree. ptr = mip->mi_fword; flen = mip->mi_fwordlen; // available case-folded bytes - byts = (char_u *)slang->sl_fbyts; + byts = (uint8_t *)slang->sl_fbyts; idxs = slang->sl_fidxs; if (mode == FIND_PREFIX) { @@ -964,7 +964,7 @@ bool can_compound(slang_T *slang, const char *word, const uint8_t *flags) bool match_compoundrule(slang_T *slang, const char_u *compflags) { // loop over all the COMPOUNDRULE entries - for (char_u *p = (char_u *)slang->sl_comprules; *p != NUL; p++) { + for (char *p = (char *)slang->sl_comprules; *p != NUL; p++) { // loop over the flags in the compound word we have made, match // them against the current rule entry for (int i = 0;; i++) { @@ -982,21 +982,21 @@ bool match_compoundrule(slang_T *slang, const char_u *compflags) // compare against all the flags in [] p++; while (*p != ']' && *p != NUL) { - if (*p++ == c) { + if ((uint8_t)(*p++) == c) { match = true; } } if (!match) { break; // none matches } - } else if (*p != c) { + } else if ((uint8_t)(*p) != c) { break; // flag of word doesn't match flag in pattern } p++; } // Skip to the next "/", where the next pattern starts. - p = (char_u *)vim_strchr((char *)p, '/'); + p = vim_strchr(p, '/'); if (p == NULL) { break; } @@ -1062,13 +1062,13 @@ static void find_prefix(matchinf_T *mip, int mode) int wlen = 0; slang_T *slang = mip->mi_lp->lp_slang; - char_u *byts = (char_u *)slang->sl_pbyts; + uint8_t *byts = (uint8_t *)slang->sl_pbyts; if (byts == NULL) { return; // array is empty } // We use the case-folded word here, since prefixes are always // case-folded. - char_u *ptr = (char_u *)mip->mi_fword; + char *ptr = mip->mi_fword; int flen = mip->mi_fwordlen; // available case-folded bytes if (mode == FIND_COMPOUND) { // Skip over the previously found word(s). @@ -1126,7 +1126,7 @@ static void find_prefix(matchinf_T *mip, int mode) } // Perform a binary search in the list of accepted bytes. - int c = ptr[wlen]; + int c = (uint8_t)ptr[wlen]; idx_T lo = arridx; idx_T hi = arridx + len - 1; while (lo < hi) { @@ -1483,9 +1483,9 @@ theend: // to skip those bytes if the word was OK. void spell_cat_line(char *buf, char *line, int maxlen) { - char_u *p = (char_u *)skipwhite(line); + char *p = skipwhite(line); while (vim_strchr("*#/\"\t", (uint8_t)(*p)) != NULL) { - p = (char_u *)skipwhite((char *)p + 1); + p = skipwhite(p + 1); } if (*p == NUL) { @@ -1494,10 +1494,10 @@ void spell_cat_line(char *buf, char *line, int maxlen) // Only worth concatenating if there is something else than spaces to // concatenate. - int n = (int)(p - (char_u *)line) + 1; + int n = (int)(p - line) + 1; if (n < maxlen - 1) { memset(buf, ' ', (size_t)n); - xstrlcpy(buf + n, (char *)p, (size_t)(maxlen - n)); + xstrlcpy(buf + n, p, (size_t)(maxlen - n)); } } @@ -1775,7 +1775,7 @@ bool byte_in_str(uint8_t *str, int n) int init_syl_tab(slang_T *slang) { ga_init(&slang->sl_syl_items, sizeof(syl_item_T), 4); - char *p = vim_strchr((char *)slang->sl_syllable, '/'); + char *p = vim_strchr(slang->sl_syllable, '/'); while (p != NULL) { *p++ = NUL; if (*p == NUL) { // trailing slash @@ -1838,7 +1838,7 @@ static int count_syllables(slang_T *slang, const char *word) // No recognized syllable item, at least a syllable char then? int c = utf_ptr2char(p); len = utfc_ptr2len(p); - if (vim_strchr((char *)slang->sl_syllable, c) == NULL) { + if (vim_strchr(slang->sl_syllable, c) == NULL) { skip = false; // No, search for next syllable } else if (!skip) { cnt++; // Yes, count it @@ -2167,7 +2167,7 @@ static void use_midword(slang_T *lp, win_T *wp) return; } - for (char *p = (char *)lp->sl_midword; *p != NUL;) { + for (char *p = lp->sl_midword; *p != NUL;) { const int c = utf_ptr2char(p); const int l = utfc_ptr2len(p); if (c < 256 && l <= 2) { @@ -2660,24 +2660,24 @@ void onecap_copy(char *word, char *wcopy, bool upper) // "wcopy[MAXWLEN]". The result is NUL terminated. void allcap_copy(char *word, char *wcopy) { - char_u *d = (char_u *)wcopy; + char *d = wcopy; for (char *s = word; *s != NUL;) { int c = mb_cptr2char_adv((const char **)&s); if (c == 0xdf) { c = 'S'; - if (d - (char_u *)wcopy >= MAXWLEN - 1) { + if (d - wcopy >= MAXWLEN - 1) { break; } - *d++ = (char_u)c; + *d++ = (char)c; } else { c = SPELL_TOUPPER(c); } - if (d - (char_u *)wcopy >= MAXWLEN - MB_MAXBYTES) { + if (d - wcopy >= MAXWLEN - MB_MAXBYTES) { break; } - d += utf_char2bytes(c, (char *)d); + d += utf_char2bytes(c, d); } *d = NUL; } @@ -2834,7 +2834,6 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) int j, z; int reslen; int k = 0; - int z0; int k0; int n0; int pri; @@ -2847,7 +2846,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) // But keep white space. int wordlen = 0; for (const char *s = (char *)inword; *s != NUL;) { - const char_u *t = (char_u *)s; + const char *t = s; int c = mb_cptr2char_adv(&s); if (slang->sl_rem_accents) { if (utf_class(c) == 0) { @@ -2858,7 +2857,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) did_white = true; } else { did_white = false; - if (!spell_iswordp_nmw((char *)t, curwin)) { + if (!spell_iswordp_nmw(t, curwin)) { continue; } } @@ -2875,7 +2874,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) while ((c = word[i]) != NUL) { // Start with the first rule that has the character in the word. int n = slang->sl_sal_first[c & 0xff]; - z0 = 0; + int z0 = 0; if (n >= 0) { // Check all rules for the same index byte. @@ -2915,10 +2914,10 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) } k++; } - char_u *s = (char_u *)smp[n].sm_rules; + char *s = smp[n].sm_rules; pri = 5; // default priority - p0 = *s; + p0 = (uint8_t)(*s); k0 = k; while (*s == '-' && k > 1) { k--; @@ -2929,7 +2928,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) } if (ascii_isdigit(*s)) { // determine priority - pri = *s - '0'; + pri = (uint8_t)(*s) - '0'; s++; } if (*s == '^' && *(s + 1) == '^') { @@ -2992,7 +2991,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) } p0 = 5; - s = (char_u *)smp[n0].sm_rules; + s = smp[n0].sm_rules; while (*s == '-') { // "k0" gets NOT reduced because // "if (k0 == k)" @@ -3002,7 +3001,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) s++; } if (ascii_isdigit(*s)) { - p0 = *s - '0'; + p0 = (uint8_t)(*s) - '0'; s++; } @@ -3033,8 +3032,8 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) // replace string ws = smp[n].sm_to_w; - s = (char_u *)smp[n].sm_rules; - p0 = (vim_strchr((char *)s, '<') != NULL) ? 1 : 0; + s = smp[n].sm_rules; + p0 = (vim_strchr(s, '<') != NULL) ? 1 : 0; if (p0 == 1 && z == 0) { // rule with '<' is used if (reslen > 0 && ws != NULL && *ws != NUL @@ -3077,7 +3076,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) } else { c = *ws; } - if (strstr((char *)s, "^^") != NULL) { + if (strstr(s, "^^") != NULL) { if (c != NUL) { wres[reslen++] = c; } @@ -3463,7 +3462,7 @@ static linenr_T dump_prefixes(slang_T *slang, char *word, char *pat, Direction * has_word_up = true; } - char_u *byts = (char_u *)slang->sl_pbyts; + char *byts = slang->sl_pbyts; idx_T *idxs = slang->sl_pidxs; if (byts != NULL) { // array not is empty // Loop over all prefixes, building them byte-by-byte in prefix[]. @@ -3473,7 +3472,7 @@ static linenr_T dump_prefixes(slang_T *slang, char *word, char *pat, Direction * curi[0] = 1; while (depth >= 0 && !got_int) { int n = arridx[depth]; - int len = byts[n]; + int len = (uint8_t)byts[n]; if (curi[depth] > len) { // Done all bytes at this node, go up one level. depth--; @@ -3482,7 +3481,7 @@ static linenr_T dump_prefixes(slang_T *slang, char *word, char *pat, Direction * // Do one more byte at this node. n += curi[depth]; curi[depth]++; - c = byts[n]; + c = (uint8_t)byts[n]; if (c == 0) { // End of prefix, find out how many IDs there are. int i; diff --git a/src/nvim/spell_defs.h b/src/nvim/spell_defs.h index 4d365deab1..93cf335c3a 100644 --- a/src/nvim/spell_defs.h +++ b/src/nvim/spell_defs.h @@ -82,7 +82,7 @@ typedef struct fromto_S { typedef struct salitem_S { char *sm_lead; // leading letters int sm_leadlen; // length of "sm_lead" - char_u *sm_oneof; // letters from () or NULL + char *sm_oneof; // letters from () or NULL char *sm_rules; // rules like ^, $, priority char *sm_to; // replacement. int *sm_lead_w; // wide character copy of "sm_lead" @@ -119,20 +119,20 @@ struct slang_S { char *sl_fname; // name of .spl file bool sl_add; // true if it's a .add file. - char *sl_fbyts; // case-folded word bytes - long sl_fbyts_len; // length of sl_fbyts - idx_T *sl_fidxs; // case-folded word indexes - char *sl_kbyts; // keep-case word bytes - idx_T *sl_kidxs; // keep-case word indexes - char *sl_pbyts; // prefix tree word bytes - idx_T *sl_pidxs; // prefix tree word indexes + char *sl_fbyts; // case-folded word bytes + long sl_fbyts_len; // length of sl_fbyts + idx_T *sl_fidxs; // case-folded word indexes + char *sl_kbyts; // keep-case word bytes + idx_T *sl_kidxs; // keep-case word indexes + char *sl_pbyts; // prefix tree word bytes + idx_T *sl_pidxs; // prefix tree word indexes - char_u *sl_info; // infotext string or NULL + char *sl_info; // infotext string or NULL char sl_regions[MAXREGIONS * 2 + 1]; // table with up to 8 region names plus NUL - char_u *sl_midword; // MIDWORD string or NULL + char *sl_midword; // MIDWORD string or NULL hashtab_T sl_wordcount; // hashtable with word count, wordcount_T @@ -141,13 +141,13 @@ struct slang_S { int sl_compsylmax; // COMPOUNDSYLMAX (default: MAXWLEN) int sl_compoptions; // COMP_* flags garray_T sl_comppat; // CHECKCOMPOUNDPATTERN items - regprog_T *sl_compprog; // COMPOUNDRULE turned into a regexp progrm - // (NULL when no compounding) + regprog_T *sl_compprog; // COMPOUNDRULE turned into a regexp progrm + // (NULL when no compounding) uint8_t *sl_comprules; // all COMPOUNDRULE concatenated (or NULL) uint8_t *sl_compstartflags; // flags for first compound word uint8_t *sl_compallflags; // all flags for compound words bool sl_nobreak; // When true: no spaces between words - char_u *sl_syllable; // SYLLABLE repeatable chars or NULL + char *sl_syllable; // SYLLABLE repeatable chars or NULL garray_T sl_syl_items; // syllable items int sl_prefixcnt; // number of items in "sl_prefprog" diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 5e7ebc4c87..e9dd0a4d5e 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -386,7 +386,7 @@ typedef struct affheader_S { // Flag used in compound items. typedef struct compitem_S { - char_u ci_key[AH_KEY_LEN]; // key for hashtab == name of compound + char ci_key[AH_KEY_LEN]; // key for hashtab == name of compound unsigned ci_flag; // affix name as number, uses "af_flagtype" int ci_newID; // affix ID after renumbering. } compitem_T; @@ -674,7 +674,7 @@ slang_T *spell_load_file(char *fname, char *lang, slang_T *old_lp, bool silent) res = 0; switch (n) { case SN_INFO: - lp->sl_info = READ_STRING(fd, len); // <infotext> + lp->sl_info = read_string(fd, (size_t)len); // <infotext> if (lp->sl_info == NULL) { goto endFAIL; } @@ -689,7 +689,7 @@ slang_T *spell_load_file(char *fname, char *lang, slang_T *old_lp, bool silent) break; case SN_MIDWORD: - lp->sl_midword = READ_STRING(fd, len); // <midword> + lp->sl_midword = read_string(fd, (size_t)len); // <midword> if (lp->sl_midword == NULL) { goto endFAIL; } @@ -716,7 +716,7 @@ slang_T *spell_load_file(char *fname, char *lang, slang_T *old_lp, bool silent) break; case SN_MAP: - p = (char *)READ_STRING(fd, len); // <mapstr> + p = read_string(fd, (size_t)len); // <mapstr> if (p == NULL) { goto endFAIL; } @@ -749,7 +749,7 @@ slang_T *spell_load_file(char *fname, char *lang, slang_T *old_lp, bool silent) break; case SN_SYLLABLE: - lp->sl_syllable = READ_STRING(fd, len); // <syllable> + lp->sl_syllable = read_string(fd, (size_t)len); // <syllable> if (lp->sl_syllable == NULL) { goto endFAIL; } @@ -838,8 +838,9 @@ endOK: // Fill in the wordcount fields for a trie. // Returns the total number of words. -static void tree_count_words(const char_u *byts, idx_T *idxs) +static void tree_count_words(const char *byts_in, idx_T *idxs) { + const uint8_t *byts= (const uint8_t *)byts_in; int depth; idx_T arridx[MAXWLEN]; int curi[MAXWLEN]; @@ -896,7 +897,6 @@ void suggest_load_files(void) char *dotp; FILE *fd; char buf[MAXWLEN]; - int i; time_t timestamp; int wcount; int wordnr; @@ -924,7 +924,7 @@ void suggest_load_files(void) } // <SUGHEADER>: <fileID> <versionnr> <timestamp> - for (i = 0; i < VIMSUGMAGICL; i++) { + for (int i = 0; i < VIMSUGMAGICL; i++) { buf[i] = (char)getc(fd); // <fileID> } if (strncmp(buf, VIMSUGMAGIC, VIMSUGMAGICL) != 0) { @@ -1000,8 +1000,8 @@ someerror: // Need to put word counts in the word tries, so that we can find // a word by its number. - tree_count_words((char_u *)slang->sl_fbyts, slang->sl_fidxs); - tree_count_words((char_u *)slang->sl_sbyts, slang->sl_sidxs); + tree_count_words(slang->sl_fbyts, slang->sl_fidxs); + tree_count_words(slang->sl_sbyts, slang->sl_sidxs); nextone: if (fd != NULL) { @@ -1017,10 +1017,10 @@ nextone: // Returns NULL when the count is zero. // Sets "*cntp" to SP_*ERROR when there is an error, length of the result // otherwise. -static char_u *read_cnt_string(FILE *fd, int cnt_bytes, int *cntp) +static char *read_cnt_string(FILE *fd, int cnt_bytes, int *cntp) { int cnt = 0; - char_u *str; + char *str; // read the length bytes, MSB first for (int i = 0; i < cnt_bytes; i++) { @@ -1036,7 +1036,7 @@ static char_u *read_cnt_string(FILE *fd, int cnt_bytes, int *cntp) if (cnt == 0) { return NULL; // nothing to read, return NULL } - str = READ_STRING(fd, cnt); + str = read_string(fd, (size_t)cnt); if (str == NULL) { *cntp = SP_OTHERERROR; } @@ -1065,13 +1065,13 @@ static int read_charflags_section(FILE *fd) int flagslen, follen; // <charflagslen> <charflags> - flags = (char *)read_cnt_string(fd, 1, &flagslen); + flags = read_cnt_string(fd, 1, &flagslen); if (flagslen < 0) { return flagslen; } // <folcharslen> <folchars> - fol = read_cnt_string(fd, 2, &follen); + fol = (char_u *)read_cnt_string(fd, 2, &follen); if (follen < 0) { xfree(flags); return follen; @@ -1143,14 +1143,14 @@ static int read_rep_section(FILE *fd, garray_T *gap, int16_t *first) for (; gap->ga_len < cnt; gap->ga_len++) { int c; ftp = &((fromto_T *)gap->ga_data)[gap->ga_len]; - ftp->ft_from = (char *)read_cnt_string(fd, 1, &c); + ftp->ft_from = read_cnt_string(fd, 1, &c); if (c < 0) { return c; } if (c == 0) { return SP_FORMERROR; } - ftp->ft_to = (char *)read_cnt_string(fd, 1, &c); + ftp->ft_to = read_cnt_string(fd, 1, &c); if (c <= 0) { xfree(ftp->ft_from); if (c < 0) { @@ -1181,7 +1181,7 @@ static int read_sal_section(FILE *fd, slang_T *slang) garray_T *gap; salitem_T *smp; int ccnt; - char_u *p; + char *p; slang->sl_sofo = false; @@ -1215,7 +1215,7 @@ static int read_sal_section(FILE *fd, slang_T *slang) return SP_TRUNCERROR; } p = xmalloc((size_t)ccnt + 2); - smp->sm_lead = (char *)p; + smp->sm_lead = p; // Read up to the first special char into sm_lead. int i = 0; @@ -1224,9 +1224,9 @@ static int read_sal_section(FILE *fd, slang_T *slang) if (vim_strchr("0123456789(-<^$", c) != NULL) { break; } - *p++ = (char_u)c; + *p++ = (char)(uint8_t)c; } - smp->sm_leadlen = (int)(p - (char_u *)smp->sm_lead); + smp->sm_leadlen = (int)(p - smp->sm_lead); *p++ = NUL; // Put (abc) chars in sm_oneof, if any. @@ -1237,7 +1237,7 @@ static int read_sal_section(FILE *fd, slang_T *slang) if (c == ')') { break; } - *p++ = (char_u)c; + *p++ = (char)(uint8_t)c; } *p++ = NUL; if (++i < ccnt) { @@ -1248,22 +1248,22 @@ static int read_sal_section(FILE *fd, slang_T *slang) } // Any following chars go in sm_rules. - smp->sm_rules = (char *)p; + smp->sm_rules = p; if (i < ccnt) { // store the char we got while checking for end of sm_lead - *p++ = (char_u)c; + *p++ = (char)(uint8_t)c; } i++; if (i < ccnt) { SPELL_READ_NONNUL_BYTES( // <salfrom> - (char *)p, (size_t)(ccnt - i), fd, + p, (size_t)(ccnt - i), fd, xfree(smp->sm_lead)); p += (ccnt - i); } *p++ = NUL; // <saltolen> <salto> - smp->sm_to = (char *)read_cnt_string(fd, 1, &ccnt); + smp->sm_to = read_cnt_string(fd, 1, &ccnt); if (ccnt < 0) { xfree(smp->sm_lead); return ccnt; @@ -1275,7 +1275,7 @@ static int read_sal_section(FILE *fd, slang_T *slang) if (smp->sm_oneof == NULL) { smp->sm_oneof_w = NULL; } else { - smp->sm_oneof_w = mb_str2wide((char *)smp->sm_oneof); + smp->sm_oneof_w = mb_str2wide(smp->sm_oneof); } if (smp->sm_to == NULL) { smp->sm_to_w = NULL; @@ -1290,12 +1290,12 @@ static int read_sal_section(FILE *fd, slang_T *slang) smp = &((salitem_T *)gap->ga_data)[gap->ga_len]; p = xmalloc(1); p[0] = NUL; - smp->sm_lead = (char *)p; + smp->sm_lead = p; smp->sm_lead_w = mb_str2wide(smp->sm_lead); smp->sm_leadlen = 0; smp->sm_oneof = NULL; smp->sm_oneof_w = NULL; - smp->sm_rules = (char *)p; + smp->sm_rules = p; smp->sm_to = NULL; smp->sm_to_w = NULL; gap->ga_len++; @@ -1350,13 +1350,13 @@ static int read_sofo_section(FILE *fd, slang_T *slang) slang->sl_sofo = true; // <sofofromlen> <sofofrom> - from = (char *)read_cnt_string(fd, 2, &cnt); + from = read_cnt_string(fd, 2, &cnt); if (cnt < 0) { return cnt; } // <sofotolen> <sofoto> - to = (char *)read_cnt_string(fd, 2, &cnt); + to = read_cnt_string(fd, 2, &cnt); if (cnt < 0) { xfree(from); return cnt; @@ -1385,7 +1385,6 @@ static int read_compound(FILE *fd, slang_T *slang, int len) int c; int atstart; int cnt; - garray_T *gap; if (todo < 2) { return SP_FORMERROR; // need at least two bytes @@ -1420,7 +1419,7 @@ static int read_compound(FILE *fd, slang_T *slang, int len) todo--; slang->sl_compoptions = c; - gap = &slang->sl_comppat; + garray_T *gap = &slang->sl_comppat; c = get2c(fd); // <comppatcount> if (c < 0) { return SP_TRUNCERROR; @@ -1429,7 +1428,7 @@ static int read_compound(FILE *fd, slang_T *slang, int len) ga_init(gap, sizeof(char *), c); ga_grow(gap, c); while (--c >= 0) { - ((char **)(gap->ga_data))[gap->ga_len++] = (char *)read_cnt_string(fd, 1, &cnt); + ((char **)(gap->ga_data))[gap->ga_len++] = read_cnt_string(fd, 1, &cnt); // <comppatlen> <comppattext> if (cnt < 0) { return cnt; @@ -1465,7 +1464,7 @@ static int read_compound(FILE *fd, slang_T *slang, int len) uint8_t *crp = xmalloc((size_t)todo + 1); slang->sl_comprules = crp; - char_u *pp = (char_u *)pat; + char *pp = pat; *pp++ = '^'; *pp++ = '\\'; *pp++ = '('; @@ -1521,7 +1520,7 @@ static int read_compound(FILE *fd, slang_T *slang, int len) if (c == '?' || c == '+' || c == '~') { *pp++ = '\\'; // "a?" becomes "a\?", "a+" becomes "a\+" } - pp += utf_char2bytes(c, (char *)pp); + pp += utf_char2bytes(c, pp); } } @@ -1612,7 +1611,6 @@ static void set_sal_first(slang_T *lp) { salfirst_T *sfirst; salitem_T *smp; - int c; garray_T *gap = &lp->sl_sal; sfirst = lp->sl_sal_first; @@ -1624,7 +1622,7 @@ static void set_sal_first(slang_T *lp) // Use the lowest byte of the first character. For latin1 it's // the character, for other encodings it should differ for most // characters. - c = *smp[i].sm_lead_w & 0xff; + int c = *smp[i].sm_lead_w & 0xff; if (sfirst[c] == -1) { sfirst[c] = i; @@ -1735,10 +1733,8 @@ static idx_T read_tree_node(FILE *fd, char_u *byts, idx_T *idxs, int maxidx, idx bool prefixtree, int maxprefcondnr) { int len; - int i; int n; idx_T idx = startidx; - int c; int c2; #define SHARED_MASK 0x8000000 @@ -1753,8 +1749,8 @@ static idx_T read_tree_node(FILE *fd, char_u *byts, idx_T *idxs, int maxidx, idx byts[idx++] = (char_u)len; // Read the byte values, flag/region bytes and shared indexes. - for (i = 1; i <= len; i++) { - c = getc(fd); // <byte> + for (int i = 1; i <= len; i++) { + int c = getc(fd); // <byte> if (c < 0) { return SP_TRUNCERROR; } @@ -1816,7 +1812,7 @@ static idx_T read_tree_node(FILE *fd, char_u *byts, idx_T *idxs, int maxidx, idx // Recursively read the children for non-shared siblings. // Skip the end-of-word ones (zero byte value) and the shared ones (and // remove SHARED_MASK) - for (i = 1; i <= len; i++) { + for (int i = 1; i <= len; i++) { if (byts[startidx + i] != 0) { if (idxs[startidx + i] & SHARED_MASK) { idxs[startidx + i] &= ~SHARED_MASK; @@ -1957,9 +1953,9 @@ static void spell_print_node(wordnode_T *node, int depth) PRINTSOME(line1, depth, "(%d)", node->wn_nr, 0); PRINTSOME(line2, depth, " ", 0, 0); PRINTSOME(line3, depth, " ", 0, 0); - msg((char_u *)line1); - msg((char_u *)line2); - msg((char_u *)line3); + msg(line1); + msg(line2); + msg(line3); } else { node->wn_u1.index = true; @@ -1983,9 +1979,9 @@ static void spell_print_node(wordnode_T *node, int depth) } if (node->wn_byte == NUL) { - msg((char_u *)line1); - msg((char_u *)line2); - msg((char_u *)line3); + msg(line1); + msg(line2); + msg(line3); } // do the children @@ -2434,7 +2430,6 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) && strcmp(cur_aff->ah_key, items[1]) == 0 && itemcnt >= 5) { affentry_T *aff_entry; - bool upper = false; int lasti = 5; // Myspell allows extra text after the item, but that might @@ -2493,6 +2488,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) // COMPOUNDFORBIDFLAG and COMPOUNDPERMITFLAG. if (*items[0] == 'P' && aff->af_pfxpostpone && aff_entry->ae_flags == NULL) { + bool upper = false; // When the chop string is one lower-case letter and // the add string ends in the upper-case letter we set // the "upper" flag, clear "ae_chop" and remove the @@ -2502,10 +2498,8 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) && aff_entry->ae_add != NULL && aff_entry->ae_chop[utfc_ptr2len(aff_entry->ae_chop)] == NUL) { - int c, c_up; - - c = utf_ptr2char(aff_entry->ae_chop); - c_up = SPELL_TOUPPER(c); + int c = utf_ptr2char(aff_entry->ae_chop); + int c_up = SPELL_TOUPPER(c); if (c_up != c && (aff_entry->ae_cond == NULL || utf_ptr2char(aff_entry->ae_cond) == c)) { @@ -2535,8 +2529,6 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) if (aff_entry->ae_chop == NULL) { int idx; - char_u **pp; - int n; // Find a previously used condition. for (idx = spin->si_prefcond.ga_len - 1; idx >= 0; idx--) { @@ -2548,7 +2540,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) if (idx < 0) { // Not found, add a new condition. idx = spin->si_prefcond.ga_len; - pp = GA_APPEND_VIA_PTR(char_u *, &spin->si_prefcond); + char_u **pp = GA_APPEND_VIA_PTR(char_u *, &spin->si_prefcond); *pp = (aff_entry->ae_cond == NULL) ? NULL : (char_u *)getroom_save(spin, aff_entry->ae_cond); } @@ -2562,7 +2554,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) // PFX_FLAGS is a negative number, so that // tree_add_word() knows this is the prefix tree. - n = PFX_FLAGS; + int n = PFX_FLAGS; if (!cur_aff->ah_combine) { n |= WFP_NC; } @@ -2636,11 +2628,9 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) fname, lnum); } } else if (do_mapline) { - int c; - // Check that every character appears only once. for (p = items[1]; *p != NUL;) { - c = mb_ptr2char_adv((const char **)&p); + int c = mb_ptr2char_adv((const char **)&p); if ((!GA_EMPTY(&spin->si_map) && vim_strchr(spin->si_map.ga_data, c) != NULL) @@ -2681,9 +2671,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname) && sofoto == NULL) { sofoto = getroom_save(spin, items[1]); } else if (strcmp(items[0], "COMMON") == 0) { - int i; - - for (i = 1; i < itemcnt; i++) { + for (int i = 1; i < itemcnt; i++) { if (HASHITEM_EMPTY(hash_find(&spin->si_commonwords, (char *)items[i]))) { p = xstrdup(items[i]); hash_add(&spin->si_commonwords, p); @@ -2791,16 +2779,14 @@ static bool is_aff_rule(char **items, int itemcnt, char *rulename, int mincount) static void aff_process_flags(afffile_T *affile, affentry_T *entry) { char *p; - char_u *prevp; - unsigned flag; if (entry->ae_flags != NULL && (affile->af_compforbid != 0 || affile->af_comppermit != 0)) { for (p = entry->ae_flags; *p != NUL;) { - prevp = (char_u *)p; - flag = get_affitem(affile->af_flagtype, &p); + char_u *prevp = (char_u *)p; + unsigned flag = get_affitem(affile->af_flagtype, &p); if (flag == affile->af_comppermit || flag == affile->af_compforbid) { - STRMOVE(prevp, (char *)p); + STRMOVE(prevp, p); p = (char *)prevp; if (flag == affile->af_comppermit) { entry->ae_comppermit = true; @@ -2833,10 +2819,9 @@ static bool spell_info_item(char *s) // returns zero for failure. static unsigned affitem2flag(int flagtype, char *item, char *fname, int lnum) { - unsigned res; char *p = item; - res = get_affitem(flagtype, &p); + unsigned res = get_affitem(flagtype, &p); if (res == 0) { if (flagtype == AFT_NUM) { smsg(_("Flag is not a number in %s line %d: %s"), @@ -2889,30 +2874,27 @@ static unsigned get_affitem(int flagtype, char **pp) /// they fit in one byte. static void process_compflags(spellinfo_T *spin, afffile_T *aff, char *compflags) { - char *p; char *prevp; unsigned flag; compitem_T *ci; int id; - int len; - char_u *tp; char key[AH_KEY_LEN]; hashitem_T *hi; // Make room for the old and the new compflags, concatenated with a / in // between. Processing it makes it shorter, but we don't know by how // much, thus allocate the maximum. - len = (int)strlen(compflags) + 1; + int len = (int)strlen(compflags) + 1; if (spin->si_compflags != NULL) { len += (int)strlen(spin->si_compflags) + 1; } - p = getroom(spin, (size_t)len, false); + char *p = getroom(spin, (size_t)len, false); if (spin->si_compflags != NULL) { STRCPY(p, spin->si_compflags); STRCAT(p, "/"); } spin->si_compflags = p; - tp = (char_u *)p + strlen(p); + char_u *tp = (char_u *)p + strlen(p); for (p = compflags; *p != NUL;) { if (vim_strchr("/?*+[]", (uint8_t)(*p)) != NULL) { @@ -2940,9 +2922,9 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char *compflags id = spin->si_newcompID--; } while (vim_strchr("/?*+[]\\-^", id) != NULL); ci->ci_newID = id; - hash_add(&aff->af_comp, (char *)ci->ci_key); + hash_add(&aff->af_comp, ci->ci_key); } - *tp++ = (char_u)id; + *tp++ = (uint8_t)id; } if (aff->af_flagtype == AFT_NUM && *p == ',') { p++; @@ -3061,7 +3043,6 @@ static void spell_free_aff(afffile_T *aff) { hashtab_T *ht; hashitem_T *hi; - int todo; affheader_T *ah; affentry_T *ae; @@ -3069,7 +3050,7 @@ static void spell_free_aff(afffile_T *aff) // All this trouble to free the "ae_prog" items... for (ht = &aff->af_pref;; ht = &aff->af_suff) { - todo = (int)ht->ht_used; + int todo = (int)ht->ht_used; for (hi = ht->ht_array; todo > 0; hi++) { if (!HASHITEM_EMPTY(hi)) { todo--; @@ -3095,28 +3076,27 @@ static int spell_read_dic(spellinfo_T *spin, char *fname, afffile_T *affile) { hashtab_T ht; char line[MAXLINELEN]; - char_u *p; - char_u *afflist; - char_u store_afflist[MAXWLEN]; + char *p; + char *afflist; + char store_afflist[MAXWLEN]; int pfxlen; bool need_affix; char *dw; - char_u *pc; - char_u *w; + char *pc; + char *w; int l; hash_T hash; hashitem_T *hi; - FILE *fd; int lnum = 1; int non_ascii = 0; int retval = OK; - char_u message[MAXLINELEN + MAXWLEN]; + char message[MAXLINELEN + MAXWLEN]; int flags; int duplicate = 0; Timestamp last_msg_time = 0; // Open the file. - fd = os_fopen(fname, "r"); + FILE *fd = os_fopen(fname, "r"); if (fd == NULL) { semsg(_(e_notopen), fname); return FAIL; @@ -3159,7 +3139,7 @@ static int spell_read_dic(spellinfo_T *spin, char *fname, afffile_T *affile) // Convert from "SET" to 'encoding' when needed. if (spin->si_conv.vc_type != CONV_NONE) { - pc = (char_u *)string_convert(&spin->si_conv, (char *)line, NULL); + pc = string_convert(&spin->si_conv, (char *)line, NULL); if (pc == NULL) { smsg(_("Conversion failure for word in %s line %d: %s"), fname, lnum, line); @@ -3168,7 +3148,7 @@ static int spell_read_dic(spellinfo_T *spin, char *fname, afffile_T *affile) w = pc; } else { pc = NULL; - w = (char_u *)line; + w = line; } // Truncate the word at the "/", set "afflist" to what follows. @@ -3176,7 +3156,7 @@ static int spell_read_dic(spellinfo_T *spin, char *fname, afffile_T *affile) afflist = NULL; for (p = w; *p != NUL; MB_PTR_ADV(p)) { if (*p == '\\' && (p[1] == '\\' || p[1] == '/')) { - STRMOVE(p, (char *)p + 1); + STRMOVE(p, p + 1); } else if (*p == '/') { *p = NUL; afflist = p + 1; @@ -3185,7 +3165,7 @@ static int spell_read_dic(spellinfo_T *spin, char *fname, afffile_T *affile) } // Skip non-ASCII words when "spin->si_ascii" is true. - if (spin->si_ascii && has_non_ascii((char *)w)) { + if (spin->si_ascii && has_non_ascii(w)) { non_ascii++; xfree(pc); continue; @@ -3197,11 +3177,11 @@ static int spell_read_dic(spellinfo_T *spin, char *fname, afffile_T *affile) spin->si_msg_count = 0; if (os_time() > last_msg_time) { last_msg_time = os_time(); - vim_snprintf((char *)message, sizeof(message), + vim_snprintf(message, sizeof(message), _("line %6d, word %6ld - %s"), lnum, spin->si_foldwcount + spin->si_keepwcount, w); msg_start(); - msg_outtrans_long_attr((char *)message, 0); + msg_outtrans_long_attr(message, 0); msg_clr_eos(); msg_didout = false; msg_col = 0; @@ -3210,7 +3190,7 @@ static int spell_read_dic(spellinfo_T *spin, char *fname, afffile_T *affile) } // Store the word in the hashtable to be able to find duplicates. - dw = getroom_save(spin, (char *)w); + dw = getroom_save(spin, w); if (dw == NULL) { retval = FAIL; xfree(pc); @@ -3218,7 +3198,7 @@ static int spell_read_dic(spellinfo_T *spin, char *fname, afffile_T *affile) } hash = hash_hash(dw); - hi = hash_lookup(&ht, (const char *)dw, strlen(dw), hash); + hi = hash_lookup(&ht, dw, strlen(dw), hash); if (!HASHITEM_EMPTY(hi)) { if (p_verbose > 0) { smsg(_("Duplicate word in %s line %d: %s"), @@ -3238,45 +3218,45 @@ static int spell_read_dic(spellinfo_T *spin, char *fname, afffile_T *affile) need_affix = false; if (afflist != NULL) { // Extract flags from the affix list. - flags |= get_affix_flags(affile, (char *)afflist); + flags |= get_affix_flags(affile, afflist); if (affile->af_needaffix != 0 - && flag_in_afflist(affile->af_flagtype, (char *)afflist, + && flag_in_afflist(affile->af_flagtype, afflist, affile->af_needaffix)) { need_affix = true; } if (affile->af_pfxpostpone) { // Need to store the list of prefix IDs with the word. - pfxlen = get_pfxlist(affile, (char *)afflist, store_afflist); + pfxlen = get_pfxlist(affile, afflist, store_afflist); } if (spin->si_compflags != NULL) { // Need to store the list of compound flags with the word. // Concatenate them to the list of prefix IDs. - get_compflags(affile, (char *)afflist, store_afflist + pfxlen); + get_compflags(affile, afflist, (char_u *)store_afflist + pfxlen); } } // Add the word to the word tree(s). if (store_word(spin, dw, flags, spin->si_region, - (char *)store_afflist, need_affix) == FAIL) { + store_afflist, need_affix) == FAIL) { retval = FAIL; } if (afflist != NULL) { // Find all matching suffixes and add the resulting words. // Additionally do matching prefixes that combine. - if (store_aff_word(spin, dw, (char *)afflist, affile, + if (store_aff_word(spin, dw, afflist, affile, &affile->af_suff, &affile->af_pref, - CONDIT_SUF, flags, (char *)store_afflist, pfxlen) == FAIL) { + CONDIT_SUF, flags, store_afflist, pfxlen) == FAIL) { retval = FAIL; } // Find all matching prefixes and add the resulting words. - if (store_aff_word(spin, dw, (char *)afflist, affile, + if (store_aff_word(spin, dw, afflist, affile, &affile->af_pref, NULL, - CONDIT_SUF, flags, (char *)store_afflist, pfxlen) == FAIL) { + CONDIT_SUF, flags, store_afflist, pfxlen) == FAIL) { retval = FAIL; } } @@ -3338,17 +3318,15 @@ static int get_affix_flags(afffile_T *affile, char *afflist) // Used for PFXPOSTPONE. // Put the resulting flags in "store_afflist[MAXWLEN]" with a terminating NUL // and return the number of affixes. -static int get_pfxlist(afffile_T *affile, char *afflist, char_u *store_afflist) +static int get_pfxlist(afffile_T *affile, char *afflist, char *store_afflist) { - char *p; - char *prevp; int cnt = 0; int id; char key[AH_KEY_LEN]; hashitem_T *hi; - for (p = afflist; *p != NUL;) { - prevp = p; + for (char *p = afflist; *p != NUL;) { + char *prevp = p; if (get_affitem(affile->af_flagtype, &p) != 0) { // A flag is a postponed prefix flag if it appears in "af_pref" // and its ID is not zero. @@ -3357,7 +3335,7 @@ static int get_pfxlist(afffile_T *affile, char *afflist, char_u *store_afflist) if (!HASHITEM_EMPTY(hi)) { id = HI2AH(hi)->ah_newID; if (id != 0) { - store_afflist[cnt++] = (char_u)id; + store_afflist[cnt++] = (char)(uint8_t)id; } } } @@ -3375,14 +3353,12 @@ static int get_pfxlist(afffile_T *affile, char *afflist, char_u *store_afflist) // Puts the flags in "store_afflist[]". static void get_compflags(afffile_T *affile, char *afflist, char_u *store_afflist) { - char *p; - char *prevp; int cnt = 0; char key[AH_KEY_LEN]; hashitem_T *hi; - for (p = afflist; *p != NUL;) { - prevp = p; + for (char *p = afflist; *p != NUL;) { + char *prevp = p; if (get_affitem(affile->af_flagtype, &p) != 0) { // A flag is a compound flag if it appears in "af_comp". xstrlcpy(key, prevp, (size_t)(p - prevp) + 1); @@ -3418,7 +3394,6 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_ hashtab_T *ht, hashtab_T *xht, int condit, int flags, char *pfxlist, int pfxlen) { - int todo; hashitem_T *hi; affheader_T *ah; affentry_T *ae; @@ -3430,12 +3405,12 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_ char *use_pfxlist; int use_pfxlen; bool need_affix; - char_u store_afflist[MAXWLEN]; + char store_afflist[MAXWLEN]; char pfx_pfxlist[MAXWLEN]; size_t wordlen = strlen(word); int use_condit; - todo = (int)ht->ht_used; + int todo = (int)ht->ht_used; for (hi = ht->ht_array; todo > 0 && retval == OK; hi++) { if (!HASHITEM_EMPTY(hi)) { todo--; @@ -3539,7 +3514,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_ } else { use_pfxlen = 0; } - use_pfxlist = (char *)store_afflist; + use_pfxlist = store_afflist; // Combine the prefix IDs. Avoid adding the // same ID twice. @@ -3664,7 +3639,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char *fname) long lnum = 0; char rline[MAXLINELEN]; char *line; - char_u *pc = NULL; + char *pc = NULL; char_u *p; int l; int retval = OK; @@ -3706,13 +3681,13 @@ static int spell_read_wordfile(spellinfo_T *spin, char *fname) // Convert from "/encoding={encoding}" to 'encoding' when needed. xfree(pc); if (spin->si_conv.vc_type != CONV_NONE) { - pc = (char_u *)string_convert(&spin->si_conv, rline, NULL); + pc = string_convert(&spin->si_conv, rline, NULL); if (pc == NULL) { smsg(_("Conversion failure for word in %s line %ld: %s"), fname, lnum, rline); continue; } - line = (char *)pc; + line = pc; } else { pc = NULL; line = rline; @@ -3929,7 +3904,7 @@ static int store_word(spellinfo_T *spin, char *word, int flags, int region, cons { int len = (int)strlen(word); int ct = captype(word, word + len); - char_u foldword[MAXWLEN]; + char foldword[MAXWLEN]; int res = OK; // Avoid adding illegal bytes to the word tree. @@ -3937,10 +3912,10 @@ static int store_word(spellinfo_T *spin, char *word, int flags, int region, cons return FAIL; } - (void)spell_casefold(curwin, word, len, (char *)foldword, MAXWLEN); + (void)spell_casefold(curwin, word, len, foldword, MAXWLEN); for (const char_u *p = (char_u *)pfxlist; res == OK; p++) { if (!need_affix || (p != NULL && *p != NUL)) { - res = tree_add_word(spin, foldword, spin->si_foldroot, ct | flags, + res = tree_add_word(spin, (char_u *)foldword, spin->si_foldroot, ct | flags, region, p == NULL ? 0 : *p); } if (p == NULL || *p == NUL) { @@ -3975,10 +3950,9 @@ static int tree_add_word(spellinfo_T *spin, const char_u *word, wordnode_T *root wordnode_T *np; wordnode_T *copyp, **copyprev; wordnode_T **prev = NULL; - int i; // Add each byte of the word to the tree, including the NUL at the end. - for (i = 0;; i++) { + for (int i = 0;; i++) { // When there is more than one reference to this node we need to make // a copy, so that we can modify it. Copy the whole list of siblings // (we don't optimize for a partly shared list of siblings). @@ -4414,7 +4388,6 @@ static int write_vim_spell(spellinfo_T *spin, char *fname) // the table (avoids that it conflicts). File is shorter too. if (!spin->si_ascii && !spin->si_add) { char folchars[128 * 8]; - int flags; putc(SN_CHARFLAGS, fd); // <sectionID> putc(SNF_REQUIRED, fd); // <sectionflags> @@ -4428,7 +4401,7 @@ static int write_vim_spell(spellinfo_T *spin, char *fname) fputc(128, fd); // <charflagslen> for (size_t i = 128; i < 256; i++) { - flags = 0; + int flags = 0; if (spelltab.st_isw[i]) { flags |= CF_WORD; } @@ -5528,8 +5501,6 @@ void spell_add_word(char *word, int len, SpellAddType what, int idx, bool undo) char *fname; char *fnamebuf = NULL; char line[MAXWLEN * 2]; - long fpos, fpos_next = 0; - int i; char *spf; if (!valid_spell_word(word, word + len)) { @@ -5546,6 +5517,7 @@ void spell_add_word(char *word, int len, SpellAddType what, int idx, bool undo) } fname = int_wordlist; } else { + int i; // If 'spellfile' isn't set figure out a good default value. if (*curwin->w_s->b_p_spf == NUL) { init_spellfile(); @@ -5585,6 +5557,8 @@ void spell_add_word(char *word, int len, SpellAddType what, int idx, bool undo) } if (what == SPELL_ADD_BAD || undo) { + long fpos_next = 0; + long fpos = 0; // When the word appears as good word we need to remove that one, // since its flags sort before the one with WF_BANNED. fd = os_fopen(fname, "r"); @@ -5758,13 +5732,12 @@ static void set_spell_charflags(const char_u *flags, int cnt, char *fol) // We build the new tables here first, so that we can compare with the // previous one. spelltab_T new_st; - int i; char *p = fol; int c; clear_spell_chartab(&new_st); - for (i = 0; i < 128; i++) { + for (int i = 0; i < 128; i++) { if (i < cnt) { new_st.st_isw[i + 128] = (flags[i] & CF_WORD) != 0; new_st.st_isu[i + 128] = (flags[i] & CF_UPPER) != 0; @@ -5784,11 +5757,9 @@ static void set_spell_charflags(const char_u *flags, int cnt, char *fol) static int set_spell_finish(spelltab_T *new_st) { - int i; - if (did_set_spelltab) { // check that it's the same table - for (i = 0; i < 256; i++) { + for (int i = 0; i < 256; i++) { if (spelltab.st_isw[i] != new_st->st_isw[i] || spelltab.st_isu[i] != new_st->st_isu[i] || spelltab.st_fold[i] != new_st->st_fold[i] @@ -5841,8 +5812,6 @@ static void set_map_str(slang_T *lp, char *map) { char *p; int headc = 0; - int c; - int i; if (*map == NUL) { lp->sl_has_map = false; @@ -5851,7 +5820,7 @@ static void set_map_str(slang_T *lp, char *map) lp->sl_has_map = true; // Init the array and hash tables empty. - for (i = 0; i < 256; i++) { + for (int i = 0; i < 256; i++) { lp->sl_map_array[i] = 0; } hash_init(&lp->sl_map_hash); @@ -5860,7 +5829,7 @@ static void set_map_str(slang_T *lp, char *map) // "aaa/bbb/ccc/". Fill sl_map_array[c] with the character before c and // before the same slash. For characters above 255 sl_map_hash is used. for (p = map; *p != NUL;) { - c = mb_cptr2char_adv((const char **)&p); + int c = mb_cptr2char_adv((const char **)&p); if (c == '/') { headc = 0; } else { diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c index 0ddf07e3a6..d176a65228 100644 --- a/src/nvim/spellsuggest.c +++ b/src/nvim/spellsuggest.c @@ -74,9 +74,9 @@ typedef struct suginfo_S { char *su_badptr; ///< start of bad word in line int su_badlen; ///< length of detected bad word in line int su_badflags; ///< caps flags for bad word - char_u su_badword[MAXWLEN]; ///< bad word truncated at su_badlen + char su_badword[MAXWLEN]; ///< bad word truncated at su_badlen char su_fbadword[MAXWLEN]; ///< su_badword case-folded - char_u su_sal_badword[MAXWLEN]; ///< su_badword soundfolded + char su_sal_badword[MAXWLEN]; ///< su_badword soundfolded hashtab_T su_banned; ///< table with banned words slang_T *su_sallang; ///< default language for sound folding } suginfo_T; @@ -269,18 +269,17 @@ static bool can_be_compound(trystate_T *sp, slang_T *slang, char_u *compflags, i /// Adjust the score of common words. /// /// @param split word was split, less bonus -static int score_wordcount_adj(slang_T *slang, int score, char_u *word, bool split) +static int score_wordcount_adj(slang_T *slang, int score, char *word, bool split) { - wordcount_T *wc; int bonus; int newscore; - hashitem_T *hi = hash_find(&slang->sl_wordcount, (char *)word); + hashitem_T *hi = hash_find(&slang->sl_wordcount, word); if (HASHITEM_EMPTY(hi)) { return score; } - wc = HI2WC(hi); + wordcount_T *wc = HI2WC(hi); if (wc->wc_count < SCORE_THRES2) { bonus = SCORE_COMMON1; } else if (wc->wc_count < SCORE_THRES3) { @@ -302,24 +301,21 @@ static int score_wordcount_adj(slang_T *slang, int score, char_u *word, bool spl /// Like captype() but for a KEEPCAP word add ONECAP if the word starts with a /// capital. So that make_case_word() can turn WOrd into Word. /// Add ALLCAP for "WOrD". -static int badword_captype(char_u *word, char_u *end) +static int badword_captype(char *word, char *end) FUNC_ATTR_NONNULL_ALL { - int flags = captype((char *)word, (char *)end); - int c; - int l, u; - bool first; - char_u *p; + int flags = captype(word, end); if (!(flags & WF_KEEPCAP)) { return flags; } // Count the number of UPPER and lower case letters. - l = u = 0; - first = false; - for (p = word; p < end; MB_PTR_ADV(p)) { - c = utf_ptr2char((char *)p); + int l= 0; + int u= 0; + bool first = false; + for (char *p = word; p < end; MB_PTR_ADV(p)) { + int c = utf_ptr2char(p); if (SPELL_ISUPPER(c)) { u++; if (p == word) { @@ -351,13 +347,12 @@ static int badword_captype(char_u *word, char_u *end) /// "pp" points to the bytes and is advanced over it. /// /// @return the offset. -static int bytes2offset(char_u **pp) +static int bytes2offset(char **pp) { - char_u *p = *pp; + char_u *p = (char_u *)(*pp); int nr; - int c; - c = *p++; + int c = *p++; if ((c & 0x80) == 0x00) { // 1 byte nr = c - 1; } else if ((c & 0xc0) == 0x80) { // 2 bytes @@ -374,7 +369,7 @@ static int bytes2offset(char_u **pp) nr = nr * 255 + (*p++ - 1); } - *pp = p; + *pp = (char *)p; return nr; } @@ -392,20 +387,18 @@ static int sps_limit = 9999; ///< max nr of suggestions given /// Sets "sps_flags" and "sps_limit". int spell_check_sps(void) { - char *p; char *s; char buf[MAXPATHL]; - int f; sps_flags = 0; sps_limit = 9999; - for (p = p_sps; *p != NUL;) { - copy_option_part(&p, (char *)buf, MAXPATHL, ","); + for (char *p = p_sps; *p != NUL;) { + copy_option_part(&p, buf, MAXPATHL, ","); - f = 0; + int f = 0; if (ascii_isdigit(*buf)) { - s = (char *)buf; + s = buf; sps_limit = getdigits_int(&s, true, 0); if (*s != NUL && !ascii_isdigit(*s)) { f = -1; @@ -450,12 +443,10 @@ void spell_suggest(int count) char *line; pos_T prev_cursor = curwin->w_cursor; char wcopy[MAXWLEN + 2]; - char_u *p; - int c; + char *p; suginfo_T sug; suggest_T *stp; int mouse_used; - int need_cap; int limit; int selected = count; int badlen = 0; @@ -499,27 +490,27 @@ void spell_suggest(int count) // cursor. curwin->w_cursor = prev_cursor; line = get_cursor_line_ptr(); - p = (char_u *)line + curwin->w_cursor.col; + p = line + curwin->w_cursor.col; // Backup to before start of word. - while (p > (char_u *)line && spell_iswordp_nmw((char *)p, curwin)) { + while (p > line && spell_iswordp_nmw(p, curwin)) { MB_PTR_BACK(line, p); } // Forward to start of word. - while (*p != NUL && !spell_iswordp_nmw((char *)p, curwin)) { + while (*p != NUL && !spell_iswordp_nmw(p, curwin)) { MB_PTR_ADV(p); } - if (!spell_iswordp_nmw((char *)p, curwin)) { // No word found. + if (!spell_iswordp_nmw(p, curwin)) { // No word found. beep_flush(); return; } - curwin->w_cursor.col = (colnr_T)(p - (char_u *)line); + curwin->w_cursor.col = (colnr_T)(p - line); } // Get the word and its length. // Figure out if the word should be capitalised. - need_cap = check_need_cap(curwin->w_cursor.lnum, curwin->w_cursor.col); + int need_cap = check_need_cap(curwin->w_cursor.lnum, curwin->w_cursor.col); // Make a copy of current line since autocommands may free the line. line = xstrdup(get_cursor_line_ptr()); @@ -532,7 +523,7 @@ void spell_suggest(int count) } else { limit = sps_limit; } - spell_find_suggest((char_u *)line + curwin->w_cursor.col, badlen, &sug, limit, + spell_find_suggest(line + curwin->w_cursor.col, badlen, &sug, limit, true, need_cap, true); if (GA_EMPTY(&sug.su_ga)) { @@ -651,7 +642,7 @@ void spell_suggest(int count) // Replace the word. p = xmalloc(strlen(line) - (size_t)stp->st_orglen + (size_t)stp->st_wordlen + 1); - c = (int)(sug.su_badptr - line); + int c = (int)(sug.su_badptr - line); memmove(p, line, (size_t)c); STRCPY(p + c, stp->st_word); STRCAT(p, sug.su_badptr + stp->st_orglen); @@ -659,12 +650,12 @@ void spell_suggest(int count) // For redo we use a change-word command. ResetRedobuff(); AppendToRedobuff("ciw"); - AppendToRedobuffLit((char *)p + c, + AppendToRedobuffLit(p + c, stp->st_wordlen + sug.su_badlen - stp->st_orglen); AppendCharToRedobuff(ESC); // "p" may be freed here - ml_replace(curwin->w_cursor.lnum, (char *)p, false); + ml_replace(curwin->w_cursor.lnum, p, false); curwin->w_cursor.col = c; inserted_bytes(curwin->w_cursor.lnum, c, stp->st_orglen, stp->st_wordlen); @@ -685,23 +676,22 @@ void spell_suggest(int count) void spell_suggest_list(garray_T *gap, char *word, int maxcount, bool need_cap, bool interactive) { suginfo_T sug; - suggest_T *stp; - char_u *wcopy; + char *wcopy; - spell_find_suggest((char_u *)word, 0, &sug, maxcount, false, need_cap, interactive); + spell_find_suggest(word, 0, &sug, maxcount, false, need_cap, interactive); // Make room in "gap". - ga_init(gap, sizeof(char_u *), sug.su_ga.ga_len + 1); + ga_init(gap, sizeof(char *), sug.su_ga.ga_len + 1); ga_grow(gap, sug.su_ga.ga_len); for (int i = 0; i < sug.su_ga.ga_len; i++) { - stp = &SUG(sug.su_ga, i); + suggest_T *stp = &SUG(sug.su_ga, i); // The suggested word may replace only part of "word", add the not // replaced part. wcopy = xmalloc((size_t)stp->st_wordlen + strlen(sug.su_badptr + stp->st_orglen) + 1); STRCPY(wcopy, stp->st_word); STRCPY(wcopy + stp->st_wordlen, sug.su_badptr + stp->st_orglen); - ((char_u **)gap->ga_data)[gap->ga_len++] = wcopy; + ((char **)gap->ga_data)[gap->ga_len++] = wcopy; } spell_find_cleanup(&sug); @@ -716,16 +706,13 @@ void spell_suggest_list(garray_T *gap, char *word, int maxcount, bool need_cap, /// @param badlen length of bad word or 0 if unknown /// @param banbadword don't include badword in suggestions /// @param need_cap word should start with capital -static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int maxcount, +static void spell_find_suggest(char *badptr, int badlen, suginfo_T *su, int maxcount, bool banbadword, bool need_cap, bool interactive) { hlf_T attr = HLF_COUNT; char buf[MAXPATHL]; - char *p; bool do_combine = false; - char *sps_copy; static bool expr_busy = false; - int c; langp_T *lp; bool did_intern = false; @@ -738,7 +725,7 @@ static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int ma } hash_init(&su->su_banned); - su->su_badptr = (char *)badptr; + su->su_badptr = badptr; if (badlen != 0) { su->su_badlen = badlen; } else { @@ -752,7 +739,7 @@ static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int ma if (su->su_badlen >= MAXWLEN) { su->su_badlen = MAXWLEN - 1; // just in case } - xstrlcpy((char *)su->su_badword, su->su_badptr, (size_t)su->su_badlen + 1); + xstrlcpy(su->su_badword, su->su_badptr, (size_t)su->su_badlen + 1); (void)spell_casefold(curwin, su->su_badptr, su->su_badlen, su->su_fbadword, MAXWLEN); @@ -762,8 +749,8 @@ static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int ma su->su_fbadword[su->su_badlen] = NUL; // get caps flags for bad word - su->su_badflags = badword_captype((char_u *)su->su_badptr, - (char_u *)su->su_badptr + su->su_badlen); + su->su_badflags = badword_captype(su->su_badptr, + su->su_badptr + su->su_badlen); if (need_cap) { su->su_badflags |= WF_ONECAP; } @@ -783,46 +770,46 @@ static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int ma // Soundfold the bad word with the default sound folding, so that we don't // have to do this many times. if (su->su_sallang != NULL) { - spell_soundfold(su->su_sallang, (char *)su->su_fbadword, true, - (char *)su->su_sal_badword); + spell_soundfold(su->su_sallang, su->su_fbadword, true, + su->su_sal_badword); } // If the word is not capitalised and spell_check() doesn't consider the // word to be bad then it might need to be capitalised. Add a suggestion // for that. - c = utf_ptr2char(su->su_badptr); + int c = utf_ptr2char(su->su_badptr); if (!SPELL_ISUPPER(c) && attr == HLF_COUNT) { - make_case_word((char *)su->su_badword, buf, WF_ONECAP); - add_suggestion(su, &su->su_ga, (char *)buf, su->su_badlen, SCORE_ICASE, + make_case_word(su->su_badword, buf, WF_ONECAP); + add_suggestion(su, &su->su_ga, buf, su->su_badlen, SCORE_ICASE, 0, true, su->su_sallang, false); } // Ban the bad word itself. It may appear in another region. if (banbadword) { - add_banned(su, (char *)su->su_badword); + add_banned(su, su->su_badword); } // Make a copy of 'spellsuggest', because the expression may change it. - sps_copy = xstrdup(p_sps); + char *sps_copy = xstrdup(p_sps); // Loop over the items in 'spellsuggest'. - for (p = sps_copy; *p != NUL;) { - copy_option_part(&p, (char *)buf, MAXPATHL, ","); + for (char *p = sps_copy; *p != NUL;) { + copy_option_part(&p, buf, MAXPATHL, ","); if (strncmp(buf, "expr:", 5) == 0) { // Evaluate an expression. Skip this when called recursively, // when using spellsuggest() in the expression. if (!expr_busy) { expr_busy = true; - spell_suggest_expr(su, (char_u *)buf + 5); + spell_suggest_expr(su, buf + 5); expr_busy = false; } } else if (strncmp(buf, "file:", 5) == 0) { // Use list of suggestions in a file. - spell_suggest_file(su, (char_u *)buf + 5); + spell_suggest_file(su, buf + 5); } else if (strncmp(buf, "timeout:", 8) == 0) { // Limit the time searching for suggestions. - spell_suggest_timeout = atol((char *)buf + 8); + spell_suggest_timeout = atol(buf + 8); } else if (!did_intern) { // Use internal method once. spell_suggest_intern(su, interactive); @@ -843,21 +830,20 @@ static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int ma } /// Find suggestions by evaluating expression "expr". -static void spell_suggest_expr(suginfo_T *su, char_u *expr) +static void spell_suggest_expr(suginfo_T *su, char *expr) { - int score; const char *p; // The work is split up in a few parts to avoid having to export // suginfo_T. // First evaluate the expression and get the resulting list. - list_T *const list = eval_spell_expr((char *)su->su_badword, (char *)expr); + list_T *const list = eval_spell_expr(su->su_badword, expr); if (list != NULL) { // Loop over the items in the list. TV_LIST_ITER(list, li, { if (TV_LIST_ITEM_TV(li)->v_type == VAR_LIST) { // Get the word and the score from the items. - score = get_spellword(TV_LIST_ITEM_TV(li)->vval.v_list, &p); + int score = get_spellword(TV_LIST_ITEM_TV(li)->vval.v_list, &p); if (score >= 0 && score <= su->su_maxscore) { add_suggestion(su, &su->su_ga, p, su->su_badlen, score, 0, true, su->su_sallang, false); @@ -873,43 +859,41 @@ static void spell_suggest_expr(suginfo_T *su, char_u *expr) } /// Find suggestions in file "fname". Used for "file:" in 'spellsuggest'. -static void spell_suggest_file(suginfo_T *su, char_u *fname) +static void spell_suggest_file(suginfo_T *su, char *fname) { - FILE *fd; - char_u line[MAXWLEN * 2]; - char_u *p; + char line[MAXWLEN * 2]; int len; - char_u cword[MAXWLEN]; + char cword[MAXWLEN]; // Open the file. - fd = os_fopen((char *)fname, "r"); + FILE *fd = os_fopen(fname, "r"); if (fd == NULL) { semsg(_(e_notopen), fname); return; } // Read it line by line. - while (!vim_fgets((char *)line, MAXWLEN * 2, fd) && !got_int) { + while (!vim_fgets(line, MAXWLEN * 2, fd) && !got_int) { line_breakcheck(); - p = (char_u *)vim_strchr((char *)line, '/'); + char *p = vim_strchr(line, '/'); if (p == NULL) { continue; // No Tab found, just skip the line. } *p++ = NUL; if (STRICMP(su->su_badword, line) == 0) { // Match! Isolate the good word, until CR or NL. - for (len = 0; p[len] >= ' '; len++) {} + for (len = 0; (uint8_t)p[len] >= ' '; len++) {} p[len] = NUL; // If the suggestion doesn't have specific case duplicate the case // of the bad word. - if (captype((char *)p, NULL) == 0) { - make_case_word((char *)p, (char *)cword, su->su_badflags); + if (captype(p, NULL) == 0) { + make_case_word(p, cword, su->su_badflags); p = cword; } - add_suggestion(su, &su->su_ga, (char *)p, su->su_badlen, + add_suggestion(su, &su->su_ga, p, su->su_badlen, SCORE_FILE, 0, true, su->su_sallang, false); } } @@ -1013,24 +997,23 @@ static void spell_find_cleanup(suginfo_T *su) /// Try finding suggestions by recognizing specific situations. static void suggest_try_special(suginfo_T *su) { - char c; - char_u word[MAXWLEN]; + char word[MAXWLEN]; // Recognize a word that is repeated: "the the". - char *p = skiptowhite((char *)su->su_fbadword); - size_t len = (size_t)(p - (char *)su->su_fbadword); + char *p = skiptowhite(su->su_fbadword); + size_t len = (size_t)(p - su->su_fbadword); p = skipwhite(p); if (strlen(p) == len && strncmp(su->su_fbadword, p, len) == 0) { // Include badflags: if the badword is onecap or allcap // use that for the goodword too: "The the" -> "The". - c = su->su_fbadword[len]; + char c = su->su_fbadword[len]; su->su_fbadword[len] = NUL; - make_case_word(su->su_fbadword, (char *)word, su->su_badflags); + make_case_word(su->su_fbadword, word, su->su_badflags); su->su_fbadword[len] = c; // Give a soundalike score of 0, compute the score as if deleting one // character. - add_suggestion(su, &su->su_ga, (char *)word, su->su_badlen, + add_suggestion(su, &su->su_ga, word, su->su_badlen, RESCORE(SCORE_REP, 0), 0, true, su->su_sallang, false); } } @@ -1084,16 +1067,14 @@ static void prof_report(char *name) static void suggest_try_change(suginfo_T *su) { char fword[MAXWLEN]; // copy of the bad word, case-folded - int n; - char *p; langp_T *lp; // We make a copy of the case-folded bad word, so that we can modify it // to find matches (esp. REP items). Append some more text, changing // chars after the bad word may help. STRCPY(fword, su->su_fbadword); - n = (int)strlen(fword); - p = su->su_badptr + su->su_badlen; + int n = (int)strlen(fword); + char *p = su->su_badptr + su->su_badlen; (void)spell_casefold(curwin, p, (int)strlen(p), fword + n, MAXWLEN - n); // Make sure the resulting text is not longer than the original text. @@ -1165,12 +1146,10 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // when going deeper but not when coming // back. char_u compflags[MAXWLEN]; // compound flags, one for each word - trystate_T *sp; int newscore; int score; char_u *byts, *fbyts, *pbyts; idx_T *idxs, *fidxs, *pidxs; - int depth; int c, c2, c3; int n = 0; int flags; @@ -1195,8 +1174,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // "tword[]" contains the word collected from nodes in the tree. // "fword[]" the word we are trying to match with (initially the bad // word). - depth = 0; - sp = &stack[0]; + int depth = 0; + trystate_T *sp = &stack[0]; CLEAR_POINTER(sp); // -V1068 sp->ts_curi = 1; @@ -1268,9 +1247,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // Set su->su_badflags to the caps type at this position. // Use the caps type until here for the prefix itself. n = nofold_len(fword, sp->ts_fidx, su->su_badptr); - flags = badword_captype((char_u *)su->su_badptr, (char_u *)su->su_badptr + n); - su->su_badflags = badword_captype((char_u *)su->su_badptr + n, - (char_u *)su->su_badptr + su->su_badlen); + flags = badword_captype(su->su_badptr, su->su_badptr + n); + su->su_badflags = badword_captype(su->su_badptr + n, + su->su_badptr + su->su_badlen); #ifdef DEBUG_TRIEWALK sprintf(changename[depth], "prefix"); // NOLINT(runtime/printf) #endif @@ -1371,11 +1350,11 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun (size_t)(sp->ts_fidx - sp->ts_splitfidx)) == 0) { preword[sp->ts_prewordlen] = NUL; newscore = score_wordcount_adj(slang, sp->ts_score, - (char_u *)preword + sp->ts_prewordlen, + preword + sp->ts_prewordlen, sp->ts_prewordlen > 0); // Add the suggestion if the score isn't too bad. if (newscore <= su->su_maxscore) { - add_suggestion(su, &su->su_ga, (char *)preword, + add_suggestion(su, &su->su_ga, preword, sp->ts_splitfidx - repextra, newscore, 0, false, lp->lp_sallang, false); @@ -1437,7 +1416,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun STRCPY(preword + sp->ts_prewordlen, tword + sp->ts_splitoff); } else if (flags & WF_KEEPCAP) { // Must find the word in the keep-case tree. - find_keepcap_word(slang, (char *)tword + sp->ts_splitoff, preword + sp->ts_prewordlen); + find_keepcap_word(slang, tword + sp->ts_splitoff, preword + sp->ts_prewordlen); } else { // Include badflags: If the badword is onecap or allcap // use that for the goodword too. But if the badword is @@ -1465,8 +1444,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun break; } if ((sp->ts_complen == sp->ts_compsplit - && WAS_BANNED(su, (char *)preword + sp->ts_prewordlen)) - || WAS_BANNED(su, (char *)preword)) { + && WAS_BANNED(su, preword + sp->ts_prewordlen)) + || WAS_BANNED(su, preword)) { if (slang->sl_compprog == NULL) { break; } @@ -1528,12 +1507,12 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // Give a bonus to words seen before. score = score_wordcount_adj(slang, sp->ts_score + newscore, - (char_u *)preword + sp->ts_prewordlen, + preword + sp->ts_prewordlen, sp->ts_prewordlen > 0); // Add the suggestion if the score isn't too bad. if (score <= su->su_maxscore) { - add_suggestion(su, &su->su_ga, (char *)preword, + add_suggestion(su, &su->su_ga, preword, sp->ts_fidx - repextra, score, 0, false, lp->lp_sallang, false); @@ -1546,7 +1525,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun preword + sp->ts_prewordlen, c == 0 ? WF_ALLCAP : 0); - add_suggestion(su, &su->su_ga, (char *)preword, + add_suggestion(su, &su->su_ga, preword, sp->ts_fidx - repextra, score + SCORE_ICASE, 0, false, lp->lp_sallang, false); @@ -1647,7 +1626,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // Give a bonus to words seen before. newscore = score_wordcount_adj(slang, newscore, - (char_u *)preword + sp->ts_prewordlen, true); + preword + sp->ts_prewordlen, true); } if (TRY_DEEPER(su, stack, depth, newscore)) { @@ -1715,8 +1694,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // set su->su_badflags to the caps type at this // position n = nofold_len(fword, sp->ts_fidx, su->su_badptr); - su->su_badflags = badword_captype((char_u *)su->su_badptr + n, - (char_u *)su->su_badptr + su->su_badlen); + su->su_badflags = badword_captype(su->su_badptr + n, + su->su_badptr + su->su_badlen); // Restart at top of the tree. sp->ts_arridx = 0; @@ -1843,7 +1822,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun // For changing a composing character adjust // the score from SCORE_SUBST to // SCORE_SUBCOMP. - if (utf_iscomposing(utf_ptr2char((char *)tword + sp->ts_twordlen + if (utf_iscomposing(utf_ptr2char(tword + sp->ts_twordlen - sp->ts_tcharlen)) && utf_iscomposing(utf_ptr2char(fword + sp->ts_fcharstart))) { @@ -1851,7 +1830,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun } else if (!soundfold && slang->sl_has_map && similar_chars(slang, - utf_ptr2char((char *)tword + sp->ts_twordlen - + utf_ptr2char(tword + sp->ts_twordlen - sp->ts_tcharlen), utf_ptr2char(fword + sp->ts_fcharstart))) { // For a similar character adjust score from @@ -1860,7 +1839,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun } } else if (sp->ts_isdiff == DIFF_INSERT && sp->ts_twordlen > sp->ts_tcharlen) { - p = (char *)tword + sp->ts_twordlen - sp->ts_tcharlen; + p = tword + sp->ts_twordlen - sp->ts_tcharlen; c = utf_ptr2char(p); if (utf_iscomposing(c)) { // Inserting a composing char doesn't @@ -2310,7 +2289,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun fl = (int)strlen(ftp->ft_from); tl = (int)strlen(ftp->ft_to); if (fl != tl) { - STRMOVE(p + tl, (char *)p + fl); + STRMOVE(p + tl, p + fl); repextra += tl - fl; } memmove(p, ftp->ft_to, (size_t)tl); @@ -2340,7 +2319,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun tl = (int)strlen(ftp->ft_to); p = fword + sp->ts_fidx; if (fl != tl) { - STRMOVE(p + fl, (char *)p + tl); + STRMOVE(p + fl, p + tl); repextra -= tl - fl; } memmove(p, ftp->ft_from, (size_t)fl); @@ -2387,7 +2366,6 @@ static void go_deeper(trystate_T *stack, int depth, int score_add) static void find_keepcap_word(slang_T *slang, char *fword, char *kword) { char uword[MAXWLEN]; // "fword" in upper-case - int depth; idx_T tryidx; // The following arrays are used at each depth in the tree. @@ -2402,7 +2380,7 @@ static void find_keepcap_word(slang_T *slang, char *fword, char *kword) int len; int c; idx_T lo, hi, m; - char_u *p; + char *p; char_u *byts = (char_u *)slang->sl_kbyts; // array with bytes of the words idx_T *idxs = slang->sl_kidxs; // array with indexes @@ -2418,7 +2396,7 @@ static void find_keepcap_word(slang_T *slang, char *fword, char *kword) // Each character needs to be tried both case-folded and upper-case. // All this gets very complicated if we keep in mind that changing case // may change the byte length of a multi-byte character... - depth = 0; + int depth = 0; arridx[0] = 0; round[0] = 0; fwordidx[0] = 0; @@ -2443,19 +2421,19 @@ static void find_keepcap_word(slang_T *slang, char *fword, char *kword) // round[depth] == 1: Try using the folded-case character. // round[depth] == 2: Try using the upper-case character. flen = utf_ptr2len(fword + fwordidx[depth]); - ulen = utf_ptr2len((char *)uword + uwordidx[depth]); + ulen = utf_ptr2len(uword + uwordidx[depth]); if (round[depth] == 1) { - p = (char_u *)fword + fwordidx[depth]; + p = fword + fwordidx[depth]; l = flen; } else { - p = (char_u *)uword + uwordidx[depth]; + p = uword + uwordidx[depth]; l = ulen; } for (tryidx = arridx[depth]; l > 0; l--) { // Perform a binary search in the list of accepted bytes. len = byts[tryidx++]; - c = *p++; + c = (uint8_t)(*p++); lo = tryidx; hi = tryidx + len - 1; while (lo < hi) { @@ -2512,8 +2490,7 @@ static void find_keepcap_word(slang_T *slang, char *fword, char *kword) static void score_comp_sal(suginfo_T *su) { langp_T *lp; - char_u badsound[MAXWLEN]; - int i; + char badsound[MAXWLEN]; suggest_T *stp; suggest_T *sstp; int score; @@ -2525,9 +2502,9 @@ static void score_comp_sal(suginfo_T *su) lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); if (!GA_EMPTY(&lp->lp_slang->sl_sal)) { // soundfold the bad word - spell_soundfold(lp->lp_slang, (char *)su->su_fbadword, true, (char *)badsound); + spell_soundfold(lp->lp_slang, su->su_fbadword, true, badsound); - for (i = 0; i < su->su_ga.ga_len; i++) { + for (int i = 0; i < su->su_ga.ga_len; i++) { stp = &SUG(su->su_ga, i); // Case-fold the suggested word, sound-fold it and compute the @@ -2568,11 +2545,11 @@ static void score_combine(suginfo_T *su) if (!GA_EMPTY(&lp->lp_slang->sl_sal)) { // soundfold the bad word slang = lp->lp_slang; - spell_soundfold(slang, (char *)su->su_fbadword, true, badsound); + spell_soundfold(slang, su->su_fbadword, true, badsound); for (int i = 0; i < su->su_ga.ga_len; i++) { stp = &SUG(su->su_ga, i); - stp->st_altscore = stp_sal_score(stp, su, slang, (char_u *)badsound); + stp->st_altscore = stp_sal_score(stp, su, slang, badsound); if (stp->st_altscore == SCORE_MAXMAX) { stp->st_score = (stp->st_score * 3 + SCORE_BIG) / 4; } else { @@ -2593,7 +2570,7 @@ static void score_combine(suginfo_T *su) // Add the alternate score to su_sga. for (int i = 0; i < su->su_sga.ga_len; i++) { stp = &SUG(su->su_sga, i); - stp->st_altscore = spell_edit_score(slang, (char_u *)su->su_badword, (char_u *)stp->st_word); + stp->st_altscore = spell_edit_score(slang, su->su_badword, stp->st_word); if (stp->st_score == SCORE_MAXMAX) { stp->st_score = (SCORE_BIG * 7 + stp->st_altscore) / 8; } else { @@ -2654,23 +2631,21 @@ static void score_combine(suginfo_T *su) /// badword. /// /// @param badsound sound-folded badword -static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char_u *badsound) +static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char *badsound) { - char_u *p; - char_u *pbad; - char_u *pgood; - char_u badsound2[MAXWLEN]; - char_u fword[MAXWLEN]; - char_u goodsound[MAXWLEN]; + char *pbad; + char *pgood; + char badsound2[MAXWLEN]; + char fword[MAXWLEN]; + char goodsound[MAXWLEN]; char goodword[MAXWLEN]; - int lendiff; - lendiff = su->su_badlen - stp->st_orglen; + int lendiff = su->su_badlen - stp->st_orglen; if (lendiff >= 0) { pbad = badsound; } else { // soundfold the bad word with more characters following - (void)spell_casefold(curwin, su->su_badptr, stp->st_orglen, (char *)fword, MAXWLEN); + (void)spell_casefold(curwin, su->su_badptr, stp->st_orglen, fword, MAXWLEN); // When joining two words the sound often changes a lot. E.g., "t he" // sounds like "t h" while "the" sounds like "@". Avoid that by @@ -2678,12 +2653,12 @@ static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char_u * // space. if (ascii_iswhite(su->su_badptr[su->su_badlen]) && *skiptowhite(stp->st_word) == NUL) { - for (p = fword; *(p = (char_u *)skiptowhite((char *)p)) != NUL;) { - STRMOVE(p, (char *)p + 1); + for (char *p = fword; *(p = skiptowhite(p)) != NUL;) { + STRMOVE(p, p + 1); } } - spell_soundfold(slang, (char *)fword, true, (char *)badsound2); + spell_soundfold(slang, fword, true, badsound2); pbad = badsound2; } @@ -2693,15 +2668,15 @@ static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char_u * STRCPY(goodword, stp->st_word); xstrlcpy(goodword + stp->st_wordlen, su->su_badptr + su->su_badlen - lendiff, (size_t)lendiff + 1); - pgood = (char_u *)goodword; + pgood = goodword; } else { - pgood = (char_u *)stp->st_word; + pgood = stp->st_word; } // Sound-fold the word and compute the score for the difference. - spell_soundfold(slang, (char *)pgood, false, (char *)goodsound); + spell_soundfold(slang, pgood, false, goodsound); - return soundalike_score((char *)goodsound, (char *)pbad); + return soundalike_score(goodsound, pbad); } /// structure used to store soundfolded words that add_sound_suggest() has @@ -2737,7 +2712,7 @@ static void suggest_try_soundalike_prep(void) /// Note: This doesn't support postponed prefixes. static void suggest_try_soundalike(suginfo_T *su) { - char_u salword[MAXWLEN]; + char salword[MAXWLEN]; langp_T *lp; slang_T *slang; @@ -2748,7 +2723,7 @@ static void suggest_try_soundalike(suginfo_T *su) slang = lp->lp_slang; if (!GA_EMPTY(&slang->sl_sal) && slang->sl_sbyts != NULL) { // soundfold the bad word - spell_soundfold(slang, (char *)su->su_fbadword, true, (char *)salword); + spell_soundfold(slang, su->su_fbadword, true, salword); // try all kinds of inserts/deletes/swaps/etc. // TODO(vim): also soundfold the next words, so that we can try joining @@ -2756,7 +2731,7 @@ static void suggest_try_soundalike(suginfo_T *su) #ifdef SUGGEST_PROFILE prof_init(); #endif - suggest_trie_walk(su, lp, (char *)salword, true); + suggest_trie_walk(su, lp, salword, true); #ifdef SUGGEST_PROFILE prof_report("soundalike"); #endif @@ -2801,10 +2776,7 @@ static void suggest_try_soundalike_finish(void) static void add_sound_suggest(suginfo_T *su, char *goodword, int score, langp_T *lp) { slang_T *slang = lp->lp_slang; // language for sound folding - int sfwordnr; - char_u *nrline; - int orgnr; - char_u theword[MAXWLEN]; + char theword[MAXWLEN]; int i; int wlen; char_u *byts; @@ -2813,8 +2785,6 @@ static void add_sound_suggest(suginfo_T *su, char *goodword, int score, langp_T int wordcount; int wc; int goodscore; - hash_T hash; - hashitem_T *hi; sftword_T *sft; int bc, gc; int limit; @@ -2823,10 +2793,9 @@ static void add_sound_suggest(suginfo_T *su, char *goodword, int score, langp_T // times with different scores. Since the following is quite slow only do // the words that have a better score than before. Use a hashtable to // remember the words that have been done. - hash = hash_hash(goodword); + hash_T hash = hash_hash(goodword); const size_t goodword_len = strlen(goodword); - hi = hash_lookup(&slang->sl_sounddone, (const char *)goodword, goodword_len, - hash); + hashitem_T *hi = hash_lookup(&slang->sl_sounddone, (const char *)goodword, goodword_len, hash); if (HASHITEM_EMPTY(hi)) { sft = xmalloc(offsetof(sftword_T, sft_word) + goodword_len + 1); sft->sft_score = (int16_t)score; @@ -2841,15 +2810,15 @@ static void add_sound_suggest(suginfo_T *su, char *goodword, int score, langp_T } // Find the word nr in the soundfold tree. - sfwordnr = soundfold_find(slang, (char_u *)goodword); + int sfwordnr = soundfold_find(slang, goodword); if (sfwordnr < 0) { internal_error("add_sound_suggest()"); return; } // Go over the list of good words that produce this soundfold word - nrline = (char_u *)ml_get_buf(slang->sl_sugbuf, (linenr_T)sfwordnr + 1, false); - orgnr = 0; + char *nrline = ml_get_buf(slang->sl_sugbuf, (linenr_T)sfwordnr + 1, false); + int orgnr = 0; while (*nrline != NUL) { // The wordnr was stored in a minimal nr of bytes as an offset to the // previous wordnr. @@ -2888,7 +2857,7 @@ static void add_sound_suggest(suginfo_T *su, char *goodword, int score, langp_T wordcount += wc; } - theword[wlen] = byts[n + i]; + theword[wlen] = (char)byts[n + i]; n = idxs[n + i]; } badword: @@ -2896,8 +2865,8 @@ badword: // Go over the possible flags and regions. for (; i <= byts[n] && byts[n + i] == NUL; i++) { - char_u cword[MAXWLEN]; - char_u *p; + char cword[MAXWLEN]; + char *p; int flags = (int)idxs[n + i]; // Skip words with the NOSUGGEST flag @@ -2907,13 +2876,13 @@ badword: if (flags & WF_KEEPCAP) { // Must find the word in the keep-case tree. - find_keepcap_word(slang, (char *)theword, (char *)cword); + find_keepcap_word(slang, theword, cword); p = cword; } else { flags |= su->su_badflags; if ((flags & WF_CAPMASK) != 0) { // Need to fix case according to "flags". - make_case_word((char *)theword, (char *)cword, flags); + make_case_word(theword, cword, flags); p = cword; } else { p = theword; @@ -2924,7 +2893,7 @@ badword: if (sps_flags & SPS_DOUBLE) { // Add the suggestion if the score isn't too bad. if (score <= su->su_maxscore) { - add_suggestion(su, &su->su_sga, (char *)p, su->su_badlen, + add_suggestion(su, &su->su_sga, p, su->su_badlen, score, 0, false, slang, false); } } else { @@ -2940,9 +2909,9 @@ badword: // lower to upper case. Helps for "tath" -> "Kath", which is // less common than "tath" -> "path". Don't do it when the // letter is the same, that has already been counted. - gc = utf_ptr2char((char *)p); + gc = utf_ptr2char(p); if (SPELL_ISUPPER(gc)) { - bc = utf_ptr2char((char *)su->su_badword); + bc = utf_ptr2char(su->su_badword); if (!SPELL_ISUPPER(bc) && SPELL_TOFOLD(bc) != SPELL_TOFOLD(gc)) { goodscore += SCORE_ICASE / 2; @@ -2958,10 +2927,9 @@ badword: // inefficient, using an array is quicker. limit = MAXSCORE(su->su_sfmaxscore - goodscore, score); if (limit > SCORE_LIMITMAX) { - goodscore += spell_edit_score(slang, (char_u *)su->su_badword, p); + goodscore += spell_edit_score(slang, su->su_badword, p); } else { - goodscore += spell_edit_score_limit(slang, (char_u *)su->su_badword, - p, limit); + goodscore += spell_edit_score_limit(slang, su->su_badword, p, limit); } // When going over the limit don't bother to do the rest. @@ -2972,7 +2940,7 @@ badword: // Add the suggestion if the score isn't too bad. goodscore = RESCORE(goodscore, score); if (goodscore <= su->su_sfmaxscore) { - add_suggestion(su, &su->su_ga, (char *)p, su->su_badlen, + add_suggestion(su, &su->su_ga, p, su->su_badlen, goodscore, score, true, slang, true); } } @@ -2982,27 +2950,23 @@ badword: } /// Find word "word" in fold-case tree for "slang" and return the word number. -static int soundfold_find(slang_T *slang, char_u *word) +static int soundfold_find(slang_T *slang, char *word) { idx_T arridx = 0; - int len; int wlen = 0; - int c; - char_u *ptr = word; - char_u *byts; - idx_T *idxs; + char_u *ptr = (char_u *)word; int wordnr = 0; - byts = (char_u *)slang->sl_sbyts; - idxs = slang->sl_sidxs; + char_u *byts = (char_u *)slang->sl_sbyts; + idx_T *idxs = slang->sl_sidxs; for (;;) { // First byte is the number of possible bytes. - len = byts[arridx++]; + int len = byts[arridx++]; // If the first possible byte is a zero the word could end here. // If the word ends we found the word. If not skip the NUL bytes. - c = ptr[wlen]; + int c = ptr[wlen]; if (byts[arridx] == NUL) { if (c == NUL) { break; @@ -3065,7 +3029,7 @@ static bool similar_chars(slang_T *slang, int c1, int c2) hashitem_T *hi; if (c1 >= 256) { - buf[utf_char2bytes(c1, (char *)buf)] = 0; + buf[utf_char2bytes(c1, buf)] = 0; hi = hash_find(&slang->sl_map_hash, buf); if (HASHITEM_EMPTY(hi)) { m1 = 0; @@ -3080,7 +3044,7 @@ static bool similar_chars(slang_T *slang, int c1, int c2) } if (c2 >= 256) { - buf[utf_char2bytes(c2, (char *)buf)] = 0; + buf[utf_char2bytes(c2, buf)] = 0; hi = hash_find(&slang->sl_map_hash, buf); if (HASHITEM_EMPTY(hi)) { m2 = 0; @@ -3213,19 +3177,17 @@ static void add_suggestion(suginfo_T *su, garray_T *gap, const char *goodword, i /// @param gap either su_ga or su_sga static void check_suggestions(suginfo_T *su, garray_T *gap) { - suggest_T *stp; char longword[MAXWLEN + 1]; - int len; hlf_T attr; if (gap->ga_len == 0) { return; } - stp = &SUG(*gap, 0); + suggest_T *stp = &SUG(*gap, 0); for (int i = gap->ga_len - 1; i >= 0; i--) { // Need to append what follows to check for "the the". xstrlcpy(longword, stp[i].st_word, MAXWLEN + 1); - len = stp[i].st_wordlen; + int len = stp[i].st_wordlen; xstrlcpy(longword + len, su->su_badptr + stp[i].st_orglen, (size_t)(MAXWLEN - len + 1)); attr = HLF_COUNT; @@ -3244,18 +3206,14 @@ static void check_suggestions(suginfo_T *su, garray_T *gap) /// Add a word to be banned. static void add_banned(suginfo_T *su, char *word) { - char_u *s; - hash_T hash; - hashitem_T *hi; - - hash = hash_hash(word); + hash_T hash = hash_hash(word); const size_t word_len = strlen(word); - hi = hash_lookup(&su->su_banned, word, word_len, hash); + hashitem_T *hi = hash_lookup(&su->su_banned, word, word_len, hash); if (!HASHITEM_EMPTY(hi)) { // already present return; } - s = xmemdupz(word, word_len); - hash_add_item(&su->su_banned, hi, (char *)s, hash); + char *s = xmemdupz(word, word_len); + hash_add_item(&su->su_banned, hi, s, hash); } /// Recompute the score for all suggestions if sound-folding is possible. This @@ -3273,20 +3231,20 @@ static void rescore_suggestions(suginfo_T *su) static void rescore_one(suginfo_T *su, suggest_T *stp) { slang_T *slang = stp->st_slang; - char_u sal_badword[MAXWLEN]; - char_u *p; + char sal_badword[MAXWLEN]; // Only rescore suggestions that have no sal score yet and do have a // language. if (slang != NULL && !GA_EMPTY(&slang->sl_sal) && !stp->st_had_bonus) { + char_u *p; if (slang == su->su_sallang) { - p = su->su_sal_badword; + p = (char_u *)su->su_sal_badword; } else { - spell_soundfold(slang, (char *)su->su_fbadword, true, (char *)sal_badword); - p = sal_badword; + spell_soundfold(slang, su->su_fbadword, true, sal_badword); + p = (char_u *)sal_badword; } - stp->st_altscore = stp_sal_score(stp, su, slang, p); + stp->st_altscore = stp_sal_score(stp, su, slang, (char *)p); if (stp->st_altscore == SCORE_MAXMAX) { stp->st_altscore = SCORE_BIG; } @@ -3355,9 +3313,6 @@ static int soundalike_score(char *goodstart, char *badstart) { char *goodsound = goodstart; char *badsound = badstart; - int goodlen; - int badlen; - int n; char *pl, *ps; char *pl2, *ps2; int score = 0; @@ -3390,12 +3345,12 @@ static int soundalike_score(char *goodstart, char *badstart) } } - goodlen = (int)strlen(goodsound); - badlen = (int)strlen(badsound); + int goodlen = (int)strlen(goodsound); + int badlen = (int)strlen(badsound); // Return quickly if the lengths are too different to be fixed by two // changes. - n = goodlen - badlen; + int n = goodlen - badlen; if (n < -2 || n > 2) { return SCORE_MAXMAX; } @@ -3575,7 +3530,7 @@ static int soundalike_score(char *goodstart, char *badstart) /// The implementation of the algorithm comes from Aspell editdist.cpp, /// edit_distance(). It has been converted from C++ to C and modified to /// support multi-byte characters. -static int spell_edit_score(slang_T *slang, const char_u *badword, const char_u *goodword) +static int spell_edit_score(slang_T *slang, const char *badword, const char *goodword) { int *cnt; int j, i; @@ -3592,12 +3547,12 @@ static int spell_edit_score(slang_T *slang, const char_u *badword, const char_u // Get the characters from the multi-byte strings and put them in an // int array for easy access. badlen = 0; - for (const char *p = (char *)badword; *p != NUL;) { + for (const char *p = badword; *p != NUL;) { wbadword[badlen++] = mb_cptr2char_adv(&p); } wbadword[badlen++] = 0; goodlen = 0; - for (const char *p = (char *)goodword; *p != NUL;) { + for (const char *p = goodword; *p != NUL;) { wgoodword[goodlen++] = mb_cptr2char_adv(&p); } wgoodword[goodlen++] = 0; @@ -3673,37 +3628,33 @@ typedef struct { /// This uses a stack for the edits still to be tried. /// The idea comes from Aspell leditdist.cpp. Rewritten in C and added support /// for multi-byte characters. -static int spell_edit_score_limit(slang_T *slang, char_u *badword, char_u *goodword, int limit) +static int spell_edit_score_limit(slang_T *slang, char *badword, char *goodword, int limit) { return spell_edit_score_limit_w(slang, badword, goodword, limit); } /// Multi-byte version of spell_edit_score_limit(). /// Keep it in sync with the above! -static int spell_edit_score_limit_w(slang_T *slang, const char_u *badword, const char_u *goodword, +static int spell_edit_score_limit_w(slang_T *slang, const char *badword, const char *goodword, int limit) { limitscore_T stack[10]; // allow for over 3 * 2 edits - int stackidx; - int bi, gi; int bi2, gi2; int bc, gc; - int score; int score_off; - int minscore; int round; int wbadword[MAXWLEN]; int wgoodword[MAXWLEN]; // Get the characters from the multi-byte strings and put them in an // int array for easy access. - bi = 0; - for (const char *p = (char *)badword; *p != NUL;) { + int bi = 0; + for (const char *p = badword; *p != NUL;) { wbadword[bi++] = mb_cptr2char_adv(&p); } wbadword[bi++] = 0; - gi = 0; - for (const char *p = (char *)goodword; *p != NUL;) { + int gi = 0; + for (const char *p = goodword; *p != NUL;) { wgoodword[gi++] = mb_cptr2char_adv(&p); } wgoodword[gi++] = 0; @@ -3715,11 +3666,11 @@ static int spell_edit_score_limit_w(slang_T *slang, const char_u *badword, const // pushed unto a stack and tried later, some are tried right away. At the // end of the word the score for one alternative is known. The lowest // possible score is stored in "minscore". - stackidx = 0; + int stackidx = 0; bi = 0; gi = 0; - score = 0; - minscore = limit + 1; + int score = 0; + int minscore = limit + 1; for (;;) { // Skip over an equal part, score remains the same. diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index a1523f6574..ebaa14c604 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -1,6 +1,5 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -// #include <assert.h> #include <inttypes.h> @@ -38,7 +37,7 @@ #include "nvim/path.h" #include "nvim/pos.h" #include "nvim/screen.h" -#include "nvim/sign_defs.h" +#include "nvim/sign.h" #include "nvim/statusline.h" #include "nvim/strings.h" #include "nvim/types.h" @@ -261,23 +260,17 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler) { static bool entered = false; int attr; - int curattr; int row; int col = 0; int maxwidth; - int width; int n; - int len; int fillchar; char buf[MAXPATHL]; char *stl; - char *p; char *opt_name; int opt_scope = 0; stl_hlrec_t *hltab; StlClickRecord *tabtab; - win_T *ewp; - int p_crb_save; bool is_stl_global = global_stl_height() > 0; ScreenGrid *grid = &default_grid; @@ -370,22 +363,22 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler) // Temporarily reset 'cursorbind', we don't want a side effect from moving // the cursor away and back. - ewp = wp == NULL ? curwin : wp; - p_crb_save = ewp->w_p_crb; + win_T *ewp = wp == NULL ? curwin : wp; + int p_crb_save = ewp->w_p_crb; ewp->w_p_crb = false; // Make a copy, because the statusline may include a function call that // might change the option value and free the memory. stl = xstrdup(stl); - width = build_stl_str_hl(ewp, buf, sizeof(buf), stl, opt_name, opt_scope, - fillchar, maxwidth, &hltab, &tabtab, NULL); + int width = build_stl_str_hl(ewp, buf, sizeof(buf), stl, opt_name, opt_scope, + fillchar, maxwidth, &hltab, &tabtab, NULL); xfree(stl); ewp->w_p_crb = p_crb_save; // Make all characters printable. - p = transstr(buf, true); - len = (int)xstrlcpy(buf, p, sizeof(buf)); + char *p = transstr(buf, true); + int len = (int)xstrlcpy(buf, p, sizeof(buf)); len = (size_t)len < sizeof(buf) ? len : (int)sizeof(buf) - 1; xfree(p); @@ -399,7 +392,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler) // Draw each snippet with the specified highlighting. grid_puts_line_start(grid, row); - curattr = attr; + int curattr = attr; p = buf; for (n = 0; hltab[n].start != NULL; n++) { int textlen = (int)(hltab[n].start - p); @@ -583,7 +576,7 @@ void win_redr_ruler(win_T *wp, bool always) MAXSIZE_TEMP_ARRAY(content, 1); MAXSIZE_TEMP_ARRAY(chunk, 2); ADD_C(chunk, INTEGER_OBJ(attr)); - ADD_C(chunk, STRING_OBJ(cstr_as_string((char *)buffer))); + ADD_C(chunk, STRING_OBJ(cstr_as_string(buffer))); ADD_C(content, ARRAY_OBJ(chunk)); ui_call_msg_ruler(content); did_show_ext_ruler = true; @@ -710,21 +703,9 @@ static void ui_ext_tabline_update(void) /// Draw the tab pages line at the top of the Vim window. void draw_tabline(void) { - int tabcount = 0; - int tabwidth = 0; - int col = 0; - int scol = 0; - int attr; win_T *wp; - win_T *cwp; - int wincount; - int modified; - int c; - int len; int attr_nosel = HL_ATTR(HLF_TP); int attr_fill = HL_ATTR(HLF_TPF); - char *p; - int room; int use_sep_chars = (t_colors < 8); if (default_grid.chars == NULL) { @@ -749,6 +730,14 @@ void draw_tabline(void) if (*p_tal != NUL) { win_redr_custom(NULL, false, false); } else { + int tabcount = 0; + int tabwidth = 0; + int col = 0; + win_T *cwp; + int wincount; + int c; + int len; + char *p; FOR_ALL_TABS(tp) { tabcount++; } @@ -761,7 +750,7 @@ void draw_tabline(void) tabwidth = 6; } - attr = attr_nosel; + int attr = attr_nosel; tabcount = 0; FOR_ALL_TABS(tp) { @@ -769,7 +758,7 @@ void draw_tabline(void) break; } - scol = col; + int scol = col; if (tp == curtab) { cwp = curwin; @@ -792,7 +781,7 @@ void draw_tabline(void) grid_putchar(&default_grid, ' ', 0, col++, attr); - modified = false; + int modified = false; for (wincount = 0; wp != NULL; wp = wp->w_next, wincount++) { if (bufIsChanged(wp->w_buffer)) { @@ -817,7 +806,7 @@ void draw_tabline(void) grid_putchar(&default_grid, ' ', 0, col++, attr); } - room = scol - col + tabwidth - 1; + int room = scol - col + tabwidth - 1; if (room > 0) { // Get buffer name in NameBuff[] get_trans_bufname(cwp->w_buffer); @@ -1092,7 +1081,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n continue; } - // STL_SEPARATE: Separation place between left and right aligned items. + // STL_SEPARATE: Separation between items, filled with white space. if (*fmt_p == STL_SEPARATE) { fmt_p++; // Ignored when we are inside of a grouping @@ -1387,7 +1376,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n NumberBase base = kNumBaseDecimal; bool itemisflag = false; bool fillable = true; - long num = -1; + int num = -1; char *str = NULL; switch (opt) { case STL_FILEPATH: @@ -1517,10 +1506,10 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n // Overload %l with v:lnum for 'statuscolumn' if (opt_name != NULL && strcmp(opt_name, "statuscolumn") == 0) { if (wp->w_p_nu && !get_vim_var_nr(VV_VIRTNUM)) { - num = get_vim_var_nr(VV_LNUM); + num = (int)get_vim_var_nr(VV_LNUM); } } else { - num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ? 0L : (long)(wp->w_cursor.lnum); + num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ? 0L : wp->w_cursor.lnum; } break; @@ -1541,7 +1530,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n ? 0 : (int)wp->w_cursor.col + 1))) { break; } - num = (long)virtcol; + num = virtcol; break; } @@ -1601,8 +1590,8 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n long l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL, false); num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) || l < 0 ? - 0L : l + 1 + ((State & MODE_INSERT) == 0 && empty_line ? - 0 : (int)wp->w_cursor.col); + 0L : (int)l + 1 + ((State & MODE_INSERT) == 0 && empty_line ? + 0 : (int)wp->w_cursor.col); break; } case STL_BYTEVAL_X: @@ -1622,7 +1611,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n // Overload %r with v:relnum for 'statuscolumn' if (opt_name != NULL && strcmp(opt_name, "statuscolumn") == 0) { if (wp->w_p_rnu && !get_vim_var_nr(VV_VIRTNUM)) { - num = get_vim_var_nr(VV_RELNUM); + num = (int)get_vim_var_nr(VV_RELNUM); } } else { itemisflag = true; @@ -1645,20 +1634,40 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n if (stcp == NULL) { break; } - bool fold = opt == STL_FOLDCOL; + int width = fold ? (compute_foldcolumn(wp, 0) > 0) : wp->w_scwidth; + + if (width == 0) { + break; + } + + char *p; + if (fold) { + size_t n = fill_foldcolumn(out_p, wp, stcp->foldinfo, (linenr_T)get_vim_var_nr(VV_LNUM)); + stl_items[curitem].minwid = win_hl_attr(wp, stcp->use_cul ? HLF_CLF : HLF_FC); + p = out_p; + p[n] = NUL; + } + *buf_tmp = NUL; - for (int i = 0; i <= SIGN_SHOW_MAX; i++) { - char *p = fold ? stcp->fold_text : stcp->sign_text[i]; - if ((!p || !*p) && *buf_tmp == NUL) { - break; + varnumber_T virtnum = get_vim_var_nr(VV_VIRTNUM); + for (int i = 0; i <= width; i++) { + if (i == width) { + if (*buf_tmp == NUL) { + break; + } + stl_items[curitem].minwid = 0; + } else if (!fold) { + SignTextAttrs *sattr = virtnum ? NULL : sign_get_attr(i, stcp->sattrs, wp->w_scwidth); + p = sattr && sattr->text ? sattr->text : " "; + stl_items[curitem].minwid = sattr ? stcp->sign_cul_attr ? stcp->sign_cul_attr + : sattr->hl_attr_id + : win_hl_attr(wp, stcp->use_cul ? HLF_CLS : HLF_SC); } stl_items[curitem].type = Highlight; stl_items[curitem].start = out_p + strlen(buf_tmp); - stl_items[curitem].minwid = !p || (fold && i) ? 0 : fold ? stcp->fold_attr - : stcp->sign_attr[i]; curitem++; - if (!p || (fold && i)) { + if (i == width) { str = buf_tmp; break; } @@ -1886,7 +1895,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n // { Reduce the number by base^n while (num_chars-- > maxwid) { - num /= (long)base; + num /= (int)base; } // } @@ -2064,8 +2073,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n int num_separators = 0; for (int i = 0; i < itemcnt; i++) { if (stl_items[i].type == Separate) { - // Create an array of the start location for each - // separator mark. + // Create an array of the start location for each separator mark. stl_separator_locations[num_separators] = i; num_separators++; } @@ -2077,17 +2085,17 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n int final_spaces = (maxwidth - width) - standard_spaces * (num_separators - 1); - for (int i = 0; i < num_separators; i++) { - int dislocation = (i == (num_separators - 1)) ? final_spaces : standard_spaces; + for (int l = 0; l < num_separators; l++) { + int dislocation = (l == (num_separators - 1)) ? final_spaces : standard_spaces; dislocation *= utf_char2len(fillchar); - char *start = stl_items[stl_separator_locations[i]].start; + char *start = stl_items[stl_separator_locations[l]].start; char *seploc = start + dislocation; STRMOVE(seploc, start); for (char *s = start; s < seploc;) { MB_CHAR2BYTES(fillchar, s); } - for (int item_idx = stl_separator_locations[i] + 1; + for (int item_idx = stl_separator_locations[l] + 1; item_idx < itemcnt; item_idx++) { stl_items[item_idx].start += dislocation; diff --git a/src/nvim/statusline_defs.h b/src/nvim/statusline_defs.h index eac9dfd690..6835d62cdd 100644 --- a/src/nvim/statusline_defs.h +++ b/src/nvim/statusline_defs.h @@ -3,7 +3,10 @@ #include <stddef.h> +#include "nvim/fold_defs.h" #include "nvim/macros.h" +#include "nvim/os/os_defs.h" +#include "nvim/sign_defs.h" /// Status line click definition typedef struct { @@ -23,4 +26,54 @@ typedef struct { const char *start; ///< Location where region starts. } StlClickRecord; +/// Used for highlighting in the status line. +typedef struct stl_hlrec stl_hlrec_t; +struct stl_hlrec { + char *start; + int userhl; // 0: no HL, 1-9: User HL, < 0 for syn ID +}; + +/// Used for building the status line. +typedef struct stl_item stl_item_t; +struct stl_item { + // Where the item starts in the status line output buffer + char *start; + // Function to run for ClickFunc items. + char *cmd; + // The minimum width of the item + int minwid; + // The maximum width of the item + int maxwid; + enum { + Normal, + Empty, + Group, + Separate, + Highlight, + TabPage, + ClickFunc, + Trunc, + } type; +}; + +/// Struct to hold info for 'statuscolumn' +typedef struct statuscol statuscol_T; + +struct statuscol { + int width; ///< width of the status column + int cur_attr; ///< current attributes in text + int num_attr; ///< attributes used for line number + int sign_cul_attr; ///< cursorline sign attr + int truncate; ///< truncated width + bool draw; ///< whether to draw the statuscolumn + bool use_cul; ///< whether to use cursorline attrs + char text[MAXPATHL]; ///< text in status column + char *textp; ///< current position in text + char *text_end; ///< end of text (the NUL byte) + stl_hlrec_t *hlrec; ///< highlight groups + stl_hlrec_t *hlrecp; ///< current highlight group + foldinfo_T foldinfo; ///< fold information + SignTextAttrs *sattrs; ///< sign attributes +}; + #endif // NVIM_STATUSLINE_DEFS_H diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 49b63ad324..d4161b9ca2 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -1218,7 +1218,6 @@ static synstate_T *store_current_state(void) // Copy a state stack from "from" in b_sst_array[] to current_state; static void load_current_state(synstate_T *from) { - int i; bufstate_T *bp; clear_current_state(); @@ -1231,7 +1230,7 @@ static void load_current_state(synstate_T *from) } else { bp = from->sst_union.sst_stack; } - for (i = 0; i < from->sst_stacksize; i++) { + for (int i = 0; i < from->sst_stacksize; i++) { CUR_STATE(i).si_idx = bp[i].bs_idx; CUR_STATE(i).si_flags = bp[i].bs_flags; CUR_STATE(i).si_seqnr = bp[i].bs_seqnr; @@ -3441,9 +3440,7 @@ static void syn_list_one(const int id, const bool syncing, const bool link_only) static void syn_list_flags(struct name_list *nlist, int flags, int attr) { - int i; - - for (i = 0; nlist[i].flag != 0; i++) { + for (int i = 0; nlist[i].flag != 0; i++) { if (flags & nlist[i].flag) { msg_puts_attr(nlist[i].name, attr); msg_putchar(' '); @@ -4736,17 +4733,15 @@ static void init_syn_patterns(void) /// @return a pointer to the next argument, or NULL in case of an error. static char *get_syn_pattern(char *arg, synpat_T *ci) { - char *end; int *p; int idx; - char *cpo_save; // need at least three chars if (arg == NULL || arg[0] == NUL || arg[1] == NUL || arg[2] == NUL) { return NULL; } - end = skip_regexp(arg + 1, *arg, true); + char *end = skip_regexp(arg + 1, *arg, true); if (*end != *arg) { // end delimiter not found semsg(_("E401: Pattern delimiter not found: %s"), arg); return NULL; @@ -4755,7 +4750,7 @@ static char *get_syn_pattern(char *arg, synpat_T *ci) ci->sp_pattern = xstrnsave(arg + 1, (size_t)(end - arg) - 1); // Make 'cpoptions' empty, to avoid the 'l' flag - cpo_save = p_cpo; + char *cpo_save = p_cpo; p_cpo = empty_option; ci->sp_prog = vim_regcomp(ci->sp_pattern, RE_MAGIC); p_cpo = cpo_save; @@ -5145,7 +5140,6 @@ static int in_id_list(stateitem_T *cur_si, int16_t *list, struct sp_syn *ssp, in { int retval; int16_t *scl_list; - int16_t item; int16_t id = ssp->id; static int depth = 0; int r; @@ -5181,7 +5175,7 @@ static int in_id_list(stateitem_T *cur_si, int16_t *list, struct sp_syn *ssp, in // If the first item is "ALLBUT", return true if "id" is NOT in the // contains list. We also require that "id" is at the same ":syn include" // level as the list. - item = *list; + int16_t item = *list; if (item >= SYNID_ALLBUT && item < SYNID_CLUSTER) { if (item < SYNID_TOP) { // ALL or ALLBUT: accept all groups in the same file @@ -5291,9 +5285,6 @@ void ex_syntax(exarg_T *eap) void ex_ownsyntax(exarg_T *eap) { - char *old_value; - char *new_value; - if (curwin->w_s == &curwin->w_buffer->b_s) { curwin->w_s = xcalloc(1, sizeof(synblock_T)); hash_init(&curwin->w_s->b_keywtab); @@ -5309,7 +5300,7 @@ void ex_ownsyntax(exarg_T *eap) } // Save value of b:current_syntax. - old_value = get_var_value("b:current_syntax"); + char *old_value = get_var_value("b:current_syntax"); if (old_value != NULL) { old_value = xstrdup(old_value); } @@ -5318,7 +5309,7 @@ void ex_ownsyntax(exarg_T *eap) apply_autocmds(EVENT_SYNTAX, eap->arg, curbuf->b_fname, true, curbuf); // Move value of b:current_syntax to w:current_syntax. - new_value = get_var_value("b:current_syntax"); + char *new_value = get_var_value("b:current_syntax"); if (new_value != NULL) { set_internal_string_var("w:current_syntax", new_value); } @@ -5483,10 +5474,9 @@ int get_syntax_info(int *seqnrp) int syn_get_concealed_id(win_T *wp, linenr_T lnum, colnr_T col) { int seqnr; - int syntax_flags; (void)syn_get_id(wp, lnum, col, false, NULL, false); - syntax_flags = get_syntax_info(&seqnr); + int syntax_flags = get_syntax_info(&seqnr); if (syntax_flags & HL_CONCEAL) { return seqnr; diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 42618e8924..774157831d 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -795,7 +795,6 @@ static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char { taggy_T *tagstack = curwin->w_tagstack; int tagstackidx = curwin->w_tagstackidx; - int i; char *p; char *command_end; tagptrs_T tagp; @@ -821,7 +820,7 @@ static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char taglen_advance(taglen); msg_puts_attr(_("file\n"), HL_ATTR(HLF_T)); - for (i = 0; i < num_matches && !got_int; i++) { + for (int i = 0; i < num_matches && !got_int; i++) { parse_match(matches[i], &tagp); if (!new_tag && ( (g_do_tagpreview != 0 @@ -979,27 +978,21 @@ static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char /// window. static int add_llist_tags(char *tag, int num_matches, char **matches) { - list_T *list; char tag_name[128 + 1]; - char *fname; - char *cmd; - int i; char *p; tagptrs_T tagp; - fname = xmalloc(MAXPATHL + 1); - cmd = xmalloc(CMDBUFFSIZE + 1); - list = tv_list_alloc(0); + char *fname = xmalloc(MAXPATHL + 1); + char *cmd = xmalloc(CMDBUFFSIZE + 1); + list_T *list = tv_list_alloc(0); - for (i = 0; i < num_matches; i++) { - int len, cmd_len; - long lnum; + for (int i = 0; i < num_matches; i++) { dict_T *dict; parse_match(matches[i], &tagp); // Save the tag name - len = (int)(tagp.tagname_end - tagp.tagname); + int len = (int)(tagp.tagname_end - tagp.tagname); if (len > 128) { len = 128; } @@ -1016,7 +1009,7 @@ static int add_llist_tags(char *tag, int num_matches, char **matches) // Get the line number or the search pattern used to locate // the tag. - lnum = 0; + long lnum = 0; if (isdigit((uint8_t)(*tagp.command))) { // Line number is used to locate the tag lnum = atol(tagp.command); @@ -1065,7 +1058,7 @@ static int add_llist_tags(char *tag, int num_matches, char **matches) STRCAT(cmd, "\\V"); len += 2; - cmd_len = (int)(cmd_end - cmd_start + 1); + int cmd_len = (int)(cmd_end - cmd_start + 1); if (cmd_len > (CMDBUFFSIZE - 5)) { cmd_len = CMDBUFFSIZE - 5; } @@ -1124,7 +1117,6 @@ static void taglen_advance(int l) // Print the tag stack void do_tags(exarg_T *eap) { - int i; char *name; taggy_T *tagstack = curwin->w_tagstack; int tagstackidx = curwin->w_tagstackidx; @@ -1132,7 +1124,7 @@ void do_tags(exarg_T *eap) // Highlight title msg_puts_title(_("\n # TO tag FROM line in file/text")); - for (i = 0; i < tagstacklen; i++) { + for (int i = 0; i < tagstacklen; i++) { if (tagstack[i].tagname != NULL) { name = fm_getname(&(tagstack[i].fmark), 30); if (name == NULL) { // file name not available @@ -1162,10 +1154,8 @@ void do_tags(exarg_T *eap) // Make sure case is folded to uppercase in comparison (like for 'sort -f') static int tag_strnicmp(char *s1, char *s2, size_t len) { - int i; - while (len > 0) { - i = TOUPPER_ASC((uint8_t)(*s1)) - TOUPPER_ASC((uint8_t)(*s2)); + int i = TOUPPER_ASC((uint8_t)(*s1)) - TOUPPER_ASC((uint8_t)(*s2)); if (i != 0) { return i; // this character different } @@ -1733,9 +1723,6 @@ static tagmatch_status_T findtags_parse_line(findtags_state_T *st, tagptrs_T *ta tagsearch_info_T *sinfo_p) { int status; - int i; - int cmplen; - int tagcmp; // Figure out where the different strings are in this line. // For "normal" tags: Do a quick check if the tag matches. @@ -1751,7 +1738,7 @@ static tagmatch_status_T findtags_parse_line(findtags_state_T *st, tagptrs_T *ta // Skip this line if the length of the tag is different and // there is no regexp, or the tag is too short. - cmplen = (int)(tagpp->tagname_end - tagpp->tagname); + int cmplen = (int)(tagpp->tagname_end - tagpp->tagname); if (p_tl != 0 && cmplen > p_tl) { // adjust for 'taglength' cmplen = (int)p_tl; } @@ -1762,8 +1749,9 @@ static tagmatch_status_T findtags_parse_line(findtags_state_T *st, tagptrs_T *ta } if (st->state == TS_BINARY) { + int tagcmp; // Simplistic check for unsorted tags file. - i = (int)tagpp->tagname[0]; + int i = (int)tagpp->tagname[0]; if (margs->sortic) { i = TOUPPER_ASC(tagpp->tagname[0]); } @@ -2253,7 +2241,6 @@ static int findtags_copy_matches(findtags_state_T *st, char ***matchesp) const bool name_only = (st->flags & TAG_NAMES); char **matches; int mtt; - int i; char *mfp; char *p; @@ -2264,7 +2251,7 @@ static int findtags_copy_matches(findtags_state_T *st, char ***matchesp) } st->match_count = 0; for (mtt = 0; mtt < MT_COUNT; mtt++) { - for (i = 0; i < st->ga_match[mtt].ga_len; i++) { + for (int i = 0; i < st->ga_match[mtt].ga_len; i++) { mfp = ((char **)(st->ga_match[mtt].ga_data))[i]; if (matches == NULL) { xfree(mfp); @@ -2719,7 +2706,7 @@ static int parse_match(char *lbuf, tagptrs_T *tagp) { int retval; char *p; - char *pc, *pt; + char *pt; tagp->tag_fname = lbuf + 1; lbuf += strlen(tagp->tag_fname) + 2; @@ -2759,7 +2746,7 @@ static int parse_match(char *lbuf, tagptrs_T *tagp) break; } - pc = vim_strchr(p, ':'); + char *pc = vim_strchr(p, ':'); pt = vim_strchr(p, '\t'); if (pc == NULL || (pt != NULL && pc > pt)) { tagp->tagkind = p; @@ -2995,7 +2982,6 @@ static int jumpto_tag(const char *lbuf_arg, int forceit, int keep_help) retval = OK; } else { int found = 1; - char cc; // try again, ignore case now p_ic = true; @@ -3004,7 +2990,7 @@ static int jumpto_tag(const char *lbuf_arg, int forceit, int keep_help) // Failed to find pattern, take a guess: "^func (" found = 2; (void)test_for_static(&tagp); - cc = *tagp.tagname_end; + char cc = *tagp.tagname_end; *tagp.tagname_end = NUL; snprintf(pbuf, LSIZE, "^%s\\s\\*(", tagp.tagname); if (!do_search(NULL, '/', '/', pbuf, (long)1, search_options, NULL)) { @@ -3155,10 +3141,10 @@ static char *expand_tag_fname(char *fname, char *const tag_fname, const bool exp /// file. static int test_for_current(char *fname, char *fname_end, char *tag_fname, char *buf_ffname) { - char c; int retval = false; if (buf_ffname != NULL) { // if the buffer has a name + char c; { c = *fname_end; *fname_end = NUL; @@ -3225,7 +3211,6 @@ static void tagstack_clear_entry(taggy_T *item) /// @param tagnames expand tag names int expand_tags(int tagnames, char *pat, int *num_file, char ***file) { - int i; int extra_flag; char *name_buf; size_t name_buf_size = 100; @@ -3251,7 +3236,7 @@ int expand_tags(int tagnames, char *pat, int *num_file, char ***file) if (ret == OK && !tagnames) { // Reorganize the tags for display and matching as strings of: // "<tagname>\0<kind>\0<filename>\0" - for (i = 0; i < *num_file; i++) { + for (int i = 0; i < *num_file; i++) { size_t len; parse_match((*file)[i], &t_p); @@ -3327,7 +3312,6 @@ int get_tags(list_T *list, char *pat, char *buf_fname) char *full_fname; dict_T *dict; tagptrs_T tp; - bool is_static; ret = find_tags(pat, &num_matches, &matches, TAG_REGEXP | TAG_NOIC, MAXCOL, buf_fname); @@ -3342,7 +3326,7 @@ int get_tags(list_T *list, char *pat, char *buf_fname) (void)parse_result; assert(parse_result == OK); - is_static = test_for_static(&tp); + bool is_static = test_for_static(&tp); // Skip pseudo-tag lines. if (strncmp(tp.tagname, "!_TAG_", 6) == 0) { @@ -3377,7 +3361,7 @@ int get_tags(list_T *list, char *pat, char *buf_fname) // skip "file:" (static tag) p += 4; } else if (!ascii_iswhite(*p)) { - char *s, *n; + char *n; int len; // Add extra field as a dict entry. Fields are @@ -3388,7 +3372,7 @@ int get_tags(list_T *list, char *pat, char *buf_fname) } len = (int)(p - n); if (*p == ':' && len > 0) { - s = ++p; + char *s = ++p; while (*p != NUL && (uint8_t)(*p) >= ' ') { p++; } @@ -3445,17 +3429,13 @@ static void get_tag_details(taggy_T *tag, dict_T *retdict) // 'retdict'. void get_tagstack(win_T *wp, dict_T *retdict) { - list_T *l; - int i; - dict_T *d; - tv_dict_add_nr(retdict, S_LEN("length"), wp->w_tagstacklen); tv_dict_add_nr(retdict, S_LEN("curidx"), wp->w_tagstackidx + 1); - l = tv_list_alloc(2); + list_T *l = tv_list_alloc(2); tv_dict_add_list(retdict, S_LEN("items"), l); - for (i = 0; i < wp->w_tagstacklen; i++) { - d = tv_dict_alloc(); + for (int i = 0; i < wp->w_tagstacklen; i++) { + dict_T *d = tv_dict_alloc(); tv_list_append_dict(l, d); get_tag_details(&wp->w_tagstack[i], d); } diff --git a/src/nvim/testdir/runnvim.sh b/src/nvim/testdir/runnvim.sh index 3a0a94b6bf..4d8ea0527d 100755 --- a/src/nvim/testdir/runnvim.sh +++ b/src/nvim/testdir/runnvim.sh @@ -22,13 +22,11 @@ main() {( i=$(( i+1 )) done - export CI_DIR="$root/ci" BUILD_DIR="$(dirname "$nvim_prg")/.." export BUILD_DIR export FAILED=0 - . "$CI_DIR/common/suite.sh" - . "$CI_DIR/common/test.sh" + . $(dirname $0)/test.sh # Redirect XDG_CONFIG_HOME so users local config doesn't interfere export XDG_CONFIG_HOME="$root" diff --git a/src/nvim/testdir/suite.sh b/src/nvim/testdir/suite.sh new file mode 100644 index 0000000000..bf5a16fd89 --- /dev/null +++ b/src/nvim/testdir/suite.sh @@ -0,0 +1,10 @@ +fail() { + local test_name="$1" + local message="$2" + + : "${message:=Test $test_name failed}" + + local full_msg="$test_name :: $message" + echo "Failed: $full_msg" + export FAILED=1 +} diff --git a/src/nvim/testdir/test.sh b/src/nvim/testdir/test.sh new file mode 100644 index 0000000000..affdc308d1 --- /dev/null +++ b/src/nvim/testdir/test.sh @@ -0,0 +1,91 @@ +fail() { + local test_name="$1" + local message="$2" + + : "${message:=Test $test_name failed}" + + local full_msg="$test_name :: $message" + echo "Failed: $full_msg" + export FAILED=1 +} + +print_core() { + local app="$1" + local core="$2" + if test "$app" = quiet ; then + echo "Found core $core" + return 0 + fi + echo "======= Core file $core =======" + if test "${CI_OS_NAME}" = osx ; then + lldb -Q -o "bt all" -f "${app}" -c "${core}" + else + gdb -n -batch -ex 'thread apply all bt full' "${app}" -c "${core}" + fi +} + +check_core_dumps() { + local del= + if test "$1" = "--delete" ; then + del=1 + shift + fi + local app="${1:-${BUILD_DIR}/bin/nvim}" + local cores + if test "${CI_OS_NAME}" = osx ; then + cores="$(find /cores/ -type f -print)" + local _sudo='sudo' + else + cores="$(find ./ -type f \( -name 'core.*' -o -name core -o -name nvim.core \) -print)" + local _sudo= + fi + + if test -z "${cores}" ; then + return + fi + local core + for core in $cores; do + if test "$del" = "1" ; then + print_core "$app" "$core" >&2 + "$_sudo" rm "$core" + else + print_core "$app" "$core" + fi + done + if test "$app" != quiet ; then + fail 'cores' 'Core dumps found' + fi +} + +check_logs() { + # Iterate through each log to remove an useless warning. + # shellcheck disable=SC2044 + for log in $(find "${1}" -type f -name "${2}"); do + sed -i "${log}" \ + -e '/Warning: noted but unhandled ioctl/d' \ + -e '/could cause spurious value errors to appear/d' \ + -e '/See README_MISSING_SYSCALL_OR_IOCTL for guidance/d' + done + + # Now do it again, but only consider files with size > 0. + local err="" + # shellcheck disable=SC2044 + for log in $(find "${1}" -type f -name "${2}" -size +0); do + cat "${log}" + err=1 + rm "${log}" + done + if test -n "${err}" ; then + fail 'logs' 'Runtime errors detected.' + fi +} + +valgrind_check() { + check_logs "${1}" "valgrind-*" +} + +check_sanitizer() { + if test -n "${CLANG_SANITIZER}"; then + check_logs "${1}" "*san.*" | cat + fi +} diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 83af0f6be0..30d30c8b29 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -1897,6 +1897,64 @@ func Test_Cmdline() call assert_equal(':', g:entered) au! CmdlineChanged + autocmd CmdlineChanged : let g:log += [getcmdline()] + + let g:log = [] + cnoremap <F1> <Cmd>call setcmdline('ls')<CR> + call feedkeys(":\<F1>", 'xt') + call assert_equal(['ls'], g:log) + cunmap <F1> + + let g:log = [] + call feedkeys(":sign \<Tab>\<Tab>\<C-N>\<C-P>\<S-Tab>\<S-Tab>\<Esc>", 'xt') + call assert_equal([ + \ 's', + \ 'si', + \ 'sig', + \ 'sign', + \ 'sign ', + \ 'sign define', + \ 'sign jump', + \ 'sign list', + \ 'sign jump', + \ 'sign define', + \ 'sign ', + \ ], g:log) + let g:log = [] + set wildmenu wildoptions+=pum + call feedkeys(":sign \<S-Tab>\<PageUp>\<kPageUp>\<kPageDown>\<PageDown>\<Esc>", 'xt') + call assert_equal([ + \ 's', + \ 'si', + \ 'sig', + \ 'sign', + \ 'sign ', + \ 'sign unplace', + \ 'sign jump', + \ 'sign define', + \ 'sign undefine', + \ 'sign unplace', + \ ], g:log) + set wildmenu& wildoptions& + + let g:log = [] + let @r = 'abc' + call feedkeys(":0\<C-R>r1\<C-R>\<C-O>r2\<C-R>\<C-R>r3\<Esc>", 'xt') + call assert_equal([ + \ '0', + \ '0a', + \ '0ab', + \ '0abc', + \ '0abc1', + \ '0abc1abc', + \ '0abc1abc2', + \ '0abc1abc2abc', + \ '0abc1abc2abc3', + \ ], g:log) + + unlet g:log + au! CmdlineChanged + au! CmdlineEnter : let g:entered = expand('<afile>') au! CmdlineLeave : let g:left = expand('<afile>') let g:entered = 0 diff --git a/src/nvim/testdir/test_environ.vim b/src/nvim/testdir/test_environ.vim index d8344817f5..b5dbdce104 100644 --- a/src/nvim/testdir/test_environ.vim +++ b/src/nvim/testdir/test_environ.vim @@ -73,7 +73,7 @@ func Test_mac_locale() " If $LANG is not set then the system locale will be used. " Run Vim after unsetting all the locale environmental vars, and capture the " output of :lang. - let lang_results = system("unset LANG; unset LC_MESSAGES; " .. + let lang_results = system("unset LANG; unset LC_MESSAGES; unset LC_CTYPE; " .. \ shellescape(v:progpath) .. \ " --clean -esX -c 'redir @a' -c 'lang' -c 'put a' -c 'print' -c 'qa!' ") diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 7b5ec22dd4..0264e203d9 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -211,6 +211,7 @@ let s:filename_checks = { \ 'fsh': ['file.fsh'], \ 'fsharp': ['file.fs', 'file.fsi', 'file.fsx'], \ 'fstab': ['fstab', 'mtab'], + \ 'func': ['file.fc'], \ 'fusion': ['file.fusion'], \ 'fvwm': ['/.fvwm/file', 'any/.fvwm/file'], \ 'gdb': ['.gdbinit', 'gdbinit', 'file.gdb', '.config/gdbearlyinit', '.gdbearlyinit'], @@ -235,7 +236,7 @@ let s:filename_checks = { \ 'gnuplot': ['file.gpi', '.gnuplot'], \ 'go': ['file.go'], \ 'gomod': ['go.mod'], - \ 'gosum': ['go.sum'], + \ 'gosum': ['go.sum', 'go.work.sum'], \ 'gowork': ['go.work'], \ 'gp': ['file.gp', '.gprc'], \ 'gpg': ['/.gnupg/options', '/.gnupg/gpg.conf', '/usr/any/gnupg/options.skel', 'any/.gnupg/gpg.conf', 'any/.gnupg/options', 'any/usr/any/gnupg/options.skel'], @@ -380,6 +381,7 @@ let s:filename_checks = { \ 'monk': ['file.isc', 'file.monk', 'file.ssc', 'file.tsc'], \ 'moo': ['file.moo'], \ 'moonscript': ['file.moon'], + \ 'move': ['file.move'], \ 'mp': ['file.mp', 'file.mpxl', 'file.mpiv', 'file.mpvi'], \ 'mplayerconf': ['mplayer.conf', '/.mplayer/config', 'any/.mplayer/config'], \ 'mrxvtrc': ['mrxvtrc', '.mrxvtrc'], @@ -489,6 +491,7 @@ let s:filename_checks = { \ 'rnoweb': ['file.rnw', 'file.snw'], \ 'robot': ['file.robot', 'file.resource'], \ 'robots': ['robots.txt'], + \ 'ron': ['file.ron'], \ 'routeros': ['file.rsc'], \ 'rpcgen': ['file.x'], \ 'rpl': ['file.rpl'], @@ -522,6 +525,7 @@ let s:filename_checks = { \ 'sinda': ['file.sin', 'file.s85'], \ 'sisu': ['file.sst', 'file.ssm', 'file.ssi', 'file.-sst', 'file._sst', 'file.sst.meta', 'file.-sst.meta', 'file._sst.meta'], \ 'skill': ['file.il', 'file.ils', 'file.cdf'], + \ 'cdc': ['file.cdc'], \ 'slang': ['file.sl'], \ 'slice': ['file.ice'], \ 'slpconf': ['/etc/slp.conf', 'any/etc/slp.conf'], diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index 500c30c76b..4ed1187a19 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -1511,7 +1511,7 @@ endfunc func Test_setbufvar_options() " This tests that aucmd_prepbuf() and aucmd_restbuf() properly restore the - " window layout. + " window layout and cursor position. call assert_equal(1, winnr('$')) split dummy_preview resize 2 @@ -1525,11 +1525,20 @@ func Test_setbufvar_options() execute 'belowright vertical split #' . dummy_buf call assert_equal(wh, winheight(0)) let dum1_id = win_getid() + call setline(1, 'foo') + normal! V$ + call assert_equal(4, col('.')) + call setbufvar('dummy_preview', '&buftype', 'nofile') + call assert_equal(4, col('.')) wincmd h let wh = winheight(0) + call setline(1, 'foo') + normal! V$ + call assert_equal(4, col('.')) let dummy_buf = bufnr('dummy_buf2', v:true) eval 'nofile'->setbufvar(dummy_buf, '&buftype') + call assert_equal(4, col('.')) execute 'belowright vertical split #' . dummy_buf call assert_equal(wh, winheight(0)) diff --git a/src/nvim/testdir/test_hlsearch.vim b/src/nvim/testdir/test_hlsearch.vim index cf2791113a..043d378a39 100644 --- a/src/nvim/testdir/test_hlsearch.vim +++ b/src/nvim/testdir/test_hlsearch.vim @@ -1,5 +1,8 @@ " Test for v:hlsearch +source check.vim +source screendump.vim + func Test_hlsearch() new call setline(1, repeat(['aaa'], 10)) @@ -63,3 +66,23 @@ func Test_hlsearch_eol_highlight() set nohlsearch bwipe! endfunc + +func Test_hlsearch_Ctrl_R() + CheckRunVimInTerminal + + let lines =<< trim END + set incsearch hlsearch + let @" = "text" + put + END + call writefile(lines, 'XhlsearchCtrlR', 'D') + let buf = RunVimInTerminal('-S XhlsearchCtrlR', #{rows: 6, cols: 60}) + + call term_sendkeys(buf, "/\<C-R>\<C-R>\"") + call VerifyScreenDump(buf, 'Test_hlsearch_ctrlr_1', {}) + + call term_sendkeys(buf, "\<Esc>") + call StopVimInTerminal(buf) +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_move.vim b/src/nvim/testdir/test_move.vim index 8c40369dbd..40d75d887e 100644 --- a/src/nvim/testdir/test_move.vim +++ b/src/nvim/testdir/test_move.vim @@ -1,5 +1,8 @@ " Test the ":move" command. +source check.vim +source screendump.vim + func Test_move() enew! call append(0, ['line 1', 'line 2', 'line 3']) @@ -43,4 +46,25 @@ func Test_move() %bwipeout! endfunc +func Test_move_undo() + CheckRunVimInTerminal + + let lines =<< trim END + call setline(1, ['First', 'Second', 'Third', 'Fourth']) + END + call writefile(lines, 'Xtest_move_undo.vim', 'D') + let buf = RunVimInTerminal('-S Xtest_move_undo.vim', #{rows: 10, cols: 60, statusoff: 2}) + + call term_sendkeys(buf, "gg:move +1\<CR>") + call VerifyScreenDump(buf, 'Test_move_undo_1', {}) + + " here the display would show the last few lines scrolled down + call term_sendkeys(buf, "u") + call term_sendkeys(buf, ":\<Esc>") + call VerifyScreenDump(buf, 'Test_move_undo_2', {}) + + call StopVimInTerminal(buf) +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index f51de94bac..43cc3632e6 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -434,6 +434,8 @@ func Test_set_errors() call assert_fails('set fileencoding=latin1', 'E21:') set modifiable& " call assert_fails('set t_#-&', 'E522:') + call assert_fails('let &formatoptions = "?"', 'E539:') + call assert_fails('call setbufvar("", "&formatoptions", "?")', 'E539:') endfunc func CheckWasSet(name) @@ -1300,5 +1302,44 @@ func Test_endoffile_default() call delete('Xtestout') endfunc +" Test for setting the 'lines' and 'columns' options to a minimum value +func Test_set_min_lines_columns() + let save_lines = &lines + let save_columns = &columns + + let after =<< trim END + set laststatus=1 + set nomore + let msg = [] + let v:errmsg = '' + silent! let &columns=0 + call add(msg, v:errmsg) + silent! set columns=0 + call add(msg, v:errmsg) + silent! call setbufvar('', '&columns', 0) + call add(msg, v:errmsg) + "call writefile(msg, 'XResultsetminlines') + silent! let &lines=0 + call add(msg, v:errmsg) + silent! set lines=0 + call add(msg, v:errmsg) + silent! call setbufvar('', '&lines', 0) + call add(msg, v:errmsg) + call writefile(msg, 'XResultsetminlines') + qall! + END + if RunVim([], after, '') + call assert_equal(['E594: Need at least 12 columns', + \ 'E594: Need at least 12 columns: columns=0', + \ 'E594: Need at least 12 columns', + \ 'E593: Need at least 2 lines', + \ 'E593: Need at least 2 lines: lines=0', + \ 'E593: Need at least 2 lines',], readfile('XResultsetminlines')) + endif + + call delete('XResultsetminlines') + let &lines = save_lines + let &columns = save_columns +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_statusline.vim b/src/nvim/testdir/test_statusline.vim index 990c852ccd..1e06ad1c67 100644 --- a/src/nvim/testdir/test_statusline.vim +++ b/src/nvim/testdir/test_statusline.vim @@ -231,6 +231,10 @@ func Test_statusline() " %=: Separation point between left and right aligned items. set statusline=foo%=bar call assert_match('^foo\s\+bar\s*$', s:get_statusline()) + set statusline=foo%=bar%=baz + call assert_match('^foo\s\+bar\s\+baz\s*$', s:get_statusline()) + set statusline=foo%=bar%=baz%=qux + call assert_match('^foo\s\+bar\s\+baz\s\+qux\s*$', s:get_statusline()) " Test min/max width, leading zeroes, left/right justify. set statusline=%04B diff --git a/src/nvim/testing.c b/src/nvim/testing.c index b5921b3445..3569856f2c 100644 --- a/src/nvim/testing.c +++ b/src/nvim/testing.c @@ -395,12 +395,12 @@ static int assert_equalfile(typval_T *argvars) char line2[200]; ptrdiff_t lineidx = 0; if (fd1 == NULL) { - snprintf(IObuff, IOSIZE, (char *)e_notread, fname1); + snprintf(IObuff, IOSIZE, e_notread, fname1); } else { FILE *const fd2 = os_fopen(fname2, READBIN); if (fd2 == NULL) { fclose(fd1); - snprintf(IObuff, IOSIZE, (char *)e_notread, fname2); + snprintf(IObuff, IOSIZE, e_notread, fname2); } else { int64_t linecount = 1; for (int64_t count = 0;; count++) { diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c index e30580a748..05e57e4b8f 100644 --- a/src/nvim/textformat.c +++ b/src/nvim/textformat.c @@ -72,7 +72,7 @@ bool has_format_option(int x) void internal_format(int textwidth, int second_indent, int flags, bool format_only, int c) { int cc; - int save_char = NUL; + char save_char = NUL; bool haveto_redraw = false; const bool fo_ins_blank = has_format_option(FO_INS_BLANK); const bool fo_multibyte = has_format_option(FO_MBYTE_BREAK); @@ -93,7 +93,7 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on && !(State & VREPLACE_FLAG)) { cc = gchar_cursor(); if (ascii_iswhite(cc)) { - save_char = cc; + save_char = (char)cc; pchar_cursor('x'); } } @@ -458,7 +458,7 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on } if (save_char != NUL) { // put back space after cursor - pchar_cursor((char_u)save_char); + pchar_cursor(save_char); } curwin->w_p_lbr = has_lbr; @@ -633,19 +633,16 @@ static bool paragraph_start(linenr_T lnum) /// @param prev_line may start in previous line void auto_format(bool trailblank, bool prev_line) { - pos_T pos; colnr_T len; - char *old; char *new, *pnew; - int wasatend; int cc; if (!has_format_option(FO_AUTO)) { return; } - pos = curwin->w_cursor; - old = get_cursor_line_ptr(); + pos_T pos = curwin->w_cursor; + char *old = get_cursor_line_ptr(); // may remove added space check_auto_format(false); @@ -655,7 +652,7 @@ void auto_format(bool trailblank, bool prev_line) // in 'formatoptions' and there is a single character before the cursor. // Otherwise the line would be broken and when typing another non-white // next they are not joined back together. - wasatend = (pos.col == (colnr_T)strlen(old)); + int wasatend = (pos.col == (colnr_T)strlen(old)); if (*old != NUL && !trailblank && wasatend) { dec_cursor(); cc = gchar_cursor(); @@ -733,18 +730,16 @@ void auto_format(bool trailblank, bool prev_line) /// @param end_insert true when ending Insert mode void check_auto_format(bool end_insert) { - int c = ' '; - int cc; - if (!did_add_space) { return; } - cc = gchar_cursor(); + int cc = gchar_cursor(); if (!WHITECHAR(cc)) { // Somehow the space was removed already. did_add_space = false; } else { + int c = ' '; if (!end_insert) { inc_cursor(); c = gchar_cursor(); @@ -886,7 +881,6 @@ void op_formatexpr(oparg_T *oap) int fex_format(linenr_T lnum, long count, int c) { int use_sandbox = was_set_insecurely(curwin, "formatexpr", OPT_LOCAL); - int r; // 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). @@ -900,7 +894,7 @@ int fex_format(linenr_T lnum, long count, int c) if (use_sandbox) { sandbox++; } - r = (int)eval_to_number(fex); + int r = (int)eval_to_number(fex); if (use_sandbox) { sandbox--; } diff --git a/src/nvim/textobject.c b/src/nvim/textobject.c index 8e786c271c..37f893ecec 100644 --- a/src/nvim/textobject.c +++ b/src/nvim/textobject.c @@ -176,7 +176,6 @@ found: bool findpar(bool *pincl, int dir, long count, int what, bool both) { linenr_T curr; - bool did_skip; // true after separating lines have been skipped bool first; // true on first line linenr_T fold_first; // first line of a closed fold linenr_T fold_last; // last line of a closed fold @@ -186,7 +185,7 @@ bool findpar(bool *pincl, int dir, long count, int what, bool both) curr = curwin->w_cursor.lnum; while (count--) { - did_skip = false; + bool did_skip = false; // true after separating lines have been skipped for (first = true;; first = false) { if (*ml_get(curr) != NUL) { did_skip = true; @@ -324,10 +323,6 @@ static int cls(void) /// @param bigword "W", "E" or "B" int fwd_word(long count, bool bigword, bool eol) { - int sclass; // starting class - int i; - int last_line; - curwin->w_cursor.coladd = 0; cls_bigword = bigword; while (--count >= 0) { @@ -336,12 +331,12 @@ int fwd_word(long count, bool bigword, bool eol) if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { coladvance(MAXCOL); } - sclass = cls(); + int sclass = cls(); // starting class // We always move at least one character, unless on the last // character in the buffer. - last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count); - i = inc_cursor(); + int last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count); + int i = inc_cursor(); if (i == -1 || (i >= 1 && last_line)) { // started at last char in file return FAIL; } @@ -493,13 +488,11 @@ finished: /// @return FAIL if start of the file was reached. int bckend_word(long count, bool bigword, bool eol) { - int sclass; // starting class - int i; - curwin->w_cursor.coladd = 0; cls_bigword = bigword; while (--count >= 0) { - sclass = cls(); + int i; + int sclass = cls(); // starting class if ((i = dec_cursor()) == -1) { return FAIL; } @@ -562,10 +555,8 @@ static void back_in_line(void) static void find_first_blank(pos_T *posp) { - int c; - while (decl(posp) != -1) { - c = gchar_pos(posp); + int c = gchar_pos(posp); if (!ascii_iswhite(c)) { incl(posp); break; @@ -598,7 +589,6 @@ static void findsent_forward(long count, bool at_start_sent) int current_word(oparg_T *oap, long count, bool include, bool bigword) { pos_T start_pos; - pos_T pos; bool inclusive = true; int include_white = false; @@ -703,7 +693,7 @@ int current_word(oparg_T *oap, long count, bool include, bool bigword) // word). Also when "2daw" deletes "word." at the end of the line // (cursor is at start of next line). // But don't delete white space at start of line (indent). - pos = curwin->w_cursor; // save cursor position + pos_T pos = curwin->w_cursor; // save cursor position curwin->w_cursor = start_pos; if (oneleft() == OK) { back_in_line(); @@ -1042,7 +1032,6 @@ static bool in_html_tag(bool end_tag) { char *line = get_cursor_line_ptr(); char *p; - int c; int lc = NUL; pos_T pos; @@ -1078,7 +1067,7 @@ static bool in_html_tag(bool end_tag) if (inc(&pos) < 0) { return false; } - c = (uint8_t)(*ml_get_pos(&pos)); + int c = (uint8_t)(*ml_get_pos(&pos)); if (c == '>') { break; } @@ -1443,10 +1432,8 @@ extend: /// @return column number of "quotechar" or -1 when not found. static int find_next_quote(char *line, int col, int quotechar, char *escape) { - int c; - for (;;) { - c = (uint8_t)line[col]; + int c = (uint8_t)line[col]; if (c == NUL) { return -1; } else if (escape != NULL && vim_strchr(escape, c)) { @@ -1471,12 +1458,10 @@ static int find_next_quote(char *line, int col, int quotechar, char *escape) /// @return the found column or zero. static int find_prev_quote(char *line, int col_start, int quotechar, char *escape) { - int n; - while (col_start > 0) { col_start--; col_start -= utf_head_off(line, line + col_start); - n = 0; + int n = 0; if (escape != NULL) { while (col_start - n > 0 && vim_strchr(escape, (uint8_t)line[col_start - n - 1]) != NULL) { diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 733aa25f03..c992253e1f 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -185,8 +185,9 @@ void tinput_stop(TermInput *input) } static void tinput_done_event(void **argv) + FUNC_ATTR_NORETURN { - input_done(); + os_exit(1); } static void tinput_wait_enqueue(void **argv) diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index f760e99262..f7bc931e21 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -34,15 +34,17 @@ #include "nvim/msgpack_rpc/channel.h" #include "nvim/os/input.h" #include "nvim/os/os.h" -#include "nvim/ui_client.h" -#ifdef MSWIN -# include "nvim/os/os_win_console.h" -#endif #include "nvim/tui/input.h" #include "nvim/tui/terminfo.h" #include "nvim/tui/tui.h" #include "nvim/ugrid.h" #include "nvim/ui.h" +#include "nvim/ui_client.h" + +#ifdef MSWIN +# include "nvim/os/os_win_console.h" +# include "nvim/os/tty.h" +#endif // Space reserved in two output buffers to make the cursor normal or invisible // when flushing. No existing terminal will require 32 bytes to do that. @@ -165,7 +167,7 @@ static bool cursor_style_enabled = false; # include "tui/tui.c.generated.h" #endif -TUIData *tui_start(int *width, int *height, char **term) +void tui_start(TUIData **tui_p, int *width, int *height, char **term) { TUIData *tui = xcalloc(1, sizeof(TUIData)); tui->is_starting = true; @@ -188,11 +190,11 @@ TUIData *tui_start(int *width, int *height, char **term) uv_timer_start(&tui->startup_delay_timer, after_startup_cb, 100, 0); + *tui_p = tui; loop_poll_events(&main_loop, 1); *width = tui->width; *height = tui->height; *term = tui->term; - return tui; } void tui_enable_extkeys(TUIData *tui) @@ -458,9 +460,6 @@ static void tui_terminal_stop(TUIData *tui) void tui_stop(TUIData *tui) { - if (tui->stopped) { - return; - } tui_terminal_stop(tui); stream_set_blocking(tui->input.in_fd, true); // normalize stream (#2598) tinput_destroy(&tui->input); @@ -470,7 +469,7 @@ void tui_stop(TUIData *tui) } /// Returns true if UI `ui` is stopped. -static bool tui_is_stopped(TUIData *tui) +bool tui_is_stopped(TUIData *tui) { return tui->stopped; } diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 9f1cb87eb0..1693595ce8 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -11,6 +11,7 @@ #include "klib/kvec.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/validate.h" #include "nvim/api/ui.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" @@ -419,7 +420,7 @@ void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol, (const sattr_T *)grid->attrs + off); // 'writedelay': flush & delay each time. - if (p_wd && !(rdb_flags & RDB_COMPOSITOR)) { + if (p_wd && (rdb_flags & RDB_LINE)) { // If 'writedelay' is active, set the cursor to indicate what was drawn. ui_call_grid_cursor_goto(grid->handle, row, MIN(clearcol, (int)grid->cols - 1)); @@ -472,11 +473,6 @@ int ui_current_col(void) return cursor_col; } -handle_T ui_cursor_grid(void) -{ - return cursor_grid_handle; -} - void ui_flush(void) { assert(!ui_client_channel_id); @@ -510,6 +506,10 @@ void ui_flush(void) pending_has_mouse = has_mouse; } ui_call_flush(); + + if (p_wd && (rdb_flags & RDB_FLUSH)) { + os_microdelay((uint64_t)labs(p_wd) * 1000U, true); + } } /// Check if 'mouse' is active for the current mode @@ -609,7 +609,7 @@ Array ui_array(void) return all_uis; } -void ui_grid_resize(handle_T grid_handle, int width, int height, Error *error) +void ui_grid_resize(handle_T grid_handle, int width, int height, Error *err) { if (grid_handle == DEFAULT_GRID_HANDLE) { screen_resize(width, height); @@ -617,11 +617,9 @@ void ui_grid_resize(handle_T grid_handle, int width, int height, Error *error) } win_T *wp = get_win_by_grid_handle(grid_handle); - if (wp == NULL) { - api_set_error(error, kErrorTypeValidation, - "No window with the given handle"); + VALIDATE_INT((wp != NULL), "window handle", (int64_t)grid_handle, { return; - } + }); if (wp->w_floating) { if (width != wp->w_width || height != wp->w_height) { diff --git a/src/nvim/ui.h b/src/nvim/ui.h index 9140a9f1f3..e83f93eb07 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -79,6 +79,8 @@ typedef struct { uint32_t ncalls; ///< number of calls made to the current event (plus one for the name!) bool flushed_events; ///< events where sent to client without "flush" event + size_t ncells_pending; ///< total number of cells since last buffer flush + int hl_id; // Current highlight for legacy put event. Integer cursor_row, cursor_col; // Intended visible cursor position. diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c index b5c8dff412..df0a26c6ee 100644 --- a/src/nvim/ui_client.c +++ b/src/nvim/ui_client.c @@ -22,6 +22,10 @@ #include "nvim/ui.h" #include "nvim/ui_client.h" +#ifdef MSWIN +# include "nvim/os/os_win_console.h" +#endif + static TUIData *tui = NULL; static bool ui_client_is_remote = false; @@ -31,7 +35,6 @@ static bool ui_client_is_remote = false; # include "ui_events_client.generated.h" #endif // uncrustify:on -// uint64_t ui_client_start_server(int argc, char **argv) { @@ -110,7 +113,7 @@ void ui_client_run(bool remote_ui) ui_client_is_remote = remote_ui; int width, height; char *term; - tui = tui_start(&width, &height, &term); + tui_start(&tui, &width, &height, &term); ui_client_attach(width, height, term); @@ -122,7 +125,9 @@ void ui_client_run(bool remote_ui) void ui_client_stop(void) { - tui_stop(tui); + if (!tui_is_stopped(tui)) { + tui_stop(tui); + } } void ui_client_set_size(int width, int height) diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c index ef13f67e49..3a5a4c3e91 100644 --- a/src/nvim/usercmd.c +++ b/src/nvim/usercmd.c @@ -298,8 +298,8 @@ const char *set_context_in_user_cmdarg(const char *cmd FUNC_ATTR_UNUSED, const c return arg; } if (context == EXPAND_MAPPINGS) { - return (const char *)set_context_in_map_cmd(xp, "map", (char *)arg, forceit, false, false, - CMD_map); + return set_context_in_map_cmd(xp, "map", (char *)arg, forceit, false, false, + CMD_map); } // Find start of last argument. const char *p = arg; @@ -531,15 +531,13 @@ static void uc_list(char *name, size_t name_len) if (a & (EX_RANGE | EX_COUNT)) { if (a & EX_COUNT) { // -count=N - snprintf(IObuff + len, IOSIZE, "%" PRId64 "c", - (int64_t)cmd->uc_def); + snprintf(IObuff + len, IOSIZE, "%" PRId64 "c", cmd->uc_def); len += (int)strlen(IObuff + len); } else if (a & EX_DFLALL) { IObuff[len++] = '%'; } else if (cmd->uc_def >= 0) { // -range=N - snprintf(IObuff + len, IOSIZE, "%" PRId64 "", - (int64_t)cmd->uc_def); + snprintf(IObuff + len, IOSIZE, "%" PRId64 "", cmd->uc_def); len += (int)strlen(IObuff + len); } else { IObuff[len++] = '.'; @@ -862,9 +860,9 @@ char *uc_validate_name(char *name) /// This function takes ownership of compl_arg, compl_luaref, and luaref. /// /// @return OK if the command is created, FAIL otherwise. -int uc_add_command(char *name, size_t name_len, const char *rep, uint32_t argt, long def, int flags, - int compl, char *compl_arg, LuaRef compl_luaref, LuaRef preview_luaref, - cmd_addr_T addr_type, LuaRef luaref, bool force) +int uc_add_command(char *name, size_t name_len, const char *rep, uint32_t argt, int64_t def, + int flags, int compl, char *compl_arg, LuaRef compl_luaref, + LuaRef preview_luaref, cmd_addr_T addr_type, LuaRef luaref, bool force) FUNC_ATTR_NONNULL_ARG(1, 3) { ucmd_T *cmd = NULL; @@ -1540,13 +1538,13 @@ static size_t uc_check_code(char *code, size_t len, char *buf, ucmd_T *cmd, exar case ct_RANGE: case ct_COUNT: { char num_buf[20]; - long num = (type == ct_LINE1) ? eap->line1 : - (type == ct_LINE2) ? eap->line2 : - (type == ct_RANGE) ? eap->addr_count : - (eap->addr_count > 0) ? eap->line2 : cmd->uc_def; + int64_t num = (type == ct_LINE1) ? eap->line1 : + (type == ct_LINE2) ? eap->line2 : + (type == ct_RANGE) ? eap->addr_count : + (eap->addr_count > 0) ? eap->line2 : cmd->uc_def; size_t num_len; - snprintf(num_buf, sizeof(num_buf), "%" PRId64, (int64_t)num); + snprintf(num_buf, sizeof(num_buf), "%" PRId64, num); num_len = strlen(num_buf); result = num_len; @@ -1751,8 +1749,8 @@ Dictionary commands_array(buf_T *buf) Dictionary d = ARRAY_DICT_INIT; ucmd_T *cmd = USER_CMD_GA(gap, i); - PUT(d, "name", STRING_OBJ(cstr_to_string((char *)cmd->uc_name))); - PUT(d, "definition", STRING_OBJ(cstr_to_string((char *)cmd->uc_rep))); + PUT(d, "name", STRING_OBJ(cstr_to_string(cmd->uc_name))); + PUT(d, "definition", STRING_OBJ(cstr_to_string(cmd->uc_rep))); PUT(d, "script_id", INTEGER_OBJ(cmd->uc_script_ctx.sc_sid)); PUT(d, "bang", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_BANG))); PUT(d, "bar", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_TRLBAR))); @@ -1778,12 +1776,12 @@ Dictionary commands_array(buf_T *buf) PUT(d, "complete", (cmd_compl == NULL ? NIL : STRING_OBJ(cstr_to_string(cmd_compl)))); PUT(d, "complete_arg", cmd->uc_compl_arg == NULL - ? NIL : STRING_OBJ(cstr_to_string((char *)cmd->uc_compl_arg))); + ? NIL : STRING_OBJ(cstr_to_string(cmd->uc_compl_arg))); Object obj = NIL; if (cmd->uc_argt & EX_COUNT) { if (cmd->uc_def >= 0) { - snprintf(str, sizeof(str), "%" PRId64, (int64_t)cmd->uc_def); + snprintf(str, sizeof(str), "%" PRId64, cmd->uc_def); obj = STRING_OBJ(cstr_to_string(str)); // -count=N } else { obj = STRING_OBJ(cstr_to_string("0")); // -count @@ -1796,7 +1794,7 @@ Dictionary commands_array(buf_T *buf) if (cmd->uc_argt & EX_DFLALL) { obj = STRING_OBJ(cstr_to_string("%")); // -range=% } else if (cmd->uc_def >= 0) { - snprintf(str, sizeof(str), "%" PRId64, (int64_t)cmd->uc_def); + snprintf(str, sizeof(str), "%" PRId64, cmd->uc_def); obj = STRING_OBJ(cstr_to_string(str)); // -range=N } else { obj = STRING_OBJ(cstr_to_string(".")); // -range @@ -1814,7 +1812,7 @@ Dictionary commands_array(buf_T *buf) } PUT(d, "addr", obj); - PUT(rv, (char *)cmd->uc_name, DICTIONARY_OBJ(d)); + PUT(rv, cmd->uc_name, DICTIONARY_OBJ(d)); } return rv; } diff --git a/src/nvim/usercmd.h b/src/nvim/usercmd.h index b6bf6c1e33..0d9838abf2 100644 --- a/src/nvim/usercmd.h +++ b/src/nvim/usercmd.h @@ -12,7 +12,7 @@ typedef struct ucmd { char *uc_name; // The command name uint32_t uc_argt; // The argument type char *uc_rep; // The command's replacement string - long uc_def; // The default value for a range/count + int64_t uc_def; // The default value for a range/count int uc_compl; // completion type cmd_addr_T uc_addr_type; // The command's address type sctx_T uc_script_ctx; // SCTX where the command was defined diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 3c765f8eb2..00e28e3e68 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -195,7 +195,6 @@ enum { FOLD_TEXT_LEN = 51, }; //!< buffer size for get_foldtext() #define CLEAR_FIELD(field) memset(&(field), 0, sizeof(field)) #define CLEAR_POINTER(ptr) memset((ptr), 0, sizeof(*(ptr))) -// defines to avoid typecasts from (char_u *) to (char *) and back // (vim_strchr() is now in strings.c) #ifndef HAVE_STRNLEN diff --git a/src/nvim/window.c b/src/nvim/window.c index 6b40ccdb84..c6694cd489 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -358,14 +358,13 @@ newwindow: msg(_(m_onlyone)); } else { tabpage_T *oldtab = curtab; - tabpage_T *newtab; // First create a new tab with the window, then go back to // the old tab and close the window there. win_T *wp = curwin; if (win_new_tabpage((int)Prenum, NULL) == OK && valid_tabpage(oldtab)) { - newtab = curtab; + tabpage_T *newtab = curtab; goto_tabpage_tp(oldtab, true, true); if (curwin == wp) { win_close(curwin, false, false); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000000..dc74838760 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,96 @@ +add_subdirectory(functional/fixtures) # compile test programs +get_directory_property(GENERATED_HELP_TAGS DIRECTORY ${PROJECT_SOURCE_DIR}/runtime DEFINITION GENERATED_HELP_TAGS) + +if(NOT BUSTED_OUTPUT_TYPE) + set(BUSTED_OUTPUT_TYPE "nvim") +endif() + +find_program(BUSTED_PRG NAMES busted busted.bat) +if(BUSTED_PRG) + get_target_property(TEST_INCLUDE_DIRS main_lib INTERFACE_INCLUDE_DIRECTORIES) + + set(UNITTEST_PREREQS nvim) + set(FUNCTIONALTEST_PREREQS nvim printenv-test printargs-test shell-test pwsh-test streams-test tty-test ${GENERATED_HELP_TAGS}) + set(BENCHMARK_PREREQS nvim tty-test) + + check_lua_module(${LUA_PRG} "ffi" LUA_HAS_FFI) + if(LUA_HAS_FFI) + add_custom_target(unittest + COMMAND ${CMAKE_COMMAND} + -D BUSTED_PRG=${BUSTED_PRG} + -D LUA_PRG=${LUA_PRG} + -D NVIM_PRG=$<TARGET_FILE:nvim> + -D WORKING_DIR=${PROJECT_SOURCE_DIR} + -D BUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} + -D TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR} + -D BUILD_DIR=${CMAKE_BINARY_DIR} + -D TEST_TYPE=unit + -D CIRRUS_CI=$ENV{CIRRUS_CI} + -D CI_BUILD=${CI_BUILD} + -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake + DEPENDS ${UNITTEST_PREREQS} + USES_TERMINAL) + set_target_properties(unittest PROPERTIES FOLDER test) + else() + message(WARNING "disabling unit tests: no Luajit FFI in ${LUA_PRG}") + endif() + + configure_file( + ${CMAKE_SOURCE_DIR}/test/cmakeconfig/paths.lua.in + ${CMAKE_BINARY_DIR}/test/cmakeconfig/paths.lua) + + add_custom_target(functionaltest + COMMAND ${CMAKE_COMMAND} + -D BUSTED_PRG=${BUSTED_PRG} + -D LUA_PRG=${LUA_PRG} + -D NVIM_PRG=$<TARGET_FILE:nvim> + -D WORKING_DIR=${PROJECT_SOURCE_DIR} + -D BUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} + -D TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR} + -D BUILD_DIR=${CMAKE_BINARY_DIR} + -D DEPS_PREFIX=${DEPS_PREFIX} + -D TEST_TYPE=functional + -D CIRRUS_CI=$ENV{CIRRUS_CI} + -D CI_BUILD=${CI_BUILD} + -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake + DEPENDS ${FUNCTIONALTEST_PREREQS} + USES_TERMINAL) + set_target_properties(functionaltest PROPERTIES FOLDER test) + + add_custom_target(benchmark + COMMAND ${CMAKE_COMMAND} + -D BUSTED_PRG=${BUSTED_PRG} + -D LUA_PRG=${LUA_PRG} + -D NVIM_PRG=$<TARGET_FILE:nvim> + -D WORKING_DIR=${PROJECT_SOURCE_DIR} + -D BUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} + -D TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR} + -D BUILD_DIR=${CMAKE_BINARY_DIR} + -D TEST_TYPE=benchmark + -D CIRRUS_CI=$ENV{CIRRUS_CI} + -D CI_BUILD=${CI_BUILD} + -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake + DEPENDS ${BENCHMARK_PREREQS} + USES_TERMINAL) + set_target_properties(benchmark PROPERTIES FOLDER test) +endif() + +find_program(BUSTED_LUA_PRG busted-lua) +if(BUSTED_LUA_PRG) + add_custom_target(functionaltest-lua + COMMAND ${CMAKE_COMMAND} + -D BUSTED_PRG=${BUSTED_LUA_PRG} + -D LUA_PRG=${LUA_PRG} + -D NVIM_PRG=$<TARGET_FILE:nvim> + -D WORKING_DIR=${PROJECT_SOURCE_DIR} + -D BUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} + -D TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR} + -D BUILD_DIR=${CMAKE_BINARY_DIR} + -D TEST_TYPE=functional + -D CIRRUS_CI=$ENV{CIRRUS_CI} + -D CI_BUILD=${CI_BUILD} + -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake + DEPENDS ${FUNCTIONALTEST_PREREQS} + USES_TERMINAL) + set_target_properties(functionaltest-lua PROPERTIES FOLDER test) +endif() diff --git a/test/busted_runner.lua b/test/busted_runner.lua index b195ce3cc5..62d1e611e7 100644 --- a/test/busted_runner.lua +++ b/test/busted_runner.lua @@ -1 +1,12 @@ +local platform = vim.loop.os_uname() +if platform and platform.sysname:lower():find'windows' then + local deps_prefix = os.getenv 'DEPS_PREFIX' + if deps_prefix ~= nil and deps_prefix ~= "" then + package.path = deps_prefix.."/share/lua/5.1/?.lua;"..deps_prefix.."/share/lua/5.1/?/init.lua;"..package.path + package.path = deps_prefix.."/bin/lua/?.lua;"..deps_prefix.."/bin/lua/?/init.lua;"..package.path + package.cpath = deps_prefix.."/lib/lua/5.1/?.dll;"..package.cpath; + package.cpath = deps_prefix.."/bin/?.dll;"..deps_prefix.."/bin/loadall.dll;"..package.cpath; + end +end + require 'busted.runner'({ standalone = false }) diff --git a/test/client/msgpack_rpc_stream.lua b/test/client/msgpack_rpc_stream.lua new file mode 100644 index 0000000000..5711616b17 --- /dev/null +++ b/test/client/msgpack_rpc_stream.lua @@ -0,0 +1,112 @@ +local mpack = require('mpack') + +-- temporary hack to be able to manipulate buffer/window/tabpage +local Buffer = {} +Buffer.__index = Buffer +function Buffer.new(id) return setmetatable({id=id}, Buffer) end +local Window = {} +Window.__index = Window +function Window.new(id) return setmetatable({id=id}, Window) end +local Tabpage = {} +Tabpage.__index = Tabpage +function Tabpage.new(id) return setmetatable({id=id}, Tabpage) end + +local Response = {} +Response.__index = Response + +function Response.new(msgpack_rpc_stream, request_id) + return setmetatable({ + _msgpack_rpc_stream = msgpack_rpc_stream, + _request_id = request_id + }, Response) +end + +function Response:send(value, is_error) + local data = self._msgpack_rpc_stream._session:reply(self._request_id) + if is_error then + data = data .. self._msgpack_rpc_stream._pack(value) + data = data .. self._msgpack_rpc_stream._pack(mpack.NIL) + else + data = data .. self._msgpack_rpc_stream._pack(mpack.NIL) + data = data .. self._msgpack_rpc_stream._pack(value) + end + self._msgpack_rpc_stream._stream:write(data) +end + +local MsgpackRpcStream = {} +MsgpackRpcStream.__index = MsgpackRpcStream + +function MsgpackRpcStream.new(stream) + return setmetatable({ + _stream = stream, + _pack = mpack.Packer({ + ext = { + [Buffer] = function(o) return 0, mpack.encode(o.id) end, + [Window] = function(o) return 1, mpack.encode(o.id) end, + [Tabpage] = function(o) return 2, mpack.encode(o.id) end + } + }), + _session = mpack.Session({ + unpack = mpack.Unpacker({ + ext = { + [0] = function(_c, s) return Buffer.new(mpack.decode(s)) end, + [1] = function(_c, s) return Window.new(mpack.decode(s)) end, + [2] = function(_c, s) return Tabpage.new(mpack.decode(s)) end + } + }) + }), + }, MsgpackRpcStream) +end + +function MsgpackRpcStream:write(method, args, response_cb) + local data + if response_cb then + assert(type(response_cb) == 'function') + data = self._session:request(response_cb) + else + data = self._session:notify() + end + + data = data .. self._pack(method) .. self._pack(args) + self._stream:write(data) +end + +function MsgpackRpcStream:read_start(request_cb, notification_cb, eof_cb) + self._stream:read_start(function(data) + if not data then + return eof_cb() + end + local type, id_or_cb, method_or_error, args_or_result + local pos = 1 + local len = #data + while pos <= len do + type, id_or_cb, method_or_error, args_or_result, pos = + self._session:receive(data, pos) + if type == 'request' or type == 'notification' then + if type == 'request' then + request_cb(method_or_error, args_or_result, Response.new(self, + id_or_cb)) + else + notification_cb(method_or_error, args_or_result) + end + elseif type == 'response' then + if method_or_error == mpack.NIL then + method_or_error = nil + else + args_or_result = nil + end + id_or_cb(method_or_error, args_or_result) + end + end + end) +end + +function MsgpackRpcStream:read_stop() + self._stream:read_stop() +end + +function MsgpackRpcStream:close(signal) + self._stream:close(signal) +end + +return MsgpackRpcStream diff --git a/test/client/session.lua b/test/client/session.lua new file mode 100644 index 0000000000..0509fa88be --- /dev/null +++ b/test/client/session.lua @@ -0,0 +1,192 @@ +local uv = require('luv') +local MsgpackRpcStream = require('test.client.msgpack_rpc_stream') + +local Session = {} +Session.__index = Session +if package.loaded['jit'] then + -- luajit pcall is already coroutine safe + Session.safe_pcall = pcall +else + Session.safe_pcall = require'coxpcall'.pcall +end + +local function resume(co, ...) + local status, result = coroutine.resume(co, ...) + + if coroutine.status(co) == 'dead' then + if not status then + error(result) + end + return + end + + assert(coroutine.status(co) == 'suspended') + result(co) +end + +local function coroutine_exec(func, ...) + local args = {...} + local on_complete + + if #args > 0 and type(args[#args]) == 'function' then + -- completion callback + on_complete = table.remove(args) + end + + resume(coroutine.create(function() + local status, result, flag = Session.safe_pcall(func, unpack(args)) + if on_complete then + coroutine.yield(function() + -- run the completion callback on the main thread + on_complete(status, result, flag) + end) + end + end)) +end + +function Session.new(stream) + return setmetatable({ + _msgpack_rpc_stream = MsgpackRpcStream.new(stream), + _pending_messages = {}, + _prepare = uv.new_prepare(), + _timer = uv.new_timer(), + _is_running = false + }, Session) +end + +function Session:next_message(timeout) + local function on_request(method, args, response) + table.insert(self._pending_messages, {'request', method, args, response}) + uv.stop() + end + + local function on_notification(method, args) + table.insert(self._pending_messages, {'notification', method, args}) + uv.stop() + end + + if self._is_running then + error('Event loop already running') + end + + if #self._pending_messages > 0 then + return table.remove(self._pending_messages, 1) + end + + self:_run(on_request, on_notification, timeout) + return table.remove(self._pending_messages, 1) +end + +function Session:notify(method, ...) + self._msgpack_rpc_stream:write(method, {...}) +end + +function Session:request(method, ...) + local args = {...} + local err, result + if self._is_running then + err, result = self:_yielding_request(method, args) + else + err, result = self:_blocking_request(method, args) + end + + if err then + return false, err + end + + return true, result +end + +function Session:run(request_cb, notification_cb, setup_cb, timeout) + local function on_request(method, args, response) + coroutine_exec(request_cb, method, args, function(status, result, flag) + if status then + response:send(result, flag) + else + response:send(result, true) + end + end) + end + + local function on_notification(method, args) + coroutine_exec(notification_cb, method, args) + end + + self._is_running = true + + if setup_cb then + coroutine_exec(setup_cb) + end + + while #self._pending_messages > 0 do + local msg = table.remove(self._pending_messages, 1) + if msg[1] == 'request' then + on_request(msg[2], msg[3], msg[4]) + else + on_notification(msg[2], msg[3]) + end + end + + self:_run(on_request, on_notification, timeout) + self._is_running = false +end + +function Session:stop() + uv.stop() +end + +function Session:close(signal) + if not self._timer:is_closing() then self._timer:close() end + if not self._prepare:is_closing() then self._prepare:close() end + self._msgpack_rpc_stream:close(signal) +end + +function Session:_yielding_request(method, args) + return coroutine.yield(function(co) + self._msgpack_rpc_stream:write(method, args, function(err, result) + resume(co, err, result) + end) + end) +end + +function Session:_blocking_request(method, args) + local err, result + + local function on_request(method_, args_, response) + table.insert(self._pending_messages, {'request', method_, args_, response}) + end + + local function on_notification(method_, args_) + table.insert(self._pending_messages, {'notification', method_, args_}) + end + + self._msgpack_rpc_stream:write(method, args, function(e, r) + err = e + result = r + uv.stop() + end) + + self:_run(on_request, on_notification) + return (err or self.eof_err), result +end + +function Session:_run(request_cb, notification_cb, timeout) + if type(timeout) == 'number' then + self._prepare:start(function() + self._timer:start(timeout, 0, function() + uv.stop() + end) + self._prepare:stop() + end) + end + self._msgpack_rpc_stream:read_start(request_cb, notification_cb, function() + uv.stop() + self.eof_err = {1, "EOF was received from Nvim. Likely the Nvim process crashed."} + end) + uv.run() + self._prepare:stop() + self._timer:stop() + self._msgpack_rpc_stream:read_stop() +end + +return Session diff --git a/test/client/uv_stream.lua b/test/client/uv_stream.lua new file mode 100644 index 0000000000..cea77f0dbd --- /dev/null +++ b/test/client/uv_stream.lua @@ -0,0 +1,169 @@ +local uv = require('luv') + +local StdioStream = {} +StdioStream.__index = StdioStream + +function StdioStream.open() + local self = setmetatable({ + _in = uv.new_pipe(false), + _out = uv.new_pipe(false) + }, StdioStream) + self._in:open(0) + self._out:open(1) + return self +end + +function StdioStream:write(data) + self._out:write(data) +end + +function StdioStream:read_start(cb) + self._in:read_start(function(err, chunk) + if err then + error(err) + end + cb(chunk) + end) +end + +function StdioStream:read_stop() + self._in:read_stop() +end + +function StdioStream:close() + self._in:close() + self._out:close() +end + +local SocketStream = {} +SocketStream.__index = SocketStream + +function SocketStream.open(file) + local socket = uv.new_pipe(false) + local self = setmetatable({ + _socket = socket, + _stream_error = nil + }, SocketStream) + uv.pipe_connect(socket, file, function (err) + self._stream_error = self._stream_error or err + end) + return self +end + +function SocketStream.connect(host, port) + local socket = uv.new_tcp() + local self = setmetatable({ + _socket = socket, + _stream_error = nil + }, SocketStream) + uv.tcp_connect(socket, host, port, function (err) + self._stream_error = self._stream_error or err + end) + return self +end + + +function SocketStream:write(data) + if self._stream_error then + error(self._stream_error) + end + uv.write(self._socket, data, function(err) + if err then + error(self._stream_error or err) + end + end) +end + +function SocketStream:read_start(cb) + if self._stream_error then + error(self._stream_error) + end + uv.read_start(self._socket, function(err, chunk) + if err then + error(err) + end + cb(chunk) + end) +end + +function SocketStream:read_stop() + if self._stream_error then + error(self._stream_error) + end + uv.read_stop(self._socket) +end + +function SocketStream:close() + uv.close(self._socket) +end + +local ChildProcessStream = {} +ChildProcessStream.__index = ChildProcessStream + +function ChildProcessStream.spawn(argv, env, io_extra) + local self = setmetatable({ + _child_stdin = uv.new_pipe(false); + _child_stdout = uv.new_pipe(false); + _exiting = false; + }, ChildProcessStream) + local prog = argv[1] + local args = {} + for i = 2, #argv do + args[#args + 1] = argv[i] + end + self._proc, self._pid = uv.spawn(prog, { + stdio = {self._child_stdin, self._child_stdout, 2, io_extra}, + args = args, + env = env, + }, function(status, signal) + self.status = status + self.signal = signal + end) + + if not self._proc then + local err = self._pid + error(err) + end + + return self +end + +function ChildProcessStream:write(data) + self._child_stdin:write(data) +end + +function ChildProcessStream:read_start(cb) + self._child_stdout:read_start(function(err, chunk) + if err then + error(err) + end + cb(chunk) + end) +end + +function ChildProcessStream:read_stop() + self._child_stdout:read_stop() +end + +function ChildProcessStream:close(signal) + if self._closed then + return + end + self._closed = true + self:read_stop() + self._child_stdin:close() + self._child_stdout:close() + if type(signal) == 'string' then + self._proc:kill('sig'..signal) + end + while self.status == nil do + uv.run 'once' + end + return self.status, self.signal +end + +return { + StdioStream = StdioStream; + ChildProcessStream = ChildProcessStream; + SocketStream = SocketStream; +} diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua index 22a1311ee9..f10f18174e 100644 --- a/test/functional/api/autocmd_spec.lua +++ b/test/functional/api/autocmd_spec.lua @@ -14,14 +14,31 @@ before_each(clear) describe('autocmd api', function() describe('nvim_create_autocmd', function() - it('"command" and "callback" are mutually exclusive', function() - local rv = pcall_err(meths.create_autocmd, "BufReadPost", { - pattern = "*.py,*.pyi", + it('validation', function() + eq("Cannot use both 'callback' and 'command'", pcall_err(meths.create_autocmd, 'BufReadPost', { + pattern = '*.py,*.pyi', command = "echo 'Should Have Errored", - callback = "NotAllowed", - }) - - eq("specify either 'callback' or 'command', not both", rv) + callback = 'NotAllowed', + })) + eq("Cannot use both 'pattern' and 'buffer' for the same autocmd", pcall_err(meths.create_autocmd, 'FileType', { + command = 'let g:called = g:called + 1', + buffer = 0, + pattern = '*.py', + })) + eq("Required: 'event'", pcall_err(meths.create_autocmd, {}, { + command = 'ls', + })) + eq("Required: 'command' or 'callback'", pcall_err(meths.create_autocmd, 'FileType', { + })) + eq('Invalid desc: expected String, got Integer', pcall_err(meths.create_autocmd, 'FileType', { + command = 'ls', + desc = 42, + })) + eq('Invalid callback: expected Lua function or Vim function name, got Integer', pcall_err(meths.create_autocmd, 'FileType', { + callback = 0, + })) + eq("Invalid 'event' item: expected String, got Array", pcall_err(meths.create_autocmd, + {'FileType', {}}, {})) end) it('doesnt leak when you use ++once', function() @@ -59,18 +76,8 @@ describe('autocmd api', function() eq(1, meths.get_var('called')) end) - it('does not allow passing buffer and patterns', function() - local rv = pcall_err(meths.create_autocmd, "Filetype", { - command = "let g:called = g:called + 1", - buffer = 0, - pattern = "*.py", - }) - - eq("cannot pass both: 'pattern' and 'buffer' for the same autocmd", rv) - end) - it('does not allow passing invalid buffers', function() - local ok, msg = pcall(meths.create_autocmd, "Filetype", { + local ok, msg = pcall(meths.create_autocmd, 'FileType', { command = "let g:called = g:called + 1", buffer = -1, }) @@ -295,7 +302,7 @@ describe('autocmd api', function() describe('nvim_get_autocmds', function() describe('events', function() - it('should return one autocmd when there is only one for an event', function() + it('returns one autocmd when there is only one for an event', function() command [[au! InsertEnter]] command [[au InsertEnter * :echo "1"]] @@ -303,7 +310,7 @@ describe('autocmd api', function() eq(1, #aus) end) - it('should return two autocmds when there are two for an event', function() + it('returns two autocmds when there are two for an event', function() command [[au! InsertEnter]] command [[au InsertEnter * :echo "1"]] command [[au InsertEnter * :echo "2"]] @@ -312,7 +319,7 @@ describe('autocmd api', function() eq(2, #aus) end) - it('should return the same thing if you use string or list', function() + it('returns the same thing if you use string or list', function() command [[au! InsertEnter]] command [[au InsertEnter * :echo "1"]] command [[au InsertEnter * :echo "2"]] @@ -322,7 +329,7 @@ describe('autocmd api', function() eq(string_aus, array_aus) end) - it('should return two autocmds when there are two for an event', function() + it('returns two autocmds when there are two for an event', function() command [[au! InsertEnter]] command [[au! InsertLeave]] command [[au InsertEnter * :echo "1"]] @@ -332,7 +339,7 @@ describe('autocmd api', function() eq(2, #aus) end) - it('should return different IDs for different autocmds', function() + it('returns different IDs for different autocmds', function() command [[au! InsertEnter]] command [[au! InsertLeave]] command [[au InsertEnter * :echo "1"]] @@ -356,7 +363,7 @@ describe('autocmd api', function() eq(first, new_aus[1]) end) - it('should return event name', function() + it('returns event name', function() command [[au! InsertEnter]] command [[au InsertEnter * :echo "1"]] @@ -364,7 +371,7 @@ describe('autocmd api', function() eq({ { buflocal = false, command = ':echo "1"', event = "InsertEnter", once = false, pattern = "*" } }, aus) end) - it('should work with buffer numbers', function() + it('works with buffer numbers', function() command [[new]] command [[au! InsertEnter]] command [[au InsertEnter <buffer=1> :echo "1"]] @@ -407,8 +414,8 @@ describe('autocmd api', function() pattern = "<buffer=2>", }}, aus) - eq("Invalid value for 'buffer': must be an integer or array of integers", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = "foo" })) - eq("Invalid value for 'buffer': must be an integer", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { "foo", 42 } })) + eq("Invalid buffer: expected Integer or Array, got String", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = "foo" })) + eq("Invalid buffer: expected Integer, got String", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { "foo", 42 } })) eq("Invalid buffer id: 42", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { 42 } })) local bufs = {} @@ -416,10 +423,10 @@ describe('autocmd api', function() table.insert(bufs, meths.create_buf(true, false)) end - eq("Too many buffers. Please limit yourself to 256 or fewer", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = bufs })) + eq("Too many buffers (maximum of 256)", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = bufs })) end) - it('should return autocmds when group is specified by id', function() + it('returns autocmds when group is specified by id', function() local auid = meths.create_augroup("nvim_test_augroup", { clear = true }) meths.create_autocmd("FileType", { group = auid, command = 'echo "1"' }) meths.create_autocmd("FileType", { group = auid, command = 'echo "2"' }) @@ -431,7 +438,7 @@ describe('autocmd api', function() eq(0, #aus2) end) - it('should return autocmds when group is specified by name', function() + it('returns autocmds when group is specified by name', function() local auname = "nvim_test_augroup" meths.create_augroup(auname, { clear = true }) meths.create_autocmd("FileType", { group = auname, command = 'echo "1"' }) @@ -531,7 +538,7 @@ describe('autocmd api', function() command [[augroup END]] end) - it('should return all groups if no group is specified', function() + it('returns all groups if no group is specified', function() local aus = meths.get_autocmds { event = "InsertEnter" } if #aus ~= 4 then eq({}, aus) @@ -540,7 +547,7 @@ describe('autocmd api', function() eq(4, #aus) end) - it('should return only the group specified', function() + it('returns only the group specified', function() local aus = meths.get_autocmds { event = "InsertEnter", group = "GroupOne", @@ -551,7 +558,7 @@ describe('autocmd api', function() eq("GroupOne", aus[1].group_name) end) - it('should return only the group specified, multiple values', function() + it('returns only the group specified, multiple values', function() local aus = meths.get_autocmds { event = "InsertEnter", group = "GroupTwo", @@ -578,7 +585,7 @@ describe('autocmd api', function() ]], {})) eq(false, success) - matches('invalid augroup: NotDefined', code) + matches("Invalid group: 'NotDefined'", code) end) it('raises error for undefined augroup id', function() @@ -596,7 +603,7 @@ describe('autocmd api', function() ]], {})) eq(false, success) - matches('invalid augroup: 1', code) + matches('Invalid group: 1', code) end) it('raises error for invalid group type', function() @@ -611,7 +618,7 @@ describe('autocmd api', function() ]], {})) eq(false, success) - matches("'group' must be a string or an integer", code) + matches("Invalid group: expected String or Integer, got Boolean", code) end) it('raises error for invalid pattern array', function() @@ -625,7 +632,7 @@ describe('autocmd api', function() ]], {})) eq(false, success) - matches("All entries in 'pattern' must be strings", code) + matches("Invalid 'pattern' item: expected String, got Array", code) end) end) @@ -640,7 +647,7 @@ describe('autocmd api', function() command [[au InsertEnter <buffer> :echo "Buffer"]] end) - it('should should return for literal match', function() + it('returns for literal match', function() local aus = meths.get_autocmds { event = "InsertEnter", pattern = "*" @@ -650,7 +657,7 @@ describe('autocmd api', function() eq([[:echo "No Group"]], aus[1].command) end) - it('should return for multiple matches', function() + it('returns for multiple matches', function() -- vim.api.nvim_get_autocmds local aus = meths.get_autocmds { event = "InsertEnter", @@ -687,6 +694,23 @@ describe('autocmd api', function() end) describe('nvim_exec_autocmds', function() + it('validation', function() + eq('Invalid group: 9997999', pcall_err(meths.exec_autocmds, 'FileType', { + group = 9997999, + })) + eq("Invalid group: 'bogus'", pcall_err(meths.exec_autocmds, 'FileType', { + group = 'bogus', + })) + eq('Invalid group: expected String or Integer, got Array', pcall_err(meths.exec_autocmds, 'FileType', { + group = {}, + })) + eq('Invalid buffer: expected Integer, got Array', pcall_err(meths.exec_autocmds, 'FileType', { + buffer = {}, + })) + eq("Invalid 'event' item: expected String, got Array", pcall_err(meths.exec_autocmds, + {'FileType', {}}, {})) + end) + it("can trigger builtin autocmds", function() meths.set_var("autocmd_executed", false) @@ -1036,7 +1060,7 @@ describe('autocmd api', function() local augroup = "WillBeDeleted" meths.create_augroup(augroup, { clear = true }) - meths.create_autocmd({"Filetype"}, { + meths.create_autocmd({"FileType"}, { pattern = "*", command = "echo 'does not matter'", }) @@ -1055,7 +1079,7 @@ describe('autocmd api', function() meths.set_var("value_set", false) meths.create_augroup(augroup, { clear = true }) - meths.create_autocmd("Filetype", { + meths.create_autocmd("FileType", { pattern = "<buffer>", command = "let g:value_set = v:true", }) @@ -1171,6 +1195,16 @@ describe('autocmd api', function() end) describe('nvim_clear_autocmds', function() + it('validation', function() + eq("Cannot use both 'pattern' and 'buffer'", pcall_err(meths.clear_autocmds, { + pattern = '*', + buffer = 42, + })) + eq("Invalid 'event' item: expected String, got Array", pcall_err(meths.clear_autocmds, { + event = {'FileType', {}} + })) + end) + it('should clear based on event + pattern', function() command('autocmd InsertEnter *.py :echo "Python can be cool sometimes"') command('autocmd InsertEnter *.txt :echo "Text Files Are Cool"') diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index 6b13729994..d454765edb 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -193,7 +193,7 @@ describe('api/buf', function() it('fails correctly when input is not valid', function() eq(1, api.curbufmeths.get_number()) - eq([[String cannot contain newlines]], + eq([['replacement string' item contains newlines]], pcall_err(bufmeths.set_lines, 1, 1, 2, false, {'b\na'})) end) @@ -553,20 +553,20 @@ describe('api/buf', function() insert([[ hello foo! text]]) - eq('start_row out of bounds', pcall_err(set_text, 2, 0, 3, 0, {})) - eq('start_row out of bounds', pcall_err(set_text, -3, 0, 0, 0, {})) - eq('end_row out of bounds', pcall_err(set_text, 0, 0, 2, 0, {})) - eq('end_row out of bounds', pcall_err(set_text, 0, 0, -3, 0, {})) - eq('start_col out of bounds', pcall_err(set_text, 1, 5, 1, 5, {})) - eq('end_col out of bounds', pcall_err(set_text, 1, 0, 1, 5, {})) + eq("Invalid 'start_row': out of range", pcall_err(set_text, 2, 0, 3, 0, {})) + eq("Invalid 'start_row': out of range", pcall_err(set_text, -3, 0, 0, 0, {})) + eq("Invalid 'end_row': out of range", pcall_err(set_text, 0, 0, 2, 0, {})) + eq("Invalid 'end_row': out of range", pcall_err(set_text, 0, 0, -3, 0, {})) + eq("Invalid 'start_col': out of range", pcall_err(set_text, 1, 5, 1, 5, {})) + eq("Invalid 'end_col': out of range", pcall_err(set_text, 1, 0, 1, 5, {})) end) it('errors when start is greater than end', function() insert([[ hello foo! text]]) - eq('start is higher than end', pcall_err(set_text, 1, 0, 0, 0, {})) - eq('start is higher than end', pcall_err(set_text, 0, 1, 0, 0, {})) + eq("'start' is higher than 'end'", pcall_err(set_text, 1, 0, 0, 0, {})) + eq("'start' is higher than 'end'", pcall_err(set_text, 0, 1, 0, 0, {})) end) it('no heap-use-after-free when called consecutively #19643', function() @@ -611,7 +611,7 @@ describe('api/buf', function() end) it('errors when start is greater than end', function() - eq('start is higher than end', pcall_err(get_text, 1, 0, 0, 0, {})) + eq("'start' is higher than 'end'", pcall_err(get_text, 1, 0, 0, 0, {})) eq('start_col must be less than end_col', pcall_err(get_text, 0, 1, 0, 0, {})) end) end) diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua index d5f06c8f1f..1510d31945 100644 --- a/test/functional/api/buffer_updates_spec.lua +++ b/test/functional/api/buffer_updates_spec.lua @@ -762,7 +762,7 @@ describe('API: buffer events:', function() it('returns a proper error on nonempty options dict', function() clear() local b = editoriginal(false) - eq("unexpected key: builtin", pcall_err(buffer, 'attach', b, false, {builtin="asfd"})) + eq("Invalid key: 'builtin'", pcall_err(buffer, 'attach', b, false, {builtin="asfd"})) end) it('nvim_buf_attach returns response after delay #8634', function() diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua index d0fb26edc7..189f9d4f98 100644 --- a/test/functional/api/command_spec.lua +++ b/test/functional/api/command_spec.lua @@ -543,7 +543,7 @@ describe('nvim_create_user_command', function() end) it('does not allow invalid command names', function() - matches("'name' must begin with an uppercase letter", pcall_err(exec_lua, [[ + matches("Invalid command name %(must begin with an uppercase letter%): 'test'", pcall_err(exec_lua, [[ vim.api.nvim_create_user_command('test', 'echo "hi"', {}) ]])) diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 9902826c72..fab1557204 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -106,7 +106,7 @@ describe('API/extmarks', function() end_col = 0, end_row = 1 }) - eq("end_col value outside range", + eq("Invalid 'end_col': out of range", pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = 1, end_row = 1 })) end) @@ -1344,10 +1344,10 @@ describe('API/extmarks', function() it('throws consistent error codes', function() local ns_invalid = ns2 + 1 - eq("Invalid ns_id", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2])) - eq("Invalid ns_id", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1])) - eq("Invalid ns_id", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2])) - eq("Invalid ns_id", pcall_err(get_extmark_by_id, ns_invalid, marks[1])) + eq("Invalid ns_id: 3", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2])) + eq("Invalid ns_id: 3", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1])) + eq("Invalid ns_id: 3", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2])) + eq("Invalid ns_id: 3", pcall_err(get_extmark_by_id, ns_invalid, marks[1])) end) it('when col = line-length, set the mark on eol', function() @@ -1362,13 +1362,13 @@ describe('API/extmarks', function() it('when col = line-length, set the mark on eol', function() local invalid_col = init_text:len() + 1 - eq("col value outside range", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) + eq("Invalid 'col': out of range", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) end) it('fails when line > line_count', function() local invalid_col = init_text:len() + 1 local invalid_lnum = 3 - eq('line value outside range', pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) + eq("Invalid 'line': out of range", pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) eq({}, get_extmark_by_id(ns, marks[1])) end) diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index 7f044977cb..73551de42e 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -57,9 +57,7 @@ describe('API: highlight',function() eq(expected_rgb, nvim("get_hl_by_id", hl_id, true)) -- Test invalid id. - local err, emsg = pcall(meths.get_hl_by_id, 30000, false) - eq(false, err) - eq('Invalid highlight id: 30000', string.match(emsg, 'Invalid.*')) + eq('Invalid highlight id: 30000', pcall_err(meths.get_hl_by_id, 30000, false)) -- Test all highlight properties. command('hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,nocombine') @@ -70,22 +68,14 @@ describe('API: highlight',function() eq(expected_undercurl, nvim("get_hl_by_id", hl_id, true)) -- Test nil argument. - err, emsg = pcall(meths.get_hl_by_id, { nil }, false) - eq(false, err) eq('Wrong type for argument 1 when calling nvim_get_hl_by_id, expecting Integer', - string.match(emsg, 'Wrong.*')) + pcall_err(meths.get_hl_by_id, { nil }, false)) -- Test 0 argument. - err, emsg = pcall(meths.get_hl_by_id, 0, false) - eq(false, err) - eq('Invalid highlight id: 0', - string.match(emsg, 'Invalid.*')) + eq('Invalid highlight id: 0', pcall_err(meths.get_hl_by_id, 0, false)) -- Test -1 argument. - err, emsg = pcall(meths.get_hl_by_id, -1, false) - eq(false, err) - eq('Invalid highlight id: -1', - string.match(emsg, 'Invalid.*')) + eq('Invalid highlight id: -1', pcall_err(meths.get_hl_by_id, -1, false)) -- Test highlight group without ctermbg value. command('hi Normal ctermfg=red ctermbg=yellow') @@ -119,22 +109,16 @@ describe('API: highlight',function() eq(expected_normal, nvim("get_hl_by_name", 'Normal', true)) -- Test invalid name. - local err, emsg = pcall(meths.get_hl_by_name , 'unknown_highlight', false) - eq(false, err) - eq('Invalid highlight name: unknown_highlight', - string.match(emsg, 'Invalid.*')) + eq("Invalid highlight name: 'unknown_highlight'", + pcall_err(meths.get_hl_by_name , 'unknown_highlight', false)) -- Test nil argument. - err, emsg = pcall(meths.get_hl_by_name , { nil }, false) - eq(false, err) eq('Wrong type for argument 1 when calling nvim_get_hl_by_name, expecting String', - string.match(emsg, 'Wrong.*')) + pcall_err(meths.get_hl_by_name , { nil }, false)) -- Test empty string argument. - err, emsg = pcall(meths.get_hl_by_name , '', false) - eq(false, err) - eq('Invalid highlight name: ', - string.match(emsg, 'Invalid.*')) + eq('Invalid highlight name', + pcall_err(meths.get_hl_by_name , '', false)) -- Test "standout" attribute. #8054 eq({ underline = true, }, @@ -155,7 +139,7 @@ describe('API: highlight',function() it('nvim_get_hl_id_by_name', function() -- precondition: use a hl group that does not yet exist - eq('Invalid highlight name: Shrubbery', pcall_err(meths.get_hl_by_name, "Shrubbery", true)) + eq("Invalid highlight name: 'Shrubbery'", pcall_err(meths.get_hl_by_name, "Shrubbery", true)) eq(0, funcs.hlID("Shrubbery")) local hl_id = meths.get_hl_id_by_name("Shrubbery") @@ -253,25 +237,32 @@ describe("API: set highlight", function() before_each(clear) - it ("can set gui highlight", function() + it('validation', function() + eq("Invalid 'blend': out of range", + pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='#FF00FF', blend=999})) + eq("Invalid blend: expected Integer, got Array", + pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='#FF00FF', blend={}})) + end) + + it("can set gui highlight", function() local ns = get_ns() meths.set_hl(ns, 'Test_hl', highlight1) eq(highlight1, meths.get_hl_by_name('Test_hl', true)) end) - it ("can set cterm highlight", function() + it("can set cterm highlight", function() local ns = get_ns() meths.set_hl(ns, 'Test_hl', highlight2_config) eq(highlight2_result, meths.get_hl_by_name('Test_hl', false)) end) - it ("can set empty cterm attr", function() + it("can set empty cterm attr", function() local ns = get_ns() meths.set_hl(ns, 'Test_hl', { cterm = {} }) eq({}, meths.get_hl_by_name('Test_hl', false)) end) - it ("cterm attr defaults to gui attr", function() + it("cterm attr defaults to gui attr", function() local ns = get_ns() meths.set_hl(ns, 'Test_hl', highlight1) eq({ @@ -280,14 +271,14 @@ describe("API: set highlight", function() }, meths.get_hl_by_name('Test_hl', false)) end) - it ("can overwrite attr for cterm", function() + it("can overwrite attr for cterm", function() local ns = get_ns() meths.set_hl(ns, 'Test_hl', highlight3_config) eq(highlight3_result_gui, meths.get_hl_by_name('Test_hl', true)) eq(highlight3_result_cterm, meths.get_hl_by_name('Test_hl', false)) end) - it ("can set a highlight in the global namespace", function() + it("can set a highlight in the global namespace", function() meths.set_hl(0, 'Test_hl', highlight2_config) eq('Test_hl xxx cterm=underline,reverse ctermfg=8 ctermbg=15 gui=underline,reverse', exec_capture('highlight Test_hl')) @@ -307,7 +298,7 @@ describe("API: set highlight", function() exec_capture('highlight Test_hl3')) end) - it ("can modify a highlight in the global namespace", function() + it("can modify a highlight in the global namespace", function() meths.set_hl(0, 'Test_hl3', { bg = 'red', fg = 'blue'}) eq('Test_hl3 xxx guifg=Blue guibg=Red', exec_capture('highlight Test_hl3')) @@ -328,17 +319,17 @@ describe("API: set highlight", function() eq('Test_hl3 xxx ctermbg=9', exec_capture('highlight Test_hl3')) - eq("'redd' is not a valid color", + eq("Invalid highlight color: 'redd'", pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='redd'})) - eq("'bleu' is not a valid color", + eq("Invalid highlight color: 'bleu'", pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='bleu'})) meths.set_hl(0, 'Test_hl3', {fg='#FF00FF'}) eq('Test_hl3 xxx guifg=#ff00ff', exec_capture('highlight Test_hl3')) - eq("'#FF00FF' is not a valid color", + eq("Invalid highlight color: '#FF00FF'", pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='#FF00FF'})) for _, fg_val in ipairs{ nil, 'NONE', 'nOnE', '', -1 } do @@ -353,14 +344,14 @@ describe("API: set highlight", function() end) - it ("correctly sets 'Normal' internal properties", function() + it("correctly sets 'Normal' internal properties", function() -- Normal has some special handling internally. #18024 meths.set_hl(0, 'Normal', {fg='#000083', bg='#0000F3'}) eq({foreground = 131, background = 243}, nvim("get_hl_by_name", 'Normal', true)) end) it('does not segfault on invalid group name #20009', function() - eq('Invalid highlight name: foo bar', pcall_err(meths.set_hl, 0, 'foo bar', {bold = true})) + eq("Invalid highlight name: 'foo bar'", pcall_err(meths.set_hl, 0, 'foo bar', {bold = true})) assert_alive() end) end) diff --git a/test/functional/api/proc_spec.lua b/test/functional/api/proc_spec.lua index 2028a8fba5..315653af14 100644 --- a/test/functional/api/proc_spec.lua +++ b/test/functional/api/proc_spec.lua @@ -42,7 +42,7 @@ describe('API', function() end) end) - it('validates input', function() + it('validation', function() local status, rv = pcall(request, "nvim_get_proc_children", -1) eq(false, status) eq("Invalid pid: -1", string.match(rv, "Invalid.*")) @@ -68,7 +68,7 @@ describe('API', function() neq(pid, pinfo.ppid) end) - it('validates input', function() + it('validation', function() local status, rv = pcall(request, "nvim_get_proc", -1) eq(false, status) eq("Invalid pid: -1", string.match(rv, "Invalid.*")) diff --git a/test/functional/api/rpc_fixture.lua b/test/functional/api/rpc_fixture.lua index 94df751363..c860a6da59 100644 --- a/test/functional/api/rpc_fixture.lua +++ b/test/functional/api/rpc_fixture.lua @@ -4,9 +4,8 @@ package.path = arg[1] package.cpath = arg[2] -local mpack = require('mpack') -local StdioStream = require('nvim.stdio_stream') -local Session = require('nvim.session') +local StdioStream = require'test.client.uv_stream'.StdioStream +local Session = require'test.client.session' local stdio_stream = StdioStream.open() local session = Session.new(stdio_stream) @@ -19,7 +18,7 @@ local function on_request(method, args) return "done!" elseif method == "exit" then session:stop() - return mpack.NIL + return vim.NIL end end diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index ceff390dc5..cb273aedba 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -237,7 +237,7 @@ describe('server -> client', function() \ } ]]) meths.set_var("args", { - helpers.test_lua_prg, + nvim_prog, '-ll', 'test/functional/api/rpc_fixture.lua', package.path, package.cpath, @@ -337,6 +337,21 @@ describe('server -> client', function() eq('localhost:', string.sub(address,1,10)) connect_test(server, 'tcp', address) end) + + it('does not crash on receiving UI events', function() + local server = spawn(nvim_argv) + set_session(server) + local address = funcs.serverlist()[1] + local client = spawn(nvim_argv, false, nil, true) + set_session(client) + + local id = funcs.sockconnect('pipe', address, {rpc=true}) + funcs.rpcrequest(id, 'nvim_ui_attach', 80, 24, {}) + assert_alive() + + server:close() + client:close() + end) end) describe('connecting to its own pipe address', function() diff --git a/test/functional/api/ui_spec.lua b/test/functional/api/ui_spec.lua index 279cd1856d..5654ef31ef 100644 --- a/test/functional/api/ui_spec.lua +++ b/test/functional/api/ui_spec.lua @@ -11,17 +11,37 @@ describe('nvim_ui_attach()', function() before_each(function() clear() end) + it('handles very large width/height #2180', function() local screen = Screen.new(999, 999) screen:attach() eq(999, eval('&lines')) eq(999, eval('&columns')) end) - it('invalid option returns error', function() + + it('validation', function() eq('No such UI option: foo', pcall_err(meths.ui_attach, 80, 24, { foo={'foo'} })) - end) - it('validates channel arg', function() + + eq('Invalid ext_linegrid: expected Boolean, got Array', + pcall_err(meths.ui_attach, 80, 24, { ext_linegrid={} })) + eq('Invalid override: expected Boolean, got Array', + pcall_err(meths.ui_attach, 80, 24, { override={} })) + eq('Invalid rgb: expected Boolean, got Array', + pcall_err(meths.ui_attach, 80, 24, { rgb={} })) + eq('Invalid term_name: expected String, got Boolean', + pcall_err(meths.ui_attach, 80, 24, { term_name=true })) + eq('Invalid term_colors: expected Integer, got Boolean', + pcall_err(meths.ui_attach, 80, 24, { term_colors=true })) + eq('Invalid term_background: expected String, got Boolean', + pcall_err(meths.ui_attach, 80, 24, { term_background=true })) + eq('Invalid stdin_fd: expected Integer, got String', + pcall_err(meths.ui_attach, 80, 24, { stdin_fd='foo' })) + eq('Invalid stdin_tty: expected Boolean, got String', + pcall_err(meths.ui_attach, 80, 24, { stdin_tty='foo' })) + eq('Invalid stdout_tty: expected Boolean, got String', + pcall_err(meths.ui_attach, 80, 24, { stdout_tty='foo' })) + eq('UI not attached to channel: 1', pcall_err(request, 'nvim_ui_try_resize', 40, 10)) eq('UI not attached to channel: 1', diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 8fcdd9620b..469d8e8b6a 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -59,7 +59,7 @@ describe('API', function() -- XXX: This must be the last one, else next one will fail: -- "Packer instance already working. Use another Packer ..." - matches("can't serialize object$", + matches("can't serialize object of type .$", pcall_err(request, nil)) end) @@ -1155,7 +1155,7 @@ describe('API', function() describe('nvim_put', function() it('validates args', function() - eq('Invalid lines (expected array of strings)', + eq("Invalid line: expected String, got Integer", pcall_err(request, 'nvim_put', {42}, 'l', false, false)) eq("Invalid type: 'x'", pcall_err(request, 'nvim_put', {'foo'}, 'x', false, false)) @@ -1410,6 +1410,15 @@ describe('API', function() ok(not nvim('get_option_value', 'equalalways', {})) end) + it('validation', function() + eq("Invalid scope: expected 'local' or 'global'", + pcall_err(nvim, 'get_option_value', 'scrolloff', {scope = 'bogus'})) + eq("Invalid scope: expected 'local' or 'global'", + pcall_err(nvim, 'set_option_value', 'scrolloff', 1, {scope = 'bogus'})) + eq("Invalid scope: expected String, got Integer", + pcall_err(nvim, 'get_option_value', 'scrolloff', {scope = 42})) + end) + it('can get local values when global value is set', function() eq(0, nvim('get_option_value', 'scrolloff', {})) eq(-1, nvim('get_option_value', 'scrolloff', {scope = 'local'})) @@ -1780,9 +1789,9 @@ describe('API', function() it('validates args', function() eq("Invalid key: 'blah'", pcall_err(nvim, 'get_context', {blah={}})) - eq('invalid value for key: types', + eq("Invalid types: expected Array, got Integer", pcall_err(nvim, 'get_context', {types=42})) - eq('unexpected type: zub', + eq("Invalid type: 'zub'", pcall_err(nvim, 'get_context', {types={'jumps', 'zub', 'zam',}})) end) it('returns map of current editor state', function() @@ -2223,15 +2232,14 @@ describe('API', function() eq(5, meths.get_var('avar')) end) - it('throws error on malformed arguments', function() + it('validation', function() local req = { {'nvim_set_var', {'avar', 1}}, {'nvim_set_var'}, {'nvim_set_var', {'avar', 2}}, } - local status, err = pcall(meths.call_atomic, req) - eq(false, status) - ok(err:match('Items in calls array must be arrays of size 2') ~= nil) + eq('calls item must be a 2-item Array', + pcall_err(meths.call_atomic, req)) -- call before was done, but not after eq(1, meths.get_var('avar')) @@ -2239,18 +2247,16 @@ describe('API', function() { 'nvim_set_var', { 'bvar', { 2, 3 } } }, 12, } - status, err = pcall(meths.call_atomic, req) - eq(false, status) - ok(err:match('Items in calls array must be arrays') ~= nil) + eq("Invalid calls item: expected Array, got Integer", + pcall_err(meths.call_atomic, req)) eq({2,3}, meths.get_var('bvar')) req = { {'nvim_set_current_line', 'little line'}, {'nvim_set_var', {'avar', 3}}, } - status, err = pcall(meths.call_atomic, req) - eq(false, status) - ok(err:match('Args must be Array') ~= nil) + eq("Invalid args: expected Array, got String", + pcall_err(meths.call_atomic, req)) -- call before was done, but not after eq(1, meths.get_var('avar')) eq({''}, meths.buf_get_lines(0, 0, -1, true)) @@ -2750,7 +2756,7 @@ describe('API', function() describe('nvim_get_option_info', function() it('should error for unknown options', function() - eq("no such option: 'bogus'", pcall_err(meths.get_option_info, 'bogus')) + eq("Invalid option (not found): 'bogus'", pcall_err(meths.get_option_info, 'bogus')) end) it('should return the same options for short and long name', function() @@ -3031,10 +3037,10 @@ describe('API', function() eq(true, meths.del_mark('F')) eq({0, 0}, meths.buf_get_mark(buf, 'F')) end) - it('fails when invalid marks are used', function() - eq(false, pcall(meths.del_mark, 'f')) - eq(false, pcall(meths.del_mark, '!')) - eq(false, pcall(meths.del_mark, 'fail')) + it('validation', function() + eq("Invalid mark name (must be file/uppercase): 'f'", pcall_err(meths.del_mark, 'f')) + eq("Invalid mark name (must be file/uppercase): '!'", pcall_err(meths.del_mark, '!')) + eq("Invalid mark name (must be a single char): 'fail'", pcall_err(meths.del_mark, 'fail')) end) end) describe('nvim_get_mark', function() @@ -3048,10 +3054,10 @@ describe('API', function() assert(string.find(mark[4], "mybuf$")) eq({2, 2, buf.id, mark[4]}, mark) end) - it('fails when invalid marks are used', function() - eq(false, pcall(meths.del_mark, 'f')) - eq(false, pcall(meths.del_mark, '!')) - eq(false, pcall(meths.del_mark, 'fail')) + it('validation', function() + eq("Invalid mark name (must be file/uppercase): 'f'", pcall_err(meths.get_mark, 'f', {})) + eq("Invalid mark name (must be file/uppercase): '!'", pcall_err(meths.get_mark, '!', {})) + eq("Invalid mark name (must be a single char): 'fail'", pcall_err(meths.get_mark, 'fail', {})) end) it('returns the expected when mark is not set', function() eq(true, meths.del_mark('A')) @@ -3113,15 +3119,15 @@ describe('API', function() meths.eval_statusline('a%=b', { fillchar = '\031', maxwidth = 5 })) end) it('rejects multiple-character fillchar', function() - eq('fillchar must be a single character', + eq('Invalid fillchar: expected single character', pcall_err(meths.eval_statusline, '', { fillchar = 'aa' })) end) it('rejects empty string fillchar', function() - eq('fillchar must be a single character', + eq('Invalid fillchar: expected single character', pcall_err(meths.eval_statusline, '', { fillchar = '' })) end) it('rejects non-string fillchar', function() - eq('fillchar must be a single character', + eq("Invalid fillchar: expected String, got Integer", pcall_err(meths.eval_statusline, '', { fillchar = 1 })) end) it('rejects invalid string', function() diff --git a/test/functional/core/exit_spec.lua b/test/functional/core/exit_spec.lua index 05a69e1992..dc4b45b4d9 100644 --- a/test/functional/core/exit_spec.lua +++ b/test/functional/core/exit_spec.lua @@ -25,30 +25,34 @@ describe('v:exiting', function() eq(1, eval('v:exiting is v:null')) end) - it('is 0 on normal exit', function() + local function test_exiting(setup_fn) local function on_setup() - command('autocmd VimLeavePre * call rpcrequest('..cid..', "")') - command('autocmd VimLeave * call rpcrequest('..cid..', "")') - command('quit') + command('autocmd VimLeavePre * call rpcrequest('..cid..', "exit", "VimLeavePre")') + command('autocmd VimLeave * call rpcrequest('..cid..', "exit", "VimLeave")') + setup_fn() end - local function on_request() + local requests_args = {} + local function on_request(name, args) + eq('exit', name) + table.insert(requests_args, args) eq(0, eval('v:exiting')) return '' end run(on_request, nil, on_setup) + eq({{'VimLeavePre'}, {'VimLeave'}}, requests_args) + end + + it('is 0 on normal exit', function() + test_exiting(function() + command('quit') + end) end) + it('is 0 on exit from Ex mode involving try-catch vim-patch:8.0.0184', function() - local function on_setup() - command('autocmd VimLeavePre * call rpcrequest('..cid..', "")') - command('autocmd VimLeave * call rpcrequest('..cid..', "")') + test_exiting(function() feed('gQ') feed_command('try', 'call NoFunction()', 'catch', 'echo "bye"', 'endtry', 'quit') - end - local function on_request() - eq(0, eval('v:exiting')) - return '' - end - run(on_request, nil, on_setup) + end) end) end) diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua index 5f87c3cdd9..19611429e0 100644 --- a/test/functional/ex_cmds/oldfiles_spec.lua +++ b/test/functional/ex_cmds/oldfiles_spec.lua @@ -2,6 +2,8 @@ local Screen = require('test.functional.ui.screen') local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear +local command = helpers.command +local expect_exit = helpers.expect_exit local buf, eq, feed_command = helpers.curbufmeths, helpers.eq, helpers.feed_command local feed, poke_eventloop = helpers.feed, helpers.poke_eventloop local ok = helpers.ok @@ -19,6 +21,7 @@ describe(':oldfiles', function() before_each(_clear) after_each(function() + expect_exit(command, 'qall!') os.remove(shada_file) end) @@ -42,6 +45,7 @@ describe(':oldfiles', function() | Press ENTER or type command to continue^ | ]]) + feed('<CR>') end) it('can be filtered with :filter', function() @@ -107,6 +111,7 @@ describe(':browse oldfiles', function() end) after_each(function() + expect_exit(command, 'qall!') os.remove(shada_file) end) diff --git a/test/functional/ex_cmds/profile_spec.lua b/test/functional/ex_cmds/profile_spec.lua index 2b92f8d0de..bf045a4d1d 100644 --- a/test/functional/ex_cmds/profile_spec.lua +++ b/test/functional/ex_cmds/profile_spec.lua @@ -30,6 +30,7 @@ describe(':profile', function() before_each(helpers.clear) after_each(function() + helpers.expect_exit(command, 'qall!') if lfs.attributes(tempfile, 'uid') ~= nil then os.remove(tempfile) end diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua index 8eed00c973..ad59025d47 100644 --- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua +++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua @@ -13,6 +13,7 @@ local nvim_prog = helpers.nvim_prog local ok = helpers.ok local rmdir = helpers.rmdir local new_argv = helpers.new_argv +local new_pipename = helpers.new_pipename local pesc = helpers.pesc local os_kill = helpers.os_kill local set_session = helpers.set_session @@ -37,10 +38,21 @@ describe(':recover', function() end) -describe(':preserve', function() +describe("preserve and (R)ecover with custom 'directory'", function() local swapdir = lfs.currentdir()..'/Xtest_recover_dir' + local testfile = 'Xtest_recover_file1' + -- Put swapdir at the start of the 'directory' list. #1836 + -- Note: `set swapfile` *must* go after `set directory`: otherwise it may + -- attempt to create a swapfile in different directory. + local init = [[ + set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[// + set swapfile fileformat=unix undolevels=-1 + ]] + + local nvim1 before_each(function() - clear() + nvim1 = spawn(new_argv()) + set_session(nvim1) rmdir(swapdir) lfs.mkdir(swapdir) end) @@ -49,25 +61,15 @@ describe(':preserve', function() rmdir(swapdir) end) - it("saves to custom 'directory' and (R)ecovers #1836", function() - local testfile = 'Xtest_recover_file1' - -- Put swapdir at the start of the 'directory' list. #1836 - -- Note: `set swapfile` *must* go after `set directory`: otherwise it may - -- attempt to create a swapfile in different directory. - local init = [[ - set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[// - set swapfile fileformat=unix undolevels=-1 - ]] - + local function setup_swapname() exec(init) command('edit! '..testfile) feed('isometext<esc>') - command('preserve') exec('redir => g:swapname | silent swapname | redir END') + return eval('g:swapname') + end - local swappath1 = eval('g:swapname') - - os_kill(eval('getpid()')) + local function test_recover(swappath1) -- Start another Nvim instance. local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'}, true) @@ -90,6 +92,35 @@ describe(':preserve', function() -- Verify that :swapname was not truncated (:help 'shortmess'). ok(nil == string.find(swappath1, '%.%.%.')) ok(nil == string.find(swappath2, '%.%.%.')) + end + + it('with :preserve and SIGKILL', function() + local swappath1 = setup_swapname() + command('preserve') + os_kill(eval('getpid()')) + test_recover(swappath1) + end) + + it('closing stdio channel without :preserve #22096', function() + local swappath1 = setup_swapname() + nvim1:close() + test_recover(swappath1) + end) + + it('killing TUI process without :preserve #22096', function() + helpers.skip(helpers.is_os('win')) + local screen = Screen.new() + screen:attach() + local child_server = new_pipename() + funcs.termopen({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--listen', child_server}) + screen:expect({any = pesc('[No Name]')}) -- Wait for the child process to start. + local child_session = helpers.connect(child_server) + set_session(child_session) + local swappath1 = setup_swapname() + set_session(nvim1) + command('call chanclose(&channel)') -- Kill the child process. + screen:expect({any = pesc('[Process exited 1]')}) -- Wait for the child process to stop. + test_recover(swappath1) end) end) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 6400db9f87..cd6b535477 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -1,14 +1,11 @@ -require('coxpcall') local luv = require('luv') local lfs = require('lfs') -local mpack = require('mpack') local global_helpers = require('test.helpers') --- nvim client: Found in .deps/usr/share/lua/<version>/nvim/ if "bundled". -local Session = require('nvim.session') -local TcpStream = require('nvim.tcp_stream') -local SocketStream = require('nvim.socket_stream') -local ChildProcessStream = require('nvim.child_process_stream') +local Session = require('test.client.session') +local uv_stream = require('test.client.uv_stream') +local SocketStream = uv_stream.SocketStream +local ChildProcessStream = uv_stream.ChildProcessStream local check_cores = global_helpers.check_cores local check_logs = global_helpers.check_logs @@ -23,7 +20,6 @@ local tbl_contains = global_helpers.tbl_contains local fail = global_helpers.fail local module = { - NIL = mpack.NIL, mkdir = lfs.mkdir, } @@ -202,7 +198,7 @@ function module.expect_msg_seq(...) end local function call_and_stop_on_error(lsession, ...) - local status, result = copcall(...) -- luacheck: ignore + local status, result = Session.safe_pcall(...) -- luacheck: ignore if not status then lsession:stop() last_error = result @@ -428,7 +424,7 @@ end -- Creates a new Session connected by domain socket (named pipe) or TCP. function module.connect(file_or_address) local addr, port = string.match(file_or_address, "(.*):(%d+)") - local stream = (addr and port) and TcpStream.open(addr, port) or + local stream = (addr and port) and SocketStream.connect(addr, port) or SocketStream.open(file_or_address) return Session.new(stream) end diff --git a/test/functional/legacy/move_spec.lua b/test/functional/legacy/move_spec.lua new file mode 100644 index 0000000000..855996da8f --- /dev/null +++ b/test/functional/legacy/move_spec.lua @@ -0,0 +1,49 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local clear = helpers.clear +local feed = helpers.feed +local funcs = helpers.funcs + +before_each(clear) + +describe(':move', function() + -- oldtest: Test_move_undo() + it('redraws correctly when undone', function() + local screen = Screen.new(60, 10) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + }) + screen:attach() + + funcs.setline(1, {'First', 'Second', 'Third', 'Fourth'}) + feed('gg:move +1<CR>') + screen:expect([[ + Second | + ^First | + Third | + Fourth | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + :move +1 | + ]]) + + -- here the display would show the last few lines scrolled down + feed('u') + feed(':<Esc>') + screen:expect([[ + ^First | + Second | + Third | + Fourth | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end) +end) diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index 03832978a4..dc6452dd62 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -33,7 +33,7 @@ describe('luaeval(vim.api.…)', function() describe('with errors', function() it('transforms API error from nvim_buf_set_lines into lua error', function() funcs.setline(1, {"abc", "def", "a\nb", "ttt"}) - eq({false, 'String cannot contain newlines'}, + eq({false, "'replacement string' item contains newlines"}, funcs.luaeval('{pcall(vim.api.nvim_buf_set_lines, 1, 1, 2, false, {"b\\na"})}')) end) diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index 2a7be53164..add69235b6 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -94,6 +94,26 @@ describe('vim.filetype', function() return vim.filetype.match({ buf = 0 }) ]]) end) + + it('works with contents #22180', function() + eq('sh', exec_lua [[ + -- Needs to be set so detect#sh doesn't fail + vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$' + return vim.filetype.match({ contents = { '#!/usr/bin/env bash' } }) + ]]) + end) + + it('considers extension mappings when matching from hashbang', function() + eq('fooscript', exec_lua [[ + vim.filetype.add({ + extension = { + foo = 'fooscript', + } + }) + return vim.filetype.match({ contents = { '#!/usr/bin/env foo' } }) + ]]) + end) + end) describe('filetype.lua', function() diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 867f366d06..b43e5b28db 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1458,7 +1458,7 @@ describe('lua stdlib', function() ]] eq('', funcs.luaeval "vim.bo.filetype") eq(true, funcs.luaeval "vim.bo[BUF].modifiable") - matches("no such option: 'nosuchopt'$", + matches("Invalid option %(not found%): 'nosuchopt'$", pcall_err(exec_lua, 'return vim.bo.nosuchopt')) matches("Expected lua string$", pcall_err(exec_lua, 'return vim.bo[0][0].autoread')) @@ -1479,7 +1479,7 @@ describe('lua stdlib', function() eq(0, funcs.luaeval "vim.wo.cole") eq(0, funcs.luaeval "vim.wo[0].cole") eq(0, funcs.luaeval "vim.wo[1001].cole") - matches("no such option: 'notanopt'$", + matches("Invalid option %(not found%): 'notanopt'$", pcall_err(exec_lua, 'return vim.wo.notanopt')) matches("Expected lua string$", pcall_err(exec_lua, 'return vim.wo[0][0].list')) diff --git a/test/functional/shada/helpers.lua b/test/functional/shada/helpers.lua index fb3ec4a87c..cd99d38345 100644 --- a/test/functional/shada/helpers.lua +++ b/test/functional/shada/helpers.lua @@ -33,6 +33,7 @@ local function reset(o) end local clear = function() + helpers.expect_exit(helpers.command, 'qall!') os.remove(tmpname) end diff --git a/test/functional/shada/history_spec.lua b/test/functional/shada/history_spec.lua index d1daf6c7cc..aa4106ad63 100644 --- a/test/functional/shada/history_spec.lua +++ b/test/functional/shada/history_spec.lua @@ -32,7 +32,6 @@ describe('ShaDa support code', function() nvim_command('rshada') eq('" Test 2', funcs.histget(':', -1)) eq('" Test', funcs.histget(':', -2)) - expect_exit(nvim_command, 'qall') end) it('respects &history when dumping', diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua index 88a99d9b55..24bd363e95 100644 --- a/test/functional/shada/shada_spec.lua +++ b/test/functional/shada/shada_spec.lua @@ -126,34 +126,16 @@ describe('ShaDa support code', function() wshada(s .. table.concat(msgpack, e .. s) .. e) eq(0, exc_exec('wshada ' .. shada_fname)) local found = 0 - local typ = mpack.unpack(s) + local typ = mpack.decode(s) for _, v in ipairs(read_shada_file(shada_fname)) do if v.type == typ then found = found + 1 - eq(mpack.unpack(msgpack[found]), v.timestamp) + eq(mpack.decode(msgpack[found]), v.timestamp) end end eq(#msgpack, found) end) - it('does not write NONE file', function() - local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', - '--headless', '--cmd', 'qall'}, true) - session:close() - eq(nil, lfs.attributes('NONE')) - eq(nil, lfs.attributes('NONE.tmp.a')) - end) - - it('does not read NONE file', function() - write_file('NONE', '\005\001\015\131\161na\162rX\194\162rc\145\196\001-') - local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', - '--headless'}, true) - set_session(session) - eq('', funcs.getreg('a')) - session:close() - os.remove('NONE') - end) - local marklike = {[7]=true, [8]=true, [10]=true, [11]=true} local find_file = function(fname) local found = {} @@ -263,3 +245,23 @@ describe('ShaDa support code', function() meths.set_option('shada', '') end) end) + +describe('ShaDa support code', function() + it('does not write NONE file', function() + local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', + '--headless', '--cmd', 'qall'}, true) + session:close() + eq(nil, lfs.attributes('NONE')) + eq(nil, lfs.attributes('NONE.tmp.a')) + end) + + it('does not read NONE file', function() + write_file('NONE', '\005\001\015\131\161na\162rX\194\162rc\145\196\001-') + local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', + '--headless'}, true) + set_session(session) + eq('', funcs.getreg('a')) + session:close() + os.remove('NONE') + end) +end) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 1d9e7b8e11..4e62354ed8 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -2365,18 +2365,18 @@ describe("TUI as a client", function() set_session(client_super) local screen_client = thelpers.screen_setup(0, - string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=], + string.format([=[["%s", "--server", "%s", "--remote-ui"]]=], nvim_prog, server_pipe)) - screen_client:expect{grid=[[ - Hello, Worl{1:d} | - {4:~ }| - {4:~ }| - {4:~ }| - {5:[No Name] [+] }| - | - {3:-- TERMINAL --} | - ]]} + screen_client:expect{grid=[[ + Hello, Worl{1:d} | + {4:~ }| + {4:~ }| + {4:~ }| + {5:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]} feed_data(":q!\n") @@ -2394,7 +2394,7 @@ describe("TUI as a client", function() set_session(client_super) local screen = thelpers.screen_setup(0, - string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=], + string.format([=[["%s", "--server", "%s", "--remote-ui"]]=], nvim_prog, server_pipe)) screen:expect{grid=[[ @@ -2407,15 +2407,24 @@ describe("TUI as a client", function() {3:-- TERMINAL --} | ]]} + -- No heap-use-after-free when receiving UI events after deadly signal #22184 + server:request('nvim_input', ('a'):rep(1000)) + exec_lua([[vim.loop.kill(vim.fn.jobpid(vim.bo.channel), 'sigterm')]]) + screen:expect({any = '%[Process exited 1%]'}) + + eq(0, meths.get_vvar('shell_error')) + -- exits on input eof #22244 + funcs.system({nvim_prog, '--server', server_pipe, '--remote-ui'}) + eq(1, meths.get_vvar('shell_error')) + client_super:close() server:close() end) - it("throws error when no server exists", function() clear() local screen = thelpers.screen_setup(0, - string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "127.0.0.1:2436546", "--remote-ui"]]=], + string.format([=[["%s", "--server", "127.0.0.1:2436546", "--remote-ui"]]=], nvim_prog), 60) screen:expect([[ @@ -2462,7 +2471,7 @@ describe("TUI as a client", function() set_session(client_super) local screen_client = thelpers.screen_setup(0, - string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=], + string.format([=[["%s", "--server", "%s", "--remote-ui"]]=], nvim_prog, server_pipe)) screen_client:expect{grid=[[ diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index df45c9b384..51d8eb62f3 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -82,7 +82,7 @@ describe('treesitter language API', function() command("set filetype=borklang") -- Should throw an error when filetype changes to borklang eq(".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", - pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0)")) + pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0, 'borklang')")) end) it('retrieve the tree given a range', function () diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index f006ad4539..2d0d57fbd0 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -277,6 +277,9 @@ end]] function fake_node:end_() return 3, 0, 23 end + function fake_node:range() + return 3, 0, 3, 0 + end return vim.treesitter.get_node_text(fake_node, 0) == nil ]]) eq(true, result) @@ -296,6 +299,9 @@ end]] function fake_node:end_() return 1, 0, 7 end + function fake_node:range() + return 1, 0, 1, 0 + end return vim.treesitter.get_node_text(fake_node, 0) == '' ]]) eq(true, result) @@ -728,7 +734,7 @@ int x = INT_MAX; return list ]] - eq({ 'offset!', 'set!' }, res_list) + eq({ 'gsub!', 'offset!', 'set!' }, res_list) end) end) end) diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index 46bfae8de2..76baf2cddb 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -751,8 +751,8 @@ describe('Buffer highlighting', function() it('validates contents', function() -- this used to leak memory - eq('Chunk is not an array', pcall_err(set_virtual_text, id1, 0, {"texty"}, {})) - eq('Chunk is not an array', pcall_err(set_virtual_text, id1, 0, {{"very"}, "texty"}, {})) + eq('Invalid chunk: expected Array, got String', pcall_err(set_virtual_text, id1, 0, {"texty"}, {})) + eq('Invalid chunk: expected Array, got String', pcall_err(set_virtual_text, id1, 0, {{"very"}, "texty"}, {})) end) it('can be retrieved', function() diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 489c33d8b1..6ed32a8cd4 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -2109,6 +2109,20 @@ l5 | ]]} end) + + it('does not set signcolumn for signs without text', function() + screen:try_resize(20, 3) + meths.win_set_option(0, 'signcolumn', 'auto') + insert(example_text) + feed 'gg' + meths.buf_set_extmark(0, ns, 0, -1, {number_hl_group='Error'}) + screen:expect{grid=[[ + ^l1 | + l2 | + | + ]]} + end) + end) describe('decorations: virt_text', function() diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index 46a478c1ea..420a4654f8 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -10,6 +10,7 @@ local meths = helpers.meths local exec = helpers.exec local exec_lua = helpers.exec_lua local assert_alive = helpers.assert_alive +local poke_eventloop = helpers.poke_eventloop local content1 = [[ @@ -90,10 +91,10 @@ describe("folded lines", function() end) it("highlights with CursorLineFold when 'cursorline' is set", function() - command("set cursorline foldcolumn=2 foldmethod=marker") + command("set number cursorline foldcolumn=2") command("hi link CursorLineFold Search") insert(content1) - feed("zf3j") + feed("ggzf3jj") if multigrid then screen:expect([[ ## grid 1 @@ -106,26 +107,26 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {7: }in his cave. | - {6: }{12:^ }| + {7:+ }{8: 1 }{5:+-- 4 lines: This is a················}| + {6: }{9: 5 }{12:^in his cave. }| + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| {1:~ }| ## grid 3 | ]]) else screen:expect([[ - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {7: }in his cave. | - {6: }{12:^ }| - {1:~ }| - | + {7:+ }{8: 1 }{5:+-- 4 lines: This is a················}| + {6: }{9: 5 }{12:^in his cave. }| + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | ]]) end feed("k") @@ -141,28 +142,36 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {6: }{12:^in his cave. }| - {7: } | + {6:+ }{9: 1 }{12:^+-- 4 lines: This is a················}| + {7: }{8: 5 }in his cave. | + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| {1:~ }| ## grid 3 | ]]) else screen:expect([[ - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {6: }{12:^in his cave. }| - {7: } | - {1:~ }| - | + {6:+ }{9: 1 }{12:^+-- 4 lines: This is a················}| + {7: }{8: 5 }in his cave. | + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | ]]) end + -- CursorLine is applied correctly with screenrow motions #22232 + feed("jgk") + poke_eventloop() + screen:expect_unchanged() + -- CursorLine is applied correctly when closing a fold when cursor is not at fold start + feed("zo4Gzc") + poke_eventloop() + screen:expect_unchanged() command("set cursorlineopt=line") if multigrid then screen:expect([[ @@ -176,26 +185,61 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {7: }{12:^in his cave. }| - {7: } | + {7:+ }{8: 1 }{12:^+-- 4 lines: This is a················}| + {7: }{8: 5 }in his cave. | + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| {1:~ }| ## grid 3 | ]]) else screen:expect([[ - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {7: }{12:^in his cave. }| - {7: } | - {1:~ }| - | + {7:+ }{8: 1 }{12:^+-- 4 lines: This is a················}| + {7: }{8: 5 }in his cave. | + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end + command("set relativenumber cursorlineopt=number") + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {6:+ }{9:1 }{5:^+-- 4 lines: This is a················}| + {7: }{8: 1 }in his cave. | + {7: }{8: 2 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]]) + else + screen:expect([[ + {6:+ }{9:1 }{5:^+-- 4 lines: This is a················}| + {7: }{8: 1 }in his cave. | + {7: }{8: 2 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | ]]) end end) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 3b9cce0e6f..a059fb5b89 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -214,7 +214,7 @@ function Screen:attach(options, session) -- simplify test code by doing the same. self._options.rgb = true end - if self._options.ext_multigrid or self._options.ext_float then + if self._options.ext_multigrid then self._options.ext_linegrid = true end end diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 3bd2289a73..439021ad87 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -61,6 +61,7 @@ local function screen_tests(linegrid) [5] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Fuchsia}, [6] = {bold = true, foreground = Screen.colors.Fuchsia}, [7] = {bold = true, foreground = Screen.colors.SeaGreen}, + [8] = {foreground = Screen.colors.White, background = Screen.colors.Red}, } ) end) @@ -866,12 +867,9 @@ local function screen_tests(linegrid) end) describe('resize', function() - before_each(function() + it('rebuilds the whole screen', function() screen:try_resize(25, 5) feed('iresize') - end) - - it('rebuilds the whole screen', function() screen:expect([[ resize^ | {0:~ }| @@ -882,6 +880,7 @@ local function screen_tests(linegrid) end) it('has minimum width/height values', function() + feed('iresize') screen:try_resize(1, 1) screen:expect([[ resize^ | @@ -896,7 +895,8 @@ local function screen_tests(linegrid) end) it('VimResized autocommand does not cause invalid UI events #20692 #20759', function() - feed('<Esc>') + screen:try_resize(25, 5) + feed('iresize<Esc>') command([[autocmd VimResized * redrawtabline]]) command([[autocmd VimResized * lua vim.api.nvim_echo({ { 'Hello' } }, false, {})]]) command([[autocmd VimResized * let g:echospace = v:echospace]]) @@ -919,6 +919,77 @@ local function screen_tests(linegrid) ]]) eq(29, meths.get_var('echospace')) end) + + it('messages from the same Ex command as resize are visible #22225', function() + feed(':set columns=20 | call<CR>') + screen:expect([[ + | + | + | + | + | + | + | + | + | + {1: }| + {8:E471: Argument requi}| + {8:red} | + {7:Press ENTER or type }| + {7:command to continue}^ | + ]]) + feed('<CR>') + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + feed(':set columns=0<CR>') + screen:expect([[ + | + | + | + | + | + {1: }| + {8:E594: Need a}| + {8:t least 12 c}| + {8:olumns: colu}| + {8:mns=0} | + {7:Press ENTER }| + {7:or type comm}| + {7:and to conti}| + {7:nue}^ | + ]]) + feed('<CR>') + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end) end) describe('press enter', function() diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index 18bbb56a61..404cc6d043 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -10,7 +10,6 @@ local testprg = helpers.testprg describe('search highlighting', function() local screen - local colors = Screen.colors before_each(function() clear() @@ -18,9 +17,9 @@ describe('search highlighting', function() screen:attach() screen:set_default_attr_ids( { [1] = {bold=true, foreground=Screen.colors.Blue}, - [2] = {background = colors.Yellow}, -- Search + [2] = {background = Screen.colors.Yellow}, -- Search [3] = {reverse = true}, - [4] = {foreground = colors.Red}, -- Message + [4] = {foreground = Screen.colors.Red}, -- Message [6] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGrey}, -- Folded }) end) @@ -498,6 +497,20 @@ describe('search highlighting', function() {1:~ }│{1:~ }| //^ | ]]) + feed('<Esc>') + + -- incsearch works after c_CTRL-R_CTRL-R + command('let @" = "file"') + feed('/<C-R><C-R>"') + screen:expect([[ + the first line │the first line | + in a little {3:file} │in a little {2:file} | + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + /file^ | + ]]) end) it('works with incsearch and offset', function() @@ -572,12 +585,12 @@ describe('search highlighting', function() it('works with matchadd and syntax', function() screen:set_default_attr_ids { [1] = {bold=true, foreground=Screen.colors.Blue}; - [2] = {background = colors.Yellow}; + [2] = {background = Screen.colors.Yellow}; [3] = {reverse = true}; - [4] = {foreground = colors.Red}; - [5] = {bold = true, background = colors.Green}; - [6] = {italic = true, background = colors.Magenta}; - [7] = {bold = true, background = colors.Yellow}; + [4] = {foreground = Screen.colors.Red}; + [5] = {bold = true, background = Screen.colors.Green}; + [6] = {italic = true, background = Screen.colors.Magenta}; + [7] = {bold = true, background = Screen.colors.Yellow}; [8] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGray}; } feed_command('set hlsearch') diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index 3233e6cd19..287686cf37 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -456,7 +456,7 @@ describe('statuscolumn', function() 14 aaaaa | | ]]) - command('set stc=') -- also for the default sign column + command('set stc=') -- also for the default fold column screen:expect_unchanged() -- 'statuscolumn' is not too wide with custom (bogus) fold column command([[set stc=%{foldlevel(v:lnum)>0?repeat('-',foldlevel(v:lnum)):''}%=%l\ ]]) diff --git a/test/helpers.lua b/test/helpers.lua index 82ff23bef8..d45536b42b 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -1,5 +1,5 @@ require('test.compat') -local shared = require('vim.shared') +local shared = vim local assert = require('luassert') local busted = require('busted') local luv = require('luv') |